From a36142d2587f651f1244797495e6e4ab40328679 Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 19 Dec 2018 17:14:11 +0100 Subject: [PATCH] merge complete --- src/libslic3r/BridgeDetector.cpp | 20 +-- src/libslic3r/ExPolygon.cpp | 22 +-- src/libslic3r/Fill/Fill.cpp | 18 +-- src/libslic3r/Fill/FillBase.cpp | 10 +- src/libslic3r/Fill/FillConcentric.cpp | 4 +- src/libslic3r/Fill/FillSmooth.cpp | 28 ++-- src/libslic3r/GCode.cpp | 6 +- src/libslic3r/GCode/PreviewData.cpp | 3 + src/libslic3r/GCode/PreviewData.hpp | 1 + src/libslic3r/GCode/ToolOrdering.cpp | 12 +- src/libslic3r/Layer.hpp | 6 +- src/libslic3r/LayerRegion.cpp | 14 +- src/libslic3r/Line.cpp | 11 ++ src/libslic3r/Line.hpp | 4 + src/libslic3r/MedialAxis.cpp | 88 ++++++------ src/libslic3r/MultiPoint.cpp | 9 +- src/libslic3r/PerimeterGenerator.cpp | 14 +- src/libslic3r/Point.cpp | 23 ++++ src/libslic3r/Point.hpp | 10 ++ src/libslic3r/Polyline.hpp | 15 +- src/libslic3r/Print.hpp | 3 + src/libslic3r/PrintConfig.cpp | 33 +++-- src/libslic3r/PrintConfig.hpp | 13 +- src/libslic3r/PrintObject.cpp | 67 ++++----- src/libslic3r/TriangleMesh.cpp | 189 +++++++++++++++++++------- src/libslic3r/TriangleMesh.hpp | 2 +- src/libslic3r/libslic3r.h | 2 + src/slic3r/GUI/Tab.cpp | 2 +- 28 files changed, 397 insertions(+), 232 deletions(-) diff --git a/src/libslic3r/BridgeDetector.cpp b/src/libslic3r/BridgeDetector.cpp index 692cdeb8f..79557242f 100644 --- a/src/libslic3r/BridgeDetector.cpp +++ b/src/libslic3r/BridgeDetector.cpp @@ -244,26 +244,26 @@ Polygons BridgeDetector::coverage(double angle, bool precise) const { if (n_supported >= 2) { // trim it to not allow to go outside of the intersections BoundingBox center_bound = intersects[0].bounding_box(); - coord_t min_y = center_bound.center().y, max_y = center_bound.center().y; + coord_t min_y = center_bound.center()(1), max_y = center_bound.center()(1); for (Polygon &poly_bound : intersects) { center_bound = poly_bound.bounding_box(); - if (min_y > center_bound.center().y) min_y = center_bound.center().y; - if (max_y < center_bound.center().y) max_y = center_bound.center().y; + if (min_y > center_bound.center()(1)) min_y = center_bound.center()(1); + if (max_y < center_bound.center()(1)) max_y = center_bound.center()(1); } - coord_t min_x = trapezoid[0].x, max_x = trapezoid[0].x; + coord_t min_x = trapezoid[0](0), max_x = trapezoid[0](0); for (Point &p : trapezoid.points) { - if (min_x > p.x) min_x = p.x; - if (max_x < p.x) max_x = p.x; + if (min_x > p(0)) min_x = p(0); + if (max_x < p(0)) max_x = p(0); } //add what get_trapezoids3 has removed (+EPSILON) min_x -= (this->spacing / 4 + 1); max_x += (this->spacing / 4 + 1); coord_t mid_x = (min_x + max_x) / 2; for (Point &p : trapezoid.points) { - if (p.y < min_y) p.y = min_y; - if (p.y > max_y) p.y = max_y; - if (p.x > min_x && p.x < mid_x) p.x = min_x; - if (p.x < max_x && p.x > mid_x) p.x = max_x; + if (p(1) < min_y) p(1) = min_y; + if (p(1) > max_y) p(1) = max_y; + if (p(0) > min_x && p(0) < mid_x) p(0) = min_x; + if (p(0) < max_x && p(0) > mid_x) p(0) = max_x; } } } diff --git a/src/libslic3r/ExPolygon.cpp b/src/libslic3r/ExPolygon.cpp index 2275e8a16..7423fface 100644 --- a/src/libslic3r/ExPolygon.cpp +++ b/src/libslic3r/ExPolygon.cpp @@ -314,11 +314,11 @@ ExPolygon::get_trapezoids3_half(Polygons* polygons, float spacing) const { BoundingBox bb(pp); // get all x coordinates - int min_x = pp[0].x, max_x = pp[0].x; + int min_x = pp[0].x(), max_x = pp[0].x(); std::vector xx; for (Points::const_iterator p = pp.begin(); p != pp.end(); ++p) { - if (min_x > p->x) min_x = p->x; - if (max_x < p->x) max_x = p->x; + if (min_x > p->x()) min_x = p->x(); + if (max_x < p->x()) max_x = p->x(); } for (int x = min_x; x < max_x-spacing/2; x += spacing) { xx.push_back(x); @@ -334,14 +334,14 @@ ExPolygon::get_trapezoids3_half(Polygons* polygons, float spacing) const { // build rectangle Polygon poly; poly.points.resize(4); - poly[0].x = *x +spacing / 4; - poly[0].y = bb.min.y; - poly[1].x = next_x -spacing / 4; - poly[1].y = bb.min.y; - poly[2].x = next_x -spacing / 4; - poly[2].y = bb.max.y; - poly[3].x = *x +spacing / 4; - poly[3].y = bb.max.y; + poly[0].x() = *x + spacing / 4; + poly[0].y() = bb.min(1); + poly[1].x() = next_x - spacing / 4; + poly[1].y() = bb.min(1); + poly[2].x() = next_x - spacing / 4; + poly[2].y() = bb.max(1); + poly[3].x() = *x + spacing / 4; + poly[3].y() = bb.max(1); // intersect with this expolygon // append results to return value diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index ed1c1c5a1..83c6ed583 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -59,7 +59,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) layerm.fill_surfaces.group(&groups); //if internal infill can be dense, place it on his own group - if (layerm.region()->config.infill_dense.getBool() && layerm.region()->config.fill_density<40) { + if (layerm.region()->config().infill_dense.getBool() && layerm.region()->config().fill_density<40) { SurfacesPtr *denseGroup = NULL; const uint32_t nbGroups = groups.size(); for (uint32_t num_group = 0; num_group < nbGroups; ++num_group) { @@ -193,8 +193,8 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) (surface.is_top() ? layerm.region()->config().top_fill_pattern.value : layerm.region()->config().bottom_fill_pattern.value) : ipRectilinear; } else { - if (layerm.region()->config.infill_dense.getBool() - && layerm.region()->config.fill_density<40 + if (layerm.region()->config().infill_dense.getBool() + && layerm.region()->config().fill_density<40 && surface.maxNbSolidLayersOnTop <= 1 && surface.maxNbSolidLayersOnTop > 0) { density = 42; @@ -262,8 +262,8 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) f->loop_clipping = scale_(flow.nozzle_diameter) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER; //give the overlap size to let the infill do his overlap //add overlap if at least one perimeter - if (layerm.region()->config.perimeters.getInt() > 0) { - f->overlap = layerm.region()->config.get_abs_value("infill_overlap", (perimeter_spacing + (f->spacing)) / 2); + if (layerm.region()->config().perimeters > 0) { + f->overlap = layerm.region()->config().get_abs_value("infill_overlap", (perimeter_spacing + (f->spacing)) / 2); if (f->overlap!=0) { f->no_overlap_expolygons = intersection_ex(layerm.fill_no_overlap_expolygons, ExPolygons() = { surface.expolygon }); } else { @@ -278,8 +278,8 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) FillParams params; params.density = 0.01 * density; params.dont_adjust = false; - params.fill_exactly = layerm.region()->config.enforce_full_fill_volume.getBool(); - params.dont_connect = layerm.region()->config.infill_not_connected.getBool(); + params.fill_exactly = layerm.region()->config().enforce_full_fill_volume.getBool(); + params.dont_connect = layerm.region()->config().infill_not_connected.getBool(); // calculate actual flow from spacing (which might have been adjusted by the infill // pattern generator) @@ -293,8 +293,8 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) float flow_percent = 1; if(surface.is_overBridge()){ - params.density = layerm.region()->config.over_bridge_flow_ratio; - //params.flow_mult = layerm.region()->config.over_bridge_flow_ratio; + params.density = layerm.region()->config().over_bridge_flow_ratio; + //params.flow_mult = layerm.region()->config().over_bridge_flow_ratio; } f->fill_surface_extrusion(&surface, params, flow, erNone, out.entities); diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index f83ee71f1..bc2defe93 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -151,7 +151,7 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams ¶ for (auto pline = polylines.begin(); pline != polylines.end(); ++pline){ Lines lines = pline->lines(); for (auto line = lines.begin(); line != lines.end(); ++line){ - lengthTot += unscale(line->length()); + lengthTot += unscaled(line->length()); nbLines++; } } @@ -159,13 +159,13 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams ¶ // compute real volume double poylineVolume = 0; for (auto poly = this->no_overlap_expolygons.begin(); poly != this->no_overlap_expolygons.end(); ++poly) { - poylineVolume += flow.height*unscale(unscale(poly->area())); + poylineVolume += flow.height*unscaled(unscaled(poly->area())); // add external "perimeter gap" - double perimeterRoundGap = unscale(poly->contour.length()) * flow.height * (1 - 0.25*PI) * 0.5; + double perimeterRoundGap = unscaled(poly->contour.length()) * flow.height * (1 - 0.25*PI) * 0.5; // add holes "perimeter gaps" double holesGaps = 0; for (auto hole = poly->holes.begin(); hole != poly->holes.end(); ++hole) { - holesGaps += unscale(hole->length()) * flow.height * (1 - 0.25*PI) * 0.5; + holesGaps += unscaled(hole->length()) * flow.height * (1 - 0.25*PI) * 0.5; } poylineVolume += perimeterRoundGap + holesGaps; } @@ -196,7 +196,7 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams ¶ } /// push the path extrusion_entities_append_paths( - eec->entities, STDMOVE(polylines), + eec->entities, std::move(polylines), good_role, flow.mm3_per_mm() * params.flow_mult * multFlow, flow.width * params.flow_mult * multFlow, diff --git a/src/libslic3r/Fill/FillConcentric.cpp b/src/libslic3r/Fill/FillConcentric.cpp index 0d2f05251..b3e01b361 100644 --- a/src/libslic3r/Fill/FillConcentric.cpp +++ b/src/libslic3r/Fill/FillConcentric.cpp @@ -89,8 +89,8 @@ void FillConcentricWGapFill::fill_surface_extrusion(const Surface *surface, cons coord_t distance = coord_t(min_spacing / params.density); if (params.density > 0.9999f && !params.dont_adjust) { - distance = this->_adjust_solid_spacing(bounding_box.size().x, distance); - this->spacing = unscale(distance); + distance = this->_adjust_solid_spacing(bounding_box.size().x(), distance); + this->spacing = unscaled(distance); } ExPolygons gaps; diff --git a/src/libslic3r/Fill/FillSmooth.cpp b/src/libslic3r/Fill/FillSmooth.cpp index 3b936a653..6497af7f6 100644 --- a/src/libslic3r/Fill/FillSmooth.cpp +++ b/src/libslic3r/Fill/FillSmooth.cpp @@ -37,12 +37,12 @@ namespace Slic3r { double volumeToOccupy = 0; for (auto poly = this->no_overlap_expolygons.begin(); poly != this->no_overlap_expolygons.end(); ++poly) { // add external "perimeter gap" - double poylineVolume = flow.height*unscale(unscale(poly->area())); - double perimeterRoundGap = unscale(poly->contour.length()) * flow.height * (1 - 0.25*PI) * 0.5; + double poylineVolume = flow.height*unscaled(unscaled(poly->area())); + double perimeterRoundGap = unscaled(poly->contour.length()) * flow.height * (1 - 0.25*PI) * 0.5; // add holes "perimeter gaps" double holesGaps = 0; for (auto hole = poly->holes.begin(); hole != poly->holes.end(); ++hole) { - holesGaps += unscale(hole->length()) * flow.height * (1 - 0.25*PI) * 0.5; + holesGaps += unscaled(hole->length()) * flow.height * (1 - 0.25*PI) * 0.5; } poylineVolume += perimeterRoundGap + holesGaps; @@ -88,7 +88,7 @@ namespace Slic3r { for (auto pline = polylines_layer1.begin(); pline != polylines_layer1.end(); ++pline) { Lines lines = pline->lines(); for (auto line = lines.begin(); line != lines.end(); ++line) { - lengthTot += unscale(line->length()); + lengthTot += unscaled(line->length()); nbLines++; } } @@ -102,7 +102,7 @@ namespace Slic3r { eecroot->entities.push_back(eec); eec->no_sort = false; //can be sorted inside the pass extrusion_entities_append_paths( - eec->entities, STDMOVE(polylines_layer1), + eec->entities, std::move(polylines_layer1), flow.bridge ? erBridgeInfill : rolePass[0], //reduced flow height for a better view (it's only a gui thing) params.flow_mult * flow.mm3_per_mm() * percentFlow[0] * (params.fill_exactly ? volumeToOccupy / extrudedVolume : 1), @@ -122,18 +122,18 @@ namespace Slic3r { for (auto pline = polylines_layer1.begin(); pline != polylines_layer1.end(); ++pline) { Lines lines = pline->lines(); for (auto line = lines.begin(); line != lines.end(); ++line) { - lengthTot += unscale(line->length()); + lengthTot += unscaled(line->length()); nbLines++; } } // add external "perimeter gap" - double poylineVolume = flow.height*unscale(unscale(poly->area())); - double perimeterRoundGap = unscale(poly->contour.length()) * flow.height * (1 - 0.25*PI) * 0.5; + double poylineVolume = flow.height*unscaled(unscaled(poly->area())); + double perimeterRoundGap = unscaled(poly->contour.length()) * flow.height * (1 - 0.25*PI) * 0.5; // add holes "perimeter gaps" double holesGaps = 0; for (auto hole = poly->holes.begin(); hole != poly->holes.end(); ++hole) { - holesGaps += unscale(hole->length()) * flow.height * (1 - 0.25*PI) * 0.5; + holesGaps += unscaled(hole->length()) * flow.height * (1 - 0.25*PI) * 0.5; } poylineVolume += perimeterRoundGap + holesGaps; @@ -149,7 +149,7 @@ namespace Slic3r { good_role = flow.bridge ? erBridgeInfill : rolePass[0]; } extrusion_entities_append_paths( - eec->entities, STDMOVE(polylines_layer1), + eec->entities, std::move(polylines_layer1), good_role, //reduced flow height for a better view (it's only a gui thing) params.flow_mult * flow.mm3_per_mm() * percentFlow[0] * (params.fill_exactly ? poylineVolume / extrudedVolume : 1), @@ -187,7 +187,7 @@ namespace Slic3r { for (auto pline = polylines_layer2.begin(); pline != polylines_layer2.end(); ++pline){ Lines lines = pline->lines(); for (auto line = lines.begin(); line != lines.end(); ++line){ - lengthTot += unscale(line->length()); + lengthTot += unscaled(line->length()); nbLines++; } } @@ -205,7 +205,7 @@ namespace Slic3r { } // print thin extrusion_entities_append_paths( - eec->entities, STDMOVE(polylines_layer2), + eec->entities, std::move(polylines_layer2), good_role, params.flow_mult * flow.mm3_per_mm() * percentFlow[1] * (params.fill_exactly ? volumeToOccupy / extrudedVolume : 1), //min-reduced flow width for a better view (it's only a gui thing) @@ -244,7 +244,7 @@ namespace Slic3r { for (auto pline = polylines_layer3.begin(); pline != polylines_layer3.end(); ++pline){ Lines lines = pline->lines(); for (auto line = lines.begin(); line != lines.end(); ++line){ - lengthTot += unscale(line->length()); + lengthTot += unscaled(line->length()); nbLines++; } } @@ -261,7 +261,7 @@ namespace Slic3r { } // print thin extrusion_entities_append_paths( - eec->entities, STDMOVE(polylines_layer3), + eec->entities, std::move(polylines_layer3), good_role, //slow (if last) //reduced flow width for a better view (it's only a gui thing) params.flow_mult * flow.mm3_per_mm() * percentFlow[2] * (params.fill_exactly ? volumeToOccupy / extrudedVolume : 1), diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 5101eafda..e6f66015a 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1502,7 +1502,7 @@ void GCode::process_layer( // fill->first_point fits inside ith slice point_inside_surface(i, fill->first_point())) { if (islands[i].by_region.empty()) { - islands[i].by_region.assign(print.regions.size(), ObjectByExtruder::Island::Region()); + islands[i].by_region.assign(print.regions().size(), ObjectByExtruder::Island::Region()); } //don't do fill->entities because it will discard no_sort islands[i].by_region[region_id].append(entity_type, fill, entity_overrides, layer_to_print.object()->copies().size()); @@ -2293,8 +2293,8 @@ std::string GCode::extrude_infill(const Print &print, const std::vectorconfig().infill_first == is_infill_first) { - m_config.apply(print.regions[®ion - &by_region.front()]->config); + if (print.regions()[®ion - &by_region.front()]->config().infill_first == is_infill_first) { + m_config.apply(print.regions()[®ion - &by_region.front()]->config()); ExtrusionEntityCollection chained = region.infills.chained_path_from(m_last_pos, false); gcode += extrude_entity(chained, "infill"); } diff --git a/src/libslic3r/GCode/PreviewData.cpp b/src/libslic3r/GCode/PreviewData.cpp index 3f2df9532..50d441e5e 100644 --- a/src/libslic3r/GCode/PreviewData.cpp +++ b/src/libslic3r/GCode/PreviewData.cpp @@ -375,6 +375,8 @@ std::string GCodePreviewData::get_legend_title() const return L("Volumetric flow rate (mm3/s)"); case Extrusion::Tool: return L("Tool"); + case Extrusion::Filament: + return L("Filament"); case Extrusion::ColorPrint: return L("Color Print"); } @@ -438,6 +440,7 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std:: break; } case Extrusion::Tool: + case Extrusion::Filament: { unsigned int tools_colors_count = tool_colors.size() / 4; items.reserve(tools_colors_count); diff --git a/src/libslic3r/GCode/PreviewData.hpp b/src/libslic3r/GCode/PreviewData.hpp index 9f882788d..c1854505e 100644 --- a/src/libslic3r/GCode/PreviewData.hpp +++ b/src/libslic3r/GCode/PreviewData.hpp @@ -71,6 +71,7 @@ public: Feedrate, VolumetricRate, Tool, + Filament, ColorPrint, Num_View_Types }; diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index e800cd53f..51622e39a 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -485,7 +485,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int continue; - if ((!print.config().infill_first ? perimeters_done : !perimeters_done) || (!object->config().wipe_into_objects && region.config().wipe_into_infill)) { + if ((!region.config().infill_first ? perimeters_done : !perimeters_done) || (!object->config().wipe_into_objects && region.config().wipe_into_infill)) { for (const ExtrusionEntity* ee : this_layer->regions()[region_id]->fills.entities) { // iterate through all infill Collections auto* fill = dynamic_cast(ee); @@ -498,7 +498,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int if (volume_to_wipe<=0) continue; - if (!object->config().wipe_into_objects && !print.config().infill_first && region.config().wipe_into_infill) + if (!object->config().wipe_into_objects && !region.config().infill_first && region.config().wipe_into_infill) // In this case we must check that the original extruder is used on this layer before the one we are overridding // (and the perimeters will be finished before the infill is printed): if (!lt.is_extruder_order(region.config().perimeter_extruder - 1, new_extruder)) @@ -512,7 +512,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int } // Now the same for perimeters - see comments above for explanation: - if (object->config().wipe_into_objects && (print.config().infill_first ? perimeters_done : !perimeters_done)) + if (object->config().wipe_into_objects && (region.config().infill_first ? perimeters_done : !perimeters_done)) { for (const ExtrusionEntity* ee : this_layer->regions()[region_id]->perimeters.entities) { auto* fill = dynamic_cast(ee); @@ -572,12 +572,12 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print) // printed before its perimeter, or not be printed at all (in case its original extruder has // not been added to LayerTools // Either way, we will now force-override it with something suitable: - if (print.config().infill_first + if (region.config().infill_first || object->config().wipe_into_objects // in this case the perimeter is overridden, so we can override by the last one safely || lt.is_extruder_order(region.config().perimeter_extruder - 1, last_nonsoluble_extruder // !infill_first, but perimeter is already printed when last extruder prints || std::find(lt.extruders.begin(), lt.extruders.end(), region.config().infill_extruder - 1) == lt.extruders.end()) // we have to force override - this could violate infill_first (FIXME) ) - set_extruder_override(fill, copy, (print.config().infill_first ? first_nonsoluble_extruder : last_nonsoluble_extruder), num_of_copies); + set_extruder_override(fill, copy, (region.config().infill_first ? first_nonsoluble_extruder : last_nonsoluble_extruder), num_of_copies); else { // In this case we can (and should) leave it to be printed normally. // Force overriding would mean it gets printed before its perimeter. @@ -591,7 +591,7 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print) || is_entity_overridden(fill, copy) ) continue; - set_extruder_override(fill, copy, (print.config().infill_first ? last_nonsoluble_extruder : first_nonsoluble_extruder), num_of_copies); + set_extruder_override(fill, copy, (region.config().infill_first ? last_nonsoluble_extruder : first_nonsoluble_extruder), num_of_copies); } } } diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp index 78897a2db..0f75cd39a 100644 --- a/src/libslic3r/Layer.hpp +++ b/src/libslic3r/Layer.hpp @@ -35,6 +35,8 @@ public: // Unspecified fill polygons, used for overhang detection ("ensure vertical wall thickness feature") // and for re-starting of infills. ExPolygons fill_expolygons; + // Unspecified fill polygons, used for interecting when we don't want the infill/perimeter overlap + ExPolygons fill_no_overlap_expolygons; // collection of surfaces for infill generation SurfaceCollection fill_surfaces; @@ -110,8 +112,8 @@ public: ExPolygonCollection slices; size_t region_count() const { return m_regions.size(); } - const LayerRegion* get_region(int idx) const { return m_regions.at(idx); } - LayerRegion* get_region(int idx) { return m_regions[idx]; } + const LayerRegion* get_region(size_t idx) const { return m_regions.at(idx); } + LayerRegion* get_region(size_t idx) { return m_regions[idx]; } LayerRegion* add_region(PrintRegion* print_region); const LayerRegionPtrs& regions() const { return m_regions; } // Test whether whether there are any slices assigned to this layer. diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index 59a29d4d5..7eaae5348 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -93,15 +93,15 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec void LayerRegion::process_external_surfaces(const Layer* lower_layer) { const Surfaces &surfaces = this->fill_surfaces.surfaces; - const bool has_infill = this->region()->config.fill_density.value > 0.; - coord_t margin = scale_(this->region()->config.external_infill_margin.getFloat()); - coord_t margin_bridged = scale_(this->region()->config.bridged_infill_margin.getFloat()); + const bool has_infill = this->region()->config().fill_density.value > 0.; + coord_t margin = scale_(this->region()->config().external_infill_margin.getFloat()); + coord_t margin_bridged = scale_(this->region()->config().bridged_infill_margin.getFloat()); //if no infill, reduce the margin for averythign to only the perimeter if (!has_infill) { - if ((this->region()->config.perimeters.value > 0)) { - const coord_t perimeter_width = scale_(this->region()->config.perimeter_extrusion_width.get_abs_value(this->layer()->object()->config.layer_height.value)); - const coord_t first_perimeter_width = scale_(this->region()->config.external_perimeter_extrusion_width.get_abs_value(this->layer()->object()->config.layer_height.value)); - margin = first_perimeter_width + perimeter_width * (this->region()->config.perimeters.value - 1); + if ((this->region()->config().perimeters > 0)) { + const coord_t perimeter_width = scale_(this->region()->config().perimeter_extrusion_width.get_abs_value(this->layer()->object()->config().layer_height.value)); + const coord_t first_perimeter_width = scale_(this->region()->config().external_perimeter_extrusion_width.get_abs_value(this->layer()->object()->config().layer_height.value)); + margin = first_perimeter_width + perimeter_width * (this->region()->config().perimeters.value - 1); } else margin = 0; margin_bridged = margin; } diff --git a/src/libslic3r/Line.cpp b/src/libslic3r/Line.cpp index 02f1cb7c2..c66a8885d 100644 --- a/src/libslic3r/Line.cpp +++ b/src/libslic3r/Line.cpp @@ -115,4 +115,15 @@ Vec3d Linef3::intersect_plane(double z) const return Vec3d(this->a(0) + v(0) * t, this->a(1) + v(1) * t, z); } +Point Line::point_at(double distance) const { + Point point; + double len = this->length(); + point = this->a; + if (this->a.x() != this->b.x()) + point.x() = this->a.x() + (this->b.x() - this->a.x()) * distance / len; + if (this->a.y() != this->b.y()) + point.y() = this->a.y() + (this->b.y() - this->a.y()) * distance / len; + return point; +} + } diff --git a/src/libslic3r/Line.hpp b/src/libslic3r/Line.hpp index 559ca946a..a1f42d111 100644 --- a/src/libslic3r/Line.hpp +++ b/src/libslic3r/Line.hpp @@ -46,6 +46,10 @@ public: static double distance_to_squared(const Point &point, const Point &a, const Point &b); static double distance_to(const Point &point, const Point &a, const Point &b) { return sqrt(distance_to_squared(point, a, b)); } + Point point_at(double distance) const; + coord_t Line::dot(Line &l2) const { return vector().dot(l2.vector()); } + void extend_end(double distance) { Line line = *this; line.reverse(); this->b = line.point_at(-distance); } + void extend_start(double distance) { this->a = this->point_at(-distance); } Point a; Point b; diff --git a/src/libslic3r/MedialAxis.cpp b/src/libslic3r/MedialAxis.cpp index 18242b8ab..ebffc871e 100644 --- a/src/libslic3r/MedialAxis.cpp +++ b/src/libslic3r/MedialAxis.cpp @@ -344,10 +344,10 @@ add_point_same_percent(ThickPolyline* pattern, ThickPolyline* to_modify) coordf_t new_width = to_modify->width[idx_other - 1] * (1 - percent_dist); new_width += to_modify->width[idx_other] * (percent_dist); Point new_point; - new_point.x = (coord_t)((double)(to_modify->points[idx_other - 1].x) * (1 - percent_dist)); - new_point.x += (coord_t)((double)(to_modify->points[idx_other].x) * (percent_dist)); - new_point.y = (coord_t)((double)(to_modify->points[idx_other - 1].y) * (1 - percent_dist)); - new_point.y += (coord_t)((double)(to_modify->points[idx_other].y) * (percent_dist)); + new_point.x() = (coord_t)((double)(to_modify->points[idx_other - 1].x()) * (1 - percent_dist)); + new_point.x() += (coord_t)((double)(to_modify->points[idx_other].x()) * (percent_dist)); + new_point.y() = (coord_t)((double)(to_modify->points[idx_other - 1].y()) * (1 - percent_dist)); + new_point.y() += (coord_t)((double)(to_modify->points[idx_other].y()) * (percent_dist)); to_modify->width.insert(to_modify->width.begin() + idx_other, new_width); to_modify->points.insert(to_modify->points.begin() + idx_other, new_point); } @@ -425,9 +425,11 @@ get_coeff_from_angle_countour(Point &point, const ExPolygon &contour, coord_t mi double dot(Line l1, Line l2) { - Vectorf v_1 = normalize(Vectorf(l1.b.x - l1.a.x, l1.b.y - l1.a.y)); - Vectorf v_2 = normalize(Vectorf(l2.b.x - l2.a.x, l2.b.y - l2.a.y)); - return v_1.x*v_2.x + v_1.y*v_2.y; + Vec2d v_1(l1.b.x() - l1.a.x(), l1.b.y() - l1.a.y()); + v_1.normalize(); + Vec2d v_2(l2.b.x() - l2.a.x(), l2.b.y() - l2.a.y()); + v_2.normalize(); + return v_1.x()*v_2.x() + v_1.y()*v_2.y(); } void @@ -503,19 +505,19 @@ MedialAxis::fusion_curve(ThickPolylines &pp) //length_pull *= 0.144 * get_coeff_from_angle_countour(polyline.points.back(), this->expolygon, min(min_width, polyline.length() / 2)); ////compute dir - //Vectorf pull_direction(polyline.points[1].x - polyline.points[0].x, polyline.points[1].y - polyline.points[0].y); + //Vectorf pull_direction(polyline.points[1].x() - polyline.points[0].x(), polyline.points[1].y() - polyline.points[0].y()); //pull_direction = normalize(pull_direction); - //pull_direction.x *= length_pull; - //pull_direction.y *= length_pull; + //pull_direction.x() *= length_pull; + //pull_direction.y() *= length_pull; ////pull the points //Point &p1 = pp[crosspoint[0]].points[0]; - //p1.x = p1.x + (coord_t)pull_direction.x; - //p1.y = p1.y + (coord_t)pull_direction.y; + //p1.x() = p1.x() + (coord_t)pull_direction.x(); + //p1.y() = p1.y() + (coord_t)pull_direction.y(); //Point &p2 = pp[crosspoint[1]].points[0]; - //p2.x = p2.x + (coord_t)pull_direction.x; - //p2.y = p2.y + (coord_t)pull_direction.y; + //p2.x() = p2.x() + (coord_t)pull_direction.x(); + //p2.y() = p2.y() + (coord_t)pull_direction.y(); //delete the now unused polyline pp.erase(pp.begin() + i); @@ -579,19 +581,19 @@ MedialAxis::fusion_corners(ThickPolylines &pp) length_pull *= 0.144 * get_coeff_from_angle_countour(polyline.points.back(), this->expolygon, min(min_width, polyline.length() / 2)); //compute dir - Vectorf pull_direction(polyline.points[1].x - polyline.points[0].x, polyline.points[1].y - polyline.points[0].y); - pull_direction = normalize(pull_direction); - pull_direction.x *= length_pull; - pull_direction.y *= length_pull; + Vec2d pull_direction(polyline.points[1].x() - polyline.points[0].x(), polyline.points[1].y() - polyline.points[0].y()); + pull_direction.normalize(); + pull_direction.x() *= length_pull; + pull_direction.y() *= length_pull; //pull the points Point &p1 = pp[crosspoint[0]].points[0]; - p1.x = p1.x + pull_direction.x; - p1.y = p1.y + pull_direction.y; + p1.x() = p1.x() + pull_direction.x(); + p1.y() = p1.y() + pull_direction.y(); Point &p2 = pp[crosspoint[1]].points[0]; - p2.x = p2.x + pull_direction.x; - p2.y = p2.y + pull_direction.y; + p2.x() = p2.x() + pull_direction.x(); + p2.y() = p2.y() + pull_direction.y(); //delete the now unused polyline pp.erase(pp.begin() + i); @@ -711,10 +713,10 @@ MedialAxis::extends_line(ThickPolyline& polyline, const ExPolygons& anchors, con best_anchor = p_maybe_inside; } } - if (best_anchor.x != 0 && best_anchor.y != 0) { + if (best_anchor.x() != 0 && best_anchor.y() != 0) { Point p_obj = best_anchor + new_bound; - p_obj.x /= 2; - p_obj.y /= 2; + p_obj.x() /= 2; + p_obj.y() /= 2; Line l2 = Line(new_back, p_obj); l2.extend_end(max_width); (void)bounds.contour.first_intersection(l2, &new_bound); @@ -937,8 +939,8 @@ MedialAxis::main_fusion(ThickPolylines& pp) size_t idx_point = 1; while (idx_point < min(polyline.points.size(), best_candidate->points.size())) { //fusion - polyline.points[idx_point].x = polyline.points[idx_point].x * coeff_poly + best_candidate->points[idx_point].x * coeff_candi; - polyline.points[idx_point].y = polyline.points[idx_point].y * coeff_poly + best_candidate->points[idx_point].y * coeff_candi; + polyline.points[idx_point].x() = polyline.points[idx_point].x() * coeff_poly + best_candidate->points[idx_point].x() * coeff_candi; + polyline.points[idx_point].y() = polyline.points[idx_point].y() * coeff_poly + best_candidate->points[idx_point].y() * coeff_candi; // The width decrease with distance from the centerline. // This formula is what works the best, even if it's not perfect (created empirically). 0->3% error on a gap fill on some tests. @@ -1048,10 +1050,10 @@ MedialAxis::remove_too_thin_extrusion(ThickPolylines& pp) if (polyline.points.front().distance_to(polyline.points[1]) * percent_can_keep > SCALED_RESOLUTION) { //Can split => move the first point and assign a new weight. //the update of endpoints wil be performed in concatThickPolylines - polyline.points.front().x = polyline.points.front().x + - (coord_t)((polyline.points[1].x - polyline.points.front().x) * (1 - percent_can_keep)); - polyline.points.front().y = polyline.points.front().y + - (coord_t)((polyline.points[1].y - polyline.points.front().y) * (1 - percent_can_keep)); + polyline.points.front().x() = polyline.points.front().x() + + (coord_t)((polyline.points[1].x() - polyline.points.front().x()) * (1 - percent_can_keep)); + polyline.points.front().y() = polyline.points.front().y() + + (coord_t)((polyline.points[1].y() - polyline.points.front().y()) * (1 - percent_can_keep)); polyline.width.front() = min_width; } else { /// almost 0-length, Remove @@ -1072,10 +1074,10 @@ MedialAxis::remove_too_thin_extrusion(ThickPolylines& pp) if (polyline.points.back().distance_to(polyline.points[polyline.points.size() - 2]) * percent_can_keep > SCALED_RESOLUTION) { //Can split => move the first point and assign a new weight. //the update of endpoints wil be performed in concatThickPolylines - polyline.points.back().x = polyline.points.back().x + - (coord_t)((polyline.points[polyline.points.size() - 2].x - polyline.points.back().x) * (1 - percent_can_keep)); - polyline.points.back().y = polyline.points.back().y + - (coord_t)((polyline.points[polyline.points.size() - 2].y - polyline.points.back().y) * (1 - percent_can_keep)); + polyline.points.back().x() = polyline.points.back().x() + + (coord_t)((polyline.points[polyline.points.size() - 2].x() - polyline.points.back().x()) * (1 - percent_can_keep)); + polyline.points.back().y() = polyline.points.back().y() + + (coord_t)((polyline.points[polyline.points.size() - 2].y() - polyline.points.back().y()) * (1 - percent_can_keep)); polyline.width.back() = min_width; } else { /// almost 0-length, Remove @@ -1139,11 +1141,11 @@ MedialAxis::concatenate_polylines_with_crossing(ThickPolylines& pp) continue; } - Pointf v_poly(polyline.lines().back().vector().x, polyline.lines().back().vector().y); - v_poly.scale(1 / std::sqrt(v_poly.x*v_poly.x + v_poly.y*v_poly.y)); - Pointf v_other(other.lines().front().vector().x, other.lines().front().vector().y); - v_other.scale(1 / std::sqrt(v_other.x*v_other.x + v_other.y*v_other.y)); - float other_dot = v_poly.x*v_other.x + v_poly.y*v_other.y; + Vec2d v_poly(polyline.lines().back().vector().x(), polyline.lines().back().vector().y()); + v_poly *= (1 / std::sqrt(v_poly.x()*v_poly.x() + v_poly.y()*v_poly.y())); + Vec2d v_other(other.lines().front().vector().x(), other.lines().front().vector().y()); + v_other *= (1 / std::sqrt(v_other.x()*v_other.x() + v_other.y()*v_other.y())); + float other_dot = v_poly.x()*v_other.x() + v_poly.y()*v_other.y(); if (other_dot > best_dot) { best_candidate = &other; best_idx = j; @@ -1306,8 +1308,8 @@ MedialAxis::simplify_polygon_frontier() const Point* closest = bounds.contour.closest_point(p_check); if (closest != nullptr && closest->distance_to(p_check) + SCALED_EPSILON < min(p_check.distance_to(simplified_poly.contour.points[prev_i]), p_check.distance_to(simplified_poly.contour.points[next_i])) / 2) { - p_check.x = closest->x; - p_check.y = closest->y; + p_check.x() = closest->x(); + p_check.y() = closest->y(); need_intersect = true; } else { simplified_poly.contour.points.erase(simplified_poly.contour.points.begin() + i); @@ -1553,7 +1555,7 @@ ExtrusionEntityCollection thin_variable_width(const ThickPolylines &polylines, E path.polyline.append(line.b); // Convert from spacing to extrusion width based on the extrusion model // of a square extrusion ended with semi circles. - flow.width = unscale(w) + flow.height * (1. - 0.25 * PI); + flow.width = unscaled(w) + flow.height * (1. - 0.25 * PI); #ifdef SLIC3R_DEBUG printf(" filling %f gap\n", flow.width); #endif diff --git a/src/libslic3r/MultiPoint.cpp b/src/libslic3r/MultiPoint.cpp index 6ab37c91b..7278a64f4 100644 --- a/src/libslic3r/MultiPoint.cpp +++ b/src/libslic3r/MultiPoint.cpp @@ -180,13 +180,13 @@ Point MultiPoint::point_projection(const Point &point) const { dmin = d; proj = pt1; } - Pointf v1(coordf_t(pt1.x - pt0.x), coordf_t(pt1.y - pt0.y)); + Vec2d v1(coordf_t(pt1(0) - pt0(0)), coordf_t(pt1(1) - pt0(1))); coordf_t div = dot(v1); if (div > 0.) { - Pointf v2(coordf_t(point.x - pt0.x), coordf_t(point.y - pt0.y)); + Vec2d v2(coordf_t(point(0) - pt0(0)), coordf_t(point(1) - pt0(1))); coordf_t t = dot(v1, v2) / div; if (t > 0. && t < 1.) { - Point foot(coord_t(floor(coordf_t(pt0.x) + t * v1.x + 0.5)), coord_t(floor(coordf_t(pt0.y) + t * v1.y + 0.5))); + Point foot(coord_t(floor(coordf_t(pt0(0)) + t * v1(0) + 0.5)), coord_t(floor(coordf_t(pt0(1)) + t * v1(1) + 0.5))); d = foot.distance_to(point); if (d < dmin) { dmin = d; @@ -199,8 +199,7 @@ Point MultiPoint::point_projection(const Point &point) const { return proj; } -Points -MultiPoint::_douglas_peucker(const Points &points, const double tolerance) +std::vector MultiPoint::_douglas_peucker(const std::vector& pts, const double tolerance) { std::vector result_pts; if (! pts.empty()) { diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 6947b1444..a40dafe89 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -131,7 +131,7 @@ void PerimeterGenerator::process() //it's not dangerous as it will be intersected by 'unsupported' later //FIXME: add overlap in this->fill_surfaces->append // add overlap (perimeter_spacing/4 was good in test, ie 25%) - coord_t overlap = scale_(this->config->get_abs_value("infill_overlap", unscale(perimeter_spacing))); + coord_t overlap = scale_(this->config->get_abs_value("infill_overlap", unscale(perimeter_spacing))); unsupported_filtered = intersection_ex(unsupported_filtered, offset_ex(bridgeable_simplified, overlap)); } else { unsupported_filtered.clear(); @@ -675,7 +675,7 @@ PerimeterGenerator::_get_nearest_point(const PerimeterGeneratorLoops &children, const double dist = nearest_p.distance_to(p); //Try to find a point in the far side, aligning them if (dist + dist_cut / 20 < intersect.distance || - (config->perimeter_loop_seam.value == spRear && (intersect.idx_polyline_outter <0 || p.y > intersect.outter_best.y) + (config->perimeter_loop_seam.value == spRear && (intersect.idx_polyline_outter <0 || p.y() > intersect.outter_best.y()) && dist <= max_dist && intersect.distance + dist_cut / 20)) { //ok, copy the idx intersect.distance = (coord_t)nearest_p.distance_to(p); @@ -692,7 +692,7 @@ PerimeterGenerator::_get_nearest_point(const PerimeterGeneratorLoops &children, const Point &nearest_p = *child.polygon.closest_point(p); const double dist = nearest_p.distance_to(p); if (dist + SCALED_EPSILON < intersect.distance || - (config->perimeter_loop_seam.value == spRear && (intersect.idx_polyline_outter<0 || p.y < intersect.outter_best.y) + (config->perimeter_loop_seam.value == spRear && (intersect.idx_polyline_outter<0 || p.y() < intersect.outter_best.y()) && dist <= max_dist && intersect.distance + dist_cut / 20)) { //ok, copy the idx intersect.distance = (coord_t)nearest_p.distance_to(p); @@ -1131,8 +1131,8 @@ PerimeterGenerator::_traverse_and_join_loops(const PerimeterGeneratorLoop &loop, travel_path_begin[2].extruder_id = -1; Line line(outer_start->polyline.points.back(), inner_start->polyline.points.front()); Point p_dist_cut_extrude = (line.b - line.a); - p_dist_cut_extrude.x = (coord_t)(p_dist_cut_extrude.x * ((double)max_width_extrusion) / (line.length() * 2)); - p_dist_cut_extrude.y = (coord_t)(p_dist_cut_extrude.y * ((double)max_width_extrusion) / (line.length() * 2)); + p_dist_cut_extrude.x() = (coord_t)(p_dist_cut_extrude.x() * ((double)max_width_extrusion) / (line.length() * 2)); + p_dist_cut_extrude.y() = (coord_t)(p_dist_cut_extrude.y() * ((double)max_width_extrusion) / (line.length() * 2)); //extrude a bit after the turn, to close the loop Point p_start_travel = line.a; p_start_travel += p_dist_cut_extrude; @@ -1168,8 +1168,8 @@ PerimeterGenerator::_traverse_and_join_loops(const PerimeterGeneratorLoop &loop, travel_path_end[2].extruder_id = -1; Line line(inner_end->polyline.points.back(), outer_end->polyline.points.front()); Point p_dist_cut_extrude = (line.b - line.a); - p_dist_cut_extrude.x = (coord_t)(p_dist_cut_extrude.x * ((double)max_width_extrusion) / (line.length() * 2)); - p_dist_cut_extrude.y = (coord_t)(p_dist_cut_extrude.y * ((double)max_width_extrusion) / (line.length() * 2)); + p_dist_cut_extrude.x() = (coord_t)(p_dist_cut_extrude.x() * ((double)max_width_extrusion) / (line.length() * 2)); + p_dist_cut_extrude.y() = (coord_t)(p_dist_cut_extrude.y() * ((double)max_width_extrusion) / (line.length() * 2)); //extrude a bit after the turn, to close the loop Point p_start_travel_2 = line.a; p_start_travel_2 += p_dist_cut_extrude; diff --git a/src/libslic3r/Point.cpp b/src/libslic3r/Point.cpp index c2417d0dc..0e0b6e0ad 100644 --- a/src/libslic3r/Point.cpp +++ b/src/libslic3r/Point.cpp @@ -100,6 +100,29 @@ int Point::nearest_point_index(const PointConstPtrs &points) const return idx; } +/* distance to the closest point of line */ +double +Point::distance_to(const Line &line) const { + const double dx = line.b.x() - line.a.x(); + const double dy = line.b.y() - line.a.y(); + + const double l2 = dx*dx + dy*dy; // avoid a sqrt + if (l2 == 0.0) return this->distance_to(line.a); // line.a == line.b case + + // Consider the line extending the segment, parameterized as line.a + t (line.b - line.a). + // We find projection of this point onto the line. + // It falls where t = [(this-line.a) . (line.b-line.a)] / |line.b-line.a|^2 + const double t = ((this->x() - line.a.x()) * dx + (this->y() - line.a.y()) * dy) / l2; + if (t < 0.0) return this->distance_to(line.a); // beyond the 'a' end of the segment + else if (t > 1.0) return this->distance_to(line.b); // beyond the 'b' end of the segment + Point projection( + line.a.x() + t * dx, + line.a.y() + t * dy + ); + return this->distance_to(projection); +} + + int Point::nearest_point_index(const PointPtrs &points) const { PointConstPtrs p; diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index d92667362..4c6de13f1 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -51,6 +51,9 @@ inline coord_t cross2(const Vec2crd &v1, const Vec2crd &v2) { return v1(0) * v2( inline float cross2(const Vec2f &v1, const Vec2f &v2) { return v1(0) * v2(1) - v1(1) * v2(0); } inline double cross2(const Vec2d &v1, const Vec2d &v2) { return v1(0) * v2(1) - v1(1) * v2(0); } +inline coordf_t dot(const Vec2d &v1, const Vec2d &v2) { return v1.x() * v2.x() + v1.y() * v2.y(); } +inline coordf_t dot(const Vec2d &v) { return v.x() * v.x() + v.y() * v.y(); } + inline Vec2crd to_2d(const Vec3crd &pt3) { return Vec2crd(pt3(0), pt3(1)); } inline Vec2i64 to_2d(const Vec3i64 &pt3) { return Vec2i64(pt3(0), pt3(1)); } inline Vec2f to_2d(const Vec3f &pt3) { return Vec2f (pt3(0), pt3(1)); } @@ -118,6 +121,13 @@ public: double ccw_angle(const Point &p1, const Point &p2) const; Point projection_onto(const MultiPoint &poly) const; Point projection_onto(const Line &line) const; + + double distance_to(const Point &point) const { return (point - *this).cast().norm(); } + double distance_to(const Line &line) const; + bool coincides_with(const Point &point) const { return this->x() == point.x() && this->y() == point.y(); } + bool coincides_with_epsilon(const Point &point) const { + return std::abs(this->x() - point.x()) < SCALED_EPSILON && std::abs(this->y() - point.y()) < SCALED_EPSILON; + } }; namespace int128 { diff --git a/src/libslic3r/Polyline.hpp b/src/libslic3r/Polyline.hpp index e3ebc5ee6..1886d565c 100644 --- a/src/libslic3r/Polyline.hpp +++ b/src/libslic3r/Polyline.hpp @@ -26,7 +26,7 @@ public: Polyline& operator=(const Polyline &other) { points = other.points; return *this; } Polyline& operator=(Polyline &&other) { points = std::move(other.points); return *this; } static Polyline new_scale(const std::vector &points) { - Polyline pl; + Polyline pl; pl.points.reserve(points.size()); for (const Vec2d &pt : points) pl.points.emplace_back(Point::new_scale(pt(0), pt(1))); @@ -138,6 +138,11 @@ bool remove_degenerate(Polylines &polylines); /// join something or is a dead-end. class ThickPolyline : public Polyline { public: + /// width size must be == point size + std::vector width; + /// if true => it's an endpoint, if false it join an other ThickPolyline. first is at front(), second is at back() + std::pair endpoints; + ThickPolyline() : endpoints(std::make_pair(false, false)) {} ThickLines thicklines() const; void reverse() { @@ -145,14 +150,6 @@ public: std::reverse(this->width.begin(), this->width.end()); std::swap(this->endpoints.first, this->endpoints.second); } - - /// width size must be == point size - std::vector width; - /// if true => it's an endpoint, if false it join an other ThickPolyline. first is at front(), second is at back() - std::pair endpoints; - ThickPolyline() : endpoints(std::make_pair(false, false)) {}; - ThickLines thicklines() const; - void reverse(); }; /// concatenate poylines if possible and refresh the endpoints diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 1b79ef295..62c42237c 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -179,6 +179,7 @@ private: void generate_support_material(); void _slice(); + void _offsetHoles(float hole_delta, LayerRegion *layerm); std::string _fix_slicing_errors(); void _simplify_slices(double distance); void _make_perimeters(); @@ -187,7 +188,9 @@ private: void process_external_surfaces(); void discover_vertical_shells(); void bridge_over_infill(); + void replaceSurfaceType(SurfaceType st_to_replace, SurfaceType st_replacement, SurfaceType st_under_it); void clip_fill_surfaces(); + void count_distance_solid(); void discover_horizontal_shells(); void combine_infill(); void _generate_support_material(); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 4d3f6af6a..92074901a 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -84,12 +84,9 @@ void PrintConfigDef::init_fff_params() "are very confident on your model, or you want to print an item with a geometry " "designed for vase mode."); def->cli = "remove-small-gaps!"; + def->mode = comAdvanced; def->default_value = new ConfigOptionBool(true); - def = this->add("bed_shape", coPoints); - def->label = L("Bed shape"); - def->default_value = new ConfigOptionPoints { Pointf(0,0), Pointf(200,0), Pointf(200,200), Pointf(0,200) }; - def = this->add("bed_temperature", coInts); def->label = L("Other layers"); def->tooltip = L("Bed temperature for layers after the first one. " @@ -170,6 +167,7 @@ void PrintConfigDef::init_fff_params() def->cli = "top-fan-speed=i@"; def->min = 0; def->max = 100; + def->mode = comAdvanced; def->default_value = new ConfigOptionInts{ 100 }; def = this->add("bridge_flow_ratio", coFloat); @@ -191,9 +189,10 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("This factor affects the amount of plastic to overextrude " "when we are filling on top of a bridge surface." "With a number >1, we can retreive the correct z-height " - "even if the bridged layer has fallen a bit."); + "even if the bridged layer has fallen a bit."); def->cli = "over-bridge-flow-ratio=f"; def->min = 0; + def->mode = comAdvanced; def->default_value = new ConfigOptionFloat(1); def = this->add("bridge_speed", coFloat); @@ -439,6 +438,7 @@ void PrintConfigDef::init_fff_params() def->enum_labels.push_back(L("Hilbert Curve")); def->enum_labels.push_back(L("Archimedean Chords")); def->enum_labels.push_back(L("Octagram Spiral")); + def->mode = comAdvanced; def->default_value = new ConfigOptionEnum(ipRectilinear); def = this->add("enforce_full_fill_volume", coBool); @@ -446,6 +446,7 @@ void PrintConfigDef::init_fff_params() def->category = L("Infill"); def->tooltip = L("Experimental option which modifies (top/bottom) fill flow to have the exact amount of plastic inside the volume to fill."); def->cli = "enforce-full-fill-volume!"; + def->mode = comExpert; def->default_value = new ConfigOptionBool(true); def = this->add("external_infill_margin", coFloat); @@ -455,6 +456,7 @@ void PrintConfigDef::init_fff_params() def->sidetext = L("mm"); def->cli = "top-layer-anchor=f"; def->min = 0; + def->mode = comExpert; def->default_value = new ConfigOptionFloat(1.5); def = this->add("bridged_infill_margin", coFloat); @@ -464,6 +466,7 @@ void PrintConfigDef::init_fff_params() def->sidetext = L("mm"); def->cli = "top-layer-anchor=f"; def->min = 0; + def->mode = comExpert; def->default_value = new ConfigOptionFloat(2); def = this->add("external_perimeter_extrusion_width", coFloatOrPercent); @@ -504,6 +507,7 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Join the perimeters to create only one continuous extrusion without any z-hop." " Long inside travel (from external to holes) are not extruded to give some space to the infill."); def->cli = "loop-perimeter!"; + def->mode = comAdvanced; def->default_value = new ConfigOptionBool(false); def = this->add("perimeter_loop_seam", coEnum); @@ -516,9 +520,10 @@ void PrintConfigDef::init_fff_params() def->enum_values.push_back("rear"); def->enum_labels.push_back(L("Nearest")); def->enum_labels.push_back(L("Rear")); + def->mode = comAdvanced; def->default_value = new ConfigOptionEnum(spRear); - def = this->add("extra_perimeters", coBool); + def = this->add("extra_perimeters", coBool);avoid def->label = L("Extra perimeters if needed"); def->category = L("Layers and Perimeters"); def->tooltip = L("Add more perimeters when needed for avoiding gaps in sloping walls. " @@ -903,7 +908,6 @@ void PrintConfigDef::init_fff_params() def->enum_values.push_back("cubic"); def->enum_values.push_back("line"); def->enum_values.push_back("concentric"); - def->enum_values.push_back("concentricgapfill"); def->enum_values.push_back("honeycomb"); def->enum_values.push_back("3dhoneycomb"); def->enum_values.push_back("gyroid"); @@ -917,7 +921,6 @@ void PrintConfigDef::init_fff_params() def->enum_labels.push_back(L("Cubic")); def->enum_labels.push_back(L("Line")); def->enum_labels.push_back(L("Concentric")); - def->enum_labels.push_back(L("Concentric (filled)")); def->enum_labels.push_back(L("Honeycomb")); def->enum_labels.push_back(L("3D Honeycomb")); def->enum_labels.push_back(L("Gyroid")); @@ -969,7 +972,7 @@ void PrintConfigDef::init_fff_params() def->cli = "first-layer-height=s"; def->ratio_over = "layer_height"; def->default_value = new ConfigOptionFloatOrPercent(0.35, false); - + def = this->add("first_layer_speed", coFloatOrPercent); def->label = L("default"); def->tooltip = L("If expressed as absolute value in mm/s, this speed will be applied to all the print moves " @@ -993,6 +996,7 @@ void PrintConfigDef::init_fff_params() def->sidetext = L("mm/s or %"); def->cli = "first-layer-infill-speed=s"; def->min = 0; + def->mode = comExpert; def->default_value = new ConfigOptionFloatOrPercent(30, false); def = this->add("first_layer_temperature", coInts); @@ -1090,6 +1094,7 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Enables the creation of a support layer under the first solid layer. This allows you to use a lower infill ratio without compromizing the top quality." " The dense infill is laid out with a 50% infill density."); def->cli = "infill-dense!"; + def->mode = comAdvanced; def->default_value = new ConfigOptionBool(false); def = this->add("infill_not_connected", coBool); @@ -1097,6 +1102,7 @@ void PrintConfigDef::init_fff_params() def->category = L("Infill"); def->tooltip = L("If checked, the infill algorithm will try to not connect the lines near the infill. Can be useful for art or with high infill/perimeter overlap."); def->cli = "infill-not-connected!"; + def->mode = comAdvanced; def->default_value = new ConfigOptionBool(false); def = this->add("infill_dense_algo", coEnum); @@ -1112,6 +1118,7 @@ void PrintConfigDef::init_fff_params() def->enum_labels.push_back(L("Automatic")); def->enum_labels.push_back(L("Automatic, only for small areas")); def->enum_labels.push_back(L("Anchored")); + def->mode = comAdvanced; def->default_value = new ConfigOptionEnum(dfaAutomatic); def = this->add("infill_extruder", coInt); @@ -1522,6 +1529,7 @@ void PrintConfigDef::init_fff_params() def->category = L("Layers and Perimeters"); def->tooltip = L("Experimental option to remove perimeters where there is nothing under it and a bridged infill should be better."); def->cli = "no-perimeter-unsupported!"; + def->mode = comExpert; def->default_value = new ConfigOptionBool(false); def = this->add("min_perimeter_unsupported", coInt); @@ -1530,6 +1538,7 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Number of permieter exluded from this option."); def->cli = "min-perimeter-unsupported=i"; def->min = 0; + def->mode = comExpert; def->default_value = new ConfigOptionInt(0); def = this->add("noperi_bridge_only", coBool); @@ -1537,6 +1546,7 @@ void PrintConfigDef::init_fff_params() def->category = L("Layers and Perimeters"); def->tooltip = L("Only remove perimeters over areas marked as 'bridge'. Can be useful to let perimeter run over overhangs, but it's not very reliable."); def->cli = "noperi-bridge-only!"; + def->mode = comExpert; def->default_value = new ConfigOptionBool(true); def = this->add("parking_pos_retraction", coFloat); @@ -1665,6 +1675,7 @@ void PrintConfigDef::init_fff_params() def->category = L("Support material"); def->tooltip = L("Use a solid layer instead of a raft for the layer that touch the build plate."); def->cli = "support-material-solid-first-layer!"; + def->mode = comAdvanced; def->default_value = new ConfigOptionBool(false); def = this->add("raft_layers", coInt); @@ -1825,6 +1836,7 @@ void PrintConfigDef::init_fff_params() def->category = L("Layers and Perimeters"); def->tooltip = L("Add a big cost to travel paths when possible (when going into a loop), so it will prefer a less optimal seam posistion if it's nearer."); def->cli = "seam-travel!"; + def->mode = comExpert; def->default_value = new ConfigOptionBool(false); #if 0 @@ -2463,7 +2475,7 @@ void PrintConfigDef::init_fff_params() def->cli = "wipe-tower-rotation-angle=f"; def->mode = comAdvanced; def->default_value = new ConfigOptionFloat(0.); - + def = this->add("wipe_into_infill", coBool); def->category = L("Extruders"); def->label = L("Wipe into this object's infill"); @@ -2509,6 +2521,7 @@ void PrintConfigDef::init_fff_params() " This might be useful for fine-tuning hole sizes."); def->sidetext = L("mm"); def->cli = "hole-size-compensation=f"; + def->mode = comExpert; def->default_value = new ConfigOptionFloat(0); def = this->add("z_offset", coFloat); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 724085d25..e5651e329 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -164,13 +164,12 @@ template<> inline const t_config_enum_values& ConfigOptionEnum::ge return keys_map; } -template<> inline t_config_enum_values& ConfigOptionEnum::get_enum_values() { - static t_config_enum_values keys_map; - if (keys_map.empty()) { - keys_map["automatic"] = dfaAutomatic; - keys_map["autosmall"] = dfaAutoNotFull; - keys_map["enlarged"] = dfaEnlarged; - } +template<> inline const t_config_enum_values& ConfigOptionEnum::get_enum_values() { + static const t_config_enum_values keys_map = { + { "automatic", dfaAutomatic }, + { "autosmall", dfaAutoNotFull }, + { "enlarged", dfaEnlarged } + }; return keys_map; } diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 9426fefd2..37781fd1a 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -695,18 +695,18 @@ void PrintObject::count_distance_solid() { // sparse area = layer's fill area - solid area const float COEFF_SPLIT = 2; const int NB_DENSE_LAYERS = 1; - for (int idx_region = 0; idx_region < this->_print->regions.size(); ++idx_region) { + for (size_t idx_region = 0; idx_region < this->m_print->regions().size(); ++idx_region) { //count how many surface there are on each one LayerRegion *previousOne = NULL; - if (this->layers.size() > 1) previousOne = this->layers[this->layers.size() - 1]->get_region(idx_region); - if (previousOne != NULL && previousOne->region()->config.infill_dense.getBool() && previousOne->region()->config.fill_density<40) { + if (this->layers().size() > 1) previousOne = this->layers()[this->layers().size() - 1]->get_region(idx_region); + if (previousOne != NULL && previousOne->region()->config().infill_dense.getBool() && previousOne->region()->config().fill_density<40) { for (Surface &surf : previousOne->fill_surfaces.surfaces) { if (surf.is_solid()) { surf.maxNbSolidLayersOnTop = 0; } } - for (int idx_layer = this->layers.size() - 2; idx_layer >= 0; --idx_layer){ - LayerRegion *layerm = this->layers[idx_layer]->get_region(idx_region); + for (size_t idx_layer = this->layers().size() - 2; idx_layer >= 0; --idx_layer){ + LayerRegion *layerm = this->layers()[idx_layer]->get_region(idx_region); Surfaces surf_to_add; for (auto it_surf = layerm->fill_surfaces.surfaces.begin(); it_surf != layerm->fill_surfaces.surfaces.end(); ++it_surf) { Surface &surf = *it_surf; @@ -721,7 +721,7 @@ void PrintObject::count_distance_solid() { // upp.expolygon.overlaps(surf.expolygon) or surf.expolygon.overlaps(upp.expolygon) ExPolygons intersect = intersection_ex(sparse_polys, offset_ex(upp.expolygon, -layerm->flow(frInfill).scaled_width()), true); if (!intersect.empty()) { - if (layerm->region()->config.infill_dense_algo == dfaEnlarged) { + if (layerm->region()->config().infill_dense_algo == dfaEnlarged) { uint16_t dist = (uint16_t)(upp.maxNbSolidLayersOnTop + 1); const int nb_dense_layers = 1; if (dist <= nb_dense_layers) { @@ -729,11 +729,11 @@ void PrintObject::count_distance_solid() { uint64_t area_intersect = 0; for (ExPolygon poly_inter : intersect) area_intersect += poly_inter.area(); //if it's in a dense area and the current surface isn't a dense one yet and the not-dense is too small. - std::cout << idx_layer << " dfaEnlarged: " << layerm->region()->config.infill_dense_algo << "\n"; - std::cout << idx_layer << " dfaEnlarged: 1-" << (layerm->region()->config.infill_dense_algo == dfaEnlarged) << "\n"; + std::cout << idx_layer << " dfaEnlarged: " << layerm->region()->config().infill_dense_algo << "\n"; + std::cout << idx_layer << " dfaEnlarged: 1-" << (layerm->region()->config().infill_dense_algo == dfaEnlarged) << "\n"; std::cout << idx_layer << " dfaEnlarged: 2-" << (surf.area() > area_intersect * COEFF_SPLIT) << "\n"; std::cout << idx_layer << " dfaEnlarged: 3-" << (surf.maxNbSolidLayersOnTop > nb_dense_layers) << "\n"; - std::cout << idx_layer << " dfaEnlarged: surf.area()=" << unscale(unscale(surf.area())) << ", area_intersect=" << unscale(unscale(area_intersect)) << "\n"; + std::cout << idx_layer << " dfaEnlarged: surf.area()=" << unscale(unscale(surf.area())) << ", area_intersect=" << unscale(unscale(area_intersect)) << "\n"; std::cout << idx_layer << " dfaEnlarged: surf.maxNbSolidLayersOnTop=" << surf.maxNbSolidLayersOnTop << ", NB_DENSE_LAYERS=" << NB_DENSE_LAYERS << "\n"; if ((surf.area() > area_intersect * COEFF_SPLIT) && surf.maxNbSolidLayersOnTop > nb_dense_layers) { @@ -742,8 +742,7 @@ void PrintObject::count_distance_solid() { if (dist == 1) { //if just under the solid area, we can expand a bit //remove too small sections and grew a bit to anchor it into the part - intersect = offset_ex(intersect, - layerm->flow(frInfill).scaled_width() + scale_(layerm->region()->config.bridged_infill_margin)); + intersect = offset_ex(intersect, layerm->flow(frInfill).scaled_width() + scale_(layerm->region()->config().bridged_infill_margin)); } else { //just remove too small sections intersect = offset_ex(intersect, @@ -767,7 +766,7 @@ void PrintObject::count_distance_solid() { } else { surf.maxNbSolidLayersOnTop = std::min(surf.maxNbSolidLayersOnTop, dist); } - } else if (layerm->region()->config.infill_dense_algo == dfaAutoNotFull || layerm->region()->config.infill_dense_algo == dfaAutomatic) { + } else if (layerm->region()->config().infill_dense_algo == dfaAutoNotFull || layerm->region()->config().infill_dense_algo == dfaAutomatic) { double area_intersect = 0; for (ExPolygon poly_inter : intersect) area_intersect += poly_inter.area(); //like intersect.empty() but more resilient @@ -776,7 +775,7 @@ void PrintObject::count_distance_solid() { if (dist <= NB_DENSE_LAYERS) { // it will be a dense infill, split the surface if needed //if the not-dense is too big to do a full dense and the current surface isn't a dense one yet. - if ((layerm->region()->config.infill_dense_algo == dfaAutomatic || surf.area() > area_intersect * COEFF_SPLIT) && + if ((layerm->region()->config().infill_dense_algo == dfaAutomatic || surf.area() > area_intersect * COEFF_SPLIT) && surf.maxNbSolidLayersOnTop > NB_DENSE_LAYERS) { //split in two if (dist == 1) { @@ -792,7 +791,7 @@ void PrintObject::count_distance_solid() { } intersect = offset_ex(cover_intersect, layerm->flow(frInfill).scaled_width());// +scale_(expandby)); - //layerm->region()->config.external_infill_margin)); + //layerm->region()->config().external_infill_margin)); } else { //just remove too small sections intersect = offset_ex(intersect, @@ -818,10 +817,10 @@ void PrintObject::count_distance_solid() { surf.maxNbSolidLayersOnTop = std::min(surf.maxNbSolidLayersOnTop, dist); } } - } else if (layerm->region()->config.infill_dense_algo == dfaAutomatic) { + } else if (layerm->region()->config().infill_dense_algo == dfaAutomatic) { double area_intersect = 0; for (ExPolygon poly_inter : intersect) area_intersect += poly_inter.area(); - std::cout << idx_layer << " dfaAutomatic: area_intersect=" << unscale(unscale(area_intersect)) << "\n"; + std::cout << idx_layer << " dfaAutomatic: area_intersect=" << unscale(unscale(area_intersect)) << "\n"; //like intersect.empty() but more resilient if (area_intersect > layerm->flow(frInfill).scaled_width() * layerm->flow(frInfill).scaled_width() * 2) { std::cout << idx_layer << " dfaAutomatic: ok\n"; @@ -847,7 +846,7 @@ void PrintObject::count_distance_solid() { } intersect = offset_ex(cover_intersect, layerm->flow(frInfill).scaled_width());// +scale_(expandby)); - //layerm->region()->config.external_infill_margin)); + //layerm->region()->config().external_infill_margin)); } else { std::cout << "dfaAutomatic: remove too small sections\n"; //just remove too small sections @@ -978,7 +977,7 @@ void PrintObject::detect_surfaces_type() // unless internal shells are requested Layer *upper_layer = (idx_layer + 1 < this->layer_count()) ? m_layers[idx_layer + 1] : nullptr; Layer *lower_layer = (idx_layer > 0) ? m_layers[idx_layer - 1] : nullptr; - Layer *under_lower_layer = (idx_layer > 1) ? this->layers[idx_layer - 2] : nullptr; + Layer *under_lower_layer = (idx_layer > 1) ? this->layers()[idx_layer - 2] : nullptr; // collapse very narrow parts (using the safety offset in the diff is not enough) float offset = layerm->flow(frExternalPerimeter).scaled_width() / 10.f; @@ -1672,15 +1671,16 @@ void PrintObject::replaceSurfaceType(SurfaceType st_to_replace, SurfaceType st_r { BOOST_LOG_TRIVIAL(info) << "overextrude over Bridge..."; - FOREACH_REGION(this->_print, region) { - size_t region_id = region - this->_print->regions.begin(); - - FOREACH_LAYER(this, layer_it) { + for (size_t region_id = 0; region_id < this->region_volumes.size(); ++region_id) { + const PrintRegion ®ion = *m_print->regions()[region_id]; + + for (LayerPtrs::iterator layer_it = m_layers.begin(); layer_it != m_layers.end(); ++layer_it) { + // skip first layer - if (layer_it == this->layers.begin()) continue; + if (layer_it == this->layers().begin()) continue; Layer* layer = *layer_it; - LayerRegion* layerm = layer->regions[region_id]; + LayerRegion* layerm = layer->regions()[region_id]; // extract the stInternalSolid surfaces that might be transformed into bridges Polygons internal_solid; @@ -1717,24 +1717,25 @@ void PrintObject::replaceSurfaceType(SurfaceType st_to_replace, SurfaceType st_r Polygons to_overextrude_pp = internal_solid; // get previous layer - if (int(layer_it - this->layers.begin()) - 1 >= 0) { - const Layer* lower_layer = this->layers[int(layer_it - this->layers.begin()) - 1]; + if (int(layer_it - this->layers().begin()) - 1 >= 0) { + const Layer* lower_layer = this->layers()[int(layer_it - this->layers().begin()) - 1]; // iterate through regions and collect internal surfaces Polygons lower_internal; - FOREACH_LAYERREGION(lower_layer, lower_layerm_it){ + for (LayerRegion *lower_layerm : lower_layer->m_regions) { + lower_layerm->fill_surfaces.filter_by_type(stInternal, &lower_internal); Polygons lower_internal_OK; Polygons lower_internal_Bridge; Polygons lower_internal_Over; - (*lower_layerm_it)->fill_surfaces.filter_by_type(st_replacement, &lower_internal_OK); - (*lower_layerm_it)->fill_surfaces.filter_by_type(st_under_it, &lower_internal_Bridge); - (*lower_layerm_it)->fill_surfaces.filter_by_type(st_to_replace, &lower_internal_Over); + lower_layerm->fill_surfaces.filter_by_type(st_replacement, &lower_internal_OK); + lower_layerm->fill_surfaces.filter_by_type(st_under_it, &lower_internal_Bridge); + lower_layerm->fill_surfaces.filter_by_type(st_to_replace, &lower_internal_Over); double okarea =0, bridgearea=0, overarea=0; for (ExPolygon &ex : union_ex(lower_internal_OK)) okarea+=ex.area(); for (ExPolygon &ex : union_ex(lower_internal_Bridge)) bridgearea+=ex.area(); for (ExPolygon &ex : union_ex(lower_internal_Over)) overarea+=ex.area(); - (*lower_layerm_it)->fill_surfaces.filter_by_type(st_under_it, &lower_internal); + lower_layerm->fill_surfaces.filter_by_type(st_under_it, &lower_internal); } double sumarea=0; for (ExPolygon &ex : union_ex(lower_internal)) sumarea+=ex.area(); @@ -1990,7 +1991,7 @@ end: Layer *layer = m_layers[layer_id]; // Apply size compensation and perform clipping of multi-part objects. float delta = float(scale_(m_config.xy_size_compensation.value)); - float hole_delta = float(scale_(this->config.hole_size_compensation.value)); + float hole_delta = float(scale_(this->config().hole_size_compensation.value)); if (layer_id == 0) delta -= float(scale_(m_config.elefant_foot_compensation.value)); bool scale = delta != 0.f; @@ -2001,7 +2002,7 @@ end: LayerRegion *layerm = layer->m_regions.front(); layerm->slices.set(offset_ex(to_expolygons(std::move(layerm->slices.surfaces)), delta), stInternal); } - _offsetHoles(hole_delta, layer->regions.front()); + _offsetHoles(hole_delta, layer->regions().front()); } else if (scale || clip || hole_delta != 0.f) { // Multiple regions, growing, shrinking or just clipping one region by the other. // When clipping the regions, priority is given to the first regions. diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index b4d0baf79..507d6f813 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -1197,6 +1197,7 @@ static inline void remove_tangent_edges(std::vector &lines) if (l1.edge_type == l2.edge_type) { l1.set_skip(); break; + } } else { assert(l1.a_id == l2.b_id && l1.b_id == l2.a_id); // If this edge joins two horizontal facets, remove both of them. @@ -1212,21 +1213,24 @@ static inline void remove_tangent_edges(std::vector &lines) } - struct OpenPolyline { - OpenPolyline() {}; - OpenPolyline(const IntersectionReference &start, const IntersectionReference &end, Points &&points) : - start(start), end(end), points(std::move(points)), consumed(false) {} - void reverse() { - std::swap(start, end); - std::reverse(points.begin(), points.end()); - } - std::sort(out.begin(), out.end(), [](const OpenPolyline *lhs, const OpenPolyline *rhs){ return lhs->length > rhs->length; }); - return out; -} +struct OpenPolyline { + OpenPolyline() {}; + OpenPolyline(const IntersectionReference &start, const IntersectionReference &end, Points &&points) : + start(start), end(end), points(std::move(points)), consumed(false) { this->length = Slic3r::length(this->points); } + void reverse() { + std::swap(start, end); + std::reverse(points.begin(), points.end()); + } + IntersectionReference start; + IntersectionReference end; + Points points; + double length; + bool consumed; +}; -// called by TriangleMeshSlicer::make_loops() to connect remaining open polylines across shared triangle edges and vertices. -// Depending on "try_connect_reversed", it may or may not connect segments crossing triangles of opposite orientation. -static void chain_open_polylines_exact(std::vector &open_polylines, Polygons &loops, bool try_connect_reversed) +// called by TriangleMeshSlicer::make_loops() to connect sliced triangles into closed loops and open polylines by the triangle connectivity. +// Only connects segments crossing triangles of the same orientation. +static void chain_lines_by_triangle_connectivity(std::vector &lines, Polygons &loops, std::vector &open_polylines) { // Build a map of lines by edge_a_id and a_id. std::vector by_edge_a_id; @@ -1256,13 +1260,20 @@ static void chain_open_polylines_exact(std::vector &open_polylines first_line = &(*it_line_seed ++); break; } - } - auto by_edge_lower = [](const IntersectionLine* il1, const IntersectionLine *il2) { return il1->edge_a_id < il2->edge_a_id; }; - auto by_vertex_lower = [](const IntersectionLine* il1, const IntersectionLine *il2) { return il1->a_id < il2->a_id; }; - std::sort(by_edge_a_id.begin(), by_edge_a_id.end(), by_edge_lower); - std::sort(by_a_id.begin(), by_a_id.end(), by_vertex_lower); - // Chain the segments with a greedy algorithm, collect the loops and unclosed polylines. - IntersectionLines::iterator it_line_seed = lines.begin(); + if (first_line == nullptr) + break; + first_line->set_skip(); + Points loop_pts; + loop_pts.emplace_back(first_line->a); + IntersectionLine *last_line = first_line; + + /* + printf("first_line edge_a_id = %d, edge_b_id = %d, a_id = %d, b_id = %d, a = %d,%d, b = %d,%d\n", + first_line->edge_a_id, first_line->edge_b_id, first_line->a_id, first_line->b_id, + first_line->a.x, first_line->a.y, first_line->b.x, first_line->b.y); + */ + + IntersectionLine key; for (;;) { // find a line starting where last one finishes IntersectionLine* next_line = nullptr; @@ -1308,37 +1319,121 @@ static void chain_open_polylines_exact(std::vector &open_polylines } break; } - // Continue with the current loop. + /* + printf("next_line edge_a_id = %d, edge_b_id = %d, a_id = %d, b_id = %d, a = %d,%d, b = %d,%d\n", + next_line->edge_a_id, next_line->edge_b_id, next_line->a_id, next_line->b_id, + next_line->a.x, next_line->a.y, next_line->b.x, next_line->b.y); + */ + loop_pts.emplace_back(next_line->a); + last_line = next_line; + next_line->set_skip(); } } } -// called by TriangleMeshSlicer::make_loops() to connect remaining open polylines across shared triangle edges and vertices, -// possibly closing small gaps. -// Depending on "try_connect_reversed", it may or may not connect segments crossing triangles of opposite orientation. -static void chain_open_polylines_close_gaps(std::vector &open_polylines, Polygons &loops, double max_gap, bool try_connect_reversed) +std::vector open_polylines_sorted(std::vector &open_polylines, bool update_lengths) { - const coord_t max_gap_scaled = (coord_t)scale_(max_gap); + std::vector out; + out.reserve(open_polylines.size()); + for (OpenPolyline &opl : open_polylines) + if (! opl.consumed) { + if (update_lengths) + opl.length = Slic3r::length(opl.points); + out.emplace_back(&opl); + } + std::sort(out.begin(), out.end(), [](const OpenPolyline *lhs, const OpenPolyline *rhs){ return lhs->length > rhs->length; }); + return out; +} - // Try to connect the loops. - for (OpenPolyline &opl : open_polylines) { - if (opl.consumed) - continue; - opl.consumed = true; - OpenPolylineEnd end(&opl, false); - for (;;) { - // find a line starting where last one finishes - OpenPolylineEnd* next_start = nullptr; - if (end.edge_id() != -1) { - auto it_begin = std::lower_bound(by_edge_id.begin(), by_edge_id.end(), end, by_edge_lower); - if (it_begin != by_edge_id.end()) { - auto it_end = std::upper_bound(it_begin, by_edge_id.end(), end, by_edge_lower); - for (auto it_edge = it_begin; it_edge != it_end; ++ it_edge) - if (! it_edge->polyline->consumed) { - next_start = &(*it_edge); - break; - } - } +// called by TriangleMeshSlicer::make_loops() to connect remaining open polylines across shared triangle edges and vertices. +// Depending on "try_connect_reversed", it may or may not connect segments crossing triangles of opposite orientation. +static void chain_open_polylines_exact(std::vector &open_polylines, Polygons &loops, bool try_connect_reversed) +{ + // Store the end points of open_polylines into vectors sorted + struct OpenPolylineEnd { + OpenPolylineEnd(OpenPolyline *polyline, bool start) : polyline(polyline), start(start) {} + OpenPolyline *polyline; + // Is it the start or end point? + bool start; + const IntersectionReference& ipref() const { return start ? polyline->start : polyline->end; } + // Return a unique ID for the intersection point. + // Return a positive id for a point, or a negative id for an edge. + int id() const { const IntersectionReference &r = ipref(); return (r.point_id >= 0) ? r.point_id : - r.edge_id; } + bool operator==(const OpenPolylineEnd &rhs) const { return this->polyline == rhs.polyline && this->start == rhs.start; } + }; + auto by_id_lower = [](const OpenPolylineEnd &ope1, const OpenPolylineEnd &ope2) { return ope1.id() < ope2.id(); }; + std::vector by_id; + by_id.reserve(2 * open_polylines.size()); + for (OpenPolyline &opl : open_polylines) { + if (opl.start.point_id != -1 || opl.start.edge_id != -1) + by_id.emplace_back(OpenPolylineEnd(&opl, true)); + if (try_connect_reversed && (opl.end.point_id != -1 || opl.end.edge_id != -1)) + by_id.emplace_back(OpenPolylineEnd(&opl, false)); + } + std::sort(by_id.begin(), by_id.end(), by_id_lower); + // Find an iterator to by_id_lower for the particular end of OpenPolyline (by comparing the OpenPolyline pointer and the start attribute). + auto find_polyline_end = [&by_id, by_id_lower](const OpenPolylineEnd &end) -> std::vector::iterator { + for (auto it = std::lower_bound(by_id.begin(), by_id.end(), end, by_id_lower); + it != by_id.end() && it->id() == end.id(); ++ it) + if (*it == end) + return it; + return by_id.end(); + }; + // Try to connect the loops. + std::vector sorted_by_length = open_polylines_sorted(open_polylines, false); + for (OpenPolyline *opl : sorted_by_length) { + if (opl->consumed) + continue; + opl->consumed = true; + OpenPolylineEnd end(opl, false); + for (;;) { + // find a line starting where last one finishes + auto it_next_start = std::lower_bound(by_id.begin(), by_id.end(), end, by_id_lower); + for (; it_next_start != by_id.end() && it_next_start->id() == end.id(); ++ it_next_start) + if (! it_next_start->polyline->consumed) + goto found; + // The current loop could not be closed. Unmark the segment. + opl->consumed = false; + break; + found: + // Attach this polyline to the end of the initial polyline. + if (it_next_start->start) { + auto it = it_next_start->polyline->points.begin(); + std::copy(++ it, it_next_start->polyline->points.end(), back_inserter(opl->points)); + } else { + auto it = it_next_start->polyline->points.rbegin(); + std::copy(++ it, it_next_start->polyline->points.rend(), back_inserter(opl->points)); + } + opl->length += it_next_start->polyline->length; + // Mark the next polyline as consumed. + it_next_start->polyline->points.clear(); + it_next_start->polyline->length = 0.; + it_next_start->polyline->consumed = true; + if (try_connect_reversed) { + // Running in a mode, where the polylines may be connected by mixing their orientations. + // Update the end point lookup structure after the end point of the current polyline was extended. + auto it_end = find_polyline_end(end); + auto it_next_end = find_polyline_end(OpenPolylineEnd(it_next_start->polyline, !it_next_start->start)); + // Swap the end points of the current and next polyline, but keep the polyline ptr and the start flag. + std::swap(opl->end, it_next_end->start ? it_next_end->polyline->start : it_next_end->polyline->end); + // Swap the positions of OpenPolylineEnd structures in the sorted array to match their respective end point positions. + std::swap(*it_end, *it_next_end); + } + // Check whether we closed this loop. + if ((opl->start.edge_id != -1 && opl->start.edge_id == opl->end.edge_id) || + (opl->start.point_id != -1 && opl->start.point_id == opl->end.point_id)) { + // The current loop is complete. Add it to the output. + //assert(opl->points.front().point_id == opl->points.back().point_id); + //assert(opl->points.front().edge_id == opl->points.back().edge_id); + // Remove the duplicate last point. + opl->points.pop_back(); + if (opl->points.size() >= 3) { + if (try_connect_reversed && area(opl->points) < 0) + // The closed polygon is patched from pieces with messed up orientation, therefore + // the orientation of the patched up polygon is not known. + // Orient the patched up polygons CCW. This heuristic may close some holes and cavities. + std::reverse(opl->points.begin(), opl->points.end()); + loops.emplace_back(std::move(opl->points)); } opl->points.clear(); break; @@ -1680,7 +1775,7 @@ void TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slic // 0.0499 comes from https://github.com/slic3r/Slic3r/issues/959 // double safety_offset = scale_(0.0499); // 0.0001 is set to satisfy GH #520, #1029, #1364 -// double safety_offset = scale_(0.0001); +// double safety_offset = scale_(0.0001); // now a config value /* The following line is commented out because it can generate wrong polygons, see for example issue #661 */ diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index 356256154..b6194b596 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -174,7 +174,7 @@ public: const float min_z, const float max_z, IntersectionLine *line_out) const; void cut(float z, TriangleMesh* upper, TriangleMesh* lower) const; - double safety_offset = scale_(0.0499); + double safety_offset = scale_(0.02); private: const TriangleMesh *mesh; // Map from a facet to an edge index. diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h index 59d33a96d..6a4cc140a 100644 --- a/src/libslic3r/libslic3r.h +++ b/src/libslic3r/libslic3r.h @@ -80,6 +80,8 @@ namespace Slic3r { template inline T unscale(Q v) { return T(v) * T(SCALING_FACTOR); } +inline double unscaled(double v) { return v * SCALING_FACTOR; } + enum Axis { X=0, Y, Z, E, F, NUM_AXES }; template diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 011ee88d4..100e6874a 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -930,7 +930,7 @@ void TabPrint::build() optgroup = page->new_optgroup(_(L("Advanced"))); optgroup->append_single_option_line("remove_small_gaps"); - line = { _(L("Avoid unsupported perimeters")), "" }; + line = { _(L("Seam")), "" }; line.append_option(optgroup->get_option("seam_position")); line.append_option(optgroup->get_option("seam_travel")); optgroup->append_line(line);