Prusa Slicer 2.6.0
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

class  AGGRaster
 
struct  Anchor
 
struct  Ball
 
struct  Beam_
 
struct  BeamSamples
 
struct  BeamSamples< DefaultWideningModel >
 
class  BoxIndex
 
class  BranchingTreeBuilder
 
struct  Bridge
 
struct  Colors
 
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...
 
class  DefaultSupportTree
 
struct  DefaultWideningModel
 
struct  DiffBridge
 
struct  DivFace
 
struct  DrainHole
 
class  EncodedRaster
 
struct  FaceHash
 
struct  GroundConnection
 
struct  Head
 
struct  HollowingConfig
 
struct  Interior
 
struct  InteriorDeleter
 
struct  JobController
 A Control structure for the support calculation. Consists of the status indicator callback and the stop condition predicate. More...
 
struct  Junction
 
struct  PadConfig
 
struct  Pedestal
 
struct  Pillar
 
class  PillarIndex
 
struct  PixelDim
 Types that represents the dimension of a pixel in millimeters. More...
 
struct  PNGRasterEncoder
 
class  PointIndex
 
class  PointRing
 
struct  PPMRasterEncoder
 
class  RasterBase
 
class  RasterGrayscaleAA
 
class  RasterGrayscaleAAGammaPower
 
struct  Resolution
 Type that represents a resolution in pixels. More...
 
struct  RotfinderBoilerplate
 
class  RotOptimizeParams
 
struct  SupportableMesh
 
struct  SupportPoint
 
class  SupportPointGenerator
 
class  SupportTreeBuilder
 
struct  SupportTreeConfig
 
struct  SupportTreeNode
 
struct  TriangleBubble
 

Typedefs

using _RasterGrayscaleAA = AGGRaster< agg::pixfmt_gray8, agg::renderer_scanline_aa_solid >
 
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 InteriorPtr = std::unique_ptr< Interior, InteriorDeleter >
 
using DrainHoles = std::vector< DrainHole >
 
using RasterEncoder = std::function< EncodedRaster(const void *ptr, size_t w, size_t h, size_t num_components)>
 
using RotOptimizeStatusCB = std::function< bool(int)>
 
typedef Eigen::Matrix< double, 3, 1, Eigen::DontAlignVec3d
 
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 Hit = AABBMesh::hit_result
 
using Beam = Beam_<>
 

Enumerations

enum  { NEW_FACE = -1 }
 
enum  HollowingFlags { hfRemoveInsideTriangles = 0x1 }
 
enum class  HollowMeshResult { Ok = 0 , FaultyMesh = 1 , FaultyHoles = 2 , DrillingFailed = 4 }
 
enum class  PointsStatus { NoPoints , Generating , AutoGenerated , UserModified }
 
enum class  MeshType { Support , Pad }
 
enum class  SupportTreeType { Default , Branching , Organic }
 
enum class  PillarConnectionMode { zigzag , cross , dynamic }
 
enum class  GroundRouteCheck { Full , PillarOnly }
 

Functions

static std::optional< Vec3fget_avoidance (const GroundConnection &conn, float maxdist)
 
void build_pillars (SupportTreeBuilder &builder, BranchingTreeBuilder &vbuilder, const SupportableMesh &sm)
 
void create_branching_tree (SupportTreeBuilder &builder, const SupportableMesh &sm)
 
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)
 
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)
 
void create_default_tree (SupportTreeBuilder &builder, const SupportableMesh &sm)
 
indexed_triangle_setget_mesh (Interior &interior)
 
const indexed_triangle_setget_mesh (const Interior &interior)
 
const VoxelGridget_grid (const Interior &interior)
 
VoxelGridget_grid (Interior &interior)
 
InteriorPtr generate_interior (const VoxelGrid &vgrid, 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)
 
void hollow_mesh (indexed_triangle_set &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 T >
FloatingOnly< T > get_distance (const Vec< 3, T > &p, const Interior &interior)
 
template<class Fn >
void divide_triangle (const DivFace &face, Fn &&visitor)
 
void remove_inside_triangles (indexed_triangle_set &mesh, const Interior &interior, const std::vector< bool > &exclude_mask)
 
void remove_inside_triangles (TriangleMesh &mesh, const Interior &interior, const std::vector< bool > &exclude_mask)
 
static void exclude_neighbors (const Vec3i &face, std::vector< bool > &mask, const indexed_triangle_set &its, const VertexFaceIndex &index, size_t recursions)
 
std::vector< bool > create_exclude_mask (const indexed_triangle_set &its, const Interior &interior, const std::vector< DrainHole > &holes)
 
DrainHoles transformed_drainhole_points (const ModelObject &mo, const Transform3d &trafo)
 
double get_voxel_scale (double mesh_volume, const HollowingConfig &hc)
 
static indexed_triangle_set remove_unconnected_vertices (const indexed_triangle_set &its)
 
int hollow_mesh_and_drill (indexed_triangle_set &hollowed_mesh, const Interior &interior, const DrainHoles &drainholes, std::function< void(size_t)> on_hole_fail)
 
InteriorPtr generate_interior (const indexed_triangle_set &mesh, const HollowingConfig &hc={}, const JobController &ctl={})
 
template<class Cont >
double csgmesh_positive_maxvolume (const Cont &csg)
 
template<class It >
InteriorPtr generate_interior (const Range< It > &csgparts, const HollowingConfig &hc={}, const JobController &ctl={})
 
void hollow_mesh (indexed_triangle_set &mesh, const HollowingConfig &cfg, int flags=0)
 
void swap_normals (indexed_triangle_set &its)
 
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< RasterBasecreate_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, Vec2i 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 AABBMesh &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)
 
SupportPoints transformed_support_points (const ModelObject &mo, const Transform3d &trafo)
 
static std::vector< SupportPointGenerator::MyLayermake_layers (const std::vector< ExPolygons > &slices, const std::vector< float > &heights, std::function< void(void)> throw_on_cancel)
 
std::vector< Vec2fsample_expolygon (const ExPolygon &expoly, float samples_per_mm2, std::mt19937 &rng)
 
std::vector< Vec2fsample_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< Vec2fsample_expolygon_with_boundary (const ExPolygon &expoly, float samples_per_mm2, float samples_per_mm_boundary, std::mt19937 &rng)
 
std::vector< Vec2fsample_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< Vec2fpoisson_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)
 
indexed_triangle_set create_support_tree (const SupportableMesh &sm, const JobController &ctl)
 
indexed_triangle_set create_pad (const SupportableMesh &sm, const indexed_triangle_set &support_mesh, const JobController &ctl)
 
std::vector< ExPolygonsslice (const indexed_triangle_set &sup_mesh, const indexed_triangle_set &pad_mesh, const std::vector< float > &grid, float cr, const JobController &ctl)
 
double ground_level (const SupportableMesh &sm)
 
template<class T , int I>
distance (const Vec< I, T > &p)
 
template<class T , int I>
distance (const Vec< I, T > &pp1, const Vec< I, T > &pp2)
 
indexed_triangle_set sphere (double rho, Portion portion, double fa)
 
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)
 
indexed_triangle_set get_mesh (const Head &h, 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)
 
Portion make_portion (double a, double b)
 
indexed_triangle_set cylinder (double r, double h, size_t steps=45)
 
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)
 
template<class T , int N>
Vec< N, T > dirv (const Vec< N, T > &startp, const Vec< N, T > &endp)
 
template<class It >
Hit min_hit (It from, It to)
 
StopCriteria get_criteria (const SupportTreeConfig &cfg)
 
template<class Ex , size_t RayCount = Beam::SAMPLES>
Hit beam_mesh_hit (Ex policy, const AABBMesh &mesh, const Beam_< RayCount > &beam, double sd)
 
template<class Ex >
Hit pinhead_mesh_hit (Ex ex, const AABBMesh &mesh, const Vec3d &s, const Vec3d &dir, double r_pin, double r_back, double width, double sd)
 
template<class Ex >
Hit pinhead_mesh_hit (Ex ex, const AABBMesh &mesh, const Head &head, double safety_d)
 
double distance (const SupportPoint &a, const SupportPoint &b)
 
template<class PtIndex >
std::vector< size_t > non_duplicate_suppt_indices (const PtIndex &index, const SupportPoints &suppts, double eps)
 
template<class Ex >
bool optimize_pinhead_placement (Ex policy, const SupportableMesh &m, Head &head)
 
template<class Ex >
std::optional< Headcalculate_pinhead_placement (Ex policy, const SupportableMesh &sm, size_t suppt_idx)
 
long build_ground_connection (SupportTreeBuilder &builder, const SupportableMesh &sm, const GroundConnection &conn)
 
template<class Ex , class WideningFn , class = std::enable_if_t<IsWideningFn<WideningFn>>>
Vec3d check_ground_route (Ex policy, const SupportableMesh &sm, const Junction &source, const Vec3d &dir, double bridge_len, WideningFn &&wideningfn, GroundRouteCheck type=GroundRouteCheck::Full)
 
template<class Ex , class WideningFn , class = std::enable_if_t<IsWideningFn<WideningFn>>>
GroundConnection deepsearch_ground_connection (Ex policy, const SupportableMesh &sm, const Junction &source, WideningFn &&wideningfn, const Vec3d &init_dir=DOWN)
 
template<class Ex >
GroundConnection deepsearch_ground_connection (Ex policy, const SupportableMesh &sm, const Junction &source, double end_radius, const Vec3d &init_dir=DOWN)
 
template<class Ex >
GroundConnection deepsearch_ground_connection (Ex policy, const SupportableMesh &sm, const Junction &source, const Vec3d &init_dir=DOWN)
 
template<class Ex >
bool optimize_anchor_placement (Ex policy, const SupportableMesh &sm, const Junction &from, Anchor &anchor)
 
template<class Ex >
std::optional< Anchorcalculate_anchor_placement (Ex policy, const SupportableMesh &sm, const Junction &from, const Vec3d &to_hint)
 
bool is_outside_support_cone (const Vec3f &supp, const Vec3f &pt, float angle)
 
std::optional< Vec3ffind_merge_pt (const Vec3f &A, const Vec3f &B, float critical_angle)
 
template<class I , class DoubleI = IntegerOnly<I>>
IntegerOnly< DoubleI > pairhash (I a, I b)
 
template<class Ex >
std::optional< DiffBridgesearch_widening_path (Ex policy, const SupportableMesh &sm, const Vec3d &jp, const Vec3d &dir, double radius, double new_radius)
 
template<class Ex >
std::pair< bool, longcreate_ground_pillar (Ex policy, SupportTreeBuilder &builder, const SupportableMesh &sm, const Vec3d &pinhead_junctionpt, const Vec3d &sourcedir, double radius, double end_radius, long head_id=SupportTreeNode::ID_UNSET)
 
template<class Ex >
std::pair< bool, longconnect_to_ground (Ex policy, SupportTreeBuilder &builder, const SupportableMesh &sm, const Junction &j, const Vec3d &dir, double end_r)
 
template<class Ex >
std::pair< bool, longsearch_ground_route (Ex policy, SupportTreeBuilder &builder, const SupportableMesh &sm, const Junction &j, double end_radius, const Vec3d &init_dir=DOWN)
 

Variables

constexpr const auto & beam_ex_policy = ex_tbb
 
constexpr const auto & suptree_ex_policy = ex_tbb
 
constexpr float HoleStickOutLength = 1.f
 
const Vec3d DOWN = {0.0, 0.0, -1.0}
 
template<class Fn >
constexpr bool IsWideningFn
 
template<class WFn >
constexpr size_t BeamSamplesV = BeamSamples<remove_cvref_t<WFn>>::Value
 

Class Documentation

◆ Slic3r::sla::Ball

struct Slic3r::sla::Ball
+ Collaboration diagram for Slic3r::sla::Ball:
Class Members
Vec3d p
double R

◆ Slic3r::sla::DivFace

struct Slic3r::sla::DivFace
+ Collaboration diagram for Slic3r::sla::DivFace:
Class Members
long faceid = NEW_FACE
Vec3i 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
typedef function< void(unsigned, const string &)> StatusFn
typedef function< bool(void)> StopCond
Class Members
CancelFn cancelfn = [](){}
StatusFn statuscb = [](unsigned, const std::string&){}
StopCond stopcondition = [](){ return false; }

◆ Slic3r::sla::TriangleBubble

struct Slic3r::sla::TriangleBubble
+ Collaboration diagram for Slic3r::sla::TriangleBubble:
Class Members
Vec3f center
double R

Typedef Documentation

◆ _RasterGrayscaleAA

◆ Beam

using Slic3r::sla::Beam = typedef Beam_<>

◆ BoxIndexEl

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

◆ ClusteredPoints

using Slic3r::sla::ClusteredPoints = typedef std::vector<ClusterEl>

◆ ClusterEl

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

◆ DrainHoles

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

◆ Hit

◆ Index3D

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

◆ InteriorPtr

using Slic3r::sla::InteriorPtr = typedef std::unique_ptr<Interior, InteriorDeleter>

◆ PointIndexEl

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

◆ Portion

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

◆ RasterEncoder

using Slic3r::sla::RasterEncoder = typedef std::function<EncodedRaster(const void *ptr, size_t w, size_t h, size_t num_components)>

◆ RotOptimizeStatusCB

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

◆ SupportPoints

using Slic3r::sla::SupportPoints = typedef std::vector<SupportPoint>

◆ ThrowOnCancel

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

◆ Vec3d

Enumeration Type Documentation

◆ anonymous enum

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

◆ GroundRouteCheck

enum class Slic3r::sla::GroundRouteCheck
strong
Enumerator
Full 
PillarOnly 

◆ HollowingFlags

Enumerator
hfRemoveInsideTriangles 
@ hfRemoveInsideTriangles
Definition Hollowing.hpp:24

◆ HollowMeshResult

enum class Slic3r::sla::HollowMeshResult
strong
Enumerator
Ok 
FaultyMesh 
FaultyHoles 
DrillingFailed 

◆ MeshType

enum class Slic3r::sla::MeshType
strong
Enumerator
Support 
Pad 

◆ PillarConnectionMode

Enumerator
zigzag 
cross 
dynamic 

◆ 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};

◆ SupportTreeType

enum class Slic3r::sla::SupportTreeType
strong
Enumerator
Default 
Branching 
Organic 

Function Documentation

◆ beam_mesh_hit()

template<class Ex , size_t RayCount = Beam::SAMPLES>
Hit Slic3r::sla::beam_mesh_hit ( Ex  policy,
const AABBMesh mesh,
const Beam_< RayCount > &  beam,
double  sd 
)
150{
151 Vec3d src = beam.src;
152 Vec3d dst = src + beam.dir;
153 double r_src = beam.r1;
154 double r_dst = beam.r2;
155
156 Vec3d D = (dst - src);
157 Vec3d dir = D.normalized();
158 PointRing<RayCount> ring{dir};
159
160 using Hit = AABBMesh::hit_result;
161
162 // Hit results
163 std::array<Hit, RayCount> hits;
164
165 execution::for_each(
166 policy, size_t(0), hits.size(),
167 [&mesh, r_src, r_dst, src, dst, &ring, dir, sd, &hits](size_t i) {
168 Hit &hit = hits[i];
169
170 // Point on the circle on the pin sphere
171 Vec3d p_src = ring.get(i, src, r_src + sd);
172 Vec3d p_dst = ring.get(i, dst, r_dst + sd);
173 Vec3d raydir = (p_dst - p_src).normalized();
174
175 auto hr = mesh.query_ray_hit(p_src + r_src * raydir, raydir);
176
177 if (hr.is_inside()) {
178 if (hr.distance() > 2 * r_src + sd)
179 hit = Hit(0.0);
180 else {
181 // re-cast the ray from the outside of the object
182 auto q = p_src + (hr.distance() + EPSILON) * raydir;
183 hit = mesh.query_ray_hit(q, raydir);
184 }
185 } else
186 hit = hr;
187 }, std::min(execution::max_concurrency(policy), RayCount));
188
189 return min_hit(hits.begin(), hits.end());
190}
Definition AABBMesh.hpp:65
Definition SupportTreeUtils.hpp:33
Vec3d src
Definition SupportTreeUtils.hpp:120
double r1
Definition SupportTreeUtils.hpp:122
Vec3d dir
Definition SupportTreeUtils.hpp:121
double r2
Definition SupportTreeUtils.hpp:123

References Slic3r::sla::Beam_< Samples >::dir, Slic3r::execution::for_each(), Slic3r::sla::Beam_< Samples >::r1, Slic3r::sla::Beam_< Samples >::r2, and Slic3r::sla::Beam_< Samples >::src.

Referenced by Slic3r::sla::BranchingTreeBuilder::add_bridge(), Slic3r::sla::BranchingTreeBuilder::add_merger(), Slic3r::sla::BranchingTreeBuilder::add_mesh_bridge(), Slic3r::sla::DefaultSupportTree::bridge_mesh_intersect(), check_ground_route(), connect_to_ground(), create_ground_pillar(), search_ground_route(), and search_widening_path().

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

◆ bounding_box_with_tr()

BoundingBoxf3 Slic3r::sla::bounding_box_with_tr ( const indexed_triangle_set its,
const Transform3f tr 
)
inline
419{
420 if (its.vertices.empty())
421 return {};
422
423 Vec3f bmin = tr * its.vertices.front(), bmax = tr * its.vertices.front();
424
425 for (const Vec3f &p : its.vertices) {
426 Vec3f pp = tr * p;
427 bmin = pp.cwiseMin(bmin);
428 bmax = pp.cwiseMax(bmax);
429 }
430
431 return {bmin.cast<double>(), bmax.cast<double>()};
432}
std::vector< stl_vertex > vertices
Definition stl.h:165

References indexed_triangle_set::vertices.

Referenced by find_min_z_height_rotation().

+ Here is the caller graph for this function:

◆ build_ground_connection()

long Slic3r::sla::build_ground_connection ( SupportTreeBuilder builder,
const SupportableMesh sm,
const GroundConnection conn 
)
inline
459{
460 long ret = SupportTreeNode::ID_UNSET;
461
462 if (!conn)
463 return ret;
464
465 auto it = conn.path.begin();
466 auto itnx = std::next(it);
467
468 while (itnx != conn.path.end()) {
469 builder.add_diffbridge(*it, *itnx);
470 builder.add_junction(*itnx);
471 ++it; ++itnx;
472 }
473
474 auto gp = conn.path.back().pos;
475 gp.z() = ground_level(sm);
476 double h = conn.path.back().pos.z() - gp.z();
477
478 if (conn.pillar_base->r_top < sm.cfg.head_back_radius_mm) {
480 gp.z() -= sm.pad_cfg.wall_thickness_mm;
481 }
482
483// TODO: does not work yet
484// if (conn.path.back().id < 0) {
485// // this is a head
486// long head_id = std::abs(conn.path.back().id);
487// ret = builder.add_pillar(head_id, h);
488// } else
489
490 ret = builder.add_pillar(gp, h, conn.path.back().r, conn.pillar_base->r_top);
491
492 if (conn.pillar_base->r_top >= sm.cfg.head_back_radius_mm)
493 builder.add_pillar_base(ret, conn.pillar_base->height, conn.pillar_base->r_bottom);
494
495 return ret;
496}
long add_pillar(long headid, double length)
Definition SupportTreeBuilder.hpp:271
const Junction & add_junction(Args &&... args)
Definition SupportTreeBuilder.hpp:342
void add_pillar_base(long pid, double baseheight=3, double radius=2)
Definition SupportTreeBuilder.cpp:74
const DiffBridge & add_diffbridge(Args &&... args)
Definition SupportTreeBuilder.hpp:375
boost::container::small_vector< Junction, MaxExpectedJunctions > path
Definition SupportTreeUtils.hpp:450
std::optional< Pedestal > pillar_base
Definition SupportTreeUtils.hpp:451
double wall_thickness_mm
Definition Pad.hpp:39
double head_back_radius_mm
Definition SupportTree.hpp:34
PadConfig pad_cfg
Definition SupportTree.hpp:118
SupportTreeConfig cfg
Definition SupportTree.hpp:117

References Slic3r::sla::SupportTreeBuilder::add_diffbridge(), Slic3r::sla::SupportTreeBuilder::add_junction(), Slic3r::sla::SupportTreeBuilder::add_pillar(), Slic3r::sla::SupportTreeBuilder::add_pillar_base(), build_ground_connection(), Slic3r::sla::SupportableMesh::cfg, ground_level(), Slic3r::sla::SupportTreeConfig::head_back_radius_mm, Slic3r::sla::SupportableMesh::pad_cfg, Slic3r::sla::GroundConnection::path, Slic3r::sla::GroundConnection::pillar_base, and Slic3r::sla::PadConfig::wall_thickness_mm.

Referenced by build_ground_connection(), and build_pillars().

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

◆ build_pillars()

void Slic3r::sla::build_pillars ( SupportTreeBuilder builder,
BranchingTreeBuilder vbuilder,
const SupportableMesh sm 
)
inline
348{
349 for (size_t pill_id = 0; pill_id < vbuilder.pillars().size(); ++pill_id) {
350 auto * conn = vbuilder.ground_conn(pill_id);
351 if (conn)
352 build_ground_connection(builder, sm, *conn);
353 }
354}
const std::vector< branchingtree::Node > & pillars() const
Definition BranchingTreeSLA.cpp:174
const GroundConnection * ground_conn(size_t pillar) const
Definition BranchingTreeSLA.cpp:176
long build_ground_connection(SupportTreeBuilder &builder, const SupportableMesh &sm, const GroundConnection &conn)
Definition SupportTreeUtils.hpp:456

References build_ground_connection(), build_pillars(), Slic3r::sla::BranchingTreeBuilder::ground_conn(), and Slic3r::sla::BranchingTreeBuilder::pillars().

Referenced by build_pillars(), and create_branching_tree().

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

◆ calculate_anchor_placement()

template<class Ex >
std::optional< Anchor > Slic3r::sla::calculate_anchor_placement ( Ex  policy,
const SupportableMesh sm,
const Junction from,
const Vec3d to_hint 
)
834{
835 double back_r = from.r;
836 double pin_r = sm.cfg.head_front_radius_mm;
837 double penetr = sm.cfg.head_penetration_mm;
838 double hwidth = sm.cfg.head_width_mm;
839 Vec3d bridgedir = dirv(from.pos, to_hint);
840 Vec3d anchordir = -bridgedir;
841
842 std::optional<Anchor> ret;
843
844 Anchor anchor(back_r, pin_r, hwidth, penetr, anchordir, to_hint);
845
846 if (optimize_anchor_placement(policy, sm, from, anchor)) {
847 ret = anchor;
848 } else if (anchor.r_back_mm = sm.cfg.head_fallback_radius_mm;
849 optimize_anchor_placement(policy, sm, from, anchor)) {
850 // Retrying with the fallback strut radius as a last resort.
851 ret = anchor;
852 }
853
854 return anchor;
855}
bool optimize_anchor_placement(Ex policy, const SupportableMesh &sm, const Junction &from, Anchor &anchor)
Definition SupportTreeUtils.hpp:775
Vec< N, T > dirv(const Vec< N, T > &startp, const Vec< N, T > &endp)
Definition SupportTreeUtils.hpp:91
Definition SupportTreeBuilder.hpp:177
Vec3d pos
Definition SupportTreeBuilder.hpp:73
double r
Definition SupportTreeBuilder.hpp:72
double head_front_radius_mm
Definition SupportTree.hpp:28
double head_penetration_mm
Definition SupportTree.hpp:31
double head_width_mm
Definition SupportTree.hpp:39
double head_fallback_radius_mm
Definition SupportTree.hpp:36

References calculate_anchor_placement(), Slic3r::sla::SupportableMesh::cfg, dirv(), Slic3r::sla::SupportTreeConfig::head_fallback_radius_mm, Slic3r::sla::SupportTreeConfig::head_front_radius_mm, Slic3r::sla::SupportTreeConfig::head_penetration_mm, Slic3r::sla::SupportTreeConfig::head_width_mm, optimize_anchor_placement(), Slic3r::sla::Junction::pos, Slic3r::sla::Junction::r, and Slic3r::sla::Head::r_back_mm.

Referenced by Slic3r::sla::BranchingTreeBuilder::add_mesh_bridge(), and calculate_anchor_placement().

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

◆ calculate_pinhead_placement()

template<class Ex >
std::optional< Head > Slic3r::sla::calculate_pinhead_placement ( Ex  policy,
const SupportableMesh sm,
size_t  suppt_idx 
)
420{
421 if (suppt_idx >= sm.pts.size())
422 return {};
423
424 const SupportPoint &sp = sm.pts[suppt_idx];
425 Head head{
427 sp.head_front_radius,
428 0.,
430 Vec3d::Zero(), // dir
431 sp.pos.cast<double>() // displacement
432 };
433
434 if (optimize_pinhead_placement(policy, sm, head)) {
435 head.id = long(suppt_idx);
436
437 return head;
438 }
439
440 return {};
441}
EIGEN_DEVICE_FUNC SegmentReturnType head(Index n)
This is the const version of head(Index).
Definition BlockMethods.h:919
SupportPoints pts
Definition SupportTree.hpp:116
wchar_t const wchar_t unsigned long
Definition windows.hpp:29

References calculate_pinhead_placement(), Slic3r::sla::SupportableMesh::cfg, head(), Slic3r::sla::SupportTreeConfig::head_back_radius_mm, Slic3r::sla::SupportPoint::head_front_radius, Slic3r::sla::SupportTreeConfig::head_penetration_mm, long, optimize_pinhead_placement(), Slic3r::sla::SupportPoint::pos, and Slic3r::sla::SupportableMesh::pts.

Referenced by calculate_pinhead_placement().

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

◆ check_ground_route()

template<class Ex , class WideningFn , class = std::enable_if_t<IsWideningFn<WideningFn>>>
Vec3d Slic3r::sla::check_ground_route ( Ex  policy,
const SupportableMesh sm,
const Junction source,
const Vec3d dir,
double  bridge_len,
WideningFn &&  wideningfn,
GroundRouteCheck  type = GroundRouteCheck::Full 
)
528{
529 static const constexpr auto Samples = BeamSamplesV<WideningFn>;
530
531 Vec3d ret;
532
533 const auto sd = sm.cfg.safety_distance(source.r);
534 const auto gndlvl = ground_level(sm);
535
536 // Intersection of the suggested bridge with ground plane. If the bridge
537 // spans below ground, stop it at ground level.
538 double t = (gndlvl - source.pos.z()) / dir.z();
539 bridge_len = std::min(t, bridge_len);
540
541 Vec3d bridge_end = source.pos + bridge_len * dir;
542
543 double down_l = bridge_end.z() - gndlvl;
544 double bridge_r = wideningfn(Ball{source.pos, source.r}, dir, bridge_len);
545 double brhit_dist = 0.;
546
547 if (bridge_len > EPSILON && type == GroundRouteCheck::Full) {
548 // beam_mesh_hit with a zero lenght bridge is invalid
549
550 Beam_<Samples> bridgebeam{Ball{source.pos, source.r},
551 Ball{bridge_end, bridge_r}};
552
553 auto brhit = beam_mesh_hit(policy, sm.emesh, bridgebeam, sd);
554 brhit_dist = brhit.distance();
555 } else {
556 brhit_dist = bridge_len;
557 }
558
559 if (brhit_dist < bridge_len) {
560 ret = (source.pos + brhit_dist * dir);
561 } else if (down_l > 0.) {
562 // check if pillar can be placed below
563 auto gp = Vec3d{bridge_end.x(), bridge_end.y(), gndlvl};
564 double end_radius = wideningfn(
565 Ball{bridge_end, bridge_r}, DOWN, bridge_end.z() - gndlvl);
566
567 Beam_<Samples> gndbeam {{bridge_end, bridge_r}, {gp, end_radius}};
568 auto gndhit = beam_mesh_hit(policy, sm.emesh, gndbeam, sd);
569 double gnd_hit_d = std::min(gndhit.distance(), down_l + EPSILON);
570
571 if (source.r >= sm.cfg.head_back_radius_mm && gndhit.distance() > down_l && sm.cfg.object_elevation_mm < EPSILON) {
572 // Dealing with zero elevation mode, to not route pillars
573 // into the gap between the optional pad and the model
574 double gap = std::sqrt(sm.emesh.squared_distance(gp));
575 double base_r = std::max(sm.cfg.base_radius_mm, end_radius);
576 double min_gap = sm.cfg.pillar_base_safety_distance_mm + base_r;
577
578 if (gap < min_gap) {
579 gnd_hit_d = down_l - min_gap + gap;
580 }
581 }
582
583 ret = Vec3d{bridge_end.x(), bridge_end.y(), bridge_end.z() - gnd_hit_d};
584 } else {
585 ret = bridge_end;
586 }
587
588 return ret;
589}
double squared_distance(const Vec3d &p, int &i, Vec3d &c) const
Definition AABBMesh.cpp:313
static constexpr double EPSILON
Definition libslic3r.h:51
const Vec3f DOWN
Definition Rotfinder.cpp:22
double ground_level(const SupportableMesh &sm)
Definition SupportTree.hpp:134
Hit beam_mesh_hit(Ex policy, const AABBMesh &mesh, const Beam_< RayCount > &beam, double sd)
Definition SupportTreeUtils.hpp:146
Definition SupportTreeUtils.hpp:114
Eigen::Matrix< double, 3, 1, Eigen::DontAlign > Vec3d
Definition Point.hpp:52
double object_elevation_mm
Definition SupportTree.hpp:70
double safety_distance() const
Definition SupportTree.hpp:85
double pillar_base_safety_distance_mm
Definition SupportTree.hpp:74
double base_radius_mm
Definition SupportTree.hpp:54
AABBMesh emesh
Definition SupportTree.hpp:115

References Slic3r::sla::SupportTreeConfig::base_radius_mm, beam_mesh_hit(), Slic3r::sla::SupportableMesh::cfg, check_ground_route(), Slic3r::sla::SupportableMesh::emesh, EPSILON, ground_level(), Slic3r::sla::SupportTreeConfig::head_back_radius_mm, Slic3r::sla::SupportTreeConfig::object_elevation_mm, Slic3r::sla::SupportTreeConfig::pillar_base_safety_distance_mm, Slic3r::sla::Junction::pos, Slic3r::sla::Junction::r, Slic3r::sla::SupportTreeConfig::safety_distance(), and Slic3r::AABBMesh::squared_distance().

Referenced by check_ground_route(), and deepsearch_ground_connection().

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

◆ cluster() [1/3]

ClusteredPoints Slic3r::sla::cluster ( const Eigen::MatrixXd &  pts,
double  dist,
unsigned  max_points 
)
137{
138 // A spatial index for querying the nearest points
139 Index3D sindex;
140
141 // Build the index
142 for(Eigen::Index i = 0; i < pts.rows(); i++)
143 sindex.insert(std::make_pair(Vec3d(pts.row(i)), unsigned(i)));
144
145 return cluster(sindex, max_points,
146 [dist, max_points](const Index3D& sidx, const PointIndexEl& p)
147 {
148 return distance_queryfn(sidx, p, dist, max_points);
149 });
150}
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition Meta.h:33
bgi::rtree< PointIndexEl, bgi::rstar< 16, 4 > > Index3D
Definition Clustering.cpp:10
std::pair< Vec3d, unsigned > PointIndexEl
Definition SpatIndex.hpp:16

References cluster().

+ 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 
)
98{
99 // A spatial index for querying the nearest points
100 Index3D sindex;
101
102 // Build the index
103 for(auto idx : indices) sindex.insert( std::make_pair(pointfn(idx), idx));
104
105 return cluster(sindex, max_points,
106 [dist, max_points](const Index3D& sidx, const PointIndexEl& p)
107 {
108 return distance_queryfn(sidx, p, dist, max_points);
109 });
110}
STL namespace.

References cluster().

Referenced by Slic3r::sla::DefaultSupportTree::add_pinheads(), Slic3r::sla::DefaultSupportTree::classify(), cluster(), cluster(), and cluster().

+ 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 
)
118{
119 // A spatial index for querying the nearest points
120 Index3D sindex;
121
122 // Build the index
123 for(auto idx : indices) sindex.insert( std::make_pair(pointfn(idx), idx));
124
125 return cluster(sindex, max_points,
126 [max_points, predicate](const Index3D& sidx, const PointIndexEl& p)
127 {
128 std::vector<PointIndexEl> tmp; tmp.reserve(max_points);
129 sidx.query(bgi::satisfies([p, predicate](const PointIndexEl& e){
130 return predicate(p, e);
131 }), std::back_inserter(tmp));
132 return tmp;
133 });
134}

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

References long.

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

+ Here is the caller graph for this function:

◆ connect_to_ground()

template<class Ex >
std::pair< bool, long > Slic3r::sla::connect_to_ground ( Ex  policy,
SupportTreeBuilder builder,
const SupportableMesh sm,
const Junction j,
const Vec3d dir,
double  end_r 
)
229{
230 auto hjp = j.pos;
231 double r = j.r;
232 auto sd = r * sm.cfg.safety_distance_mm / sm.cfg.head_back_radius_mm;
233 double r2 = j.r + (end_r - j.r) / (j.pos.z() - ground_level(sm));
234
235 double t = beam_mesh_hit(policy, sm.emesh, Beam{hjp, dir, r, r2}, sd).distance();
236 double d = 0, tdown = 0;
237 t = std::min(t, sm.cfg.max_bridge_length_mm * r / sm.cfg.head_back_radius_mm);
238
239 while (d < t &&
240 !std::isinf(tdown = beam_mesh_hit(policy, sm.emesh,
241 Beam{hjp + d * dir, DOWN, r, r2}, sd)
242 .distance())) {
243 d += r;
244 }
245
246 if(!std::isinf(tdown))
247 return {false, SupportTreeNode::ID_UNSET};
248
249 Vec3d endp = hjp + d * dir;
250 auto ret = create_ground_pillar(policy, builder, sm, endp, dir, r, end_r);
251
252 if (ret.second >= 0) {
253 builder.add_bridge(hjp, endp, r);
254 builder.add_junction(endp, r);
255 }
256
257 return ret;
258}
double distance() const
Definition AABBMesh.hpp:84
const Bridge & add_bridge(const Vec3d &s, const Vec3d &e, double r)
Definition SupportTreeBuilder.hpp:351
Definition SupportTreeUtils.hpp:117
double max_bridge_length_mm
Definition SupportTree.hpp:63
static const double constexpr safety_distance_mm
Definition SupportTree.hpp:101

References Slic3r::sla::SupportTreeBuilder::add_bridge(), Slic3r::sla::SupportTreeBuilder::add_junction(), beam_mesh_hit(), Slic3r::sla::SupportableMesh::cfg, create_ground_pillar(), Slic3r::AABBMesh::hit_result::distance(), Slic3r::sla::SupportableMesh::emesh, ground_level(), Slic3r::sla::SupportTreeConfig::head_back_radius_mm, Slic3r::sla::SupportTreeNode::ID_UNSET, Slic3r::sla::SupportTreeConfig::max_bridge_length_mm, Slic3r::sla::Junction::pos, Slic3r::sla::Junction::r, and Slic3r::sla::SupportTreeConfig::safety_distance_mm.

Referenced by search_ground_route().

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

◆ create_branching_tree()

void Slic3r::sla::create_branching_tree ( SupportTreeBuilder builder,
const SupportableMesh sm 
)
357{
358 auto coordfn = [&sm](size_t id, size_t dim) { return sm.pts[id].pos(dim); };
359 KDTreeIndirect<3, float, decltype (coordfn)> tree{coordfn, sm.pts.size()};
360
361 auto nondup_idx = non_duplicate_suppt_indices(tree, sm.pts, 0.1);
362 std::vector<std::optional<Head>> heads(nondup_idx.size());
363 auto leafs = reserve_vector<branchingtree::Node>(nondup_idx.size());
364
365 execution::for_each(
366 ex_tbb, size_t(0), nondup_idx.size(),
367 [&sm, &heads, &nondup_idx, &builder](size_t i) {
368 if (!builder.ctl().stopcondition())
369 heads[i] = calculate_pinhead_placement(ex_seq, sm, nondup_idx[i]);
370 },
371 execution::max_concurrency(ex_tbb)
372 );
373
374 if (builder.ctl().stopcondition())
375 return;
376
377 for (auto &h : heads)
378 if (h && h->is_valid()) {
379 leafs.emplace_back(h->junction_point().cast<float>(), h->r_back_mm);
380 h->id = long(leafs.size() - 1);
381 builder.add_head(h->id, *h);
382 }
383
384 auto &its = *sm.emesh.get_triangle_mesh();
385 ExPolygons bedpolys = {branchingtree::make_bed_poly(its)};
386
387 auto props = branchingtree::Properties{}
388 .bed_shape(bedpolys)
389 .ground_level(sla::ground_level(sm))
390 .max_slope(sm.cfg.bridge_slope)
391 .max_branch_length(sm.cfg.max_bridge_length_mm);
392
393 auto meshpts = sm.cfg.ground_facing_only ?
394 std::vector<branchingtree::Node>{} :
395 branchingtree::sample_mesh(its,
396 props.sampling_radius());
397
398 auto bedpts = branchingtree::sample_bed(props.bed_shape(),
399 float(props.ground_level()),
400 props.sampling_radius());
401
402 for (auto &bp : bedpts)
403 bp.Rmin = sm.cfg.head_back_radius_mm;
404
405 branchingtree::PointCloud nodes{std::move(meshpts), std::move(bedpts),
406 std::move(leafs), props};
407
408 BranchingTreeBuilder vbuilder{builder, sm, nodes};
409
410 execution::for_each(ex_tbb,
411 size_t(0),
412 nodes.get_leafs().size(),
413 [&nodes, &vbuilder](size_t leaf_idx) {
414 vbuilder.suggest_avoidance(nodes.get_leafs()[leaf_idx],
415 nodes.properties().max_branch_length());
416 });
417
418 branchingtree::build_tree(nodes, vbuilder);
419
420 build_pillars(builder, vbuilder, sm);
421
422 for (size_t id : vbuilder.unroutable_pinheads())
423 builder.head(id).invalidate();
424
425}
const indexed_triangle_set * get_triangle_mesh() const
Definition AABBMesh.hpp:133
Definition KDTreeIndirect.hpp:23
const JobController & ctl() const
Definition SupportTreeBuilder.hpp:256
Head & add_head(unsigned id, Args &&... args)
Definition SupportTreeBuilder.hpp:258
if(!(yy_init))
Definition lexer.c:1190
void build_pillars(SupportTreeBuilder &builder, BranchingTreeBuilder &vbuilder, const SupportableMesh &sm)
Definition BranchingTreeSLA.cpp:345
StopCond stopcondition
Definition JobController.hpp:21
std::vector< ExPolygon > ExPolygons
Definition ExPolygon.hpp:13
double bridge_slope
Definition SupportTree.hpp:60
bool ground_facing_only
Definition SupportTree.hpp:45

References Slic3r::sla::SupportTreeBuilder::add_head(), Slic3r::branchingtree::Properties::bed_shape(), Slic3r::sla::SupportTreeConfig::bridge_slope, build_pillars(), Slic3r::branchingtree::build_tree(), Slic3r::sla::SupportableMesh::cfg, create_branching_tree(), Slic3r::sla::SupportTreeBuilder::ctl(), Slic3r::sla::SupportableMesh::emesh, Slic3r::ex_tbb, Slic3r::execution::for_each(), Slic3r::AABBMesh::get_triangle_mesh(), Slic3r::sla::SupportTreeConfig::ground_facing_only, ground_level(), Slic3r::branchingtree::Properties::ground_level(), Slic3r::sla::SupportTreeBuilder::head(), Slic3r::sla::SupportTreeConfig::head_back_radius_mm, Slic3r::sla::Head::invalidate(), long, Slic3r::branchingtree::make_bed_poly(), Slic3r::branchingtree::Properties::max_branch_length(), Slic3r::sla::SupportTreeConfig::max_bridge_length_mm, Slic3r::execution::max_concurrency(), Slic3r::branchingtree::Properties::max_slope(), non_duplicate_suppt_indices(), Slic3r::sla::SupportableMesh::pts, Slic3r::branchingtree::sample_bed(), Slic3r::branchingtree::sample_mesh(), and Slic3r::sla::JobController::stopcondition.

Referenced by create_branching_tree(), and create_support_tree().

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

◆ create_default_tree()

void Slic3r::sla::create_default_tree ( SupportTreeBuilder builder,
const SupportableMesh sm 
)
inline
239{
240 DefaultSupportTree::execute(builder, sm);
241}

References Slic3r::sla::DefaultSupportTree::execute().

Referenced by create_support_tree().

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

◆ create_exclude_mask()

std::vector< bool > Slic3r::sla::create_exclude_mask ( const indexed_triangle_set its,
const Interior interior,
const std::vector< DrainHole > &  holes 
)
648{
649 FaceHash interior_hash{sla::get_mesh(interior)};
650
651 std::vector<bool> exclude_mask(its.indices.size(), false);
652
653 VertexFaceIndex neighbor_index{its};
654
655 for (size_t fi = 0; fi < its.indices.size(); ++fi) {
656 auto &face = its.indices[fi];
657
658 if (interior_hash.find(FaceHash::facekey(face, its.vertices))) {
659 exclude_mask[fi] = true;
660 continue;
661 }
662
663 if (exclude_mask[fi]) {
664 exclude_neighbors(face, exclude_mask, its, neighbor_index, 1);
665 continue;
666 }
667
668 // Lets deal with the holes. All the triangles of a hole and all the
669 // neighbors of these triangles need to be kept. The neigbors were
670 // created by CGAL mesh boolean operation that modified the original
671 // interior inside the input mesh to contain the holes.
672 Vec3d tr_center = (
673 its.vertices[face(0)] +
674 its.vertices[face(1)] +
675 its.vertices[face(2)]
676 ).cast<double>() / 3.;
677
678 // If the center is more than half a mm inside the interior,
679 // it cannot possibly be part of a hole wall.
680 if (sla::get_distance(tr_center, interior) < -0.5)
681 continue;
682
683 Vec3f U = its.vertices[face(1)] - its.vertices[face(0)];
684 Vec3f V = its.vertices[face(2)] - its.vertices[face(0)];
685 Vec3f C = U.cross(V);
686 Vec3f face_normal = C.normalized();
687
688 for (const sla::DrainHole &dh : holes) {
689 if (dh.failed) continue;
690
691 Vec3d dhpos = dh.pos.cast<double>();
692 Vec3d dhend = dhpos + dh.normal.cast<double>() * dh.height;
693
694 Linef3 holeaxis{dhpos, dhend};
695
696 double D_hole_center = line_alg::distance_to(holeaxis, tr_center);
697 double D_hole = std::abs(D_hole_center - dh.radius);
698 float dot = dh.normal.dot(face_normal);
699
700 // Empiric tolerances for center distance and normals angle.
701 // For triangles that are part of a hole wall the angle of
702 // triangle normal and the hole axis is around 90 degrees,
703 // so the dot product is around zero.
704 double D_tol = dh.radius / sla::DrainHole::steps;
705 float normal_angle_tol = 1.f / sla::DrainHole::steps;
706
707 if (D_hole < D_tol && std::abs(dot) < normal_angle_tol) {
708 exclude_mask[fi] = true;
709 exclude_neighbors(face, exclude_mask, its, neighbor_index, 1);
710 }
711 }
712 }
713
714 return exclude_mask;
715}
static void exclude_neighbors(const Vec3i &face, std::vector< bool > &mask, const indexed_triangle_set &its, const VertexFaceIndex &index, size_t recursions)
Definition Hollowing.cpp:629
Eigen::Matrix< float, 3, 1, Eigen::DontAlign > Vec3f
Definition Point.hpp:49
Vec3f face_normal(const stl_vertex vertex[3])
Definition TriangleMesh.hpp:309
IGL_INLINE double dot(const double *a, const double *b)
Definition dot.cpp:11
const THolesContainer< PolygonImpl > & holes(const Slic3r::ExPolygon &sh)
Definition geometries.hpp:189
Definition TriangleMesh.hpp:163
Definition Hollowing.cpp:554
std::vector< stl_triangle_vertex_indices > indices
Definition stl.h:164

References create_exclude_mask(), exclude_neighbors(), Slic3r::face_normal(), indexed_triangle_set::indices, and indexed_triangle_set::vertices.

Referenced by create_exclude_mask(), and hollow_mesh_and_drill().

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

◆ create_ground_pillar()

template<class Ex >
std::pair< bool, long > Slic3r::sla::create_ground_pillar ( Ex  policy,
SupportTreeBuilder builder,
const SupportableMesh sm,
const Vec3d pinhead_junctionpt,
const Vec3d sourcedir,
double  radius,
double  end_radius,
long  head_id = SupportTreeNode::ID_UNSET 
)
106{
107 Vec3d jp = pinhead_junctionpt, endp = jp, dir = sourcedir;
108 long pillar_id = SupportTreeNode::ID_UNSET;
109 bool can_add_base = false, non_head = false;
110
111 double gndlvl = 0.; // The Z level where pedestals should be
112 double jp_gnd = 0.; // The lowest Z where a junction center can be
113 double gap_dist = 0.; // The gap distance between the model and the pad
114
115 double r2 = radius + (end_radius - radius) / (jp.z() - ground_level(sm));
116
117 auto to_floor = [&gndlvl](const Vec3d &p) { return Vec3d{p.x(), p.y(), gndlvl}; };
118
119 auto eval_limits = [&sm, &radius, &can_add_base, &gndlvl, &gap_dist, &jp_gnd]
120 (bool base_en = true)
121 {
122 can_add_base = base_en && radius >= sm.cfg.head_back_radius_mm;
123 double base_r = can_add_base ? sm.cfg.base_radius_mm : 0.;
124 gndlvl = ground_level(sm);
125 if (!can_add_base) gndlvl -= sm.pad_cfg.wall_thickness_mm;
126 jp_gnd = gndlvl + (can_add_base ? 0. : sm.cfg.head_back_radius_mm);
127 gap_dist = sm.cfg.pillar_base_safety_distance_mm + base_r + EPSILON;
128 };
129
130 eval_limits();
131
132 // We are dealing with a mini pillar that's potentially too long
133 if (radius < sm.cfg.head_back_radius_mm && jp.z() - gndlvl > 20 * radius)
134 {
135 std::optional<DiffBridge> diffbr =
136 search_widening_path(policy, sm, jp, dir, radius,
138
139 if (diffbr && diffbr->endp.z() > jp_gnd) {
140 auto &br = builder.add_diffbridge(*diffbr);
141 if (head_id >= 0) builder.head(head_id).bridge_id = br.id;
142 endp = diffbr->endp;
143 radius = diffbr->end_r;
144 end_radius = diffbr->end_r;
145 builder.add_junction(endp, radius);
146 non_head = true;
147 dir = diffbr->get_dir();
148 eval_limits();
149 } else return {false, pillar_id};
150 }
151
153 {
154 // get a suitable direction for the corrector bridge. It is the
155 // original sourcedir's azimuth but the polar angle is saturated to the
156 // configured bridge slope.
157 auto [polar, azimuth] = dir_to_spheric(dir);
158 polar = PI - sm.cfg.bridge_slope;
159 Vec3d d = spheric_to_dir(polar, azimuth).normalized();
160 auto sd = radius * sm.cfg.safety_distance_mm / sm.cfg.head_back_radius_mm;
161 double t = beam_mesh_hit(policy, sm.emesh, Beam{endp, d, radius, r2}, sd).distance();
162 double tmax = std::min(sm.cfg.max_bridge_length_mm, t);
163 t = 0.;
164
165 double zd = endp.z() - jp_gnd;
166 double tmax2 = zd / std::sqrt(1 - sm.cfg.bridge_slope * sm.cfg.bridge_slope);
167 tmax = std::min(tmax, tmax2);
168
169 Vec3d nexp = endp;
170 double dlast = 0.;
171 while (((dlast = std::sqrt(sm.emesh.squared_distance(to_floor(nexp)))) < gap_dist ||
172 !std::isinf(beam_mesh_hit(policy, sm.emesh, Beam{nexp, DOWN, radius, r2}, sd).distance())) &&
173 t < tmax)
174 {
175 t += radius;
176 nexp = endp + t * d;
177 }
178
179 if (dlast < gap_dist && can_add_base) {
180 nexp = endp;
181 t = 0.;
182 can_add_base = false;
183 eval_limits(can_add_base);
184
185 zd = endp.z() - jp_gnd;
186 tmax2 = zd / std::sqrt(1 - sm.cfg.bridge_slope * sm.cfg.bridge_slope);
187 tmax = std::min(tmax, tmax2);
188
189 while (((dlast = std::sqrt(sm.emesh.squared_distance(to_floor(nexp)))) < gap_dist ||
190 !std::isinf(beam_mesh_hit(policy, sm.emesh, Beam{nexp, DOWN, radius}, sd).distance())) && t < tmax) {
191 t += radius;
192 nexp = endp + t * d;
193 }
194 }
195
196 // Could not find a path to avoid the pad gap
197 if (dlast < gap_dist) return {false, pillar_id};
198
199 if (t > 0.) { // Need to make additional bridge
200 const Bridge& br = builder.add_bridge(endp, nexp, radius);
201 if (head_id >= 0) builder.head(head_id).bridge_id = br.id;
202
203 builder.add_junction(nexp, radius);
204 endp = nexp;
205 non_head = true;
206 }
207 }
208
209 Vec3d gp = to_floor(endp);
210 double h = endp.z() - gp.z();
211
212 pillar_id = head_id >= 0 && !non_head ? builder.add_pillar(head_id, h) :
213 builder.add_pillar(gp, h, radius, end_radius);
214
215 if (can_add_base)
216 builder.add_pillar_base(pillar_id, sm.cfg.base_height_mm,
218
219 return {true, pillar_id};
220}
Head & head(unsigned id)
Definition SupportTreeBuilder.hpp:380
static constexpr double PI
Definition libslic3r.h:58
Vec< 3, T > spheric_to_dir(double polar, double azimuth)
Definition Geometry.hpp:519
std::pair< Tout, Tout > dir_to_spheric(const Vec< 3, Tin > &n, Tout norm=1.)
Definition Geometry.hpp:509
std::optional< DiffBridge > search_widening_path(Ex policy, const SupportableMesh &sm, const Vec3d &jp, const Vec3d &dir, double radius, double new_radius)
Definition SupportTreeUtilsLegacy.hpp:36
long bridge_id
Definition SupportTreeBuilder.hpp:91
double base_height_mm
Definition SupportTree.hpp:57

References Slic3r::sla::SupportTreeBuilder::add_bridge(), Slic3r::sla::SupportTreeBuilder::add_diffbridge(), Slic3r::sla::SupportTreeBuilder::add_junction(), Slic3r::sla::SupportTreeBuilder::add_pillar(), Slic3r::sla::SupportTreeBuilder::add_pillar_base(), Slic3r::sla::SupportTreeConfig::base_height_mm, Slic3r::sla::SupportTreeConfig::base_radius_mm, beam_mesh_hit(), Slic3r::sla::Head::bridge_id, Slic3r::sla::SupportTreeConfig::bridge_slope, Slic3r::sla::SupportableMesh::cfg, Slic3r::AABBMesh::hit_result::distance(), Slic3r::sla::SupportableMesh::emesh, EPSILON, ground_level(), Slic3r::sla::SupportTreeBuilder::head(), Slic3r::sla::SupportTreeConfig::head_back_radius_mm, Slic3r::sla::SupportTreeNode::id, Slic3r::sla::SupportTreeNode::ID_UNSET, Slic3r::sla::SupportTreeConfig::max_bridge_length_mm, Slic3r::sla::SupportTreeConfig::object_elevation_mm, Slic3r::sla::SupportableMesh::pad_cfg, PI, Slic3r::sla::SupportTreeConfig::pillar_base_safety_distance_mm, Slic3r::sla::SupportTreeConfig::safety_distance_mm, search_widening_path(), Slic3r::AABBMesh::squared_distance(), and Slic3r::sla::PadConfig::wall_thickness_mm.

Referenced by connect_to_ground(), and Slic3r::sla::DefaultSupportTree::create_ground_pillar().

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

◆ create_pad() [1/2]

void Slic3r::sla::create_pad ( const ExPolygons sup_blueprint,
const ExPolygons model_blueprint,
indexed_triangle_set out,
const PadConfig cfg,
ThrowOnCancel  thr 
)
518{
519 auto t = create_pad_geometry(sup_blueprint, model_blueprint, cfg, thr);
520 its_merge(out, t);
521}
void its_merge(indexed_triangle_set &its, indexed_triangle_set &&its_add)
Merge one triangle mesh to another Added triangle set will be consumed.
Definition TriangleMesh.cpp:1355

References Slic3r::its_merge().

Referenced by Slic3r::SLAPrintObject::SupportData::create_pad(), and create_pad().

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

◆ create_pad() [2/2]

indexed_triangle_set Slic3r::sla::create_pad ( const SupportableMesh sm,
const indexed_triangle_set support_mesh,
const JobController ctl 
)
66{
67 constexpr float PadSamplingLH = 0.1f;
68
69 ExPolygons model_contours; // This will store the base plate of the pad.
70 double pad_h = sm.pad_cfg.full_height();
71 auto gndlvl = float(ground_level(sm));
72 float zstart = gndlvl - bool(sm.pad_cfg.embed_object) * sm.pad_cfg.wall_thickness_mm;
73 float zend = zstart + float(pad_h + PadSamplingLH + EPSILON);
74 auto heights = grid(zstart, zend, PadSamplingLH);
75
76 if (!sm.cfg.enabled || sm.pad_cfg.embed_object) {
77 // No support (thus no elevation) or zero elevation mode
78 // we sometimes call it "builtin pad" is enabled so we will
79 // get a sample from the bottom of the mesh and use it for pad
80 // creation.
81 sla::pad_blueprint(*sm.emesh.get_triangle_mesh(), model_contours,
82 heights, ctl.cancelfn);
83 }
84
85 ExPolygons sup_contours;
86 pad_blueprint(support_mesh, sup_contours, heights, ctl.cancelfn);
87
89 create_pad(sup_contours, model_contours, out, sm.pad_cfg);
90
91 Vec3f offs{.0f, .0f, gndlvl};
92 for (auto &p : out.vertices) p += offs;
93
94 its_merge_vertices(out);
95
96 return out;
97}
CancelFn cancelfn
Definition JobController.hpp:27
struct Slic3r::sla::PadConfig::EmbedObject embed_object
double full_height() const
Definition Pad.hpp:76
bool enabled
Definition SupportTree.hpp:22
Definition stl.h:157

References Slic3r::sla::JobController::cancelfn, Slic3r::sla::SupportableMesh::cfg, create_pad(), Slic3r::sla::PadConfig::embed_object, Slic3r::sla::SupportableMesh::emesh, Slic3r::sla::SupportTreeConfig::enabled, EPSILON, Slic3r::sla::PadConfig::full_height(), Slic3r::AABBMesh::get_triangle_mesh(), Slic3r::grid(), ground_level(), Slic3r::its_merge_vertices(), pad_blueprint(), Slic3r::sla::SupportableMesh::pad_cfg, indexed_triangle_set::vertices, and Slic3r::sla::PadConfig::wall_thickness_mm.

+ Here is the call 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 
)
70{
71 std::unique_ptr<RasterBase> rst;
72
73 if (gamma > 0)
74 rst = std::make_unique<RasterGrayscaleAAGammaPower>(res, pxdim, tr, gamma);
75 else if (std::abs(gamma - 1.) < 1e-6)
76 rst = std::make_unique<RasterGrayscaleAA>(res, pxdim, tr, agg::gamma_none());
77 else
78 rst = std::make_unique<RasterGrayscaleAA>(res, pxdim, tr, agg::gamma_threshold(.5));
79
80 return rst;
81}
Definition agg_gamma_functions.h:53
Definition agg_gamma_functions.h:26

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

+ Here is the caller graph for this function:

◆ create_support_tree()

indexed_triangle_set Slic3r::sla::create_support_tree ( const SupportableMesh sm,
const JobController ctl 
)
27{
28 auto builder = make_unique<SupportTreeBuilder>(ctl);
29
30 if (sm.cfg.enabled) {
31 Benchmark bench;
32 bench.start();
33
34 switch (sm.cfg.tree_type) {
35 case SupportTreeType::Default: {
36 create_default_tree(*builder, sm);
37 break;
38 }
39 case SupportTreeType::Branching: {
40 create_branching_tree(*builder, sm);
41 break;
42 }
43 case SupportTreeType::Organic: {
44 // TODO
45 }
46 default:;
47 }
48
49 bench.stop();
50
51 BOOST_LOG_TRIVIAL(info) << "Support tree creation took: "
52 << bench.getElapsedSec()
53 << " seconds";
54
55 builder->merge_and_cleanup(); // clean metadata, leave only the meshes.
56 }
57
58 indexed_triangle_set out = builder->retrieve_mesh(MeshType::Support);
59
60 return out;
61}
Definition benchmark.h:26
double getElapsedSec()
Definition benchmark.h:54
void stop()
Definition benchmark.h:48
void start()
Definition benchmark.h:43
void create_default_tree(SupportTreeBuilder &builder, const SupportableMesh &sm)
Definition DefaultSupportTree.hpp:238
SupportTreeType tree_type
Definition SupportTree.hpp:25

References Branching, Slic3r::sla::SupportableMesh::cfg, create_branching_tree(), create_default_tree(), Default, Slic3r::sla::SupportTreeConfig::enabled, Benchmark::getElapsedSec(), Organic, Benchmark::start(), Benchmark::stop(), Support, and Slic3r::sla::SupportTreeConfig::tree_type.

Referenced by Slic3r::SLAPrintObject::SupportData::create_support_tree().

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

◆ csgmesh_positive_maxvolume()

template<class Cont >
double Slic3r::sla::csgmesh_positive_maxvolume ( const Cont &  csg)
108{
109 double mesh_vol = 0;
110
111 bool skip = false;
112 for (const auto &m : csg) {
113 auto op = csg::get_operation(m);
114 auto stackop = csg::get_stack_operation(m);
115 if (stackop == csg::CSGStackOp::Push && op != csg::CSGType::Union)
116 skip = true;
117
118 if (!skip && csg::get_mesh(m) && op == csg::CSGType::Union)
119 mesh_vol = std::max(mesh_vol,
120 double(its_volume(*(csg::get_mesh(m)))));
121
122 if (stackop == csg::CSGStackOp::Pop)
123 skip = false;
124 }
125
126 return mesh_vol;
127}
float its_volume(const indexed_triangle_set &its)
Definition TriangleMesh.cpp:1403

References Slic3r::csg::get_mesh(), Slic3r::csg::get_operation(), Slic3r::csg::get_stack_operation(), Slic3r::its_volume(), Slic3r::csg::Pop, Slic3r::csg::Push, and Slic3r::csg::Union.

+ Here is the call 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 
)
254{
255 TriangleMesh mesh;
256 for (const sla::DrainHole &holept : holes)
257 mesh.merge(TriangleMesh{holept.to_mesh()});
258
259 if (mesh.empty()) return;
260
261 std::vector<ExPolygons> hole_slices = slice_mesh_ex(mesh.its, slicegrid, closing_radius, thr);
262
263 if (obj_slices.size() != hole_slices.size())
264 BOOST_LOG_TRIVIAL(warning)
265 << "Sliced object and drain-holes layer count does not match!";
266
267 size_t until = std::min(obj_slices.size(), hole_slices.size());
268
269 for (size_t i = 0; i < until; ++i)
270 obj_slices[i] = diff_ex(obj_slices[i], hole_slices[i]);
271}
Definition TriangleMesh.hpp:88
bool empty() const
Definition TriangleMesh.hpp:139
indexed_triangle_set its
Definition TriangleMesh.hpp:155
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:726
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:1908
Definition Hollowing.hpp:39

References Slic3r::holes(), and Slic3r::TriangleMesh::merge().

+ Here is the call graph for this function:

◆ cylinder()

indexed_triangle_set Slic3r::sla::cylinder ( double  r,
double  h,
size_t  steps = 45 
)
inline
31{
32 return its_make_cylinder(r, h, 2 * PI / steps);
33}
indexed_triangle_set its_make_cylinder(double r, double h, double fa)
Definition TriangleMesh.cpp:955

References Slic3r::its_make_cylinder(), and PI.

Referenced by get_mesh().

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

◆ deepsearch_ground_connection() [1/3]

template<class Ex >
GroundConnection Slic3r::sla::deepsearch_ground_connection ( Ex  policy,
const SupportableMesh sm,
const Junction source,
const Vec3d init_dir = DOWN 
)
769{
770 return deepsearch_ground_connection(policy, sm, source,
771 DefaultWideningModel{sm}, init_dir);
772}
GroundConnection deepsearch_ground_connection(Ex policy, const SupportableMesh &sm, const Junction &source, WideningFn &&wideningfn, const Vec3d &init_dir=DOWN)
Definition SupportTreeUtils.hpp:596
Definition SupportTreeUtils.hpp:747

References deepsearch_ground_connection().

+ Here is the call graph for this function:

◆ deepsearch_ground_connection() [2/3]

template<class Ex >
GroundConnection Slic3r::sla::deepsearch_ground_connection ( Ex  policy,
const SupportableMesh sm,
const Junction source,
double  end_radius,
const Vec3d init_dir = DOWN 
)
727{
728 double gndlvl = ground_level(sm);
729 auto wfn = [end_radius, gndlvl](const Ball &src, const Vec3d &dir, double len) {
730 if (len < EPSILON)
731 return src.R;
732
733 Vec3d dst = src.p + len * dir;
734 double widening = end_radius - src.R;
735 double zlen = dst.z() - gndlvl;
736 double full_len = len + zlen;
737 double r = src.R + widening * len / full_len;
738
739 return r;
740 };
741
742 static_assert(IsWideningFn<decltype(wfn)>, "Not a widening function");
743
744 return deepsearch_ground_connection(policy, sm, source, wfn, init_dir);
745}

References deepsearch_ground_connection(), EPSILON, ground_level(), and IsWideningFn.

+ Here is the call graph for this function:

◆ deepsearch_ground_connection() [3/3]

template<class Ex , class WideningFn , class = std::enable_if_t<IsWideningFn<WideningFn>>>
GroundConnection Slic3r::sla::deepsearch_ground_connection ( Ex  policy,
const SupportableMesh sm,
const Junction source,
WideningFn &&  wideningfn,
const Vec3d init_dir = DOWN 
)
602{
603 constexpr unsigned MaxIterationsGlobal = 5000;
604 constexpr unsigned MaxIterationsLocal = 100;
605 constexpr double RelScoreDiff = 0.05;
606
607 const auto gndlvl = ground_level(sm);
608
609 // The used solver (AlgNLoptMLSL_Subplx search method) is composed of a global (MLSL)
610 // and a local (Subplex) search method. Criteria can be set in a way that
611 // local searches are quick and less accurate. The global method will only
612 // consider the max iteration number and the stop score (Z level <= ground)
613
614 auto criteria = get_criteria(sm.cfg); // get defaults from cfg
615 criteria.max_iterations(MaxIterationsGlobal);
616 criteria.abs_score_diff(NaNd);
617 criteria.rel_score_diff(NaNd);
618 criteria.stop_score(gndlvl);
619
620 auto criteria_loc = criteria;
621 criteria_loc.max_iterations(MaxIterationsLocal);
622 criteria_loc.abs_score_diff(EPSILON);
623 criteria_loc.rel_score_diff(RelScoreDiff);
624
626 solver.set_loc_criteria(criteria_loc);
627 solver.seed(0); // require repeatability
628
629 // functor returns the z height of collision point, given a polar and
630 // azimuth angles as bridge direction and bridge length. The route is
631 // traced from source, through this bridge and an attached pillar. If there
632 // is a collision with the mesh, the Z height is returned. Otherwise the
633 // z level of ground is returned.
634 auto z_fn = [&](const opt::Input<3> &input) {
635 // solver suggests polar, azimuth and bridge length values:
636 auto &[plr, azm, bridge_len] = input;
637
638 Vec3d n = spheric_to_dir(plr, azm);
639
640 Vec3d hitpt = check_ground_route(policy, sm, source, n, bridge_len, wideningfn);
641
642 return hitpt.z();
643 };
644
645 // Calculate the initial direction of the search by
646 // saturating the polar angle to max tilt defined in config
647 auto [plr_init, azm_init] = dir_to_spheric(init_dir);
648 plr_init = std::max(plr_init, PI - sm.cfg.bridge_slope);
649
650 auto bound_constraints =
651 bounds({
652 {PI - sm.cfg.bridge_slope, PI}, // bounds for polar angle
653 {-PI, PI}, // bounds for azimuth
654 {0., sm.cfg.max_bridge_length_mm} // bounds bridge length
655 });
656
657 // The optimizer can navigate fairly well on the mesh surface, finding
658 // lower and lower Z coordinates as collision points. MLSL is not a local
659 // search method, so it should not be trapped in a local minima. Eventually,
660 // this search should arrive at a ground location.
661 auto oresult = solver.to_min().optimize(
662 z_fn,
663 initvals({plr_init, azm_init, 0.}),
664 bound_constraints
665 );
666
667 GroundConnection conn;
668
669 // Extract and apply the result
670 auto [plr, azm, bridge_l] = oresult.optimum;
671 Vec3d n = spheric_to_dir(plr, azm);
672 assert(std::abs(n.norm() - 1.) < EPSILON);
673
674 double t = (gndlvl - source.pos.z()) / n.z();
675 bridge_l = std::min(t, bridge_l);
676
677 // Now the optimizer gave a possible route to ground with a bridge direction
678 // and length. This length can be shortened further by brute-force queries
679 // of free route straigt down for a possible pillar.
680 // NOTE: This requirement could be incorporated into the optimization as a
681 // constraint, but it would not find quickly enough an accurate solution,
682 // and it would be very hard to define a stop score which is very useful in
683 // terminating the search as soon as the ground is found.
684 double l = 0., l_max = bridge_l;
685 double zlvl = std::numeric_limits<double>::infinity();
686 while(zlvl > gndlvl && l <= l_max) {
687
688 zlvl = check_ground_route(policy, sm, source, n, l, wideningfn,
689 GroundRouteCheck::PillarOnly).z();
690
691 if (zlvl <= gndlvl)
692 bridge_l = l;
693
694 l += source.r;
695 }
696
697 Vec3d bridge_end = source.pos + bridge_l * n;
698 Vec3d gp{bridge_end.x(), bridge_end.y(), gndlvl};
699
700 double bridge_r = wideningfn(Ball{source.pos, source.r}, n, bridge_l);
701 double down_l = bridge_end.z() - gndlvl;
702 double end_radius = wideningfn(Ball{bridge_end, bridge_r}, DOWN, down_l);
703 double base_r = std::max(sm.cfg.base_radius_mm, end_radius);
704
705 // Even if the search was not succesful, the result is populated by the
706 // source and the last best result of the optimization.
707 conn.path.emplace_back(source);
708 if (bridge_l > EPSILON)
709 conn.path.emplace_back(Junction{bridge_end, bridge_r});
710
711 // The resulting ground connection is only valid if the pillar base is set.
712 // At this point it will only be set if the search was succesful.
713 if (z_fn(opt::Input<3>({plr, azm, bridge_l})) <= gndlvl)
714 conn.pillar_base =
715 Pedestal{gp, sm.cfg.base_height_mm, base_r, end_radius};
716
717 return conn;
718}
Definition Optimizer.hpp:120
static int input(void)
std::array< double, N > Input
Definition Optimizer.hpp:46
StopCriteria get_criteria(const SupportTreeConfig &cfg)
Definition SupportTreeUtils.hpp:106
Vec3d check_ground_route(Ex policy, const SupportableMesh &sm, const Junction &source, const Vec3d &dir, double bridge_len, WideningFn &&wideningfn, GroundRouteCheck type=GroundRouteCheck::Full)
Definition SupportTreeUtils.hpp:519
tuple< Args... > initvals(Args...args)
Definition optimizer.hpp:54

References Slic3r::sla::SupportTreeConfig::base_height_mm, Slic3r::sla::SupportTreeConfig::base_radius_mm, Slic3r::sla::SupportTreeConfig::bridge_slope, Slic3r::sla::SupportableMesh::cfg, check_ground_route(), deepsearch_ground_connection(), EPSILON, get_criteria(), ground_level(), input(), Slic3r::sla::SupportTreeConfig::max_bridge_length_mm, Slic3r::NaNd, Slic3r::opt::Optimizer< Method, Enable >::optimize(), Slic3r::sla::GroundConnection::path, PI, Slic3r::sla::GroundConnection::pillar_base, Slic3r::sla::Junction::pos, Slic3r::sla::Junction::r, Slic3r::opt::Optimizer< Method, Enable >::seed(), and Slic3r::opt::Optimizer< Method, Enable >::to_min().

Referenced by Slic3r::sla::BranchingTreeBuilder::add_ground_bridge(), deepsearch_ground_connection(), deepsearch_ground_connection(), deepsearch_ground_connection(), and Slic3r::sla::BranchingTreeBuilder::suggest_avoidance().

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

◆ dirv()

template<class T , int N>
Vec< N, T > Slic3r::sla::dirv ( const Vec< N, T > &  startp,
const Vec< N, T > &  endp 
)
91 {
92 return (endp - startp).normalized();
93}

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

+ Here is the caller graph for this function:

◆ distance() [1/3]

double Slic3r::sla::distance ( const SupportPoint a,
const SupportPoint b 
)
inline
289{
290 return (a.pos - b.pos).norm();
291}

◆ distance() [2/3]

template<class T , int I>
T Slic3r::sla::distance ( const Vec< I, T > &  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.

52 {
53 return p.norm();
54}

Referenced by Slic3r::sla::Beam_< Samples >::Beam_(), Slic3r::sla::BranchingTreeBuilder::add_mesh_bridge(), Slic3r::sla::DefaultSupportTree::classify(), Slic3r::sla::DefaultSupportTree::connect_to_nearpillar(), Slic3r::sla::DefaultSupportTree::interconnect(), and Slic3r::sla::DefaultSupportTree::routing_to_ground().

+ Here is the caller graph for this function:

◆ distance() [3/3]

template<class T , int I>
T Slic3r::sla::distance ( const Vec< I, T > &  pp1,
const Vec< I, T > &  pp2 
)
57 {
58 return (pp1 - pp2).norm();
59}

◆ divide_triangle()

template<class Fn >
void Slic3r::sla::divide_triangle ( const DivFace face,
Fn &&  visitor 
)
359{
360 std::array<Vec3f, 3> edges = {(face.verts[0] - face.verts[1]),
361 (face.verts[1] - face.verts[2]),
362 (face.verts[2] - face.verts[0])};
363
364 std::array<size_t, 3> edgeidx = {0, 1, 2};
365
366 std::sort(edgeidx.begin(), edgeidx.end(), [&edges](size_t e1, size_t e2) {
367 return edges[e1].squaredNorm() > edges[e2].squaredNorm();
368 });
369
370 DivFace child1, child2;
371
372 child1.parent = face.faceid == NEW_FACE ? face.parent : face.faceid;
373 child1.indx(0) = -1;
374 child1.indx(1) = face.indx(edgeidx[1]);
375 child1.indx(2) = face.indx((edgeidx[1] + 1) % 3);
376 child1.verts[0] = (face.verts[edgeidx[0]] + face.verts[(edgeidx[0] + 1) % 3]) / 2.;
377 child1.verts[1] = face.verts[edgeidx[1]];
378 child1.verts[2] = face.verts[(edgeidx[1] + 1) % 3];
379
380 if (visitor(child1))
381 divide_triangle(child1, std::forward<Fn>(visitor));
382
383 child2.parent = face.faceid == NEW_FACE ? face.parent : face.faceid;
384 child2.indx(0) = -1;
385 child2.indx(1) = face.indx(edgeidx[2]);
386 child2.indx(2) = face.indx((edgeidx[2] + 1) % 3);
387 child2.verts[0] = child1.verts[0];
388 child2.verts[1] = face.verts[edgeidx[2]];
389 child2.verts[2] = face.verts[(edgeidx[2] + 1) % 3];
390
391 if (visitor(child2))
392 divide_triangle(child2, std::forward<Fn>(visitor));
393}
long parent
Definition Hollowing.cpp:353
std::array< Vec3f, 3 > verts
Definition Hollowing.cpp:351
long faceid
Definition Hollowing.cpp:352
Vec3i indx
Definition Hollowing.cpp:350

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:

◆ exclude_neighbors()

static void Slic3r::sla::exclude_neighbors ( const Vec3i face,
std::vector< bool > &  mask,
const indexed_triangle_set its,
const VertexFaceIndex index,
size_t  recursions 
)
static
634{
635 for (int i = 0; i < 3; ++i) {
636 const auto &neighbors_range = index[face(i)];
637 for (size_t fi_n : neighbors_range) {
638 mask[fi_n] = true;
639 if (recursions > 0)
640 exclude_neighbors(its.indices[fi_n], mask, its, index, recursions - 1);
641 }
642 }
643}

References exclude_neighbors(), and indexed_triangle_set::indices.

Referenced by create_exclude_mask(), and exclude_neighbors().

+ 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)
331{
332 RotfinderBoilerplate<1000> bp{mo, params};
333
334 // Preparing the optimizer.
335 size_t gridsize = std::sqrt(bp.max_tries);
337 opt::StopCriteria{}.max_iterations(bp.max_tries)
338 .stop_condition([&bp] { return bp.stopcond(); }),
339 gridsize
340 );
341
342 // We are searching rotations around only two axes x, y. Thus the
343 // problem becomes a 2 dimensional optimization task.
344 // We can specify the bounds for a dimension in the following way:
345 auto bounds = opt::bounds({ {-PI, PI}, {-PI, PI} });
346
347 auto result = solver.to_max().optimize(
348 [&bp] (const XYRotation &rot)
349 {
350 bp.statusfn();
351 return get_misalginment_score(bp.mesh, to_transform3f(rot));
352 }, opt::initvals({0., 0.}), bounds);
353
354 return {result.optimum[0], result.optimum[1]};
355}
Definition Optimizer.hpp:50
StopCriteria & stop_condition(Fn &&cond)
Definition Optimizer.hpp:98
StopCriteria & max_iterations(unsigned val)
Definition Optimizer.hpp:91
Transform3f to_transform3f(const XYRotation &rot)
Definition Rotfinder.cpp:181
double get_misalginment_score(const TriangleMesh &mesh, const Transform3f &tr)
Definition Rotfinder.cpp:77
Definition Rotfinder.cpp:288

References Slic3r::opt::bounds(), Slic3r::opt::initvals(), Slic3r::opt::StopCriteria::max_iterations(), Slic3r::opt::Optimizer< Method, Enable >::optimize(), PI, 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 
)
359{
360 RotfinderBoilerplate<1000> bp{mo, params};
361
363 if (params.print_config())
364 pocfg.apply(*params.print_config(), true);
365
366 pocfg.apply(mo.config.get());
367
368 XYRotation rot;
369
370 // Different search methods have to be used depending on the model elevation
371 if (is_on_floor(pocfg)) {
372
373 std::vector<XYRotation> inputs = get_chull_rotations(bp.mesh, bp.max_tries);
374 bp.max_tries = inputs.size();
375
376 // If the model can be placed on the bed directly, we only need to
377 // check the 3D convex hull face rotations.
378
379 auto objfn = [&bp](const XYRotation &rot) {
380 bp.statusfn();
381 Transform3f tr = to_transform3f(rot);
382 return get_supportedness_onfloor_score(bp.mesh, tr);
383 };
384
385 rot = find_min_score<2>(objfn, inputs.begin(), inputs.end(), [&bp] {
386 return bp.stopcond();
387 });
388
389 } else {
390 // Preparing the optimizer.
391 size_t gridsize = std::sqrt(bp.max_tries); // 2D grid has gridsize^2 calls
392 opt::Optimizer<opt::AlgBruteForce> solver(
393 opt::StopCriteria{}.max_iterations(bp.max_tries)
394 .stop_condition([&bp] { return bp.stopcond(); }),
395 gridsize
396 );
397
398 // We are searching rotations around only two axes x, y. Thus the
399 // problem becomes a 2 dimensional optimization task.
400 // We can specify the bounds for a dimension in the following way:
401 auto bounds = opt::bounds({ {-PI, PI}, {-PI, PI} });
402
403 auto result = solver.to_min().optimize(
404 [&bp] (const XYRotation &rot)
405 {
406 bp.statusfn();
407 return get_supportedness_score(bp.mesh, to_transform3f(rot));
408 }, opt::initvals({0., 0.}), bounds);
409
410 // Save the result
411 rot = result.optimum;
412 }
413
414 return {rot[0], rot[1]};
415}
const DynamicPrintConfig & get() const
Definition PrintConfig.hpp:1268
ModelConfigObject config
Definition Model.hpp:339
RotOptimizeParams & print_config(const DynamicPrintConfig *c)
Definition Rotfinder.hpp:28
Bounds< N > bounds(const Bound(&b)[N])
Definition Optimizer.hpp:192
double get_supportedness_score(const Facestats &fc)
Definition Rotfinder.cpp:101
SLAPrintObjectConfig
Definition PrintConfig.hpp:1111

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

+ Here is the call graph for this function:

◆ find_merge_pt()

std::optional< Vec3f > Slic3r::sla::find_merge_pt ( const Vec3f A,
const Vec3f B,
float  critical_angle 
)
inline
874{
875 // The idea is that A and B both have their support cones. But searching
876 // for the intersection of these support cones is difficult and its enough
877 // to reduce this problem to 2D and search for the intersection of two
878 // rays that merge somewhere between A and B. The 2D plane is a vertical
879 // slice of the 3D scene where the 2D Y axis is equal to the 3D Z axis and
880 // the 2D X axis is determined by the XY direction of the AB vector.
881 //
882 // Z^
883 // | A *
884 // | . . B *
885 // | . . . .
886 // | . . . .
887 // | . x .
888 // -------------------> XY
889
890 // Determine the transformation matrix for the 2D projection:
891 Vec3f diff = {B.x() - A.x(), B.y() - A.y(), 0.f};
892 Vec3f dir = diff.normalized(); // TODO: avoid normalization
893
895 tr2D.row(0) = Vec3f{dir.x(), dir.y(), dir.z()};
896 tr2D.row(1) = Vec3f{0.f, 0.f, 1.f};
897
898 // Transform the 2 vectors A and B into 2D vector 'a' and 'b'. Here we can
899 // omit 'a', pretend that its the origin and use BA as the vector b.
900 Vec2f b = tr2D * (B - A);
901
902 // Get the square sine of the ray emanating from 'a' towards 'b'. This ray might
903 // exceed the allowed angle but that is corrected subsequently.
904 // The sign of the original sine is also needed, hence b.y is multiplied by
905 // abs(b.y)
906 float b_sqn = b.squaredNorm();
907 float sin2sig_a = b_sqn > EPSILON ? (b.y() * std::abs(b.y())) / b_sqn : 0.f;
908
909 // sine2 from 'b' to 'a' is the opposite of sine2 from a to b
910 float sin2sig_b = -sin2sig_a;
911
912 // Derive the allowed angles from the given critical angle.
913 // critical_angle is measured from the horizontal X axis.
914 // The rays need to go downwards which corresponds to negative angles
915
916 float sincrit = std::sin(critical_angle); // sine of the critical angle
917 float sin2crit = -sincrit * sincrit; // signed sine squared
918 sin2sig_a = std::min(sin2sig_a, sin2crit); // Do the angle saturation of both rays
919 sin2sig_b = std::min(sin2sig_b, sin2crit); //
920 float sin2_a = std::abs(sin2sig_a); // Get cosine squared values
921 float sin2_b = std::abs(sin2sig_b);
922 float cos2_a = 1.f - sin2_a;
923 float cos2_b = 1.f - sin2_b;
924
925 // Derive the new direction vectors. This is by square rooting the sin2
926 // and cos2 values and restoring the original signs
927 Vec2f Da = {std::copysign(std::sqrt(cos2_a), b.x()), std::copysign(std::sqrt(sin2_a), sin2sig_a)};
928 Vec2f Db = {-std::copysign(std::sqrt(cos2_b), b.x()), std::copysign(std::sqrt(sin2_b), sin2sig_b)};
929
930 // Determine where two rays ([0, 0], Da), (b, Db) intersect.
931 // Based on
932 // https://stackoverflow.com/questions/27459080/given-two-points-and-two-direction-vectors-find-the-point-where-they-intersect
933 // One ray is emanating from (0, 0) so the formula is simplified
934 double t1 = (Db.y() * b.x() - b.y() * Db.x()) /
935 (Da.x() * Db.y() - Da.y() * Db.x());
936
937 Vec2f mp = t1 * Da;
938 Vec3f Mp = A + tr2D.transpose() * mp;
939
940 return t1 >= 0.f ? Mp : Vec3f{};
941}
Eigen::Matrix< float, 2, 1, Eigen::DontAlign > Vec2f
Definition Point.hpp:48
Slic3r::Polygons diff(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:672

References Slic3r::diff(), and EPSILON.

Referenced by Slic3r::branchingtree::find_merge_pt().

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

◆ find_min_z_height_rotation()

Vec2d Slic3r::sla::find_min_z_height_rotation ( const ModelObject mo,
const RotOptimizeParams params 
)
436{
437 RotfinderBoilerplate<1000> bp{mo, params};
438
439 TriangleMesh chull = bp.mesh.convex_hull_3d();
440 auto inputs = reserve_vector<XYRotation>(chull.its.indices.size());
441 auto rotcmp = [](const XYRotation &r1, const XYRotation &r2) {
442 double xdiff = r1[X] - r2[X], ydiff = r1[Y] - r2[Y];
443 return std::abs(xdiff) < EPSILON ? ydiff < 0. : xdiff < 0.;
444 };
445 auto eqcmp = [](const XYRotation &r1, const XYRotation &r2) {
446 double xdiff = r1[X] - r2[X], ydiff = r1[Y] - r2[Y];
447 return std::abs(xdiff) < EPSILON && std::abs(ydiff) < EPSILON;
448 };
449
450 for (size_t fi = 0; fi < chull.its.indices.size(); ++fi) {
451 Facestats fc{get_triangle_vertices(chull, fi)};
452
453 auto q = Eigen::Quaternionf{}.FromTwoVectors(fc.normal, DOWN);
454 XYRotation rot = from_transform3f(Transform3f::Identity() * q);
455
456 auto it = std::lower_bound(inputs.begin(), inputs.end(), rot, rotcmp);
457
458 if (it == inputs.end() || !eqcmp(*it, rot))
459 inputs.insert(it, rot);
460 }
461
462 inputs.shrink_to_fit();
463 bp.max_tries = inputs.size();
464
465 auto objfn = [&bp, &chull](const XYRotation &rot) {
466 bp.statusfn();
467 Transform3f tr = to_transform3f(rot);
468 return bounding_box_with_tr(chull.its, tr).size().z();
469 };
470
471 XYRotation rot = find_min_score<2>(objfn, inputs.begin(), inputs.end(), [&bp] {
472 return bp.stopcond();
473 });
474
475 return {rot[0], rot[1]};
476}
PointType size() const
Definition BoundingBox.cpp:153
TriangleMesh convex_hull_3d() const
Definition TriangleMesh.cpp:500
static EIGEN_DEVICE_FUNC Quaternion FromTwoVectors(const MatrixBase< Derived1 > &a, const MatrixBase< Derived2 > &b)
The quaternion class used to represent 3D orientations and rotations.
Definition Quaternion.h:233
XYRotation from_transform3f(const Transform3f &tr)
Definition Rotfinder.cpp:190
std::array< double, 2 > XYRotation
Definition Rotfinder.cpp:178
std::array< Vec3f, 3 > get_triangle_vertices(const TriangleMesh &mesh, size_t faceidx)
Definition Rotfinder.cpp:26
BoundingBoxf3 bounding_box_with_tr(const indexed_triangle_set &its, const Transform3f &tr)
Definition Rotfinder.cpp:417
Eigen::Transform< float, 3, Eigen::Affine, Eigen::DontAlign > Transform3f
Definition Point.hpp:80
@ Y
Definition libslic3r.h:99
@ X
Definition libslic3r.h:98

References bounding_box_with_tr(), Slic3r::TriangleMesh::convex_hull_3d(), DOWN, EPSILON, Eigen::Quaternion< _Scalar, _Options >::FromTwoVectors(), Eigen::Transform< float, 3, Eigen::Affine, Eigen::DontAlign >::Identity(), indexed_triangle_set::indices, Slic3r::TriangleMesh::its, Slic3r::BoundingBox3Base< PointType >::size(), Slic3r::X, and Slic3r::Y.

+ Here is the call graph for this function:

◆ foreach_vertex()

template<class Fn >
void Slic3r::sla::foreach_vertex ( ExPolygon poly,
Fn &&  fn 
)
30{
31 for (auto &p : poly.contour.points) fn(p);
32 for (auto &h : poly.holes)
33 for (auto &p : h.points) fn(p);
34}

References Slic3r::ExPolygon::contour, Slic3r::ExPolygon::holes, and Slic3r::MultiPoint::points.

Referenced by raster_to_polygons().

+ Here is the caller graph for this function:

◆ generate_interior() [1/3]

InteriorPtr Slic3r::sla::generate_interior ( const indexed_triangle_set mesh,
const HollowingConfig hc = {},
const JobController ctl = {} 
)
inline
87 {},
88 const JobController &ctl = {})
89{
90 auto voxel_scale = get_voxel_scale(its_volume(mesh), hc);
91 auto statusfn = [&ctl](int){ return ctl.stopcondition && ctl.stopcondition(); };
92 auto grid = mesh_to_grid(mesh, MeshToGridParams{}
93 .voxel_scale(voxel_scale)
94 .exterior_bandwidth(3.f)
95 .interior_bandwidth(3.f)
96 .statusfn(statusfn));
97
98 if (!grid || (ctl.stopcondition && ctl.stopcondition()))
99 return {};
100
101// if (its_is_splittable(mesh))
102 grid = redistance_grid(*grid, 0.0f, 3.f, 3.f);
103
104 return grid ? generate_interior(*grid, hc, ctl) : InteriorPtr{};
105}
std::unique_ptr< Interior, InteriorDeleter > InteriorPtr
Definition Hollowing.hpp:30
InteriorPtr generate_interior(const VoxelGrid &vgrid, const HollowingConfig &hc, const JobController &ctl)
Definition Hollowing.cpp:70
VoxelGridPtr mesh_to_grid(const indexed_triangle_set &mesh, const MeshToGridParams &params)
Definition OpenVDBUtils.cpp:87
VoxelGridPtr redistance_grid(const VoxelGrid &vgrid, float iso, float er, float ir)
Definition OpenVDBUtils.cpp:216
IGL_INLINE void grid(const Eigen::MatrixBase< Derivedres > &res, Eigen::PlainObjectBase< DerivedGV > &GV)
Definition grid.cpp:13

◆ generate_interior() [2/3]

template<class It >
InteriorPtr Slic3r::sla::generate_interior ( const Range< It > &  csgparts,
const HollowingConfig hc = {},
const JobController ctl = {} 
)
131 {},
132 const JobController &ctl = {})
133{
134 double mesh_vol = csgmesh_positive_maxvolume(csgparts);
135 double voxsc = get_voxel_scale(mesh_vol, hc);
136
137 auto params = csg::VoxelizeParams{}
138 .voxel_scale(voxsc)
139 .exterior_bandwidth(3.f)
140 .interior_bandwidth(3.f)
141 .statusfn([&ctl](int){ return ctl.stopcondition && ctl.stopcondition(); });
142
143 auto ptr = csg::voxelize_csgmesh(csgparts, params);
144
145 if (!ptr || (ctl.stopcondition && ctl.stopcondition()))
146 return {};
147
148 // TODO: figure out issues without the redistance
149// if (csgparts.size() > 1 || its_is_splittable(*csg::get_mesh(*csgparts.begin())))
150
151 ptr = redistance_grid(*ptr, 0.0f, 3.f, 3.f);
152
153 return ptr ? generate_interior(*ptr, hc, ctl) : InteriorPtr{};
154}

◆ generate_interior() [3/3]

InteriorPtr Slic3r::sla::generate_interior ( const VoxelGrid vgrid,
const HollowingConfig hc,
const JobController ctl 
)
73{
74 double voxsc = get_voxel_scale(vgrid);
75 double offset = hc.min_thickness; // world units
76 double D = hc.closing_distance; // world units
77 float in_range = 1.1f * float(offset + D); // world units
78 float out_range = 1.f / voxsc; // world units
79 auto narrowb = 1.f; // voxel units (voxel count)
80
81 if (ctl.stopcondition()) return {};
82 else ctl.statuscb(0, _u8L("Hollowing"));
83
84 auto gridptr = dilate_grid(vgrid, out_range, in_range);
85
86 if (ctl.stopcondition()) return {};
87 else ctl.statuscb(30, _u8L("Hollowing"));
88
89 double iso_surface = D;
90 if (D > EPSILON) {
91 gridptr = redistance_grid(*gridptr, -(offset + D), narrowb, narrowb);
92
93 gridptr = dilate_grid(*gridptr, 1.1 * std::ceil(iso_surface), 0.f);
94
95 out_range = iso_surface;
96 in_range = narrowb / voxsc;
97 } else {
98 iso_surface = -offset;
99 }
100
101 if (ctl.stopcondition()) return {};
102 else ctl.statuscb(70, _u8L("Hollowing"));
103
104 double adaptivity = 0.;
105 InteriorPtr interior = InteriorPtr{new Interior{}};
106
107 interior->mesh = grid_to_mesh(*gridptr, iso_surface, adaptivity);
108 interior->gridptr = std::move(gridptr);
109
110 if (ctl.stopcondition()) return {};
111 else ctl.statuscb(100, _u8L("Hollowing"));
112
113 interior->iso_surface = iso_surface;
114 interior->thickness = offset;
115 interior->full_narrowb = (out_range + in_range) / 2.;
116
117 return interior;
118}
#define _u8L(s)
macro used to mark string used at localization, return same string
Definition SLAPrint.cpp:29
double closing_distance
Definition Hollowing.hpp:20
double min_thickness
Definition Hollowing.hpp:18
StatusFn statuscb
Definition JobController.hpp:18
VoxelGridPtr dilate_grid(const VoxelGrid &vgrid, float exteriorBandWidth, float interiorBandWidth)
Definition OpenVDBUtils.cpp:179
indexed_triangle_set grid_to_mesh(const VoxelGrid &vgrid, double isovalue, double adaptivity, bool relaxDisorientedTriangles)
Definition OpenVDBUtils.cpp:149
float get_voxel_scale(const VoxelGrid &vgrid)
Definition OpenVDBUtils.cpp:275
void offset(Slic3r::ExPolygon &sh, coord_t distance, const PolygonTag &)
Definition geometries.hpp:132

References _u8L, Slic3r::sla::HollowingConfig::closing_distance, Slic3r::dilate_grid(), EPSILON, get_voxel_scale(), Slic3r::grid_to_mesh(), Slic3r::sla::Interior::mesh, Slic3r::sla::HollowingConfig::min_thickness, Slic3r::offset(), Slic3r::redistance_grid(), Slic3r::sla::JobController::statuscb, and Slic3r::sla::JobController::stopcondition.

Referenced by hollow_mesh().

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

◆ get_avoidance()

static std::optional< Vec3f > Slic3r::sla::get_avoidance ( const GroundConnection conn,
float  maxdist 
)
static
294{
295 std::optional<Vec3f> ret;
296
297 if (conn) {
298 if (conn.path.size() > 1) {
299 ret = conn.path[1].pos.cast<float>();
300 } else {
301 Vec3f pbeg = conn.path[0].pos.cast<float>();
302 Vec3f pend = conn.pillar_base->pos.cast<float>();
303 pbeg.z() = std::max(pbeg.z() - maxdist, pend.z());
304 ret = pbeg;
305 }
306 }
307
308 return ret;
309}

References get_avoidance(), Slic3r::sla::GroundConnection::path, and Slic3r::sla::GroundConnection::pillar_base.

Referenced by get_avoidance(), and Slic3r::sla::BranchingTreeBuilder::suggest_avoidance().

+ 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
10{
11 Polygons ret; ret.reserve(poly.size());
12 for (const ExPolygon &p : poly) ret.emplace_back(p.contour);
13
14 return ret;
15}
Definition ExPolygon.hpp:16
std::vector< Polygon, PointsAllocator< Polygon > > Polygons
Definition Polygon.hpp:15

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)
inline
107{
108 return StopCriteria{}
111}
StopCriteria & rel_score_diff(double val)
Definition Optimizer.hpp:77
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::DefaultSupportTree::add_pinheads(), deepsearch_ground_connection(), optimize_anchor_placement(), optimize_pinhead_placement(), search_ground_route(), and search_widening_path().

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

◆ get_distance() [1/3]

static double Slic3r::sla::get_distance ( const TriangleBubble b,
const Interior interior 
)
static
323{
324 double R = b.R;
325 double D = 2. * R;
326 double Dst = get_distance_raw(b.center, interior);
327
328 return D > interior.full_narrowb ||
329 ((Dst - R) < 0. && 2 * R > interior.thickness) ?
330 std::nan("") :
331 Dst - interior.iso_surface;
332}
#define Dst
Definition mesh.h:153
double get_distance_raw(const Vec3f &p, const VoxelGrid &vgrid)
Definition OpenVDBUtils.cpp:263
double full_narrowb
Definition Hollowing.cpp:35
double thickness
Definition Hollowing.cpp:34

References Dst, Slic3r::sla::Interior::full_narrowb, get_distance(), Slic3r::get_distance_raw(), Slic3r::sla::Interior::iso_surface, and Slic3r::sla::Interior::thickness.

Referenced by get_distance(), get_distance(), 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 
)
inline
335{
336 double d = get_distance_raw(p, interior) - interior.iso_surface;
337 return d;
338}
double iso_surface
Definition Hollowing.cpp:33

References get_distance(), Slic3r::get_distance_raw(), and Slic3r::sla::Interior::iso_surface.

+ 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 
)
342{
343 return get_distance(Vec3f(p.template cast<float>()), interior);
344}
static double get_distance(const TriangleBubble &b, const Interior &interior)
Definition Hollowing.cpp:322

References get_distance().

+ Here is the call graph for this function:

◆ get_distance_raw()

static double Slic3r::sla::get_distance_raw ( const Vec3f p,
const Interior interior 
)
static
312{
313 assert(interior.gridptr);
314
315 return Slic3r::get_distance_raw(p, *interior.gridptr);
316}
VoxelGridPtr gridptr
Definition Hollowing.cpp:31

References Slic3r::get_distance_raw(), and Slic3r::sla::Interior::gridptr.

+ Here is the call graph for this function:

◆ get_grid() [1/2]

const VoxelGrid & Slic3r::sla::get_grid ( const Interior interior)
61{
62 return *interior.gridptr;
63}

References Slic3r::sla::Interior::gridptr.

◆ get_grid() [2/2]

VoxelGrid & Slic3r::sla::get_grid ( Interior interior)
66{
67 return *interior.gridptr;
68}

References Slic3r::sla::Interior::gridptr.

◆ get_mesh() [1/8]

indexed_triangle_set Slic3r::sla::get_mesh ( const Bridge br,
size_t  steps 
)
234{
235 using Quaternion = Eigen::Quaternion<float>;
236 Vec3d v = (br.endp - br.startp);
237 Vec3d dir = v.normalized();
238 double d = v.norm();
239
240 indexed_triangle_set mesh = cylinder(br.r, d, steps);
241
242 auto quater = Quaternion::FromTwoVectors(Vec3f{0.f, 0.f, 1.f},
243 dir.cast<float>());
244
245 Vec3f startp = br.startp.cast<float>();
246 for(auto& p : mesh.vertices) p = quater * p + startp;
247
248 return mesh;
249}
Vec3d endp
Definition SupportTreeBuilder.hpp:182
Vec3d startp
Definition SupportTreeBuilder.hpp:182
double r
Definition SupportTreeBuilder.hpp:181

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

+ 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 
)
252{
253 double h = br.get_length();
254 indexed_triangle_set mesh = halfcone(h, br.r, br.end_r, Vec3d::Zero(), steps);
255
256 using Quaternion = Eigen::Quaternion<float>;
257
258 // We rotate the head to the specified direction. The head's pointing
259 // side is facing upwards so this means that it would hold a support
260 // point with a normal pointing straight down. This is the reason of
261 // the -1 z coordinate
262 auto quatern = Quaternion::FromTwoVectors(Vec3f{0.f, 0.f, 1.f},
263 br.get_dir().cast<float>());
264
265 Vec3f startp = br.startp.cast<float>();
266 for(auto& p : mesh.vertices) p = quatern * p + startp;
267
268 return mesh;
269}
indexed_triangle_set halfcone(double baseheight, double r_bottom, double r_top, const Vec3d &pos, size_t steps)
Definition SupportTreeMesher.cpp:160
Vec3d get_dir() const
Definition SupportTreeBuilder.hpp:190
double get_length() const
Definition SupportTreeBuilder.hpp:189
double end_r
Definition SupportTreeBuilder.hpp:194

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

+ 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 
)
213{
215
216 for (auto& p : mesh.vertices) p.z() -= (h.fullwidth() - h.r_back_mm);
217
218 using Quaternion = Eigen::Quaternion<float>;
219
220 // We rotate the head to the specified direction. The head's pointing
221 // side is facing upwards so this means that it would hold a support
222 // point with a normal pointing straight down. This is the reason of
223 // the -1 z coordinate
224 auto quatern = Quaternion::FromTwoVectors(Vec3f{0.f, 0.f, -1.f},
225 h.dir.cast<float>());
226
227 Vec3f pos = h.pos.cast<float>();
228 for (auto& p : mesh.vertices) p = quatern * p + pos;
229
230 return mesh;
231}
indexed_triangle_set pinhead(double r_pin, double r_back, double length, size_t steps)
Definition SupportTreeMesher.cpp:96
Vec3d pos
Definition SupportTreeBuilder.hpp:81
double r_pin_mm
Definition SupportTreeBuilder.hpp:84
double r_back_mm
Definition SupportTreeBuilder.hpp:83
Vec3d dir
Definition SupportTreeBuilder.hpp:80
double width_mm
Definition SupportTreeBuilder.hpp:85

References Slic3r::sla::Head::dir, Slic3r::sla::Head::fullwidth(), pinhead(), pos(), Slic3r::sla::Head::pos, Slic3r::sla::Head::r_back_mm, Slic3r::sla::Head::r_pin_mm, indexed_triangle_set::vertices, 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)
56{
57 return interior.mesh;
58}
indexed_triangle_set mesh
Definition Hollowing.cpp:30

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

◆ get_mesh() [5/8]

indexed_triangle_set Slic3r::sla::get_mesh ( const Junction j,
size_t  steps 
)
inline
66{
67 indexed_triangle_set mesh = sphere(j.r, make_portion(0, PI), 2 * PI / steps);
68 Vec3f pos = j.pos.cast<float>();
69 for(auto& p : mesh.vertices) p += pos;
70 return mesh;
71}
Vec3d pos(const Pt &p)
Definition ReprojectPointsOnMesh.hpp:14
indexed_triangle_set sphere(double rho, Portion portion, double fa)
Definition SupportTreeMesher.cpp:5
Portion make_portion(double a, double b)
Definition SupportTreeMesher.hpp:14

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

+ 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
61{
62 return halfcone(p.height, p.r_bottom, p.r_top, p.pos, steps);
63}
double height
Definition SupportTreeBuilder.hpp:168
Vec3d pos
Definition SupportTreeBuilder.hpp:167
double r_top
Definition SupportTreeBuilder.hpp:168
double r_bottom
Definition SupportTreeBuilder.hpp:168

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
49{
50 if(p.height > EPSILON) { // Endpoint is below the starting point
51 // We just create a bridge geometry with the pillar parameters and
52 // move the data.
53 //return cylinder(p.r_start, p.height, steps, p.endpoint());
54 return halfcone(p.height, p.r_end, p.r_start, p.endpt, steps);
55 }
56
57 return {};
58}
double height
Definition SupportTreeBuilder.hpp:132
double r_start
Definition SupportTreeBuilder.hpp:132
Vec3d endpt
Definition SupportTreeBuilder.hpp:133
double r_end
Definition SupportTreeBuilder.hpp:132

References Slic3r::sla::Pillar::endpt, EPSILON, halfcone(), Slic3r::sla::Pillar::height, Slic3r::sla::Pillar::r_end, and Slic3r::sla::Pillar::r_start.

+ Here is the call graph for this function:

◆ get_mesh() [8/8]

indexed_triangle_set & Slic3r::sla::get_mesh ( Interior interior)
51{
52 return interior.mesh;
53}

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

Referenced by Slic3r::SLAPrint::Steps::generate_preview(), Slic3r::sla::Anchor::Head(), Slic3r::SLAPrint::Steps::hollow_model(), and Slic3r::sla::SupportTreeBuilder::merged_mesh().

+ Here is the caller graph for this function:

◆ get_voxel_scale()

double Slic3r::sla::get_voxel_scale ( double  mesh_volume,
const HollowingConfig hc 
)
745{
746 static constexpr double MIN_SAMPLES_IN_WALL = 3.5;
747 static constexpr double MAX_OVERSAMPL = 8.;
748 static constexpr double UNIT_VOLUME = 500000; // empiric
749
750 // I can't figure out how to increase the grid resolution through openvdb
751 // API so the model will be scaled up before conversion and the result
752 // scaled down. Voxels have a unit size. If I set voxelSize smaller, it
753 // scales the whole geometry down, and doesn't increase the number of
754 // voxels.
755 //
756 // First an allowed range for voxel scale is determined from an initial
757 // range of <MIN_SAMPLES_IN_WALL, MAX_OVERSAMPL>. The final voxel scale is
758 // then chosen from this range using the 'quality:<0, 1>' parameter.
759 // The minimum can be lowered if the wall thickness is great enough and
760 // the maximum is lowered if the model volume very big.
761
762 double sc_divider = std::max(1.0, (mesh_volume / UNIT_VOLUME));
763 double min_oversampl = std::max(MIN_SAMPLES_IN_WALL / hc.min_thickness, 1.);
764 double max_oversampl_scaled = std::max(min_oversampl, MAX_OVERSAMPL / sc_divider);
765 auto voxel_scale = min_oversampl + (max_oversampl_scaled - min_oversampl) * hc.quality;
766
767 BOOST_LOG_TRIVIAL(debug) << "Hollowing: max oversampl will be: " << max_oversampl_scaled;
768 BOOST_LOG_TRIVIAL(debug) << "Hollowing: voxel scale will be: " << voxel_scale;
769 BOOST_LOG_TRIVIAL(debug) << "Hollowing: mesh volume is: " << mesh_volume;
770
771 return voxel_scale;
772}
double quality
Definition Hollowing.hpp:19

References Slic3r::get_voxel_scale(), Slic3r::sla::HollowingConfig::min_thickness, and Slic3r::sla::HollowingConfig::quality.

Referenced by generate_interior().

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

◆ ground_level()

double Slic3r::sla::ground_level ( const SupportableMesh sm)
inline

◆ halfcone()

indexed_triangle_set Slic3r::sla::halfcone ( double  baseheight,
double  r_bottom,
double  r_top,
const Vec3d pos,
size_t  steps 
)
165{
166 assert(steps > 0);
167
168 if (baseheight <= 0 || steps <= 0 || (r_bottom <= 0. && r_top <= 0.))
169 return {};
170
172
173 double a = 2 * PI / steps;
174 auto last = int(steps - 1);
175 Vec3d ep{pos.x(), pos.y(), pos.z() + baseheight};
176 for (size_t i = 0; i < steps; ++i) {
177 double phi = i * a;
178 auto x = float(pos.x() + r_top * std::cos(phi));
179 auto y = float(pos.y() + r_top * std::sin(phi));
180 base.vertices.emplace_back(x, y, float(ep.z()));
181 }
182
183 for (size_t i = 0; i < steps; ++i) {
184 double phi = i * a;
185 auto x = float(pos.x() + r_bottom * std::cos(phi));
186 auto y = float(pos.y() + r_bottom * std::sin(phi));
187 base.vertices.emplace_back(x, y, float(pos.z()));
188 }
189
190 base.vertices.emplace_back(pos.cast<float>());
191 base.vertices.emplace_back(ep.cast<float>());
192
193 auto &indices = base.indices;
194 auto hcenter = int(base.vertices.size() - 1);
195 auto lcenter = int(base.vertices.size() - 2);
196 auto offs = int(steps);
197 for (int i = 0; i < last; ++i) {
198 indices.emplace_back(i, i + offs, offs + i + 1);
199 indices.emplace_back(i, offs + i + 1, i + 1);
200 indices.emplace_back(i, i + 1, hcenter);
201 indices.emplace_back(lcenter, offs + i + 1, offs + i);
202 }
203
204 indices.emplace_back(0, last, offs);
205 indices.emplace_back(last, offs + last, offs);
206 indices.emplace_back(hcenter, last, 0);
207 indices.emplace_back(offs, offs + last, lcenter);
208
209 return base;
210}
const Scalar & y
Definition MathFunctions.h:552
TCoord< P > x(const P &p)
Definition geometry_traits.hpp:297

References indexed_triangle_set::indices, PI, pos(), and indexed_triangle_set::vertices.

Referenced by get_mesh(), get_mesh(), and get_mesh().

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

◆ hollow_mesh() [1/4]

void Slic3r::sla::hollow_mesh ( indexed_triangle_set mesh,
const HollowingConfig cfg,
int  flags = 0 
)

◆ hollow_mesh() [2/4]

void Slic3r::sla::hollow_mesh ( indexed_triangle_set mesh,
const Interior interior,
int  flags 
)
296{
297 if (mesh.empty() || interior.mesh.empty()) return;
298
299 if (flags & hfRemoveInsideTriangles && interior.gridptr)
300 remove_inside_triangles(mesh, interior);
301
302 indexed_triangle_set interi = interior.mesh;
303 sla::swap_normals(interi);
304
305 its_merge(mesh, interi);
306}
void remove_inside_triangles(indexed_triangle_set &mesh, const Interior &interior, const std::vector< bool > &exclude_mask)
Definition Hollowing.cpp:395
bool empty() const
Definition stl.h:167

References indexed_triangle_set::empty(), Slic3r::sla::Interior::gridptr, hfRemoveInsideTriangles, hollow_mesh(), Slic3r::its_merge(), Slic3r::sla::Interior::mesh, remove_inside_triangles(), and swap_normals().

+ Here is the call graph for this function:

◆ hollow_mesh() [3/4]

void Slic3r::sla::hollow_mesh ( TriangleMesh mesh,
const HollowingConfig cfg,
int  flags 
)
274{
275 InteriorPtr interior = generate_interior(mesh.its, cfg, JobController{});
276 if (!interior) return;
277
278 hollow_mesh(mesh, *interior, flags);
279}
void hollow_mesh(TriangleMesh &mesh, const HollowingConfig &cfg, int flags)
Definition Hollowing.cpp:273
A Control structure for the support calculation. Consists of the status indicator callback and the st...
Definition JobController.hpp:12

References generate_interior(), hollow_mesh(), and Slic3r::TriangleMesh::its.

Referenced by Slic3r::SLAPrint::Steps::generate_preview(), hollow_mesh(), hollow_mesh(), and hollow_mesh().

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

◆ hollow_mesh() [4/4]

void Slic3r::sla::hollow_mesh ( TriangleMesh mesh,
const Interior interior,
int  flags 
)
282{
283 if (mesh.empty() || interior.mesh.empty()) return;
284
285 if (flags & hfRemoveInsideTriangles && interior.gridptr)
286 remove_inside_triangles(mesh, interior);
287
288 indexed_triangle_set interi = interior.mesh;
289 sla::swap_normals(interi);
290 TriangleMesh inter{std::move(interi)};
291
292 mesh.merge(inter);
293}
void merge(const TriangleMesh &mesh)
Definition TriangleMesh.cpp:407

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

+ Here is the call graph for this function:

◆ hollow_mesh_and_drill()

int Slic3r::sla::hollow_mesh_and_drill ( indexed_triangle_set hollowed_mesh,
const Interior interior,
const DrainHoles drainholes,
std::function< void(size_t)>  on_hole_fail 
)
810{
811 auto tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(
812 hollowed_mesh.vertices,
813 hollowed_mesh.indices
814 );
815
816 std::uniform_real_distribution<float> dist(0., float(EPSILON));
817 auto holes_mesh_cgal = MeshBoolean::cgal::triangle_mesh_to_cgal({}, {});
818 indexed_triangle_set part_to_drill = hollowed_mesh;
819
820 std::mt19937 m_rng{std::random_device{}()};
821
822 for (size_t i = 0; i < drainholes.size(); ++i) {
823 sla::DrainHole holept = drainholes[i];
824
825 holept.normal += Vec3f{dist(m_rng), dist(m_rng), dist(m_rng)};
826 holept.normal.normalize();
827 holept.pos += Vec3f{dist(m_rng), dist(m_rng), dist(m_rng)};
828 indexed_triangle_set m = holept.to_mesh();
829
830 part_to_drill.indices.clear();
831 auto bb = bounding_box(m);
832 Eigen::AlignedBox<float, 3> ebb{bb.min.cast<float>(),
833 bb.max.cast<float>()};
834
835 AABBTreeIndirect::traverse(
836 tree,
837 AABBTreeIndirect::intersecting(ebb),
838 [&part_to_drill, &hollowed_mesh](const auto& node)
839 {
840 part_to_drill.indices.emplace_back(hollowed_mesh.indices[node.idx]);
841 // continue traversal
842 return true;
843 });
844
845 auto cgal_meshpart = MeshBoolean::cgal::triangle_mesh_to_cgal(
846 remove_unconnected_vertices(part_to_drill));
847
848 if (MeshBoolean::cgal::does_self_intersect(*cgal_meshpart)) {
849 on_hole_fail(i);
850 continue;
851 }
852
853 auto cgal_hole = MeshBoolean::cgal::triangle_mesh_to_cgal(m);
854 MeshBoolean::cgal::plus(*holes_mesh_cgal, *cgal_hole);
855 }
856
857 auto ret = static_cast<int>(HollowMeshResult::Ok);
858
859 if (MeshBoolean::cgal::does_self_intersect(*holes_mesh_cgal)) {
860 ret |= static_cast<int>(HollowMeshResult::DrillingFailed);
861 }
862
863 auto hollowed_mesh_cgal = MeshBoolean::cgal::triangle_mesh_to_cgal(hollowed_mesh);
864
865 if (!MeshBoolean::cgal::does_bound_a_volume(*hollowed_mesh_cgal)) {
866 ret |= static_cast<int>(HollowMeshResult::FaultyMesh);
867 }
868
869 if (!MeshBoolean::cgal::empty(*holes_mesh_cgal)
870 && !MeshBoolean::cgal::does_bound_a_volume(*holes_mesh_cgal)) {
871 ret |= static_cast<int>(HollowMeshResult::FaultyHoles);
872 }
873
874 // Don't even bother
875 if (ret & static_cast<int>(HollowMeshResult::DrillingFailed))
876 return ret;
877
878 try {
879 if (!MeshBoolean::cgal::empty(*holes_mesh_cgal))
880 MeshBoolean::cgal::minus(*hollowed_mesh_cgal, *holes_mesh_cgal);
881
882 hollowed_mesh =
883 MeshBoolean::cgal::cgal_to_indexed_triangle_set(*hollowed_mesh_cgal);
884
885 std::vector<bool> exclude_mask =
886 create_exclude_mask(hollowed_mesh, interior, drainholes);
887
888 sla::remove_inside_triangles(hollowed_mesh, interior, exclude_mask);
889 } catch (const Slic3r::RuntimeError &) {
890 ret |= static_cast<int>(HollowMeshResult::DrillingFailed);
891 }
892
893 return ret;
894}
EIGEN_DEVICE_FUNC const VectorType &() min() const
Definition AlignedBox.h:106
An axis aligned box.
Definition AlignedBox.h:31
T dist(const boost::polygon::point_data< T > &p1, const boost::polygon::point_data< T > &p2)
Definition Geometry.cpp:280
static indexed_triangle_set remove_unconnected_vertices(const indexed_triangle_set &its)
Definition Hollowing.cpp:777
std::vector< bool > create_exclude_mask(const indexed_triangle_set &its, const Interior &interior, const std::vector< DrainHole > &holes)
Definition Hollowing.cpp:645
IGL_INLINE void bounding_box(const Eigen::MatrixBase< DerivedV > &V, Eigen::PlainObjectBase< DerivedBV > &BV, Eigen::PlainObjectBase< DerivedBF > &BF)
Definition bounding_box.cpp:12

References create_exclude_mask(), EPSILON, hollow_mesh_and_drill(), indexed_triangle_set::indices, Eigen::AlignedBox< _Scalar, _AmbientDim >::min(), Slic3r::sla::DrainHole::normal, Slic3r::sla::DrainHole::pos, remove_unconnected_vertices(), Slic3r::sla::DrainHole::to_mesh(), and indexed_triangle_set::vertices.

Referenced by Slic3r::SLAPrint::Steps::generate_preview(), and hollow_mesh_and_drill().

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

◆ is_outside_support_cone()

bool Slic3r::sla::is_outside_support_cone ( const Vec3f supp,
const Vec3f pt,
float  angle 
)
inline
860{
861 using namespace Slic3r;
862
863 Vec3d D = (pt - supp).cast<double>();
864 double dot_sq = -D.z() * std::abs(-D.z());
865
866 return dot_sq <
867 D.squaredNorm() * std::cos(angle) * std::abs(std::cos(angle));
868}
Definition avrdude-slic3r.cpp:16

References Slic3r::angle(), and is_outside_support_cone().

Referenced by is_outside_support_cone().

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

◆ make_layers()

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

References Slic3r::ex_tbb, and Slic3r::execution::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
15{
16 return std::make_tuple(a, b);
17}

Referenced by get_mesh(), and pinhead().

+ Here is the caller graph for this function:

◆ min_hit()

template<class It >
Hit Slic3r::sla::min_hit ( It  from,
It  to 
)
98{
99 auto mit = std::min_element(from, to, [](const Hit &h1, const Hit &h2) {
100 return h1.distance() < h2.distance();
101 });
102
103 return *mit;
104}

References Slic3r::AABBMesh::hit_result::distance().

+ Here is the call graph for this function:

◆ non_duplicate_suppt_indices()

template<class PtIndex >
std::vector< size_t > Slic3r::sla::non_duplicate_suppt_indices ( const PtIndex &  index,
const SupportPoints suppts,
double  eps 
)
297{
298 std::vector<bool> to_remove(suppts.size(), false);
299
300 for (size_t i = 0; i < suppts.size(); ++i) {
301 size_t closest_idx =
302 find_closest_point(index, suppts[i].pos,
303 [&i, &to_remove](size_t i_closest) {
304 return i_closest != i &&
305 !to_remove[i_closest];
306 });
307
308 if (closest_idx < suppts.size() &&
309 (suppts[i].pos - suppts[closest_idx].pos).norm() < eps)
310 to_remove[i] = true;
311 }
312
313 auto ret = reserve_vector<size_t>(suppts.size());
314 for (size_t i = 0; i < to_remove.size(); i++)
315 if (!to_remove[i])
316 ret.emplace_back(i);
317
318 return ret;
319}
size_t find_closest_point(const KDTreeIndirect< D, CoordT, CoordFn > &kdtree, const PointType &point, FilterFn filter)
Definition KDTreeIndirect.hpp:266

References Slic3r::find_closest_point(), non_duplicate_suppt_indices(), and pos().

Referenced by create_branching_tree(), and non_duplicate_suppt_indices().

+ 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 
)
136{
137 auto arc_tolerance = scaled<double>(0.01);
138 Polygons res = closing(hull.polygons(), 2 * delta, delta, ClipperLib::jtRound, arc_tolerance);
139
140 auto it = std::remove_if(res.begin(), res.end(), [](Polygon &p) { return p.is_clockwise(); });
141 res.erase(it, res.end());
142
143 return res;
144}
Definition Polygon.hpp:24
const Polygons & polygons() const
Definition ConcaveHull.hpp:44
@ jtRound
Definition clipper.hpp:138
Slic3r::Polygons closing(const Slic3r::Polygons &polygons, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:587

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

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 
)
131{
132 return to_expolygons(offset_waffle_style(hull, delta));
133}
Polygons offset_waffle_style(const ConcaveHull &hull, coord_t delta)
Definition ConcaveHull.cpp:135
ExPolygons to_expolygons(const Polygons &polys)
Definition ExPolygon.hpp:347

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 
)
37{
38 stream.write(reinterpret_cast<const char *>(bytes.data()),
39 std::streamsize(bytes.size()));
40
41 return stream;
42}
const void * data() const
Definition RasterBase.hpp:29
size_t size() const
Definition RasterBase.hpp:28

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

+ Here is the call graph for this function:

◆ optimize_anchor_placement()

template<class Ex >
bool Slic3r::sla::optimize_anchor_placement ( Ex  policy,
const SupportableMesh sm,
const Junction from,
Anchor anchor 
)
779{
780 Vec3d n = get_normal(sm.emesh, anchor.pos);
781
782 auto [polar, azimuth] = dir_to_spheric(n);
783
784 // Saturate the polar angle to 3pi/4
785 polar = std::min(polar, sm.cfg.bridge_slope);
786
787 double lmin = 0;
788 double lmax = std::min(sm.cfg.head_width_mm,
789 distance(from.pos, anchor.pos) - 2 * from.r);
790
791 double sd = sm.cfg.safety_distance(anchor.r_back_mm);
792
794 .stop_score(anchor.fullwidth())
795 .max_iterations(100));
796
797 solver.seed(0); // deterministic behavior
798
799 auto oresult = solver.to_max().optimize(
800 [&sm, &anchor, sd, policy](const opt::Input<3> &input) {
801 auto &[plr, azm, l] = input;
802
803 auto dir = spheric_to_dir(plr, azm).normalized();
804
805 anchor.width_mm = l;
806 anchor.dir = dir;
807
808 return pinhead_mesh_hit(policy, sm.emesh, anchor, sd)
809 .distance();
810 },
811 initvals({polar, azimuth, (lmin + lmax) / 2.}),
812 bounds({{0., sm.cfg.bridge_slope}, // Must not exceed the slope limit
813 {-PI, PI}, // azimuth can be a full search
814 {lmin, lmax}}));
815
816 polar = std::get<0>(oresult.optimum);
817 azimuth = std::get<1>(oresult.optimum);
818 anchor.dir = spheric_to_dir(polar, azimuth).normalized();
819 anchor.width_mm = std::get<2>(oresult.optimum);
820
821 if (oresult.score < anchor.fullwidth()) {
822 // Unsuccesful search, the anchor does not fit into its intended space.
823 return false;
824 }
825
826 return true;
827}
StopCriteria & stop_score(double val)
Definition Optimizer.hpp:84
Hit pinhead_mesh_hit(Ex ex, const AABBMesh &mesh, const Vec3d &s, const Vec3d &dir, double r_pin, double r_back, double width, double sd)
Definition SupportTreeUtils.hpp:193
Vec3d get_normal(const AABBMesh &mesh, const Vec3d &picking_point, double eps)
Definition MeshNormals.cpp:17
double fullwidth() const
Definition SupportTreeBuilder.hpp:109

References Slic3r::sla::SupportTreeConfig::bridge_slope, Slic3r::sla::SupportableMesh::cfg, Slic3r::sla::Head::dir, Slic3r::AABBMesh::hit_result::distance(), Slic3r::sla::SupportableMesh::emesh, Slic3r::sla::Head::fullwidth(), get_criteria(), Slic3r::get_normal(), Slic3r::sla::SupportTreeConfig::head_width_mm, input(), Slic3r::opt::StopCriteria::max_iterations(), Slic3r::opt::Optimizer< Method, Enable >::optimize(), optimize_anchor_placement(), PI, pinhead_mesh_hit(), Slic3r::sla::Junction::pos, Slic3r::sla::Head::pos, Slic3r::sla::Junction::r, Slic3r::sla::Head::r_back_mm, Slic3r::sla::SupportTreeConfig::safety_distance(), Slic3r::opt::Optimizer< Method, Enable >::seed(), Slic3r::opt::StopCriteria::stop_score(), Slic3r::opt::Optimizer< Method, Enable >::to_max(), and Slic3r::sla::Head::width_mm.

Referenced by calculate_anchor_placement(), and optimize_anchor_placement().

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

◆ optimize_pinhead_placement()

template<class Ex >
bool Slic3r::sla::optimize_pinhead_placement ( Ex  policy,
const SupportableMesh m,
Head head 
)
325{
326 Vec3d n = get_normal(m.emesh, head.pos);
327 assert(std::abs(n.norm() - 1.0) < EPSILON);
328
329 // for all normals the spherical coordinates are generated and
330 // the polar angle is saturated to 45 degrees from the bottom then
331 // converted back to standard coordinates to get the new normal.
332 // Then a simple quaternion is created from the two normals
333 // (Quaternion::FromTwoVectors) and the rotation is applied to the
334 // pinhead.
335
336 auto [polar, azimuth] = dir_to_spheric(n);
337
338 double back_r = head.r_back_mm;
339
340 // skip if the tilt is not sane
341 if (polar < PI - m.cfg.normal_cutoff_angle) return false;
342
343 // We saturate the polar angle to 3pi/4
344 polar = std::max(polar, PI - m.cfg.bridge_slope);
345
346 // save the head (pinpoint) position
347 Vec3d hp = head.pos;
348
349 double lmin = m.cfg.head_width_mm, lmax = lmin;
350
351 if (back_r < m.cfg.head_back_radius_mm) {
352 lmin = 0., lmax = m.cfg.head_penetration_mm;
353 }
354
355 // The distance needed for a pinhead to not collide with model.
356 double w = lmin + 2 * back_r + 2 * m.cfg.head_front_radius_mm -
358
359 double pin_r = head.r_pin_mm;
360
361 // Reassemble the now corrected normal
362 auto nn = spheric_to_dir(polar, azimuth).normalized();
363
364 double sd = m.cfg.safety_distance(back_r);
365
366 // check available distance
367 Hit t = pinhead_mesh_hit(policy, m.emesh, hp, nn, pin_r, back_r, w, sd);
368
369 if (t.distance() < w) {
370 // Let's try to optimize this angle, there might be a
371 // viable normal that doesn't collide with the model
372 // geometry and its very close to the default.
373
374 Optimizer<opt::AlgNLoptMLSL_Subplx> solver(get_criteria(m.cfg).stop_score(w).max_iterations(100));
375 solver.seed(0); // we want deterministic behavior
376
377 auto oresult = solver.to_max().optimize(
378 [&m, pin_r, back_r, hp, sd, policy](const opt::Input<3> &input) {
379 auto &[plr, azm, l] = input;
380
381 auto dir = spheric_to_dir(plr, azm).normalized();
382
383 return pinhead_mesh_hit(policy, m.emesh, hp, dir, pin_r,
384 back_r, l, sd).distance();
385 },
386 initvals({polar, azimuth,
387 (lmin + lmax) / 2.}), // start with what we have
388 bounds({{PI - m.cfg.bridge_slope, PI}, // Must not exceed the slope limit
389 {-PI, PI}, // azimuth can be a full search
390 {lmin, lmax}}));
391
392 if(oresult.score > w) {
393 polar = std::get<0>(oresult.optimum);
394 azimuth = std::get<1>(oresult.optimum);
395 nn = spheric_to_dir(polar, azimuth).normalized();
396 lmin = std::get<2>(oresult.optimum);
397 t = AABBMesh::hit_result(oresult.score);
398 }
399 }
400
401 bool ret = false;
402 if (t.distance() > w && hp.z() + w * nn.z() >= ground_level(m)) {
403 head.dir = nn;
404 head.width_mm = lmin;
405 head.r_back_mm = back_r;
406
407 ret = true;
408 } else if (back_r > m.cfg.head_fallback_radius_mm) {
409 head.r_back_mm = m.cfg.head_fallback_radius_mm;
410 ret = optimize_pinhead_placement(policy, m, head);
411 }
412
413 return ret;
414}
bool optimize_pinhead_placement(Ex policy, const SupportableMesh &m, Head &head)
Definition SupportTreeUtils.hpp:322
static const double constexpr normal_cutoff_angle
Definition SupportTree.hpp:96

References Slic3r::sla::SupportTreeConfig::bridge_slope, Slic3r::sla::SupportableMesh::cfg, Slic3r::AABBMesh::hit_result::distance(), Slic3r::sla::SupportableMesh::emesh, EPSILON, get_criteria(), Slic3r::get_normal(), ground_level(), head(), Slic3r::sla::SupportTreeConfig::head_back_radius_mm, Slic3r::sla::SupportTreeConfig::head_fallback_radius_mm, Slic3r::sla::SupportTreeConfig::head_front_radius_mm, Slic3r::sla::SupportTreeConfig::head_penetration_mm, Slic3r::sla::SupportTreeConfig::head_width_mm, input(), Slic3r::opt::StopCriteria::max_iterations(), Slic3r::sla::SupportTreeConfig::normal_cutoff_angle, Slic3r::opt::Optimizer< Method, Enable >::optimize(), optimize_pinhead_placement(), PI, pinhead_mesh_hit(), Slic3r::sla::SupportTreeConfig::safety_distance(), Slic3r::opt::Optimizer< Method, Enable >::seed(), Slic3r::opt::StopCriteria::stop_score(), and Slic3r::opt::Optimizer< Method, Enable >::to_max().

Referenced by calculate_pinhead_placement(), and optimize_pinhead_placement().

+ Here is the call graph for this function:
+ Here is the caller 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.

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

References indexed_triangle_set::empty(), Slic3r::slice_mesh_ex(), and Slic3r::union_ex().

Referenced by create_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 
)
506{
507 float gnd = float(bounding_box(mesh).min(Z));
508
509 std::vector<float> slicegrid = grid(gnd, gnd + h, layerh);
510 pad_blueprint(mesh, output, slicegrid, thrfn);
511}
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:473

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

+ Here is the call graph for this function:

◆ pairhash()

template<class I , class DoubleI = IntegerOnly<I>>
IntegerOnly< DoubleI > Slic3r::sla::pairhash ( a,
b 
)
20{
21 using std::ceil; using std::log2; using std::max; using std::min;
22 static const auto constexpr Ibits = int(sizeof(I) * CHAR_BIT);
23 static const auto constexpr DoubleIbits = int(sizeof(DoubleI) * CHAR_BIT);
24 static const auto constexpr shift = DoubleIbits / 2 < Ibits ? Ibits / 2 : Ibits;
25
26 I g = min(a, b), l = max(a, b);
27
28 // Assume the hash will fit into the output variable
29 assert((g ? (ceil(log2(g))) : 0) <= shift);
30 assert((l ? (ceil(log2(l))) : 0) <= shift);
31
32 return (DoubleI(g) << shift) + l;
33}
EIGEN_DEVICE_FUNC const CeilReturnType ceil() const
Definition ArrayCwiseUnaryOps.h:402

References ceil().

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

+ Here is the call graph for this function:
+ 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 
)
100{
101 assert(steps > 0);
102 assert(length >= 0.);
103 assert(r_back > 0.);
104 assert(r_pin > 0.);
105
107
108 // We create two spheres which will be connected with a robe that fits
109 // both circles perfectly.
110
111 // Set up the model detail level
112 const double detail = 2 * PI / steps;
113
114 // We don't generate whole circles. Instead, we generate only the
115 // portions which are visible (not covered by the robe) To know the
116 // exact portion of the bottom and top circles we need to use some
117 // rules of tangent circles from which we can derive (using simple
118 // triangles the following relations:
119
120 // The height of the whole mesh
121 const double h = r_back + r_pin + length;
122 double phi = PI / 2. - std::acos((r_back - r_pin) / h);
123
124 if (std::isnan(phi))
125 return mesh;
126
127 // To generate a whole circle we would pass a portion of (0, Pi)
128 // To generate only a half horizontal circle we can pass (0, Pi/2)
129 // The calculated phi is an offset to the half circles needed to smooth
130 // the transition from the circle to the robe geometry
131
132 auto s1 = sphere(r_back, make_portion(0, PI / 2 + phi), detail);
133 auto s2 = sphere(r_pin, make_portion(PI / 2 + phi, PI), detail);
134
135 for (auto &p : s2.vertices) p.z() += h;
136
137 its_merge(mesh, s1);
138 its_merge(mesh, s2);
139
140 for (size_t idx1 = s1.vertices.size() - steps, idx2 = s1.vertices.size();
141 idx1 < s1.vertices.size() - 1; idx1++, idx2++) {
142 coord_t i1s1 = coord_t(idx1), i1s2 = coord_t(idx2);
143 coord_t i2s1 = i1s1 + 1, i2s2 = i1s2 + 1;
144
145 mesh.indices.emplace_back(i1s1, i2s1, i2s2);
146 mesh.indices.emplace_back(i1s1, i2s2, i1s2);
147 }
148
149 auto i1s1 = coord_t(s1.vertices.size()) - coord_t(steps);
150 auto i2s1 = coord_t(s1.vertices.size()) - 1;
151 auto i1s2 = coord_t(s1.vertices.size());
152 auto i2s2 = coord_t(s1.vertices.size()) + coord_t(steps) - 1;
153
154 mesh.indices.emplace_back(i2s2, i2s1, i1s1);
155 mesh.indices.emplace_back(i1s2, i2s2, i1s1);
156
157 return mesh;
158}
int32_t coord_t
Definition libslic3r.h:39

References indexed_triangle_set::indices, 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:

◆ pinhead_mesh_hit() [1/2]

template<class Ex >
Hit Slic3r::sla::pinhead_mesh_hit ( Ex  ex,
const AABBMesh mesh,
const Head head,
double  safety_d 
)
283{
284 return pinhead_mesh_hit(ex, mesh, head.pos, head.dir, head.r_pin_mm,
285 head.r_back_mm, head.width_mm, safety_d);
286}

References head(), and pinhead_mesh_hit().

+ Here is the call graph for this function:

◆ pinhead_mesh_hit() [2/2]

template<class Ex >
Hit Slic3r::sla::pinhead_mesh_hit ( Ex  ex,
const AABBMesh mesh,
const Vec3d s,
const Vec3d dir,
double  r_pin,
double  r_back,
double  width,
double  sd 
)
201{
202 // Support tree generation speed depends heavily on this value. 8 is almost
203 // ok, but to prevent rare cases of collision, 16 is necessary, which makes
204 // the algorithm run about 60% longer.
205 static const size_t SAMPLES = 16;
206
207 // Move away slightly from the touching point to avoid raycasting on the
208 // inner surface of the mesh.
209
210 auto &m = mesh;
211 using HitResult = AABBMesh::hit_result;
212
213 // Hit results
214 std::array<HitResult, SAMPLES> hits;
215
216 struct Rings
217 {
218 double rpin;
219 double rback;
220 Vec3d spin;
221 Vec3d sback;
223
224 Vec3d backring(size_t idx) { return ring.get(idx, sback, rback); }
225 Vec3d pinring(size_t idx) { return ring.get(idx, spin, rpin); }
226 } rings{r_pin + sd, r_back + sd, s, s + (r_pin + width + r_back) * dir, dir};
227
228 // We will shoot multiple rays from the head pinpoint in the direction
229 // of the pinhead robe (side) surface. The result will be the smallest
230 // hit distance.
231
232 execution::for_each(
233 ex, size_t(0), hits.size(), [&m, &rings, sd, &hits](size_t i) {
234 // Point on the circle on the pin sphere
235 Vec3d ps = rings.pinring(i);
236 // This is the point on the circle on the back sphere
237 Vec3d p = rings.backring(i);
238
239 auto &hit = hits[i];
240
241 // Point ps is not on mesh but can be inside or
242 // outside as well. This would cause many problems
243 // with ray-casting. To detect the position we will
244 // use the ray-casting result (which has an is_inside
245 // predicate).
246
247 Vec3d n = (p - ps).normalized();
248 auto q = m.query_ray_hit(ps + sd * n, n);
249
250 if (q.is_inside()) { // the hit is inside the model
251 if (q.distance() > rings.rpin) {
252 // If we are inside the model and the hit
253 // distance is bigger than our pin circle
254 // diameter, it probably indicates that the
255 // support point was already inside the
256 // model, or there is really no space
257 // around the point. We will assign a zero
258 // hit distance to these cases which will
259 // enforce the function return value to be
260 // an invalid ray with zero hit distance.
261 // (see min_element at the end)
262 hit = HitResult(0.0);
263 } else {
264 // re-cast the ray from the outside of the
265 // object. The starting point has an offset
266 // of 2*safety_distance because the
267 // original ray has also had an offset
268 auto q2 = m.query_ray_hit(ps + (q.distance() + 2 * sd) * n, n);
269 hit = q2;
270 }
271 } else
272 hit = q;
273 }, std::min(execution::max_concurrency(ex), SAMPLES));
274
275 return min_hit(hits.begin(), hits.end());
276}
Vec3d get(size_t idx, const Vec3d &src, double r) const
Definition SupportTreeUtils.hpp:71
coord_t width(const BoundingBox &box)
Definition Arrange.cpp:539
Hit min_hit(It from, It to)
Definition SupportTreeUtils.hpp:97

References Slic3r::execution::for_each(), Slic3r::sla::PointRing< N >::get(), and pinhead_mesh_hit().

Referenced by optimize_anchor_placement(), optimize_pinhead_placement(), pinhead_mesh_hit(), pinhead_mesh_hit(), Slic3r::sla::DefaultSupportTree::pinhead_mesh_intersect(), and search_widening_path().

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

◆ poisson_disk_from_samples()

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

References poisson_disk_from_samples().

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)

◆ pos() [2/2]

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

◆ raster_to_polygons()

ExPolygons Slic3r::sla::raster_to_polygons ( const RasterGrayscaleAA rst,
Vec2i  windowsize 
)
37{
38 size_t rows = rst.resolution().height_px, cols = rst.resolution().width_px;
39
40 if (rows < 2 || cols < 2) return {};
41
42 Polygons polys;
43 long w_rows = std::max(2l, long(windowsize.y()));
44 long w_cols = std::max(2l, long(windowsize.x()));
45
46 std::vector<marchsq::Ring> rings =
47 marchsq::execute(rst, 128, {w_rows, w_cols});
48
49 polys.reserve(rings.size());
50
51 auto pxd = rst.pixel_dimensions();
52 pxd.w_mm = (rst.resolution().width_px * pxd.w_mm) / (rst.resolution().width_px - 1);
53 pxd.h_mm = (rst.resolution().height_px * pxd.h_mm) / (rst.resolution().height_px - 1);
54
55 for (const marchsq::Ring &ring : rings) {
56 Polygon poly; Points &pts = poly.points;
57 pts.reserve(ring.size());
58
59 for (const marchsq::Coord &crd : ring)
60 pts.emplace_back(scaled(crd.c * pxd.w_mm), scaled(crd.r * pxd.h_mm));
61
62 polys.emplace_back(poly);
63 }
64
65 // reverse the raster transformations
66 ExPolygons unioned = union_ex(polys);
67 coord_t width = scaled(cols * pxd.h_mm), height = scaled(rows * pxd.w_mm);
68
69 auto tr = rst.trafo();
70 for (ExPolygon &expoly : unioned) {
71 if (tr.mirror_y)
72 foreach_vertex(expoly, [height](Point &p) {p.y() = height - p.y(); });
73
74 if (tr.mirror_x)
75 foreach_vertex(expoly, [width](Point &p) {p.x() = width - p.x(); });
76
77 expoly.translate(-tr.center_x, -tr.center_y);
78
79 if (tr.flipXY)
80 foreach_vertex(expoly, [](Point &p) { std::swap(p.x(), p.y()); });
81
82 if ((tr.mirror_x + tr.mirror_y + tr.flipXY) % 2) {
83 expoly.contour.reverse();
84 for (auto &h : expoly.holes) h.reverse();
85 }
86 }
87
88 return unioned;
89}
Resolution resolution() const
Definition AGGRaster.hpp:156
PixelDim pixel_dimensions() const
Definition AGGRaster.hpp:157
Trafo trafo() const override
Get the resolution of the raster.
Definition AGGRaster.hpp:155
coord_t height(const BoundingBox &box)
Definition Arrange.cpp:540
void foreach_vertex(ExPolygon &poly, Fn &&fn)
Definition RasterToPolygons.cpp:29
BoundingBox scaled(const BoundingBoxf &bb)
Definition BoundingBox.hpp:240
std::vector< Coord > Ring
Definition MarchingSquares.hpp:26
Kernel::Point_2 Point
Definition point_areas.cpp:20
double w_mm
Definition RasterBase.hpp:45
size_t height_px
Definition RasterBase.hpp:36
size_t width_px
Definition RasterBase.hpp:35
Definition MarchingSquares.hpp:13

References foreach_vertex(), Slic3r::sla::Resolution::height_px, Slic3r::sla::AGGRaster< PixelRenderer, Renderer, Rasterizer, Scanline >::pixel_dimensions(), Slic3r::MultiPoint::points, Slic3r::sla::AGGRaster< PixelRenderer, Renderer, Rasterizer, Scanline >::resolution(), Slic3r::scaled(), Slic3r::sla::AGGRaster< PixelRenderer, Renderer, Rasterizer, Scanline >::trafo(), Slic3r::union_ex(), Slic3r::sla::PixelDim::w_mm, 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 
)
625{
626 // get iterator to the reorganized vector end
627 auto endit = std::remove_if(pts.begin(), pts.end(), [lvl]
628 (const sla::SupportPoint &sp) {
629 return sp.pos.z() <= lvl;
630 });
631
632 // erase all elements after the new end
633 pts.erase(endit, pts.end());
634}
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() [1/2]

void Slic3r::sla::remove_inside_triangles ( indexed_triangle_set mesh,
const Interior interior,
const std::vector< bool > &  exclude_mask 
)
397{
398 enum TrPos { posInside, posTouch, posOutside };
399
400 auto &faces = mesh.indices;
401 auto &vertices = mesh.vertices;
402 auto bb = bounding_box(mesh); //mesh.bounding_box();
403
404 bool use_exclude_mask = faces.size() == exclude_mask.size();
405 auto is_excluded = [&exclude_mask, use_exclude_mask](size_t face_id) {
406 return use_exclude_mask && exclude_mask[face_id];
407 };
408
409 // TODO: Parallel mode not working yet
410 constexpr auto &exec_policy = ex_seq;
411
412 // Info about the needed modifications on the input mesh.
413 struct MeshMods {
414
415 // Just a thread safe wrapper for a vector of triangles.
416 struct {
417 std::vector<std::array<Vec3f, 3>> data;
418 execution::SpinningMutex<decltype(exec_policy)> mutex;
419
420 void emplace_back(const std::array<Vec3f, 3> &pts)
421 {
422 std::lock_guard lk{mutex};
423 data.emplace_back(pts);
424 }
425
426 size_t size() const { return data.size(); }
427 const std::array<Vec3f, 3>& operator[](size_t idx) const
428 {
429 return data[idx];
430 }
431
432 } new_triangles;
433
434 // A vector of bool for all faces signaling if it needs to be removed
435 // or not.
436 std::vector<bool> to_remove;
437
438 MeshMods(const indexed_triangle_set &mesh):
439 to_remove(mesh.indices.size(), false) {}
440
441 // Number of triangles that need to be removed.
442 size_t to_remove_cnt() const
443 {
444 return std::accumulate(to_remove.begin(), to_remove.end(), size_t(0));
445 }
446
447 } mesh_mods{mesh};
448
449 // Must return true if further division of the face is needed.
450 auto divfn = [&interior, bb, &mesh_mods](const DivFace &f) {
451 BoundingBoxf3 facebb { f.verts.begin(), f.verts.end() };
452
453 // Face is certainly outside the cavity
454 if (! facebb.intersects(bb) && f.faceid != NEW_FACE) {
455 return false;
456 }
457
458 TriangleBubble bubble{facebb.center().cast<float>(), facebb.radius()};
459
460 double D = get_distance(bubble, interior);
461 double R = bubble.R;
462
463 if (std::isnan(D)) // The distance cannot be measured, triangle too big
464 return true;
465
466 // Distance of the bubble wall to the interior wall. Negative if the
467 // bubble is overlapping with the interior
468 double bubble_distance = D - R;
469
470 // The face is crossing the interior or inside, it must be removed and
471 // parts of it re-added, that are outside the interior
472 if (bubble_distance < 0.) {
473 if (f.faceid != NEW_FACE)
474 mesh_mods.to_remove[f.faceid] = true;
475
476 if (f.parent != NEW_FACE) // Top parent needs to be removed as well
477 mesh_mods.to_remove[f.parent] = true;
478
479 // If the outside part is between the interior and the exterior
480 // (inside the wall being invisible), no further division is needed.
481 if ((R + D) < interior.thickness)
482 return false;
483
484 return true;
485 } else if (f.faceid == NEW_FACE) {
486 // New face completely outside needs to be re-added.
487 mesh_mods.new_triangles.emplace_back(f.verts);
488 }
489
490 return false;
491 };
492
493 interior.reset_accessor();
494
495 execution::for_each(
496 exec_policy, size_t(0), faces.size(),
497 [&](size_t face_idx) {
498 const Vec3i &face = faces[face_idx];
499
500 // If the triangle is excluded, we need to keep it.
501 if (is_excluded(face_idx))
502 return;
503
504 std::array<Vec3f, 3> pts = {vertices[face(0)], vertices[face(1)],
505 vertices[face(2)]};
506
507 BoundingBoxf3 facebb{pts.begin(), pts.end()};
508
509 // Face is certainly outside the cavity
510 if (!facebb.intersects(bb))
511 return;
512
513 DivFace df{face, pts, long(face_idx)};
514
515 if (divfn(df)) divide_triangle(df, divfn);
516 },
517 execution::max_concurrency(exec_policy)
518 );
519
520 auto new_faces = reserve_vector<Vec3i>(faces.size() +
521 mesh_mods.new_triangles.size());
522
523 for (size_t face_idx = 0; face_idx < faces.size(); ++face_idx) {
524 if (!mesh_mods.to_remove[face_idx])
525 new_faces.emplace_back(faces[face_idx]);
526 }
527
528 for(size_t i = 0; i < mesh_mods.new_triangles.size(); ++i) {
529 size_t o = vertices.size();
530 vertices.emplace_back(mesh_mods.new_triangles[i][0]);
531 vertices.emplace_back(mesh_mods.new_triangles[i][1]);
532 vertices.emplace_back(mesh_mods.new_triangles[i][2]);
533 new_faces.emplace_back(int(o), int(o + 1), int(o + 2));
534 }
535
536 BOOST_LOG_TRIVIAL(info)
537 << "Trimming: " << mesh_mods.to_remove_cnt() << " triangles removed";
538 BOOST_LOG_TRIVIAL(info)
539 << "Trimming: " << mesh_mods.new_triangles.size() << " triangles added";
540
541 faces.swap(new_faces);
542 new_faces = {};
543
544// mesh = TriangleMesh{mesh.its};
545 //FIXME do we want to repair the mesh? Are there duplicate vertices or flipped triangles?
546}
void divide_triangle(const DivFace &face, Fn &&visitor)
Definition Hollowing.cpp:358
constexpr auto size(const C &c) -> decltype(c.size())
Definition span.hpp:183
void reset_accessor() const
Definition Hollowing.cpp:37

References Slic3r::bounding_box(), Slic3r::sla::TriangleBubble::center, divide_triangle(), Slic3r::ex_seq, Slic3r::f(), Slic3r::execution::for_each(), get_distance(), indexed_triangle_set::indices, long, NEW_FACE, remove_inside_triangles(), Slic3r::sla::Interior::reset_accessor(), Slic3r::sla::Interior::thickness, and indexed_triangle_set::vertices.

Referenced by hollow_mesh(), hollow_mesh(), remove_inside_triangles(), and remove_inside_triangles().

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

◆ remove_inside_triangles() [2/2]

void Slic3r::sla::remove_inside_triangles ( TriangleMesh mesh,
const Interior interior,
const std::vector< bool > &  exclude_mask 
)
550{
551 remove_inside_triangles(mesh.its, interior, exclude_mask);
552}

References Slic3r::TriangleMesh::its, and remove_inside_triangles().

+ Here is the call graph for this function:

◆ remove_unconnected_vertices()

static indexed_triangle_set Slic3r::sla::remove_unconnected_vertices ( const indexed_triangle_set its)
static
778{
779 if (its.indices.empty()) {};
780
782
783 std::vector<int> vtransl(its.vertices.size(), -1);
784 int vcnt = 0;
785 for (auto &f : its.indices) {
786
787 for (int i = 0; i < 3; ++i)
788 if (vtransl[size_t(f(i))] < 0) {
789
790 M.vertices.emplace_back(its.vertices[size_t(f(i))]);
791 vtransl[size_t(f(i))] = vcnt++;
792 }
793
794 std::array<int, 3> new_f = {
795 vtransl[size_t(f(0))],
796 vtransl[size_t(f(1))],
797 vtransl[size_t(f(2))]
798 };
799
800 M.indices.emplace_back(new_f[0], new_f[1], new_f[2]);
801 }
802
803 return M;
804}

References indexed_triangle_set::indices, remove_unconnected_vertices(), and indexed_triangle_set::vertices.

Referenced by hollow_mesh_and_drill(), and remove_unconnected_vertices().

+ 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
29{
30 bool has_sppoints = !object->sla_support_points.empty();
31 bool has_holes = !object->sla_drain_holes.empty();
32
33 if (!object || (!has_holes && !has_sppoints)) return;
34
35 TriangleMesh rmsh = object->raw_mesh();
36 AABBMesh emesh{rmsh};
37
38 if (has_sppoints)
39 reproject_support_points(emesh, object->sla_support_points);
40
41 if (has_holes)
42 reproject_support_points(emesh, object->sla_drain_holes);
43}
Definition AABBMesh.hpp:27
sla::SupportPoints sla_support_points
Definition Model.hpp:351
sla::DrainHoles sla_drain_holes
Definition Model.hpp:357

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(), and Slic3r::GUI::Plater::priv::replace_volume_with_stl().

+ 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 AABBMesh mesh,
std::vector< PointType > &  pts 
)
19{
20 tbb::parallel_for(size_t(0), pts.size(), [&mesh, &pts](size_t idx) {
21 int junk;
22 Vec3d new_pos;
23 mesh.squared_distance(pos(pts[idx]), junk, new_pos);
24 pos(pts[idx], new_pos);
25 });
26}

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 
)
332{
333 // Triangulate the polygon with holes into triplets of 3D points.
334 std::vector<Vec2f> triangles = Slic3r::triangulate_expolygon_2f(expoly);
335
336 std::vector<Vec2f> out;
337 if (! triangles.empty())
338 {
339 // Calculate area of each triangle.
340 auto areas = reserve_vector<float>(triangles.size() / 3);
341 double aback = 0.;
342 for (size_t i = 0; i < triangles.size(); ) {
343 const Vec2f &a = triangles[i ++];
344 const Vec2f v1 = triangles[i ++] - a;
345 const Vec2f v2 = triangles[i ++] - a;
346
347 // Prefix sum of the areas.
348 areas.emplace_back(aback + 0.5f * std::abs(cross2(v1, v2)));
349 aback = areas.back();
350 }
351
352 size_t num_samples = size_t(ceil(areas.back() * samples_per_mm2));
353 std::uniform_real_distribution<> random_triangle(0., double(areas.back()));
354 std::uniform_real_distribution<> random_float(0., 1.);
355 for (size_t i = 0; i < num_samples; ++ i) {
356 double r = random_triangle(rng);
357 size_t idx_triangle = std::min<size_t>(std::upper_bound(areas.begin(), areas.end(), (float)r) - areas.begin(), areas.size() - 1) * 3;
358 // Select a random point on the triangle.
359 const Vec2f &a = triangles[idx_triangle ++];
360 const Vec2f &b = triangles[idx_triangle++];
361 const Vec2f &c = triangles[idx_triangle];
362#if 1
363 // https://www.cs.princeton.edu/~funk/tog02.pdf
364 // page 814, formula 1.
365 double u = float(std::sqrt(random_float(rng)));
366 double v = float(random_float(rng));
367 out.emplace_back(a * (1.f - u) + b * (u * (1.f - v)) + c * (v * u));
368#else
369 // Greg Turk, Graphics Gems
370 // https://devsplorer.wordpress.com/2019/08/07/find-a-random-point-on-a-plane-using-barycentric-coordinates-in-unity/
371 double u = float(random_float(rng));
372 double v = float(random_float(rng));
373 if (u + v >= 1.f) {
374 u = 1.f - u;
375 v = 1.f - v;
376 }
377 out.emplace_back(a + u * (b - a) + v * (c - a));
378#endif
379 }
380 }
381 return out;
382}
Derived::Scalar cross2(const Eigen::MatrixBase< Derived > &v1, const Eigen::MatrixBase< Derived2 > &v2)
Definition Point.hpp:93
std::vector< Vec2f > triangulate_expolygon_2f(const ExPolygon &poly, bool flip)
Definition Tesselate.cpp:226

References ceil(), Slic3r::cross2(), 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 
)
386{
387 std::vector<Vec2f> out;
388 for (const ExPolygon &expoly : expolys)
389 append(out, sample_expolygon(expoly, samples_per_mm2, rng));
390
391 return out;
392}
std::vector< Vec2f > sample_expolygon(const ExPolygon &expoly, float samples_per_mm2, std::mt19937 &rng)
Definition SupportPointGenerator.cpp:331

References 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 &   
)
398{
399 double point_stepping_scaled = scale_(1.f) / samples_per_mm;
400 for (size_t i_contour = 0; i_contour <= expoly.holes.size(); ++ i_contour) {
401 const Polygon &contour = (i_contour == 0) ? expoly.contour :
402 expoly.holes[i_contour - 1];
403
404 const Points pts = contour.equally_spaced_points(point_stepping_scaled);
405 for (size_t i = 0; i < pts.size(); ++ i)
406 out.emplace_back(unscale<float>(pts[i].x()),
407 unscale<float>(pts[i].y()));
408 }
409}
Polygon contour
Definition ExPolygon.hpp:35
Polygons holes
Definition ExPolygon.hpp:36
Points equally_spaced_points(double distance) const
Definition Polygon.hpp:54
#define scale_(val)
Definition libslic3r.h:69
std::vector< Point, PointsAllocator< Point > > Points
Definition Point.hpp:58

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

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 
)
412{
413 std::vector<Vec2f> out = sample_expolygon(expoly, samples_per_mm2, rng);
414 sample_expolygon_boundary(expoly, samples_per_mm_boundary, out, rng);
415 return out;
416}
void sample_expolygon_boundary(const ExPolygon &expoly, float samples_per_mm, std::vector< Vec2f > &out, std::mt19937 &)
Definition SupportPointGenerator.cpp:394

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 
)
419{
420 std::vector<Vec2f> out;
421 for (const ExPolygon &expoly : expolys)
422 append(out, sample_expolygon_with_boundary(expoly, samples_per_mm2, samples_per_mm_boundary, rng));
423 return out;
424}
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:411

References sample_expolygon_with_boundary().

+ Here is the call graph for this function:

◆ search_ground_route()

template<class Ex >
std::pair< bool, long > Slic3r::sla::search_ground_route ( Ex  policy,
SupportTreeBuilder builder,
const SupportableMesh sm,
const Junction j,
double  end_radius,
const Vec3d init_dir = DOWN 
)
267{
268 double downdst = j.pos.z() - ground_level(sm);
269
270 auto res = connect_to_ground(policy, builder, sm, j, init_dir, end_radius);
271 if (res.first)
272 return res;
273
274 // Optimize bridge direction:
275 // Straight path failed so we will try to search for a suitable
276 // direction out of the cavity.
277 auto [polar, azimuth] = dir_to_spheric(init_dir);
278
280 solver.seed(0); // we want deterministic behavior
281
282 auto sd = j.r * sm.cfg.safety_distance_mm / sm.cfg.head_back_radius_mm;
283 auto oresult = solver.to_max().optimize(
284 [&j, sd, &policy, &sm, &downdst, &end_radius](const opt::Input<2> &input) {
285 auto &[plr, azm] = input;
286 Vec3d n = spheric_to_dir(plr, azm).normalized();
287 Beam beam{Ball{j.pos, j.r}, Ball{j.pos + downdst * n, end_radius}};
288 return beam_mesh_hit(policy, sm.emesh, beam, sd).distance();
289 },
290 initvals({polar, azimuth}), // let's start with what we have
291 bounds({ {PI - sm.cfg.bridge_slope, PI}, {-PI, PI} })
292 );
293
294 Vec3d bridgedir = spheric_to_dir(oresult.optimum).normalized();
295
296 return connect_to_ground(policy, builder, sm, j, bridgedir, end_radius);
297}
std::pair< bool, long > connect_to_ground(Ex policy, SupportTreeBuilder &builder, const SupportableMesh &sm, const Junction &j, const Vec3d &dir, double end_r)
Definition SupportTreeUtilsLegacy.hpp:223

References beam_mesh_hit(), Slic3r::sla::SupportTreeConfig::bridge_slope, Slic3r::sla::SupportableMesh::cfg, connect_to_ground(), Slic3r::AABBMesh::hit_result::distance(), Slic3r::sla::SupportableMesh::emesh, get_criteria(), ground_level(), Slic3r::sla::SupportTreeConfig::head_back_radius_mm, input(), Slic3r::opt::Optimizer< Method, Enable >::optimize(), PI, Slic3r::sla::Junction::pos, Slic3r::sla::Junction::r, Slic3r::sla::SupportTreeConfig::safety_distance_mm, Slic3r::opt::Optimizer< Method, Enable >::seed(), Slic3r::opt::StopCriteria::stop_score(), and Slic3r::opt::Optimizer< Method, Enable >::to_max().

Referenced by Slic3r::sla::DefaultSupportTree::connect_to_ground().

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

◆ search_widening_path()

template<class Ex >
std::optional< DiffBridge > Slic3r::sla::search_widening_path ( Ex  policy,
const SupportableMesh sm,
const Vec3d jp,
const Vec3d dir,
double  radius,
double  new_radius 
)
42{
43 double w = radius + 2 * sm.cfg.head_back_radius_mm;
44 double stopval = w + jp.z() - ground_level(sm);
46
47 auto [polar, azimuth] = dir_to_spheric(dir);
48
49 double fallback_ratio = radius / sm.cfg.head_back_radius_mm;
50
51 auto oresult = solver.to_max().optimize(
52 [&policy, &sm, jp, radius, new_radius](const opt::Input<3> &input) {
53 auto &[plr, azm, t] = input;
54
55 auto d = spheric_to_dir(plr, azm).normalized();
56
57 auto sd = sm.cfg.safety_distance(new_radius);
58
59 double ret = pinhead_mesh_hit(policy, sm.emesh, jp, d, radius,
60 new_radius, t, sd)
61 .distance();
62
63 Beam beam{jp + t * d, d, new_radius};
64 double down = beam_mesh_hit(policy, sm.emesh, beam, sd).distance();
65
66 if (ret > t && std::isinf(down))
67 ret += jp.z() - ground_level(sm);
68
69 return ret;
70 },
71 initvals({polar, azimuth, w}), // start with what we have
72 bounds({
73 {PI - sm.cfg.bridge_slope, PI}, // Must not exceed the slope limit
74 {-PI, PI}, // azimuth can be a full search
75 {radius + sm.cfg.head_back_radius_mm,
76 fallback_ratio * sm.cfg.max_bridge_length_mm}
77 }));
78
79 if (oresult.score >= stopval) {
80 polar = std::get<0>(oresult.optimum);
81 azimuth = std::get<1>(oresult.optimum);
82 double t = std::get<2>(oresult.optimum);
83 Vec3d endp = jp + t * spheric_to_dir(polar, azimuth);
84
85 return DiffBridge(jp, endp, radius, sm.cfg.head_back_radius_mm);
86 }
87
88 return {};
89}

References beam_mesh_hit(), Slic3r::sla::SupportTreeConfig::bridge_slope, Slic3r::sla::SupportableMesh::cfg, Slic3r::AABBMesh::hit_result::distance(), Slic3r::sla::SupportableMesh::emesh, get_criteria(), ground_level(), Slic3r::sla::SupportTreeConfig::head_back_radius_mm, input(), Slic3r::sla::SupportTreeConfig::max_bridge_length_mm, Slic3r::opt::Optimizer< Method, Enable >::optimize(), PI, pinhead_mesh_hit(), Slic3r::sla::SupportTreeConfig::safety_distance(), Slic3r::opt::StopCriteria::stop_score(), and Slic3r::opt::Optimizer< Method, Enable >::to_max().

Referenced by create_ground_pillar(), and Slic3r::sla::DefaultSupportTree::search_widening_path().

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

◆ slice()

std::vector< ExPolygons > Slic3r::sla::slice ( const indexed_triangle_set sup_mesh,
const indexed_triangle_set pad_mesh,
const std::vector< float > &  grid,
float  cr,
const JobController ctl 
)
104{
105 using Slices = std::vector<ExPolygons>;
106
107 auto slices = reserve_vector<Slices>(2);
108
109 if (!sup_mesh.empty()) {
110 slices.emplace_back();
111 slices.back() = slice_mesh_ex(sup_mesh, grid, cr, ctl.cancelfn);
112 }
113
114 if (!pad_mesh.empty()) {
115 slices.emplace_back();
116
117 auto bb = bounding_box(pad_mesh);
118 auto maxzit = std::upper_bound(grid.begin(), grid.end(), bb.max.z());
119
120 auto cap = grid.end() - maxzit;
121 auto padgrid = reserve_vector<float>(size_t(cap > 0 ? cap : 0));
122 std::copy(grid.begin(), maxzit, std::back_inserter(padgrid));
123
124 slices.back() = slice_mesh_ex(pad_mesh, padgrid, cr, ctl.cancelfn);
125 }
126
127 size_t len = grid.size();
128 for (const Slices &slv : slices)
129 len = std::min(len, slv.size());
130
131 // Either the support or the pad or both has to be non empty
132 if (slices.empty()) return {};
133
134 Slices &mrg = slices.front();
135
136 for (auto it = std::next(slices.begin()); it != slices.end(); ++it) {
137 for (size_t i = 0; i < len; ++i) {
138 Slices &slv = *it;
139 std::copy(slv[i].begin(), slv[i].end(), std::back_inserter(mrg[i]));
140 slv[i] = {}; // clear and delete
141 }
142 }
143
144 return mrg;
145}
S::iterator begin(S &sh, const PathTag &)
Definition geometry_traits.hpp:614
S::iterator end(S &sh, const PathTag &)
Definition geometry_traits.hpp:620

References Slic3r::bounding_box(), Slic3r::sla::JobController::cancelfn, indexed_triangle_set::empty(), Slic3r::grid(), and Slic3r::slice_mesh_ex().

Referenced by Slic3r::SLAPrint::Steps::slice_supports().

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

◆ sphere()

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

References Slic3r::angle(), floor(), indexed_triangle_set::indices, PI, and indexed_triangle_set::vertices.

Referenced by get_mesh(), and pinhead().

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

◆ swap_normals()

void Slic3r::sla::swap_normals ( indexed_triangle_set its)
inline
198{
199 for (auto &face : its.indices)
200 std::swap(face(0), face(2));
201}

References indexed_triangle_set::indices.

Referenced by hollow_mesh(), and hollow_mesh().

+ Here is the caller graph for this function:

◆ to_vec2()

Vec2crd Slic3r::sla::to_vec2 ( const Vec3d v3)
inline
14{ return {coord_t(v3(X)), coord_t(v3(Y))}; }

References Slic3r::X, and Slic3r::Y.

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

+ Here is the caller graph for this function:

◆ to_vec3()

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

References Slic3r::X, and Slic3r::Y.

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

+ Here is the caller graph for this function:

◆ transformed_drainhole_points()

sla::DrainHoles Slic3r::sla::transformed_drainhole_points ( const ModelObject mo,
const Transform3d trafo 
)

vol_trafo

719{
720 auto pts = mo.sla_drain_holes;
721// const Transform3d& vol_trafo = mo.volumes.front()->get_transformation().get_matrix();
722 const Geometry::Transformation trans(trafo );
723 const Transform3d& tr = trans.get_matrix();
724 for (sla::DrainHole &hl : pts) {
725 Vec3d pos = hl.pos.cast<double>();
726 Vec3d nrm = hl.normal.cast<double>();
727
728 pos = tr * pos;
729 nrm = tr * nrm - tr.translation();
730
731 // Now shift the hole a bit above the object and make it deeper to
732 // compensate for it. This is to avoid problems when the hole is placed
733 // on (nearly) flat surface.
734 pos -= nrm.normalized() * sla::HoleStickOutLength;
735
736 hl.pos = pos.cast<float>();
737 hl.normal = nrm.cast<float>();
738 hl.height += sla::HoleStickOutLength;
739 }
740
741 return pts;
742}
Definition Geometry.hpp:380
EIGEN_DEVICE_FUNC ConstTranslationPart translation() const
Definition Transform.h:410

References Slic3r::Geometry::Transformation::get_matrix(), pos(), Slic3r::ModelObject::sla_drain_holes, transformed_drainhole_points(), and Eigen::Transform< _Scalar, _Dim, _Mode, _Options >::translation().

Referenced by Slic3r::SLAPrintObject::transformed_drainhole_points(), and transformed_drainhole_points().

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

◆ transformed_support_points()

SupportPoints Slic3r::sla::transformed_support_points ( const ModelObject mo,
const Transform3d trafo 
)
666{
667 auto spts = mo.sla_support_points;
668 Transform3f tr = trafo.cast<float>();
669 for (sla::SupportPoint& suppt : spts) {
670 suppt.pos = tr * suppt.pos;
671 }
672
673 return spts;
674}
EIGEN_DEVICE_FUNC internal::cast_return_type< Transform, Transform< NewScalarType, Dim, Mode, Options > >::type cast() const
Definition Transform.h:632

References Eigen::Transform< _Scalar, _Dim, _Mode, _Options >::cast(), Slic3r::ModelObject::sla_support_points, and transformed_support_points().

Referenced by Slic3r::SLAPrintObject::transformed_support_points(), and transformed_support_points().

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

Variable Documentation

◆ beam_ex_policy

◆ BeamSamplesV

template<class WFn >
constexpr size_t Slic3r::sla::BeamSamplesV = BeamSamples<remove_cvref_t<WFn>>::Value
constexpr

◆ DOWN

◆ HoleStickOutLength

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

◆ IsWideningFn

template<class Fn >
constexpr bool Slic3r::sla::IsWideningFn
constexpr
Initial value:
= std::is_invocable_r_v< double,
Fn,
Ball ,
double >

Referenced by deepsearch_ground_connection().

◆ suptree_ex_policy