From 04ad174e91fb307f9d088b81785ea1abe9d5b519 Mon Sep 17 00:00:00 2001 From: Wang YB <94800665+Gradbb@users.noreply.github.com> Date: Sat, 27 Apr 2024 16:09:27 +0800 Subject: [PATCH] add FillConcentricinternal update solidinfill --- src/libslic3r/CMakeLists.txt | 2 + src/libslic3r/ExtrusionEntity.hpp | 2 + src/libslic3r/Fill/Fill.cpp | 239 +++++++++--------- src/libslic3r/Fill/FillBase.cpp | 155 +++++++++++- src/libslic3r/Fill/FillBase.hpp | 15 ++ src/libslic3r/Fill/FillConcentricInternal.cpp | 74 ++++++ src/libslic3r/Fill/FillConcentricInternal.hpp | 165 ++++++++++++ src/libslic3r/Point.cpp | 46 ++++ src/libslic3r/Point.hpp | 4 + src/libslic3r/ShortestPath.hpp | 16 ++ 10 files changed, 604 insertions(+), 114 deletions(-) create mode 100644 src/libslic3r/Fill/FillConcentricInternal.cpp create mode 100644 src/libslic3r/Fill/FillConcentricInternal.hpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 60c0f9a..e17e2db 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -88,6 +88,8 @@ set(SLIC3R_SOURCES Fill/FillBase.hpp Fill/FillConcentric.cpp Fill/FillConcentric.hpp + Fill/FillConcentricInternal.cpp + Fill/FillConcentricInternal.hpp Fill/FillEnsuring.cpp Fill/FillEnsuring.hpp Fill/FillHoneycomb.cpp diff --git a/src/libslic3r/ExtrusionEntity.hpp b/src/libslic3r/ExtrusionEntity.hpp index 0d15d19..bd1dbce 100644 --- a/src/libslic3r/ExtrusionEntity.hpp +++ b/src/libslic3r/ExtrusionEntity.hpp @@ -376,6 +376,8 @@ inline void extrusion_entities_append_paths(ExtrusionEntitiesPtr &dst, Polylines polylines.clear(); } + + inline void extrusion_entities_append_loops(ExtrusionEntitiesPtr &dst, Polygons &&loops, const ExtrusionAttributes &attributes) { dst.reserve(dst.size() + loops.size()); diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index c40401b..ed4d722 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -20,6 +20,8 @@ //w21 #include "../ShortestPath.hpp" //w11 +//w29 +#include "FillConcentricInternal.hpp" #include "LayerRegion.hpp" @@ -125,9 +127,10 @@ struct SurfaceFill { //w11 static bool is_narrow_infill_area(const ExPolygon &expolygon) { + //w29 ExPolygons offsets = offset_ex(expolygon, -scale_(NARROW_INFILL_AREA_THRESHOLD)); - ExPolygons offsets_min = offset_ex(expolygon, -scale_(NARROW_INFILL_AREA_THRESHOLD_MIN)); - if (offsets.empty() && !offsets_min.empty()) + //ExPolygons offsets_min = offset_ex(expolygon, -scale_(NARROW_INFILL_AREA_THRESHOLD_MIN)); + if (offsets.empty() ) return true; return false; @@ -340,34 +343,39 @@ std::vector group_fills(const Layer &layer) // Use ipEnsuring pattern for all internal Solids. //w11 if (layer.object()->config().detect_narrow_internal_solid_infill) { - for (size_t i = 0; i < surface_fills.size(); i++) { + size_t surface_fills_size = surface_fills.size(); + for (size_t i = 0; i < surface_fills_size; i++) { if (surface_fills[i].surface.surface_type != stInternalSolid) continue; - - size_t expolygons_size = surface_fills[i].expolygons.size(); + //w29 + size_t expolygons_size = surface_fills[i].expolygons.size(); std::vector narrow_expolygons_index; narrow_expolygons_index.reserve(expolygons_size); - for (size_t j = 0; j < expolygons_size; j++) if (is_narrow_infill_area(surface_fills[i].expolygons[j])) narrow_expolygons_index.push_back(j); - if (narrow_expolygons_index.size() == expolygons_size) { - surface_fills[i].params.pattern = ipConcentricInternal; + if (narrow_expolygons_index.size() == 0) { + continue; + } else if (narrow_expolygons_index.size() == expolygons_size) { + surface_fills[i].params.pattern = ipConcentric; } else { - surface_fills[i].params.pattern = ipEnsuring; - } - //w21 - if (narrow_expolygons_index.size() != expolygons_size && narrow_expolygons_index.size() != expolygons_size) { + params = surface_fills[i].params; + params.pattern = ipConcentric; + surface_fills.emplace_back(params); + surface_fills.back().region_id = surface_fills[i].region_id; + surface_fills.back().surface.surface_type = stInternalSolid; + surface_fills.back().surface.thickness = surface_fills[i].surface.thickness; surface_fills.back().region_id_group = surface_fills[i].region_id_group; surface_fills.back().no_overlap_expolygons = surface_fills[i].no_overlap_expolygons; - } - } - } else { - for (size_t surface_fill_id = 0; surface_fill_id < surface_fills.size(); ++surface_fill_id) - if (SurfaceFill &fill = surface_fills[surface_fill_id]; fill.surface.surface_type == stInternalSolid) { - fill.params.pattern = ipEnsuring; + for (size_t j = 0; j < narrow_expolygons_index.size(); j++) { + surface_fills.back().expolygons.emplace_back(std::move(surface_fills[i].expolygons[narrow_expolygons_index[j]])); + } + for (int j = narrow_expolygons_index.size() - 1; j >= 0; j--) { + surface_fills[i].expolygons.erase(surface_fills[i].expolygons.begin() + narrow_expolygons_index[j]); + } } + } } return surface_fills; } @@ -525,14 +533,19 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: f->print_config = &this->object()->print()->config(); f->print_object_config = &this->object()->config(); - if (surface_fill.params.pattern == ipLightning) - dynamic_cast(f.get())->generator = lightning_generator; - - if (surface_fill.params.pattern == ipEnsuring) { - auto *fill_ensuring = dynamic_cast(f.get()); - assert(fill_ensuring != nullptr); - fill_ensuring->print_region_config = &m_regions[surface_fill.region_id]->region().config(); - } + //w29 + if (surface_fill.params.pattern == ipConcentricInternal) { + FillConcentricInternal *fill_concentric = dynamic_cast(f.get()); + assert(fill_concentric != nullptr); + fill_concentric->print_config = &this->object()->print()->config(); + fill_concentric->print_object_config = &this->object()->config(); + } else if (surface_fill.params.pattern == ipConcentric) { + FillConcentric *fill_concentric = dynamic_cast(f.get()); + assert(fill_concentric != nullptr); + fill_concentric->print_config = &this->object()->print()->config(); + fill_concentric->print_object_config = &this->object()->config(); + } else if (surface_fill.params.pattern == ipLightning) + dynamic_cast(f.get())->generator = lightning_generator; // calculate flow spacing for infill pattern generation bool using_internal_flow = ! surface_fill.surface.is_solid() && ! surface_fill.params.bridge; @@ -562,62 +575,59 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: params.anchor_length_max = surface_fill.params.anchor_length_max; params.resolution = resolution; //w14 - params.use_arachne = (perimeter_generator == PerimeterGeneratorType::Arachne && surface_fill.params.pattern == ipConcentric) || surface_fill.params.pattern == ipEnsuring || surface_fill.params.pattern == ipConcentricInternal; + params.use_arachne = (perimeter_generator == PerimeterGeneratorType::Arachne && surface_fill.params.pattern == ipConcentric) || surface_fill.params.pattern == ipEnsuring || surface_fill.params.pattern == ipConcentric; params.layer_height = layerm.layer()->height; + //w29 + params.flow = surface_fill.params.flow; + params.extrusion_role = surface_fill.params.extrusion_role; + params.using_internal_flow = !surface_fill.surface.is_solid() && !surface_fill.params.bridge; for (ExPolygon &expoly : surface_fill.expolygons) { - // Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon. - f->spacing = surface_fill.params.spacing; - //w21 + // Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon. + f->spacing = surface_fill.params.spacing; + // w21 f->no_overlap_expolygons = intersection_ex(surface_fill.no_overlap_expolygons, ExPolygons() = {expoly}, ApplySafetyOffset::Yes); - surface_fill.surface.expolygon = std::move(expoly); + surface_fill.surface.expolygon = std::move(expoly); Polylines polylines; ThickPolylines thick_polylines; -//w14 - if (this->object()->config().detect_narrow_internal_solid_infill && - (surface_fill.params.pattern == ipConcentricInternal || surface_fill.params.pattern == ipEnsuring)) { - layerm.region().config().infill_overlap.percent ? - f->overlap = layerm.region().config().perimeter_extrusion_width * layerm.region().config().infill_overlap.value / 100 * (-1) : - f->overlap = float(layerm.region().config().infill_overlap.value); + // w14 + //w29 + /* if (this->object()->config().detect_narrow_internal_solid_infill && + (surface_fill.params.pattern == ipConcentricInternal || surface_fill.params.pattern == ipEnsuring)) { + layerm.region().config().infill_overlap.percent ? f->overlap = layerm.region().config().perimeter_extrusion_width * + layerm.region().config().infill_overlap.value / 100 * (-1) : + f->overlap = float(layerm.region().config().infill_overlap.value); } else - f->overlap = 0; - - try { - if (params.use_arachne) { - thick_polylines = f->fill_surface_arachne(&surface_fill.surface, params); - //w21 - //if (f->layer_id % 2 == 0 && surface_fill.params.pattern == ipConcentricInternal) - // std::reverse(thick_polylines.begin(), thick_polylines.end()); - } - else { - polylines = f->fill_surface(&surface_fill.surface, params); - } - } catch (InfillFailedException &) { - } + f->overlap = 0;*/ + //w29 + f->fill_surface_extrusion(&surface_fill.surface, params, polylines, thick_polylines); if (!polylines.empty() || !thick_polylines.empty()) { // calculate actual flow from spacing (which might have been adjusted by the infill - // pattern generator) - double flow_mm3_per_mm = surface_fill.params.flow.mm3_per_mm(); - double flow_width = surface_fill.params.flow.width(); - if (using_internal_flow) { - // if we used the internal flow we're not doing a solid infill - // so we can safely ignore the slight variation that might have - // been applied to f->spacing - } else { - Flow new_flow = surface_fill.params.flow.with_spacing(float(f->spacing)); - flow_mm3_per_mm = new_flow.mm3_per_mm(); - flow_width = new_flow.width(); - } - // Save into layer. + // pattern generator) + double flow_mm3_per_mm = surface_fill.params.flow.mm3_per_mm(); + double flow_width = surface_fill.params.flow.width(); + if (using_internal_flow) { + // if we used the internal flow we're not doing a solid infill + // so we can safely ignore the slight variation that might have + // been applied to f->spacing + } else { + Flow new_flow = surface_fill.params.flow.with_spacing(float(f->spacing)); + flow_mm3_per_mm = new_flow.mm3_per_mm(); + flow_width = new_flow.width(); + } + // Save into layer. ExtrusionEntityCollection *eec = new ExtrusionEntityCollection(); - auto fill_begin = uint32_t(layerm.fills().size()); - // Only concentric fills are not sorted. - eec->no_sort = f->no_sort(); + auto fill_begin = uint32_t(layerm.fills().size()); + // Only concentric fills are not sorted. + eec->no_sort = f->no_sort(); if (params.use_arachne) { for (const ThickPolyline &thick_polyline : thick_polylines) { Flow new_flow = surface_fill.params.flow.with_spacing(float(f->spacing)); - ExtrusionMultiPath multi_path = PerimeterGenerator::thick_polyline_to_multi_path(thick_polyline, surface_fill.params.extrusion_role, new_flow, scaled(0.05), float(SCALED_EPSILON)); + ExtrusionMultiPath multi_path = PerimeterGenerator::thick_polyline_to_multi_path(thick_polyline, + surface_fill.params.extrusion_role, + new_flow, scaled(0.05), + float(SCALED_EPSILON)); // Append paths to collection. if (!multi_path.empty()) { if (multi_path.paths.front().first_point() == multi_path.paths.back().last_point()) @@ -633,15 +643,14 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: delete eec; thick_polylines.clear(); } else { - extrusion_entities_append_paths( - eec->entities, std::move(polylines), - ExtrusionAttributes{ surface_fill.params.extrusion_role, - ExtrusionFlow{ flow_mm3_per_mm, float(flow_width), surface_fill.params.flow.height() } - }); - //w21 - if (surface_fill.params.pattern == ipMonotonicLines && surface_fill.surface.surface_type == stTop) { + extrusion_entities_append_paths(eec->entities, std::move(polylines), + ExtrusionAttributes{surface_fill.params.extrusion_role, + ExtrusionFlow{flow_mm3_per_mm, float(flow_width), + surface_fill.params.flow.height()}}); + // w21 + if (surface_fill.params.pattern == ipMonotonicLines && surface_fill.surface.surface_type == stTop) { ExPolygons unextruded_areas = diff_ex(f->no_overlap_expolygons, union_ex(eec->polygons_covered_by_spacing(10))); - ExPolygons gapfill_areas = union_ex(unextruded_areas); + ExPolygons gapfill_areas = union_ex(unextruded_areas); if (!f->no_overlap_expolygons.empty()) gapfill_areas = intersection_ex(gapfill_areas, f->no_overlap_expolygons); if (gapfill_areas.size() > 0 && params.density >= 1) { @@ -650,7 +659,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: double max = 2. * new_flow.scaled_spacing(); ExPolygons gaps_ex = diff_ex(opening_ex(gapfill_areas, float(min / 2.)), offset2_ex(gapfill_areas, -float(max / 2.), float(max / 2. + ClipperSafetyOffset))); - Points ordering_points; + Points ordering_points; ordering_points.reserve(gaps_ex.size()); ExPolygons gaps_ex_sorted; gaps_ex_sorted.reserve(gaps_ex.size()); @@ -674,7 +683,8 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: }), polylines.end()); - variable_width_gap(polylines, ExtrusionRole::GapFill, surface_fill.params.flow, gap_fill.entities,filter_gap_infill_value); + variable_width_gap(polylines, ExtrusionRole::GapFill, surface_fill.params.flow, gap_fill.entities, + filter_gap_infill_value); eec->append(std::move(gap_fill.entities)); } @@ -683,46 +693,49 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: layerm.m_fills.entities.push_back(eec); } insert_fills_into_islands(*this, uint32_t(surface_fill.region_id), fill_begin, uint32_t(layerm.fills().size())); - } - } + } + } + } for (LayerSlice &lslice : this->lslices_ex) - for (LayerIsland &island : lslice.islands) { - if (! island.thin_fills.empty()) { - // Copy thin fills into fills packed as a collection. - // Fills are always stored as collections, the rest of the pipeline (wipe into infill, G-code generator) relies on it. - LayerRegion &layerm = *this->get_region(island.perimeters.region()); - ExtrusionEntityCollection &collection = *(new ExtrusionEntityCollection()); - layerm.m_fills.entities.push_back(&collection); - collection.entities.reserve(island.thin_fills.size()); - for (uint32_t fill_id : island.thin_fills) - collection.entities.push_back(layerm.thin_fills().entities[fill_id]->clone()); - island.add_fill_range({ island.perimeters.region(), { uint32_t(layerm.m_fills.entities.size() - 1), uint32_t(layerm.m_fills.entities.size()) } }); - } - // Sort the fills by region ID. - std::sort(island.fills.begin(), island.fills.end(), [](auto &l, auto &r){ return l.region() < r.region() || (l.region() == r.region() && *l.begin() < *r.begin()); }); - // Compress continuous fill ranges of the same region. - { - size_t k = 0; - for (size_t i = 0; i < island.fills.size();) { - uint32_t region_id = island.fills[i].region(); - uint32_t begin = *island.fills[i].begin(); - uint32_t end = *island.fills[i].end(); - size_t j = i + 1; - for (; j < island.fills.size() && island.fills[j].region() == region_id && *island.fills[j].begin() == end; ++ j) - end = *island.fills[j].end(); - island.fills[k ++] = { region_id, { begin, end } }; - i = j; - } - island.fills.erase(island.fills.begin() + k, island.fills.end()); - } - } + for (LayerIsland &island : lslice.islands) { + if (!island.thin_fills.empty()) { + // Copy thin fills into fills packed as a collection. + // Fills are always stored as collections, the rest of the pipeline (wipe into infill, G-code generator) relies on it. + LayerRegion & layerm = *this->get_region(island.perimeters.region()); + ExtrusionEntityCollection &collection = *(new ExtrusionEntityCollection()); + layerm.m_fills.entities.push_back(&collection); + collection.entities.reserve(island.thin_fills.size()); + for (uint32_t fill_id : island.thin_fills) + collection.entities.push_back(layerm.thin_fills().entities[fill_id]->clone()); + island.add_fill_range( + {island.perimeters.region(), {uint32_t(layerm.m_fills.entities.size() - 1), uint32_t(layerm.m_fills.entities.size())}}); + } + // Sort the fills by region ID. + std::sort(island.fills.begin(), island.fills.end(), + [](auto &l, auto &r) { return l.region() < r.region() || (l.region() == r.region() && *l.begin() < *r.begin()); }); + // Compress continuous fill ranges of the same region. + { + size_t k = 0; + for (size_t i = 0; i < island.fills.size();) { + uint32_t region_id = island.fills[i].region(); + uint32_t begin = *island.fills[i].begin(); + uint32_t end = *island.fills[i].end(); + size_t j = i + 1; + for (; j < island.fills.size() && island.fills[j].region() == region_id && *island.fills[j].begin() == end; ++j) + end = *island.fills[j].end(); + island.fills[k++] = {region_id, {begin, end}}; + i = j; + } + island.fills.erase(island.fills.begin() + k, island.fills.end()); + } + } #ifndef NDEBUG - for (LayerRegion *layerm : m_regions) - for (const ExtrusionEntity *e : layerm->fills()) - assert(dynamic_cast(e) != nullptr); + for (LayerRegion *layerm : m_regions) + for (const ExtrusionEntity *e : layerm->fills()) + assert(dynamic_cast(e) != nullptr); #endif } //w21 diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index b51da28..ef2f055 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -21,6 +21,8 @@ #include "FillAdaptive.hpp" #include "FillLightning.hpp" #include "FillEnsuring.hpp" +//w29 +#include "FillConcentricInternal.hpp" #include @@ -53,7 +55,8 @@ Fill* Fill::new_from_type(const InfillPattern type) case ipLightning: return new FillLightning::Filler(); case ipEnsuring: return new FillEnsuring(); //w14 - case ipConcentricInternal: return new FillConcentric(); + //w29 + case ipConcentricInternal: return new FillConcentricInternal(); default: throw Slic3r::InvalidArgument("unknown type"); } } @@ -105,6 +108,156 @@ ThickPolylines Fill::fill_surface_arachne(const Surface *surface, const FillPara return thick_polylines_out; } +//w29 +void Fill::fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, Polylines &polylines, ThickPolylines &thick_polylines) +{ + + try { + if (params.use_arachne) + thick_polylines = this->fill_surface_arachne(surface, params); + else + polylines = this->fill_surface(surface, params); + } catch (InfillFailedException &) {} + + +} + +void Fill::variable_width(const ThickPolylines &polylines, ExtrusionRole role, const Flow &flow, std::vector &out) +{ + const float tolerance = float(scale_(0.05)); + for (const ThickPolyline &p : polylines) { + ExtrusionPaths paths = thick_polyline_to_extrusion_paths_2(p, role, flow, tolerance); + if (!paths.empty()) { + if (paths.front().first_point() == paths.back().last_point()) + out.emplace_back(new ExtrusionLoop(std::move(paths))); + else { + for (ExtrusionPath &path : paths) + out.emplace_back(new ExtrusionPath(std::move(path))); + } + } + } +} +ExtrusionPaths Fill::thick_polyline_to_extrusion_paths_2(const ThickPolyline &thick_polyline, + ExtrusionRole role, + const Flow & flow, + const float tolerance) +{ + ExtrusionPaths paths; + ExtrusionPath path(role); + ThickLines lines = thick_polyline.thicklines(); + + size_t start_index = 0; + double max_width, min_width; + + for (int i = 0; i < (int) lines.size(); ++i) { + const ThickLine &line = lines[i]; + + if (i == 0) { + max_width = line.a_width; + min_width = line.a_width; + } + + const coordf_t line_len = line.length(); + if (line_len < SCALED_EPSILON) + continue; + + double thickness_delta = std::max(fabs(max_width - line.b_width), fabs(min_width - line.b_width)); + if (thickness_delta > tolerance) { + if (start_index != i) { + path = ExtrusionPath(role); + double length = lines[start_index].length(); + double sum = lines[start_index].length() * 0.5 * (lines[start_index].a_width + lines[start_index].b_width); + path.polyline.append(lines[start_index].a); + for (int idx = start_index + 1; idx < i; idx++) { + length += lines[idx].length(); + sum += lines[idx].length() * 0.5 * (lines[idx].a_width + lines[idx].b_width); + path.polyline.append(lines[idx].a); + } + path.polyline.append(lines[i].a); + if (length > SCALED_EPSILON) { + double w = sum / length; + Flow new_flow = flow.with_width(unscale(w) + flow.height() * float(1. - 0.25 * PI)); + + // path.mm3_per_mm = new_flow.mm3_per_mm(); + path.set_mm3_per_mm(new_flow.mm3_per_mm()); + // path.width = new_flow.width(); + path.set_width(new_flow.width()); + // path.height = new_flow.height(); + path.set_height(new_flow.height()); + paths.emplace_back(std::move(path)); + } + } + + start_index = i; + max_width = line.a_width; + min_width = line.a_width; + thickness_delta = fabs(line.a_width - line.b_width); + if (thickness_delta > tolerance) { + const unsigned int segments = (unsigned int) ceil(thickness_delta / tolerance); + const coordf_t seg_len = line_len / segments; + Points pp; + std::vector width; + { + pp.push_back(line.a); + width.push_back(line.a_width); + for (size_t j = 1; j < segments; ++j) { + pp.push_back( + (line.a.cast() + (line.b - line.a).cast().normalized() * (j * seg_len)).cast()); + + coordf_t w = line.a_width + (j * seg_len) * (line.b_width - line.a_width) / line_len; + width.push_back(w); + width.push_back(w); + } + pp.push_back(line.b); + width.push_back(line.b_width); + + assert(pp.size() == segments + 1u); + assert(width.size() == segments * 2); + } + + lines.erase(lines.begin() + i); + for (size_t j = 0; j < segments; ++j) { + ThickLine new_line(pp[j], pp[j + 1]); + new_line.a_width = width[2 * j]; + new_line.b_width = width[2 * j + 1]; + lines.insert(lines.begin() + i + j, new_line); + } + --i; + continue; + } + } else { + max_width = std::max(max_width, std::max(line.a_width, line.b_width)); + min_width = std::min(min_width, std::min(line.a_width, line.b_width)); + } + } + size_t final_size = lines.size(); + if (start_index < final_size) { + path = ExtrusionPath(role); + double length = lines[start_index].length(); + double sum = lines[start_index].length() * lines[start_index].a_width; + path.polyline.append(lines[start_index].a); + for (int idx = start_index + 1; idx < final_size; idx++) { + length += lines[idx].length(); + sum += lines[idx].length() * lines[idx].a_width; + path.polyline.append(lines[idx].a); + } + path.polyline.append(lines[final_size - 1].b); + if (length > SCALED_EPSILON) { + double w = sum / length; + Flow new_flow = flow.with_width(unscale(w) + flow.height() * float(1. - 0.25 * PI)); + // path.mm3_per_mm = new_flow.mm3_per_mm(); + path.set_mm3_per_mm(new_flow.mm3_per_mm()); + // path.width = new_flow.width(); + path.set_width(new_flow.width()); + // path.height = new_flow.height(); + path.set_height(new_flow.height()); + paths.emplace_back(std::move(path)); + } + } + + return paths; +} + // Calculate a new spacing to fill width with possibly integer number of lines, // the first and last line being centered at the interval ends. // This function possibly increases the spacing, never decreases, diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index f830555..b3907b3 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -15,6 +15,9 @@ #include "../Utils.hpp" #include "../ExPolygon.hpp" #include "../PrintConfig.hpp" +//w29 +#include "../ExtrusionEntity.hpp" +#include "../ExtrusionEntityCollection.hpp" namespace Slic3r { @@ -63,6 +66,11 @@ struct FillParams bool use_arachne { false }; // Layer height for Concentric infill with Arachne. coordf_t layer_height { 0.f }; + //w29 + Flow flow; + ExtrusionRole extrusion_role{ExtrusionRole::None}; + bool using_internal_flow{false}; + //bool can_reverse{true}; }; static_assert(IsTriviallyCopyable::value, "FillParams class is not POD (and it should be - see constructor)."); @@ -116,6 +124,13 @@ public: // Perform the fill. virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms); virtual ThickPolylines fill_surface_arachne(const Surface *surface, const FillParams ¶ms); + //w29 + virtual void fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, Polylines &polylines,ThickPolylines &thick_polylines); + void variable_width(const ThickPolylines &polylines, ExtrusionRole role, const Flow &flow, std::vector &out); + ExtrusionPaths thick_polyline_to_extrusion_paths_2(const ThickPolyline &thick_polyline, + ExtrusionRole role, + const Flow & flow, + const float tolerance); protected: Fill() : diff --git a/src/libslic3r/Fill/FillConcentricInternal.cpp b/src/libslic3r/Fill/FillConcentricInternal.cpp new file mode 100644 index 0000000..d34fa4b --- /dev/null +++ b/src/libslic3r/Fill/FillConcentricInternal.cpp @@ -0,0 +1,74 @@ +#include "../ClipperUtils.hpp" +#include "../ExPolygon.hpp" +#include "../Surface.hpp" +#include "Arachne/WallToolPaths.hpp" + +#include "FillConcentricInternal.hpp" + +#include + +namespace Slic3r { + +void FillConcentricInternal::fill_surface_extrusion(const Surface * surface, + const FillParams ¶ms, + Polylines & polylines, + ThickPolylines & thick_polylines_out) +{ + assert(this->print_config != nullptr && this->print_object_config != nullptr); + + for (size_t i = 0; i < this->no_overlap_expolygons.size(); ++i) { + ExPolygon &expolygon = this->no_overlap_expolygons[i]; + Point bbox_size = expolygon.contour.bounding_box().size(); + coord_t min_spacing = params.flow.scaled_spacing(); + + coord_t loops_count = std::max(bbox_size.x(), bbox_size.y()) / min_spacing + 1; + Polygons polygons = to_polygons(expolygon); + + Arachne::WallToolPaths wallToolPaths(polygons, min_spacing, min_spacing, loops_count, 0, params.layer_height, + *this->print_object_config, *this->print_config); + + std::vector loops = wallToolPaths.getToolPaths(); + std::vector all_extrusions; + for (Arachne::VariableWidthLines &loop : loops) { + if (loop.empty()) + continue; + for (const Arachne::ExtrusionLine &wall : loop) + all_extrusions.emplace_back(&wall); + } + + size_t firts_poly_idx = thick_polylines_out.size(); + Point last_pos(0, 0); + for (const Arachne::ExtrusionLine *extrusion : all_extrusions) { + if (extrusion->empty()) + continue; + + ThickPolyline thick_polyline = Arachne::to_thick_polyline(*extrusion); + if (extrusion->is_closed && thick_polyline.points.front() == thick_polyline.points.back() && + thick_polyline.width.front() == thick_polyline.width.back()) { + thick_polyline.points.pop_back(); + assert(thick_polyline.points.size() * 2 == thick_polyline.width.size()); + int nearest_idx = last_pos.nearest_point_index(thick_polyline.points); + std::rotate(thick_polyline.points.begin(), thick_polyline.points.begin() + nearest_idx, thick_polyline.points.end()); + std::rotate(thick_polyline.width.begin(), thick_polyline.width.begin() + 2 * nearest_idx, thick_polyline.width.end()); + thick_polyline.points.emplace_back(thick_polyline.points.front()); + } + thick_polylines_out.emplace_back(std::move(thick_polyline)); + } + + size_t j = firts_poly_idx; + for (size_t i = firts_poly_idx; i < thick_polylines_out.size(); ++i) { + thick_polylines_out[i].clip_end(this->loop_clipping); + if (thick_polylines_out[i].is_valid()) { + if (j < i) + thick_polylines_out[j] = std::move(thick_polylines_out[i]); + ++j; + } + } + if (j < thick_polylines_out.size()) + thick_polylines_out.erase(thick_polylines_out.begin() + int(j), thick_polylines_out.end()); + + reorder_by_shortest_traverse(thick_polylines_out); + } +} + +} // namespace Slic3r diff --git a/src/libslic3r/Fill/FillConcentricInternal.hpp b/src/libslic3r/Fill/FillConcentricInternal.hpp new file mode 100644 index 0000000..194910c --- /dev/null +++ b/src/libslic3r/Fill/FillConcentricInternal.hpp @@ -0,0 +1,165 @@ +#ifndef slic3r_FillConcentricInternal_hpp_ +#define slic3r_FillConcentricInternal_hpp_ + +#include "FillBase.hpp" + +namespace Slic3r { + +class FillConcentricInternal : public Fill +{ +public: + ~FillConcentricInternal() override = default; + void fill_surface_extrusion(const Surface * surface, + const FillParams ¶ms, + Polylines & polylines, + ThickPolylines & thick_polylines) override; + void variable_width(const ThickPolylines &polylines, ExtrusionRole role, const Flow &flow, std::vector &out) + { + const float tolerance = float(scale_(0.05)); + for (const ThickPolyline &p : polylines) { + ExtrusionPaths paths = thick_polyline_to_extrusion_paths_2(p, role, flow, tolerance); + // Append paths to collection. + if (!paths.empty()) { + if (paths.front().first_point() == paths.back().last_point()) + out.emplace_back(new ExtrusionLoop(std::move(paths))); + else { + for (ExtrusionPath &path : paths) + out.emplace_back(new ExtrusionPath(std::move(path))); + } + } + } + } + ExtrusionPaths thick_polyline_to_extrusion_paths_2(const ThickPolyline &thick_polyline, + ExtrusionRole role, + const Flow & flow, + const float tolerance) + { + ExtrusionPaths paths; + ExtrusionPath path(role); + ThickLines lines = thick_polyline.thicklines(); + + size_t start_index = 0; + double max_width, min_width; + + for (int i = 0; i < (int) lines.size(); ++i) { + const ThickLine &line = lines[i]; + + if (i == 0) { + max_width = line.a_width; + min_width = line.a_width; + } + + const coordf_t line_len = line.length(); + if (line_len < SCALED_EPSILON) + continue; + + double thickness_delta = std::max(fabs(max_width - line.b_width), fabs(min_width - line.b_width)); + if (thickness_delta > tolerance) { + if (start_index != i) { + path = ExtrusionPath(role); + double length = lines[start_index].length(); + double sum = lines[start_index].length() * 0.5 * (lines[start_index].a_width + lines[start_index].b_width); + path.polyline.append(lines[start_index].a); + for (int idx = start_index + 1; idx < i; idx++) { + length += lines[idx].length(); + sum += lines[idx].length() * 0.5 * (lines[idx].a_width + lines[idx].b_width); + path.polyline.append(lines[idx].a); + } + path.polyline.append(lines[i].a); + if (length > SCALED_EPSILON) { + double w = sum / length; + Flow new_flow = flow.with_width(unscale(w) + flow.height() * float(1. - 0.25 * PI)); + + // path.mm3_per_mm = new_flow.mm3_per_mm(); + path.set_mm3_per_mm(new_flow.mm3_per_mm()); + // path.width = new_flow.width(); + path.set_width(new_flow.width()); + // path.height = new_flow.height(); + path.set_height(new_flow.height()); + paths.emplace_back(std::move(path)); + } + } + + start_index = i; + max_width = line.a_width; + min_width = line.a_width; + thickness_delta = fabs(line.a_width - line.b_width); + if (thickness_delta > tolerance) { + const unsigned int segments = (unsigned int) ceil(thickness_delta / tolerance); + const coordf_t seg_len = line_len / segments; + Points pp; + std::vector width; + { + pp.push_back(line.a); + width.push_back(line.a_width); + for (size_t j = 1; j < segments; ++j) { + pp.push_back( + (line.a.cast() + (line.b - line.a).cast().normalized() * (j * seg_len)).cast()); + + coordf_t w = line.a_width + (j * seg_len) * (line.b_width - line.a_width) / line_len; + width.push_back(w); + width.push_back(w); + } + pp.push_back(line.b); + width.push_back(line.b_width); + + assert(pp.size() == segments + 1u); + assert(width.size() == segments * 2); + } + + lines.erase(lines.begin() + i); + for (size_t j = 0; j < segments; ++j) { + ThickLine new_line(pp[j], pp[j + 1]); + new_line.a_width = width[2 * j]; + new_line.b_width = width[2 * j + 1]; + lines.insert(lines.begin() + i + j, new_line); + } + --i; + continue; + } + } else { + max_width = std::max(max_width, std::max(line.a_width, line.b_width)); + min_width = std::min(min_width, std::min(line.a_width, line.b_width)); + } + } + size_t final_size = lines.size(); + if (start_index < final_size) { + path = ExtrusionPath(role); + double length = lines[start_index].length(); + double sum = lines[start_index].length() * lines[start_index].a_width; + path.polyline.append(lines[start_index].a); + for (int idx = start_index + 1; idx < final_size; idx++) { + length += lines[idx].length(); + sum += lines[idx].length() * lines[idx].a_width; + path.polyline.append(lines[idx].a); + } + path.polyline.append(lines[final_size - 1].b); + if (length > SCALED_EPSILON) { + double w = sum / length; + Flow new_flow = flow.with_width(unscale(w) + flow.height() * float(1. - 0.25 * PI)); + // path.mm3_per_mm = new_flow.mm3_per_mm(); + path.set_mm3_per_mm(new_flow.mm3_per_mm()); + // path.width = new_flow.width(); + path.set_width(new_flow.width()); + // path.height = new_flow.height(); + path.set_height(new_flow.height()); + paths.emplace_back(std::move(path)); + } + } + + return paths; + } + +protected: + Fill *clone() const override { return new FillConcentricInternal(*this); }; + bool no_sort() const override { return true; } + + const PrintConfig * print_config = nullptr; + const PrintObjectConfig *print_object_config = nullptr; + + friend class Layer; +}; + +} // namespace Slic3r + +#endif // slic3r_FillConcentricInternal_hpp_ diff --git a/src/libslic3r/Point.cpp b/src/libslic3r/Point.cpp index eae6b50..4d0835e 100644 --- a/src/libslic3r/Point.cpp +++ b/src/libslic3r/Point.cpp @@ -81,6 +81,52 @@ Points collect_duplicates(Points pts /* Copy */) } return duplicits; } +//w29 +int Point::nearest_point_index(const Points &points) const +{ + PointConstPtrs p; + p.reserve(points.size()); + for (Points::const_iterator it = points.begin(); it != points.end(); ++it) + p.push_back(&*it); + return this->nearest_point_index(p); +} + +int Point::nearest_point_index(const PointConstPtrs &points) const +{ + int idx = -1; + double distance = -1; // double because long is limited to 2147483647 on some platforms and it's not enough + + for (PointConstPtrs::const_iterator it = points.begin(); it != points.end(); ++it) { + /* If the X distance of the candidate is > than the total distance of the + best previous candidate, we know we don't want it */ + double d = sqr((*this) (0) - (*it)->x()); + if (distance != -1 && d > distance) + continue; + + /* If the Y distance of the candidate is > than the total distance of the + best previous candidate, we know we don't want it */ + d += sqr((*this) (1) - (*it)->y()); + if (distance != -1 && d > distance) + continue; + + idx = it - points.begin(); + distance = d; + + if (distance < EPSILON) + break; + } + + return idx; +} + +int Point::nearest_point_index(const PointPtrs &points) const +{ + PointConstPtrs p; + p.reserve(points.size()); + for (PointPtrs::const_iterator it = points.begin(); it != points.end(); ++it) + p.push_back(*it); + return this->nearest_point_index(p); +} template BoundingBox get_extents(const Points &pts) diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index 3ffa3dd..23bf107 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -212,6 +212,10 @@ public: Point rotated(double angle) const { Point res(*this); res.rotate(angle); return res; } Point rotated(double cos_a, double sin_a) const { Point res(*this); res.rotate(cos_a, sin_a); return res; } Point rotated(double angle, const Point ¢er) const { Point res(*this); res.rotate(angle, center); return res; } + //w29 + int nearest_point_index(const Points &points) const; + int nearest_point_index(const PointConstPtrs &points) const; + int nearest_point_index(const PointPtrs &points) const; }; inline bool operator<(const Point &l, const Point &r) diff --git a/src/libslic3r/ShortestPath.hpp b/src/libslic3r/ShortestPath.hpp index f009433..04b9b89 100644 --- a/src/libslic3r/ShortestPath.hpp +++ b/src/libslic3r/ShortestPath.hpp @@ -42,6 +42,22 @@ void chain_and_reorder_extrusion_paths(std::vect Polylines chain_polylines(Polylines &&src, const Point *start_near = nullptr); inline Polylines chain_polylines(const Polylines& src, const Point* start_near = nullptr) { Polylines tmp(src); return chain_polylines(std::move(tmp), start_near); } +//w29 +template inline void reorder_by_shortest_traverse(std::vector &polylines_out) +{ + Points start_point; + start_point.reserve(polylines_out.size()); + for (const T contour : polylines_out) + start_point.push_back(contour.points.front()); + + std::vector order = chain_points(start_point); + + std::vector Temp = polylines_out; + polylines_out.erase(polylines_out.begin(), polylines_out.end()); + + for (size_t i : order) + polylines_out.emplace_back(std::move(Temp[i])); +} ClipperLib::PolyNodes chain_clipper_polynodes(const Points &points, const ClipperLib::PolyNodes &items);