OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::Feature::FuzzySkin Namespace Reference

Classes

class  UniformNoise
struct  MergedFuzzyRegion

Functions

static double random_value ()
static std::unique_ptr< noise::module::Module > get_noise_module (const FuzzySkinConfig &cfg)
static double ripple_phase_shift_rad (const FuzzySkinConfig &cfg)
static double ripple_anchor_arc_mm (const Points &poly)
static void fuzzy_polyline_ripple (Points &poly, const FuzzySkinConfig &cfg)
static void fuzzy_extrusion_line_ripple (Arachne::ExtrusionJunctions &ext_lines, const FuzzySkinConfig &cfg)
void fuzzy_polyline (Points &poly, bool closed, coordf_t slice_z, const FuzzySkinConfig &cfg)
void fuzzy_extrusion_line (Arachne::ExtrusionJunctions &ext_lines, coordf_t slice_z, coordf_t layer_height, const FuzzySkinConfig &cfg, bool closed)
void group_region_by_fuzzify (PerimeterGenerator &g)
bool should_fuzzify (const FuzzySkinConfig &config, const int layer_id, const size_t loop_idx, const bool is_contour)
static bool same_fuzzy_effect (const FuzzySkinConfig &a, const FuzzySkinConfig &b)
static std::vector< MergedFuzzyRegion > collect_merged_fuzzy_regions (const std::vector< std::pair< FuzzySkinConfig, ExPolygons > > &regions, const int layer_id, const size_t loop_idx, const bool is_contour)
static void restrict_to_supported (std::vector< MergedFuzzyRegion > &merged_regions, const std::optional< ExPolygons > &supported)
Polygon apply_fuzzy_skin (const Polygon &polygon, const PerimeterGenerator &perimeter_generator, const size_t loop_idx, const bool is_contour)
void apply_fuzzy_skin (Arachne::ExtrusionLine *extrusion, const PerimeterGenerator &perimeter_generator, const bool is_contour, const bool closed)

Class Documentation

◆ Slic3r::Feature::FuzzySkin::MergedFuzzyRegion

struct Slic3r::Feature::FuzzySkin::MergedFuzzyRegion
Collaboration diagram for Slic3r::Feature::FuzzySkin::MergedFuzzyRegion:
Class Members
const FuzzySkinConfig * config
ExPolygons expolygons

Function Documentation

◆ apply_fuzzy_skin() [1/2]

void Slic3r::Feature::FuzzySkin::apply_fuzzy_skin ( Arachne::ExtrusionLine * extrusion,
const PerimeterGenerator & perimeter_generator,
const bool is_contour,
const bool closed )
723{
724 const auto slice_z = perimeter_generator.slice_z;
725 const auto layer_height = perimeter_generator.layer_height;
726 const auto& regions = perimeter_generator.regions_by_fuzzify;
727 const auto& supported = perimeter_generator.fuzzy_supported_area;
728 if (regions.size() == 1 && !supported) { // optimization
729 const auto& config = regions.begin()->first;
730 const bool fuzzify = should_fuzzify(config, perimeter_generator.layer_id, extrusion->inset_idx, is_contour);
731 if (fuzzify)
732 fuzzy_extrusion_line(extrusion->junctions, slice_z, perimeter_generator.layer_height, config, closed);
733 } else {
734 // Merge regions that produce identical fuzzy effects (differ only in type).
735 // When the style (e.g. External) and a painted region (All) both fuzzify this loop
736 // with the same noise parameters, merging avoids splitting the perimeter at the
737 // painted boundary — eliminating discontinuity artifacts.
738 auto merged_regions = collect_merged_fuzzy_regions(regions, perimeter_generator.layer_id, extrusion->inset_idx, is_contour);
739 if (!merged_regions.empty()) {
740
741 // Fast path: single merged region — apply directly without splitting
742 if (merged_regions.size() == 1 && merged_regions.front().expolygons.empty() && !supported) {
743 fuzzy_extrusion_line(extrusion->junctions, slice_z, perimeter_generator.layer_height, *merged_regions.front().config, closed);
744 return;
745 }
746
747 // Open path means this is a thin wall that collapsed into a single thick line, in this case the path will go exactly
748 // between the middle two sides of the object. And since the paint segmentation never goes beyond the middle line because
749 // it uses voronoi diagram, we need to expand the segmentation a little bit to make sure it covers the path.
750 if (!closed) {
751 for (auto& r : merged_regions) {
752 r.expolygons = offset_ex(r.expolygons, perimeter_generator.ext_perimeter_flow.scaled_width() / 10);
753 }
754 }
755
756#ifdef DEBUG_FUZZY
757 {
758 int i = 0;
759 for (const auto& r : merged_regions) {
760 BoundingBox bbox = get_extents(perimeter_generator.slices->surfaces);
761 bbox.offset(scale_(1.));
762 ::Slic3r::SVG svg(debug_out_path("fuzzy_traverse_loops_%d_%d_%d_region_%d.svg", perimeter_generator.layer_id,
763 is_contour ? 0 : 1, extrusion->inset_idx, i)
764 .c_str(),
765 bbox);
766
767 // Convert extrusion line to polygon for visualization
768 Polygon extrusion_polygon;
769 extrusion_polygon.points.reserve(extrusion->junctions.size());
770 for (const auto& junction : extrusion->junctions) {
771 extrusion_polygon.points.push_back(junction.p);
772 }
773
774 svg.draw_outline(perimeter_generator.slices->surfaces);
775 svg.draw_outline(extrusion_polygon, "green");
776 svg.draw(r.expolygons, "red", 0.5);
777 svg.draw_outline(r.expolygons, "red");
778 svg.Close();
779 i++;
780 }
781 }
782#endif
783
784 // Make each region's ExPolygons exclusive so overlapping regions don't double-fuzz
785 // the same perimeter section. Later regions in the list take priority over earlier ones
786 // in overlapping areas.
787 for (size_t i = 0; i < merged_regions.size(); ++i)
788 for (size_t j = i + 1; j < merged_regions.size(); ++j)
789 if (!merged_regions[i].expolygons.empty() && !merged_regions[j].expolygons.empty())
790 merged_regions[i].expolygons = diff_ex(merged_regions[i].expolygons, merged_regions[j].expolygons);
791
792 restrict_to_supported(merged_regions, supported);
793
794 // Split the loops into lines with different config, and fuzzy them separately
795 for (const auto& r : merged_regions) {
796 const auto splitted = Algorithm::split_line(*extrusion, r.expolygons, false);
797 if (splitted.empty()) {
798 // No intersection, skip
799 continue;
800 }
801
802 // Fuzzy splitted extrusion
803 if (std::all_of(splitted.begin(), splitted.end(), [](const Algorithm::SplitLineJunction& j) { return j.clipped; })) {
804 // The entire polygon is fuzzified
805 fuzzy_extrusion_line(extrusion->junctions, slice_z, perimeter_generator.layer_height, *r.config, closed);
806 continue;
807 } else {
808 const auto current_ext = extrusion->junctions;
809 std::vector<Arachne::ExtrusionJunction> segment;
810 segment.reserve(current_ext.size());
811 extrusion->junctions.clear();
812
813 const auto fuzzy_current_segment = [&segment, &extrusion, &r, slice_z, layer_height]() {
814 // Orca: non fuzzy points to isolate fuzzy region
815 const auto front = segment.front();
816 const auto back = segment.back();
817
818 fuzzy_extrusion_line(segment, slice_z, layer_height, *r.config, false);
819 // Orca: only add non fuzzy point if it's not in the extrusion closing point.
820 if (!extrusion->junctions.empty() && extrusion->junctions.front().p != front.p) {
821 extrusion->junctions.push_back(front);
822 }
823 extrusion->junctions.insert(extrusion->junctions.end(), segment.begin(), segment.end());
824 // Orca: only add non fuzzy point if it's not in the extrusion closing point.
825 if (!extrusion->junctions.empty() && extrusion->junctions.back().p != front.p) {
826 extrusion->junctions.push_back(back);
827 }
828 segment.clear();
829 };
830
831 const auto to_ex_junction = [&current_ext](const Algorithm::SplitLineJunction& j) -> Arachne::ExtrusionJunction {
832 Arachne::ExtrusionJunction res = current_ext[j.get_src_index()];
833 if (!j.is_src()) {
834 res.p = j.p;
835 }
836 return res;
837 };
838
839 for (const auto& p : splitted) {
840 if (p.clipped) {
841 segment.push_back(to_ex_junction(p));
842 } else {
843 if (segment.empty()) {
844 extrusion->junctions.push_back(to_ex_junction(p));
845 } else {
846 segment.push_back(to_ex_junction(p));
847 fuzzy_current_segment();
848 }
849 }
850 }
851 if (!segment.empty()) {
852 fuzzy_current_segment();
853 }
854
855 //Orca: ensure the loop is closed after fuzzy
856 if (closed && !extrusion->junctions.empty() && extrusion->junctions.front().p != extrusion->junctions.back().p) {
857 extrusion->junctions.back().p = extrusion->junctions.front().p;
858 extrusion->junctions.back().w = extrusion->junctions.front().w;
859 }
860 }
861 }
862 }
863 }
864}
coord_t scaled_width() const
Definition Flow.hpp:64
Points points
Definition MultiPoint.hpp:22
std::optional< ExPolygons > fuzzy_supported_area
Definition PerimeterGenerator.hpp:120
double layer_height
Definition PerimeterGenerator.hpp:92
int layer_id
Definition PerimeterGenerator.hpp:93
coordf_t slice_z
Definition PerimeterGenerator.hpp:94
const SurfaceCollection * slices
Definition PerimeterGenerator.hpp:87
Flow ext_perimeter_flow
Definition PerimeterGenerator.hpp:96
std::vector< std::pair< FuzzySkinConfig, ExPolygons > > regions_by_fuzzify
Definition PerimeterGenerator.hpp:118
Surfaces surfaces
Definition SurfaceCollection.hpp:17
#define scale_(val)
Definition libslic3r.h:106
SplittedLine split_line(const PathType &path, const ExPolygons &clip, bool closed)
Definition LineSplit.hpp:50
bool should_fuzzify(const FuzzySkinConfig &config, const int layer_id, const size_t loop_idx, const bool is_contour)
Definition FuzzySkin.cpp:501
void fuzzy_extrusion_line(Arachne::ExtrusionJunctions &ext_lines, coordf_t slice_z, coordf_t layer_height, const FuzzySkinConfig &cfg, bool closed)
Definition FuzzySkin.cpp:358
static void restrict_to_supported(std::vector< MergedFuzzyRegion > &merged_regions, const std::optional< ExPolygons > &supported)
Definition FuzzySkin.cpp:587
static std::vector< MergedFuzzyRegion > collect_merged_fuzzy_regions(const std::vector< std::pair< FuzzySkinConfig, ExPolygons > > &regions, const int layer_id, const size_t loop_idx, const bool is_contour)
Definition FuzzySkin.cpp:541
void segment(CGALMesh &src, std::vector< CGALMesh > &dst, double smoothing_alpha=0.5, int segment_number=5)
Definition MeshBoolean.cpp:480
std::string debug_out_path(const char *name,...)
Definition utils.cpp:382
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:831
layer_height((ConfigOptionInt, faded_layers))((ConfigOptionFloat
BoundingBox get_extents(const ExPolygonsWithIds &e)
Definition Emboss.cpp:1374
Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:605
Slic3r::Polygon Polygon
Definition Emboss.cpp:101
size_t inset_idx
Definition ExtrusionLine.hpp:56
std::vector< ExtrusionJunction > junctions
Definition ExtrusionLine.hpp:88

References Slic3r::SVG::Close(), collect_merged_fuzzy_regions(), Slic3r::debug_out_path(), Slic3r::diff_ex(), Slic3r::SVG::draw(), Slic3r::SVG::draw_outline(), Slic3r::PerimeterGenerator::ext_perimeter_flow, fuzzy_extrusion_line(), Slic3r::PerimeterGenerator::fuzzy_supported_area, Slic3r::get_extents(), Slic3r::Algorithm::SplitLineJunction::get_src_index(), Slic3r::Arachne::ExtrusionLine::inset_idx, Slic3r::Algorithm::SplitLineJunction::is_src(), Slic3r::Arachne::ExtrusionLine::junctions, Slic3r::layer_height(), Slic3r::PerimeterGenerator::layer_height, Slic3r::PerimeterGenerator::layer_id, Slic3r::BoundingBoxBase< PointType, APointsType >::offset(), Slic3r::offset_ex(), Slic3r::Algorithm::SplitLineJunction::p, Slic3r::Arachne::ExtrusionJunction::p, Slic3r::MultiPoint::points, Slic3r::PerimeterGenerator::regions_by_fuzzify, restrict_to_supported(), scale_, Slic3r::Flow::scaled_width(), should_fuzzify(), Slic3r::PerimeterGenerator::slice_z, Slic3r::PerimeterGenerator::slices, Slic3r::Algorithm::split_line(), and Slic3r::SurfaceCollection::surfaces.

Here is the call graph for this function:

◆ apply_fuzzy_skin() [2/2]

Polygon Slic3r::Feature::FuzzySkin::apply_fuzzy_skin ( const Polygon & polygon,
const PerimeterGenerator & perimeter_generator,
const size_t loop_idx,
const bool is_contour )
596{
597 Polygon fuzzified;
598
599 const auto slice_z = perimeter_generator.slice_z;
600 const auto& regions = perimeter_generator.regions_by_fuzzify;
601 const auto& supported = perimeter_generator.fuzzy_supported_area;
602 if (regions.size() == 1 && !supported) { // optimization
603 const auto& config = regions.begin()->first;
604 const bool fuzzify = should_fuzzify(config, perimeter_generator.layer_id, loop_idx, is_contour);
605 if (!fuzzify) {
606 return polygon;
607 }
608
609 fuzzified = polygon;
610 fuzzy_polyline(fuzzified.points, true, slice_z, config);
611 return fuzzified;
612 }
613
614 // Merge regions that produce identical fuzzy effects (differ only in type).
615 // When the style (e.g. External) and a painted region (All) both fuzzify this loop
616 // with the same noise parameters, merging their ExPolygons avoids splitting the
617 // perimeter at the painted boundary — eliminating discontinuity artifacts.
618 auto merged_regions = collect_merged_fuzzy_regions(regions, perimeter_generator.layer_id, loop_idx, is_contour);
619 if (merged_regions.empty()) {
620 return polygon;
621 }
622
623 // Fast path: single merged region — apply directly without splitting
624 if (merged_regions.size() == 1) {
625 const auto& mr = merged_regions.front();
626 if (mr.expolygons.empty() && !supported) {
627 fuzzified = polygon;
628 fuzzy_polyline(fuzzified.points, true, slice_z, *mr.config);
629 return fuzzified;
630 }
631 // Fall through to split_line with a single region below
632 }
633
634#ifdef DEBUG_FUZZY
635 {
636 int i = 0;
637 for (const auto& r : merged_regions) {
638 BoundingBox bbox = get_extents(perimeter_generator.slices->surfaces);
639 bbox.offset(scale_(1.));
640 ::Slic3r::SVG svg(debug_out_path("fuzzy_traverse_loops_%d_%d_%d_region_%d.svg", perimeter_generator.layer_id,
641 is_contour ? 0 : 1, loop_idx, i)
642 .c_str(),
643 bbox);
644 svg.draw_outline(perimeter_generator.slices->surfaces);
645 svg.draw_outline(polygon, "green");
646 svg.draw(r.expolygons, "red", 0.5);
647 svg.draw_outline(r.expolygons, "red");
648 svg.Close();
649 i++;
650 }
651 }
652#endif
653
654 // Make each region's ExPolygons exclusive so overlapping regions don't double-fuzz
655 // the same perimeter section. Later regions in the list take priority over earlier ones
656 // in overlapping areas (matching modifier precedence order).
657 for (size_t i = 0; i < merged_regions.size(); ++i)
658 for (size_t j = i + 1; j < merged_regions.size(); ++j)
659 if (!merged_regions[i].expolygons.empty() && !merged_regions[j].expolygons.empty())
660 merged_regions[i].expolygons = diff_ex(merged_regions[i].expolygons, merged_regions[j].expolygons);
661
662 restrict_to_supported(merged_regions, supported);
663
664 // Split the loops into lines with different config, and fuzzy them separately
665 fuzzified = polygon;
666 for (const auto& r : merged_regions) {
667 auto splitted = Algorithm::split_line(fuzzified, r.expolygons, true);
668 if (splitted.empty()) {
669 // No intersection, skip
670 continue;
671 }
672
673 // Fuzzy splitted polygon
674 if (std::all_of(splitted.begin(), splitted.end(), [](const Algorithm::SplitLineJunction& j) { return j.clipped; })) {
675 // The entire polygon is fuzzified
676 fuzzy_polyline(fuzzified.points, true, slice_z, *r.config);
677 } else {
678 // Start from a non-clipped junction so wrapped clipped segments do
679 // not need an artificial reconnection across the seam.
680 const auto first_non_clipped = std::find_if(splitted.begin(), splitted.end(), [](const Algorithm::SplitLineJunction& j) {
681 return !j.clipped;
682 });
683 if (first_non_clipped != splitted.begin()) {
684 std::rotate(splitted.begin(), first_non_clipped, splitted.end());
685 }
687 segment.reserve(splitted.size());
688 fuzzified.points.clear();
689
690 const auto fuzzy_current_segment = [&segment, &fuzzified, &r, slice_z]() {
691 fuzzified.points.push_back(segment.front());
692 const auto back = segment.back();
693 fuzzy_polyline(segment, false, slice_z, *r.config);
694 fuzzified.points.insert(fuzzified.points.end(), segment.begin(), segment.end());
695 fuzzified.points.push_back(back);
696 segment.clear();
697 };
698
699 for (const auto& p : splitted) {
700 if (p.clipped) {
701 segment.push_back(p.p);
702 } else {
703 if (segment.empty()) {
704 fuzzified.points.push_back(p.p);
705 } else {
706 segment.push_back(p.p);
707 fuzzy_current_segment();
708 }
709 }
710 }
711 if (!segment.empty()) {
712 // Close the loop
713 segment.push_back(splitted.front().p);
714 fuzzy_current_segment();
715 }
716 }
717 }
718
719 return fuzzified;
720}
Definition Polygon.hpp:31
void fuzzy_polyline(Points &poly, bool closed, coordf_t slice_z, const FuzzySkinConfig &cfg)
Definition FuzzySkin.cpp:307
std::vector< Point, PointsAllocator< Point > > Points
Definition Point.hpp:73

References Slic3r::SVG::Close(), collect_merged_fuzzy_regions(), Slic3r::debug_out_path(), Slic3r::diff_ex(), Slic3r::SVG::draw(), Slic3r::SVG::draw_outline(), fuzzy_polyline(), Slic3r::PerimeterGenerator::fuzzy_supported_area, Slic3r::get_extents(), Slic3r::PerimeterGenerator::layer_id, Slic3r::BoundingBoxBase< PointType, APointsType >::offset(), Slic3r::MultiPoint::points, Slic3r::PerimeterGenerator::regions_by_fuzzify, restrict_to_supported(), scale_, should_fuzzify(), Slic3r::PerimeterGenerator::slice_z, Slic3r::PerimeterGenerator::slices, Slic3r::Algorithm::split_line(), and Slic3r::SurfaceCollection::surfaces.

Referenced by Slic3r::traverse_extrusions(), and Slic3r::traverse_loops().

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

◆ collect_merged_fuzzy_regions()

std::vector< MergedFuzzyRegion > Slic3r::Feature::FuzzySkin::collect_merged_fuzzy_regions ( const std::vector< std::pair< FuzzySkinConfig, ExPolygons > > & regions,
const int layer_id,
const size_t loop_idx,
const bool is_contour )
static
545{
546 // Merge regions that produce identical fuzzy effects (differ only in type).
547 // When the style (e.g. External) and a painted region (All) both fuzzify this loop
548 // with the same noise parameters, merging their ExPolygons avoids splitting the
549 // perimeter at the painted boundary — eliminating discontinuity artifacts.
550 std::vector<MergedFuzzyRegion> merged_regions;
551 merged_regions.reserve(regions.size());
552 for (const auto& region : regions) {
553 if (!should_fuzzify(region.first, layer_id, loop_idx, is_contour)) {
554 continue;
555 }
556
557 bool merged = false;
558 for (auto& merged_region : merged_regions) {
559 if (same_fuzzy_effect(*merged_region.config, region.first)) {
560 if (merged_region.expolygons.empty()) {
561 // Already full coverage, nothing to add.
562 } else if (region.second.empty()) {
563 merged_region.expolygons.clear();
564 } else {
565 append(merged_region.expolygons, region.second);
566 }
567 merged = true;
568 break;
569 }
570 }
571
572 if (!merged) {
573 merged_regions.push_back({&region.first, region.second});
574 }
575 }
576
577 for (auto& merged_region : merged_regions) {
578 if (!merged_region.expolygons.empty()) {
579 merged_region.expolygons = union_ex(merged_region.expolygons);
580 }
581 }
582
583 return merged_regions;
584}
static bool same_fuzzy_effect(const FuzzySkinConfig &a, const FuzzySkinConfig &b)
Definition FuzzySkin.cpp:527
Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, PolyFillType fill_type)
Definition ClipperUtils.cpp:1011
void append(std::vector< T, Alloc > &dest, const std::vector< T, Alloc2 > &src)
Definition libslic3r.h:157

References Slic3r::append(), same_fuzzy_effect(), should_fuzzify(), and Slic3r::union_ex().

Referenced by apply_fuzzy_skin(), and apply_fuzzy_skin().

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

◆ fuzzy_extrusion_line()

void Slic3r::Feature::FuzzySkin::fuzzy_extrusion_line ( Arachne::ExtrusionJunctions & ext_lines,
coordf_t slice_z,
coordf_t layer_height,
const FuzzySkinConfig & cfg,
bool closed )
359{
360
361 if (cfg.noise_type == NoiseType::Ripple) {
362 if (ext_lines.size() < 3)
363 return;
364 fuzzy_extrusion_line_ripple(ext_lines, cfg);
365 return;
366 }
367
368 std::unique_ptr<noise::module::Module> noise = get_noise_module(cfg);
369
370 const double min_dist_between_points = cfg.point_distance * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value
371 const double range_random_point_dist = cfg.point_distance / 2.;
372 // ExtrusionJunction::w is a scaled coord_t, so this floor must be scaled too.
373 // Flow::rounded_rectangle_extrusion_spacing() requires width > height * (1 - 0.25 * PI); keep 5% above it.
374 const double min_extrusion_width = scaled<double>(layer_height * (1. - 0.25 * M_PI) * 1.05);
375 double dist_left_over = random_value() * (min_dist_between_points / 2.); // the distance to be traversed on the line before making the first new point
376
377 auto* p0 = &ext_lines.front();
379 out.reserve(ext_lines.size());
380 for (auto& p1 : ext_lines) {
381 // Orca: only skip the first point for closed path, open path should not skip any point
382 if (closed) {
383 if (p0->p == p1.p) { // Connect endpoints.
384 out.emplace_back(p1.p, p1.w, p1.perimeter_index);
385 continue;
386 }
387 }
388
389 // 'a' is the (next) new point between p0 and p1
390 Vec2d p0p1 = (p1.p - p0->p).cast<double>();
391 double p0p1_size = p0p1.norm();
392 double p0pa_dist = dist_left_over;
393 for (; p0pa_dist < p0p1_size; p0pa_dist += min_dist_between_points + random_value() * range_random_point_dist) {
394 Point pa = p0->p + (p0p1 * (p0pa_dist / p0p1_size)).cast<coord_t>();
395 double r = noise->GetValue(unscale_(pa.x()), unscale_(pa.y()), slice_z) * cfg.thickness;
396 switch (cfg.mode) { //the curly code for testing
398 out.emplace_back(pa + (perp(p0p1).cast<double>().normalized() * r).cast<coord_t>(), p1.w, p1.perimeter_index);
399 break;
401 out.emplace_back(pa, std::max(p1.w + r + min_extrusion_width, min_extrusion_width), p1.perimeter_index);
402 break;
404 double rad = std::max(p1.w + r + min_extrusion_width, min_extrusion_width);
405 out.emplace_back(pa + (perp(p0p1).cast<double>().normalized() * ((rad - p1.w) / 2)).cast<coord_t>(), rad, p1.perimeter_index); //0.05 - minimum width of extruded line
406 break;
407 }
408 }
409 dist_left_over = p0pa_dist - p0p1_size;
410 p0 = &p1;
411 }
412
413 while (out.size() < 3) {
414 size_t point_idx = ext_lines.size() - 2;
415 out.emplace_back(ext_lines[point_idx].p, ext_lines[point_idx].w, ext_lines[point_idx].perimeter_index);
416 if (point_idx == 0)
417 break;
418 --point_idx;
419 }
420
421 if (ext_lines.back().p == ext_lines.front().p) { // Connect endpoints.
422 out.front().p = out.back().p;
423 out.front().w = out.back().w;
424 }
425
426 if (out.size() >= 3)
427 ext_lines = std::move(out);
428}
#define M_PI
Definition ExtrusionSimulator.cpp:31
#define unscale_(val)
Definition libslic3r.h:107
int64_t coord_t
Definition libslic3r.h:48
std::vector< ExtrusionJunction > ExtrusionJunctions
Definition ExtrusionJunction.hpp:66
static std::unique_ptr< noise::module::Module > get_noise_module(const FuzzySkinConfig &cfg)
Definition FuzzySkin.cpp:54
static void fuzzy_extrusion_line_ripple(Arachne::ExtrusionJunctions &ext_lines, const FuzzySkinConfig &cfg)
Definition FuzzySkin.cpp:236
static double random_value()
Definition FuzzySkin.cpp:38
BoundingBox scaled(const BoundingBoxf &bb)
Definition BoundingBox.hpp:284
Eigen::Matrix< typename Derived::Scalar, 2, 1, Eigen::DontAlign > perp(const Eigen::MatrixBase< Derived > &v)
Definition Point.hpp:130
@ Combined
Definition PrintConfig.hpp:88
@ Extrusion
Definition PrintConfig.hpp:87
@ Displacement
Definition PrintConfig.hpp:86
Eigen::Matrix< double, 2, 1, Eigen::DontAlign > Vec2d
Definition Point.hpp:67
auto cast(const BoundingBoxBase< Tin > &b)
Definition BoundingBox.hpp:299
@ Ripple
Definition PrintConfig.hpp:110
FuzzySkinMode mode
Definition PerimeterGenerator.hpp:34
NoiseType noise_type
Definition PerimeterGenerator.hpp:30
coord_t thickness
Definition PerimeterGenerator.hpp:27
coord_t point_distance
Definition PerimeterGenerator.hpp:28

References Slic3r::cast(), Slic3r::Combined, Slic3r::Displacement, Slic3r::Extrusion, fuzzy_extrusion_line_ripple(), get_noise_module(), Slic3r::layer_height(), M_PI, Slic3r::FuzzySkinConfig::mode, Slic3r::FuzzySkinConfig::noise_type, Slic3r::perp(), Slic3r::FuzzySkinConfig::point_distance, random_value(), Slic3r::Ripple, Slic3r::scaled(), Slic3r::FuzzySkinConfig::thickness, and unscale_.

Referenced by apply_fuzzy_skin().

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

◆ fuzzy_extrusion_line_ripple()

void Slic3r::Feature::FuzzySkin::fuzzy_extrusion_line_ripple ( Arachne::ExtrusionJunctions & ext_lines,
const FuzzySkinConfig & cfg )
static
237{
238 const double amplitude = unscale_(cfg.thickness);
239 const double N = static_cast<double>(cfg.ripples_per_layer);
240 const double fill_step_mm = unscale_(cfg.point_distance);
241
242 if (N <= 0.0 || fill_step_mm < 1e-6)
243 return;
244
245 // Build a Points vector for perimeter/anchor calculations.
246 Points poly;
247 poly.reserve(ext_lines.size());
248 for (const auto& j : ext_lines)
249 poly.push_back(j.p);
250
251 // Compute total length in mm.
252 const size_t np = poly.size();
253 double perimeter_mm = 0.0;
254 for (size_t i = 0; i + 1 < np; ++i)
255 perimeter_mm += unscale_((poly[i + 1] - poly[i]).cast<double>().norm());
256
257 if (perimeter_mm < 1e-6)
258 return;
259
260 const double anchor_arc_mm = ripple_anchor_arc_mm(poly);
261 const double phase_shift_rad = ripple_phase_shift_rad(cfg);
262 const double phase_at_anchor = M_PI * 2.0 + phase_shift_rad;
263
264 auto arc_phase = [&](double arc_mm) -> double { return N * (2.0 * M_PI) * (arc_mm - anchor_arc_mm) / perimeter_mm + phase_at_anchor; };
265
267 out.reserve(static_cast<size_t>(perimeter_mm / fill_step_mm) + np * 2);
268
269 double accum_mm = 0.0;
270 for (size_t i = 0; i + 1 < np; ++i) {
271 const Arachne::ExtrusionJunction& j0 = ext_lines[i];
272 const Arachne::ExtrusionJunction& j1 = ext_lines[i + 1];
273 const Vec2d seg = (j1.p - j0.p).cast<double>();
274 const double seg_len = seg.norm();
275 if (seg_len < EPSILON)
276 continue;
277
278 const double seg_len_mm = unscale_(seg_len);
279 const Vec2d seg_unit = seg / seg_len;
280 const Vec2d seg_perp = perp(seg_unit);
281 const double seg_end_mm = accum_mm + seg_len_mm;
282 const double first_s = std::ceil(accum_mm / fill_step_mm) * fill_step_mm;
283
284 for (double s = first_s; s < seg_end_mm; s += fill_step_mm) {
285 const double t = (s - accum_mm) / seg_len_mm;
286 const double disp = std::sin(arc_phase(s)) * amplitude;
287 const Point pt = j0.p + (seg * t).cast<coord_t>();
288 out.emplace_back(pt + (seg_perp * scale_(disp)).cast<coord_t>(), j1.w, j1.perimeter_index);
289 }
290
291 accum_mm = seg_end_mm;
292 }
293
294 while (out.size() < 3) {
295 size_t point_idx = ext_lines.size() - 2;
296 out.emplace_back(ext_lines[point_idx].p, ext_lines[point_idx].w, ext_lines[point_idx].perimeter_index);
297 if (point_idx == 0)
298 break;
299 --point_idx;
300 }
301
302 if (out.size() >= 3)
303 ext_lines = std::move(out);
304}
#define EPSILON
Definition ColorUtils.cpp:64
Definition Point.hpp:199
static double ripple_phase_shift_rad(const FuzzySkinConfig &cfg)
Definition FuzzySkin.cpp:102
static double ripple_anchor_arc_mm(const Points &poly)
Definition FuzzySkin.cpp:117
Definition ExtrusionJunction.hpp:23
Point p
Definition ExtrusionJunction.hpp:28
size_t perimeter_index
Definition ExtrusionJunction.hpp:41
coord_t w
Definition ExtrusionJunction.hpp:33
int ripples_per_layer
Definition PerimeterGenerator.hpp:35

References Slic3r::cast(), EPSILON, M_PI, Slic3r::Arachne::ExtrusionJunction::p, Slic3r::Arachne::ExtrusionJunction::perimeter_index, Slic3r::perp(), Slic3r::FuzzySkinConfig::point_distance, ripple_anchor_arc_mm(), ripple_phase_shift_rad(), Slic3r::FuzzySkinConfig::ripples_per_layer, scale_, Slic3r::FuzzySkinConfig::thickness, unscale_, and Slic3r::Arachne::ExtrusionJunction::w.

Referenced by fuzzy_extrusion_line().

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

◆ fuzzy_polyline()

void Slic3r::Feature::FuzzySkin::fuzzy_polyline ( Points & poly,
bool closed,
coordf_t slice_z,
const FuzzySkinConfig & cfg )
308{
309 if (cfg.noise_type == NoiseType::Ripple) {
310 if (poly.size() < 3)
311 return;
312 fuzzy_polyline_ripple(poly, cfg);
313 return;
314 }
315
316 std::unique_ptr<noise::module::Module> noise = get_noise_module(cfg);
317
318 const double min_dist_between_points = cfg.point_distance * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value
319 const double range_random_point_dist = cfg.point_distance / 2.;
320 double dist_left_over = random_value() * (min_dist_between_points / 2.); // the distance to be traversed on the line before making the first new point
321 Point* p0 = &poly.back();
322 Points out;
323 out.reserve(poly.size());
324 for (Point &p1 : poly)
325 {
326 if (!closed) {
327 // Skip the first point for open path
328 closed = true;
329 p0 = &p1;
330 continue;
331 }
332 // 'a' is the (next) new point between p0 and p1
333 Vec2d p0p1 = (p1 - *p0).cast<double>();
334 double p0p1_size = p0p1.norm();
335 double p0pa_dist = dist_left_over;
336 for (; p0pa_dist < p0p1_size;
337 p0pa_dist += min_dist_between_points + random_value() * range_random_point_dist)
338 {
339 Point pa = *p0 + (p0p1 * (p0pa_dist / p0p1_size)).cast<coord_t>();
340 double r = noise->GetValue(unscale_(pa.x()), unscale_(pa.y()), slice_z) * cfg.thickness;
341 out.emplace_back(pa + (perp(p0p1).cast<double>().normalized() * r).cast<coord_t>());
342 }
343 dist_left_over = p0pa_dist - p0p1_size;
344 p0 = &p1;
345 }
346 while (out.size() < 3) {
347 size_t point_idx = poly.size() - 2;
348 out.emplace_back(poly[point_idx]);
349 if (point_idx == 0)
350 break;
351 -- point_idx;
352 }
353 if (out.size() >= 3)
354 poly = std::move(out);
355}
static void fuzzy_polyline_ripple(Points &poly, const FuzzySkinConfig &cfg)
Definition FuzzySkin.cpp:172
void poly(std::vector< std::pair< Vec2d, Vec2d > > &out, std::initializer_list< Vec2d > p)
Definition DesignSketchTool.cpp:7751

References Slic3r::cast(), fuzzy_polyline_ripple(), get_noise_module(), Slic3r::FuzzySkinConfig::noise_type, Slic3r::perp(), Slic3r::FuzzySkinConfig::point_distance, random_value(), Slic3r::Ripple, Slic3r::FuzzySkinConfig::thickness, and unscale_.

Referenced by apply_fuzzy_skin().

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

◆ fuzzy_polyline_ripple()

void Slic3r::Feature::FuzzySkin::fuzzy_polyline_ripple ( Points & poly,
const FuzzySkinConfig & cfg )
static
173{
174 const double amplitude = unscale_(cfg.thickness);
175 const double N = static_cast<double>(cfg.ripples_per_layer);
176 const double fill_step_mm = unscale_(cfg.point_distance);
177
178 if (N <= 0.0 || fill_step_mm < 1e-6)
179 return;
180
181 // Compute total perimeter length in mm.
182 const size_t np = poly.size();
183 double perimeter_mm = 0.0;
184 for (size_t i = 0; i < np; ++i)
185 perimeter_mm += unscale_((poly[(i + 1) % np] - poly[i]).cast<double>().norm());
186
187 if (perimeter_mm < 1e-6)
188 return;
189
190 const double anchor_arc_mm = ripple_anchor_arc_mm(poly);
191 const double phase_shift_rad = ripple_phase_shift_rad(cfg);
192
193 // Phase function: φ(s) = N·2π·(s - anchor_arc) / perimeter + π/2 + phase_shift
194 // Adding π/2 ensures sin(φ) = 1 at the anchor when phase_shift = 0 (a peak).
195 const double phase_at_anchor = M_PI * 2.0 + phase_shift_rad;
196 auto arc_phase = [&](double arc_mm) -> double { return N * (2.0 * M_PI) * (arc_mm - anchor_arc_mm) / perimeter_mm + phase_at_anchor; };
197
198 Points out;
199 out.reserve(static_cast<size_t>(perimeter_mm / fill_step_mm) + np * 2);
200
201 double accum_mm = 0.0;
202 for (size_t i = 0; i < np; ++i) {
203 const Point& p0 = poly[i];
204 const Point& p1 = poly[(i + 1) % np];
205 const Vec2d seg = (p1 - p0).cast<double>();
206 const double seg_len = seg.norm();
207 if (seg_len < EPSILON)
208 continue;
209
210 const double seg_len_mm = unscale_(seg_len);
211 const Vec2d seg_unit = seg / seg_len;
212 const Vec2d seg_perp = perp(seg_unit);
213 const double seg_end_mm = accum_mm + seg_len_mm;
214 const double first_s = std::ceil(accum_mm / fill_step_mm) * fill_step_mm;
215
216 for (double s = first_s; s < seg_end_mm; s += fill_step_mm) {
217 const double t = (s - accum_mm) / seg_len_mm;
218 const double disp = std::sin(arc_phase(s)) * amplitude;
219 const Point pt = p0 + (seg * t).cast<coord_t>();
220 out.emplace_back(pt + (seg_perp * scale_(disp)).cast<coord_t>());
221 }
222
223 accum_mm = seg_end_mm;
224 }
225
226 while (out.size() < 3)
227 out.emplace_back(poly[poly.size() - 2]);
228
229 if (out.size() >= 3)
230 poly = std::move(out);
231}

References Slic3r::cast(), EPSILON, M_PI, Slic3r::perp(), Slic3r::FuzzySkinConfig::point_distance, ripple_anchor_arc_mm(), ripple_phase_shift_rad(), Slic3r::FuzzySkinConfig::ripples_per_layer, scale_, Slic3r::FuzzySkinConfig::thickness, and unscale_.

Referenced by fuzzy_polyline().

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

◆ get_noise_module()

std::unique_ptr< noise::module::Module > Slic3r::Feature::FuzzySkin::get_noise_module ( const FuzzySkinConfig & cfg)
static
54 {
55 if (cfg.noise_type == NoiseType::Perlin) {
56 auto perlin_noise = noise::module::Perlin();
57 perlin_noise.SetFrequency(1 / cfg.noise_scale);
58 perlin_noise.SetOctaveCount(cfg.noise_octaves);
59 perlin_noise.SetPersistence(cfg.noise_persistence);
60 return std::make_unique<noise::module::Perlin>(perlin_noise);
61 } else if (cfg.noise_type == NoiseType::Billow) {
62 auto billow_noise = noise::module::Billow();
63 billow_noise.SetFrequency(1 / cfg.noise_scale);
64 billow_noise.SetOctaveCount(cfg.noise_octaves);
65 billow_noise.SetPersistence(cfg.noise_persistence);
66 return std::make_unique<noise::module::Billow>(billow_noise);
67 } else if (cfg.noise_type == NoiseType::RidgedMulti) {
68 auto ridged_multi_noise = noise::module::RidgedMulti();
69 ridged_multi_noise.SetFrequency(1 / cfg.noise_scale);
70 ridged_multi_noise.SetOctaveCount(cfg.noise_octaves);
71 return std::make_unique<noise::module::RidgedMulti>(ridged_multi_noise);
72 } else if (cfg.noise_type == NoiseType::Voronoi) {
73 auto voronoi_noise = noise::module::Voronoi();
74 voronoi_noise.SetFrequency(1 / cfg.noise_scale);
75 voronoi_noise.SetDisplacement(1.0);
76 return std::make_unique<noise::module::Voronoi>(voronoi_noise);
77 } else {
78 return std::make_unique<UniformNoise>();
79 }
80}
@ Perlin
Definition PrintConfig.hpp:106
@ Billow
Definition PrintConfig.hpp:107
@ RidgedMulti
Definition PrintConfig.hpp:108
@ Voronoi
Definition PrintConfig.hpp:109
double noise_scale
Definition PerimeterGenerator.hpp:31
int noise_octaves
Definition PerimeterGenerator.hpp:32
double noise_persistence
Definition PerimeterGenerator.hpp:33

References Slic3r::Billow, Slic3r::FuzzySkinConfig::noise_octaves, Slic3r::FuzzySkinConfig::noise_persistence, Slic3r::FuzzySkinConfig::noise_scale, Slic3r::FuzzySkinConfig::noise_type, Slic3r::Perlin, Slic3r::RidgedMulti, and Slic3r::Voronoi.

Referenced by fuzzy_extrusion_line(), and fuzzy_polyline().

Here is the caller graph for this function:

◆ group_region_by_fuzzify()

void Slic3r::Feature::FuzzySkin::group_region_by_fuzzify ( PerimeterGenerator & g)
431{
432 g.regions_by_fuzzify.clear();
433 g.has_fuzzy_skin = false;
434 g.has_fuzzy_hole = false;
435
436 struct ConfigSurfaces {
437 FuzzySkinConfig config;
438 SurfacesPtr surfaces;
439 };
440
441 std::vector<ConfigSurfaces> regions;
442 regions.reserve(g.compatible_regions->size());
443 for (auto region : *g.compatible_regions) {
444 const auto& region_config = region->region().config();
445 const FuzzySkinConfig cfg{region_config.fuzzy_skin,
446 scaled<coord_t>(region_config.fuzzy_skin_thickness.value),
447 scaled<coord_t>(region_config.fuzzy_skin_point_distance.value),
448 region_config.fuzzy_skin_first_layer,
449 region_config.fuzzy_skin_noise_type,
450 region_config.fuzzy_skin_scale,
451 region_config.fuzzy_skin_octaves,
452 region_config.fuzzy_skin_persistence,
453 region_config.fuzzy_skin_mode,
454 region_config.fuzzy_skin_ripples_per_layer,
455 region_config.fuzzy_skin_ripple_offset,
456 region_config.fuzzy_skin_layers_between_ripple_offset,
457 g.layer_id};
458
459 auto it = std::find_if(regions.begin(), regions.end(), [&cfg](const ConfigSurfaces& item) {
460 return item.config == cfg;
461 });
462 if (it == regions.end()) {
463 regions.push_back({cfg, {}});
464 it = regions.end() - 1;
465 }
466
467 auto& surfaces = it->surfaces;
468 for (const auto& surface : region->slices.surfaces) {
469 surfaces.push_back(&surface);
470 }
471
472 if (should_fuzzify(cfg, g.layer_id, 0, true)) {
473 g.has_fuzzy_skin = true;
474 }
475 if (should_fuzzify(cfg, g.layer_id, 0, false)) {
476 g.has_fuzzy_hole = true;
477 }
478 }
479
480 g.fuzzy_supported_area.reset();
481 if ((g.has_fuzzy_skin || g.has_fuzzy_hole) && g.lower_slices != nullptr) {
482 coord_t max_thickness = 0;
483 for (const auto& region : regions)
484 if (should_fuzzify(region.config, g.layer_id, 0, true) || should_fuzzify(region.config, g.layer_id, 0, false))
485 max_thickness = std::max(max_thickness, region.config.thickness);
486 // Walls farther than a line width plus the noise amplitude from the layer below are bridging; keep them smooth.
488 }
489
490 if (regions.size() == 1) { // optimization
491 g.regions_by_fuzzify.push_back({regions.front().config, {}});
492 return;
493 }
494
495 g.regions_by_fuzzify.reserve(regions.size());
496 for (const auto& region : regions) {
497 g.regions_by_fuzzify.push_back({region.config, offset_ex(region.surfaces, ClipperSafetyOffset)});
498 }
499}
bool has_fuzzy_hole
Definition PerimeterGenerator.hpp:116
bool has_fuzzy_skin
Definition PerimeterGenerator.hpp:115
const LayerRegionPtrs * compatible_regions
Definition PerimeterGenerator.hpp:88
const ExPolygons * lower_slices
Definition PerimeterGenerator.hpp:91
std::vector< const Surface * > SurfacesPtr
Definition Surface.hpp:124
static constexpr const float ClipperSafetyOffset
Definition ClipperUtils.hpp:30
Definition PerimeterGenerator.hpp:25

References Slic3r::ClipperSafetyOffset, Slic3r::PerimeterGenerator::compatible_regions, Slic3r::PerimeterGenerator::ext_perimeter_flow, Slic3r::PerimeterGenerator::fuzzy_supported_area, Slic3r::PerimeterGenerator::has_fuzzy_hole, Slic3r::PerimeterGenerator::has_fuzzy_skin, Slic3r::PerimeterGenerator::layer_id, Slic3r::PerimeterGenerator::lower_slices, Slic3r::offset_ex(), Slic3r::PerimeterGenerator::regions_by_fuzzify, Slic3r::scaled(), Slic3r::Flow::scaled_width(), and should_fuzzify().

Referenced by Slic3r::PerimeterGenerator::process_arachne(), and Slic3r::PerimeterGenerator::process_classic().

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

◆ random_value()

double Slic3r::Feature::FuzzySkin::random_value ( )
static
38 {
39 thread_local std::random_device rd;
40 // Hash thread ID for random number seed if no hardware rng seed is available
41 thread_local std::mt19937 gen(rd.entropy() > 0 ? rd() : std::hash<std::thread::id>()(std::this_thread::get_id()));
42 thread_local std::uniform_real_distribution<double> dist(0.0, 1.0);
43 return dist(gen);
44}
T dist(const boost::polygon::point_data< T > &p1, const boost::polygon::point_data< T > &p2)
Definition Geometry.cpp:298

References Slic3r::Geometry::dist().

Referenced by fuzzy_extrusion_line(), fuzzy_polyline(), and Slic3r::Feature::FuzzySkin::UniformNoise::GetValue().

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

◆ restrict_to_supported()

void Slic3r::Feature::FuzzySkin::restrict_to_supported ( std::vector< MergedFuzzyRegion > & merged_regions,
const std::optional< ExPolygons > & supported )
static
588{
589 if (!supported)
590 return;
591 for (auto& merged_region : merged_regions)
592 merged_region.expolygons = merged_region.expolygons.empty() ? *supported : intersection_ex(merged_region.expolygons, *supported);
593}
Slic3r::ExPolygons intersection_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:878

References Slic3r::intersection_ex().

Referenced by apply_fuzzy_skin(), and apply_fuzzy_skin().

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

◆ ripple_anchor_arc_mm()

double Slic3r::Feature::FuzzySkin::ripple_anchor_arc_mm ( const Points & poly)
static
118{
119 const size_t np = poly.size();
120
121 // Find anchor world position: leftmost Y=0 crossing.
122 Vec2d anchor_world(std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
123 bool found_crossing = false;
124 for (size_t i = 0; i < np; ++i) {
125 const double ya = unscale_(poly[i].y());
126 const double yb = unscale_(poly[(i + 1) % np].y());
127 if ((ya <= 0.0 && yb >= 0.0) || (ya >= 0.0 && yb <= 0.0)) {
128 const double t = (std::abs(yb - ya) < 1e-9) ? 0.0 : ya / (ya - yb);
129 const double x_cross = unscale_(poly[i].x()) +
130 std::max(0.0, std::min(1.0, t)) * (unscale_(poly[(i + 1) % np].x()) - unscale_(poly[i].x()));
131 if (!found_crossing || x_cross < anchor_world.x()) {
132 anchor_world = Vec2d(x_cross, 0.0);
133 found_crossing = true;
134 }
135 }
136 }
137 if (!found_crossing) {
138 double best_abs_y = std::numeric_limits<double>::max();
139 for (const Point& p : poly) {
140 const double ay = std::abs(unscale_(p.y()));
141 if (ay < best_abs_y) {
142 best_abs_y = ay;
143 anchor_world = Vec2d(unscale_(p.x()), unscale_(p.y()));
144 }
145 }
146 }
147
148 // Find the arc-length of the closest point on the polyline to anchor_world.
149 double anchor_arc_mm = 0.0;
150 double best_dist_sq = std::numeric_limits<double>::max();
151 double accum_mm = 0.0;
152 for (size_t i = 0; i < np; ++i) {
153 const Vec2d pa_mm(unscale_(poly[i].x()), unscale_(poly[i].y()));
154 const Vec2d pb_mm(unscale_(poly[(i + 1) % np].x()), unscale_(poly[(i + 1) % np].y()));
155 const Vec2d seg = pb_mm - pa_mm;
156 const double seg_len = seg.norm();
157 if (seg_len > 1e-9) {
158 const double t = std::max(0.0, std::min(1.0, (anchor_world - pa_mm).dot(seg) / (seg_len * seg_len)));
159 const double dist_sq = (pa_mm + seg * t - anchor_world).squaredNorm();
160 if (dist_sq < best_dist_sq) {
161 best_dist_sq = dist_sq;
162 anchor_arc_mm = accum_mm + t * seg_len;
163 }
164 }
165 accum_mm += seg_len;
166 }
167 return anchor_arc_mm;
168}
T dot(const boost::geometry::model::d2::point_xy< T > &v1, const boost::geometry::model::d2::point_xy< T > &v2)
Definition ExtrusionSimulator.cpp:154

References Slic3r::dot(), and unscale_.

Referenced by fuzzy_extrusion_line_ripple(), and fuzzy_polyline_ripple().

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

◆ ripple_phase_shift_rad()

double Slic3r::Feature::FuzzySkin::ripple_phase_shift_rad ( const FuzzySkinConfig & cfg)
static
103{
104 if (cfg.ripple_offset == 0.0 || cfg.layers_between_ripple_offset <= 0)
105 return 0.0;
106
107 const int effective_layer = std::max(cfg.layer_id, 0);
108 const int period_index = effective_layer / std::max(cfg.layers_between_ripple_offset, 1);
109 const double raw_shift = period_index * (cfg.ripple_offset/100) * (2.0 * M_PI);
110 return fmod(raw_shift, 2.0 * M_PI);
111}
int layers_between_ripple_offset
Definition PerimeterGenerator.hpp:37
int layer_id
Definition PerimeterGenerator.hpp:38
double ripple_offset
Definition PerimeterGenerator.hpp:36

References Slic3r::FuzzySkinConfig::layer_id, Slic3r::FuzzySkinConfig::layers_between_ripple_offset, M_PI, and Slic3r::FuzzySkinConfig::ripple_offset.

Referenced by fuzzy_extrusion_line_ripple(), and fuzzy_polyline_ripple().

Here is the caller graph for this function:

◆ same_fuzzy_effect()

◆ should_fuzzify()

bool Slic3r::Feature::FuzzySkin::should_fuzzify ( const FuzzySkinConfig & config,
const int layer_id,
const size_t loop_idx,
const bool is_contour )
502{
503 const auto fuzziy_type = config.type;
504
505 if (fuzziy_type == FuzzySkinType::None|| fuzziy_type == FuzzySkinType::Disabled_fuzzy) {
506 return false;
507 }
508 if (!config.fuzzy_first_layer && layer_id <= 0) {
509 // Do not fuzzy first layer unless told to
510 return false;
511 }
512
513 const bool fuzzify_contours = (loop_idx == 0 && fuzziy_type != FuzzySkinType::Hole) || fuzziy_type == FuzzySkinType::AllWalls;
514 const bool fuzzify_holes = (fuzziy_type == FuzzySkinType::Hole || fuzziy_type == FuzzySkinType::All || fuzziy_type == FuzzySkinType::AllWalls)
515 && (loop_idx == 0 || fuzziy_type == FuzzySkinType::AllWalls);
516
517 return is_contour ? fuzzify_contours : fuzzify_holes;
518}
@ Disabled_fuzzy
Definition PrintConfig.hpp:82
@ Hole
Definition PrintConfig.hpp:79
@ None
Definition PrintConfig.hpp:77
@ AllWalls
Definition PrintConfig.hpp:81
@ All
Definition PrintConfig.hpp:80
FuzzySkinType type
Definition PerimeterGenerator.hpp:26
bool fuzzy_first_layer
Definition PerimeterGenerator.hpp:29

References Slic3r::All, Slic3r::AllWalls, Slic3r::Disabled_fuzzy, Slic3r::FuzzySkinConfig::fuzzy_first_layer, Slic3r::Hole, Slic3r::None, and Slic3r::FuzzySkinConfig::type.

Referenced by apply_fuzzy_skin(), apply_fuzzy_skin(), collect_merged_fuzzy_regions(), and group_region_by_fuzzify().

Here is the caller graph for this function: