diff --git a/resources/ui_layout/print.ui b/resources/ui_layout/print.ui index 445e921b4..820d20527 100644 --- a/resources/ui_layout/print.ui +++ b/resources/ui_layout/print.ui @@ -41,6 +41,8 @@ group:Advanced line:External Perimeter setting:external_perimeters_first setting:external_perimeters_vase + setting:external_perimeters_nothole + setting:external_perimeters_hole end_line line:Looping perimeter setting:perimeter_loop diff --git a/src/libslic3r/ExtrusionEntity.hpp b/src/libslic3r/ExtrusionEntity.hpp index ca1ccdf50..02371a549 100644 --- a/src/libslic3r/ExtrusionEntity.hpp +++ b/src/libslic3r/ExtrusionEntity.hpp @@ -39,12 +39,14 @@ enum ExtrusionRole : uint8_t { // Special flags describing loop enum ExtrusionLoopRole : uint16_t { - elrDefault=0x1, + elrDefault = 0, // doesn't contains more contour: it's the most internal one - elrInternal=0x10, - elrSkirt = 0x100, + elrInternal = 1 << 1, //2 + elrSkirt = 1 << 2, //4 //it's a modifier that indicate that the loop is around a hole, not around the infill - elrHole = 0x1000, + elrHole = 1 << 3, // 16 + //it's a modifier that indicate that the loop should be printed as vase + elrVase = 1 << 4, //32 }; @@ -448,7 +450,7 @@ public: #endif /* NDEBUG */ private: - ExtrusionLoopRole m_loop_role; + ExtrusionLoopRole m_loop_role{ elrDefault }; }; inline void extrusion_paths_append(ExtrusionPaths &dst, Polylines &polylines, ExtrusionRole role, double mm3_per_mm, float width, float height) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 5db755afa..575cb42d8 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2533,6 +2533,8 @@ std::vector polygon_angles_at_vertices(const Polygon &polygon, const std: //like extrude_loop but with varying z and two full round std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const std::string &description, double speed, std::unique_ptr *lower_layer_edge_grid) { + //don't keep the speed + speed = -1; // get a copy; don't modify the orientation of the original loop object otherwise // next copies (if any) would not detect the correct orientation ExtrusionLoop loop = original_loop; @@ -2561,6 +2563,7 @@ std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const s // extrude all loops ccw //no! this was decided in perimeter_generator bool is_hole_loop = loop.loop_role() & ExtrusionLoopRole::elrHole != 0;// loop.make_counter_clockwise(); + bool reverse_turn = loop.polygon().is_clockwise() ^ is_hole_loop; split_at_seam_pos(loop, lower_layer_edge_grid); @@ -2576,9 +2579,9 @@ std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const s loop.clip_end(clip_length, &paths); if (paths.empty()) return ""; - // apply the small perimeter speed + // apply the small/external? perimeter speed if (is_perimeter(paths.front().role()) && loop.length() <= SMALL_PERIMETER_LENGTH && speed == -1) - speed = m_config.small_perimeter_speed.get_abs_value(m_config.perimeter_speed); + speed = m_config.external_perimeter_speed.get_abs_value(m_config.perimeter_speed); //get extrusion length coordf_t length = 0; @@ -2586,7 +2589,7 @@ std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const s //path->simplify(SCALED_RESOLUTION); //not useful, this should have been done before. length += path->length() * SCALING_FACTOR; } - + //all in unscaled coordinates (hence why it's coordf_t and not coord_t) const coordf_t min_height = EXTRUDER_CONFIG(min_layer_height); const coordf_t bot_init_z = - this->m_layer->height; @@ -2594,25 +2597,77 @@ std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const s const coordf_t init_z = bot_init_z + min_height; //const coordf_t last_z = bot_init_z + this->m_layer->height; + Point inward_point; + //move the seam point inward a little bit + if (paths.back().role() == erExternalPerimeter && m_layer != NULL && m_config.perimeters.value > 1 && paths.front().size() >= 2 && paths.back().polyline.points.size() >= 3) { + // detect angle between last and first segment + // the side depends on the original winding order of the polygon (left for contours, right for holes) + //FIXME improve the algorithm in case the loop is tiny. + //FIXME improve the algorithm in case the loop is split into segments with a low number of points (see the Point b query). + Point a = paths.front().polyline.points[1]; // second point + Point b = *(paths.back().polyline.points.end() - 3); // second to last point + if (reverse_turn) { + // swap points + Point c = a; a = b; b = c; + } + + double angle = paths.front().first_point().ccw_angle(a, b)*2 / 3; + + // turn left if contour, turn right if hole + if (reverse_turn) angle *= -1; + + // create the destination point along the first segment and rotate it + // we make sure we don't exceed the segment length because we don't know + // the rotation of the second segment so we might cross the object boundary + Vec2d p1 = paths.front().polyline.points.front().cast(); + Vec2d p2 = paths.front().polyline.points[1].cast(); + Vec2d v = p2 - p1; + double nd = scale_(EXTRUDER_CONFIG(nozzle_diameter)); + double l2 = v.squaredNorm(); + // Shift by no more than a nozzle diameter. + //FIXME Hiding the seams will not work nicely for very densely discretized contours! + inward_point = ((nd * nd >= l2) ? p2 : (p1 + v * (nd / sqrt(l2)))).cast(); + inward_point.rotate(angle, paths.front().polyline.points.front()); + } + coordf_t current_pos_in_length = 0; - coordf_t current_z = init_z; + coordf_t current_z = 0; // over init_z coordf_t current_height = min_height; + coordf_t starting_height = min_height; enum Step { INCR = 0, FLAT = 1 }; std::string gcode; for (int step = 0; step < 2; step++) { + current_pos_in_length = 0; + current_z = 0; const coordf_t z_per_length = (step == Step::INCR) ? ((this->m_layer->height - (min_height + min_height)) / length) : 0; const coordf_t height_per_length = (step == Step::INCR) ? ((this->m_layer->height- (min_height + min_height)) / length) : ((-this->m_layer->height + (min_height + min_height)) / length); if (step == Step::FLAT) { - current_z = 0; current_height = this->m_layer->height - min_height; + starting_height = this->m_layer->height - min_height; } Vec3d previous; for (ExtrusionPaths::iterator path = paths.begin(); path != paths.end(); ++path) { - + if (path == paths.begin() ){ + if (step == Step::INCR) { + if (paths.back().role() == erExternalPerimeter && m_layer != NULL && m_config.perimeters.value > 1 && paths.front().size() >= 2 && paths.back().polyline.points.size() >= 3) { + paths[0].polyline.points.insert(paths[0].polyline.points.begin(), inward_point); + } + this->m_writer.travel_to_z(this->m_layer->print_z + init_z); + } else { + //ensure we're at the right height + this->m_writer.travel_to_z(this->m_layer->print_z); + } + } gcode += this->_before_extrude(*path, description, speed); + if (path == paths.begin() && step == Step::INCR){ + if (paths.back().role() == erExternalPerimeter && m_layer != NULL && m_config.perimeters.value > 1 && paths.front().size() >= 2 && paths.back().polyline.points.size() >= 3) { + paths[0].polyline.points.erase(paths[0].polyline.points.begin()); + gcode += m_writer.extrude_to_xy(this->point_to_gcode(paths[0].polyline.points.front()), 0); + } + } // calculate extrusion length per distance unit double e_per_mm_per_height = m_writer.extruder()->e_per_mm3() * path->mm3_per_mm / this->m_layer->height; @@ -2636,9 +2691,10 @@ std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const s for (int i = 0; i < nb_sections - 1; i++) { Vec3d new_point = last_point + pos_increment; gcode += m_writer.extrude_to_xyz(new_point, - e_per_mm_per_height * line_length * current_height_internal, + e_per_mm_per_height * (line_length / nb_sections) * current_height_internal, description); current_height_internal += height_increment; + last_point = new_point; } //last bit will go to the exact last pos last_point.x() = this->point_to_gcode(line.b).x(); @@ -2646,14 +2702,14 @@ std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const s last_point.z() = current_z + z_per_length * line_length; gcode += m_writer.extrude_to_xyz( last_point, - e_per_mm_per_height * line_length * current_height_internal, + e_per_mm_per_height * (line_length / nb_sections) * current_height_internal, comment); previous = last_point; //update vars for next line current_pos_in_length += line_length; - current_z = last_point.z(); - current_height += height_per_length * line_length; + current_z = current_pos_in_length * z_per_length;//last_point.z(); + current_height = starting_height + current_pos_in_length * height_per_length; } } gcode += this->_after_extrude(*path); @@ -2696,7 +2752,7 @@ std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const s //FIXME improve the algorithm in case the loop is split into segments with a low number of points (see the Point b query). Point a = paths.front().polyline.points[1]; // second point Point b = *(paths.back().polyline.points.end() - 3); // second to last point - if (is_hole_loop) { + if (reverse_turn) { // swap points Point c = a; a = b; b = c; } @@ -2704,7 +2760,7 @@ std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const s double angle = paths.front().first_point().ccw_angle(a, b) / 3; // turn left if contour, turn right if hole - if (is_hole_loop) angle *= -1; + if (reverse_turn) angle *= -1; // create the destination point along the first segment and rotate it // we make sure we don't exceed the segment length because we don't know @@ -2716,10 +2772,11 @@ std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const s double l2 = v.squaredNorm(); // Shift by no more than a nozzle diameter. //FIXME Hiding the seams will not work nicely for very densely discretized contours! - Point pt = ((nd * nd >= l2) ? p2 : (p1 + v * (nd / sqrt(l2)))).cast(); - pt.rotate(angle, paths.front().polyline.points.front()); + inward_point = ((nd * nd >= l2) ? p2 : (p1 + v * (nd / sqrt(l2)))).cast(); + inward_point.rotate(angle, paths.front().polyline.points.front()); + // generate the travel move - gcode += m_writer.travel_to_xy(this->point_to_gcode(pt), "move inwards before travel"); + gcode += m_writer.travel_to_xy(this->point_to_gcode(inward_point), "move inwards before travel"); } return gcode; @@ -2895,7 +2952,7 @@ void GCode::split_at_seam_pos(ExtrusionLoop &loop, std::unique_ptrm_config.external_perimeters_vase && !this->m_config.spiral_vase + if (original_loop.role() == ExtrusionRole::erExternalPerimeter && (original_loop.loop_role() & elrVase) != 0 && !this->m_config.spiral_vase //but not for the first layer && this->m_layer->id() > 0 //exclude if min_layer_height * 2 > layer_height (increase from 2 to 3 because it's working but uses in-between) - && this->m_layer->height >= EXTRUDER_CONFIG(min_layer_height) * 2 + && this->m_layer->height >= EXTRUDER_CONFIG(min_layer_height) * 2 - EPSILON ) { - + std::cout << " ok, loop vase @"<< this->m_layer->id()<<", "<< this->m_layer->print_z<<"\n"; return extrude_loop_vase(original_loop, description, speed, lower_layer_edge_grid); } @@ -3040,7 +3097,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s // generate the travel move gcode += m_writer.travel_to_xy(this->point_to_gcode(pt), "move inwards before travel"); } - + return gcode; } diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index b88f47880..970c8f862 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -131,6 +131,9 @@ void Layer::make_perimeters() && config.perimeter_speed == other_config.perimeter_speed // it os mandatory? can't this be set at gcode.cpp? && config.external_perimeter_extrusion_width == other_config.external_perimeter_extrusion_width && config.external_perimeters_first == other_config.external_perimeters_first + && config.external_perimeters_vase == other_config.external_perimeters_vase + && config.external_perimeters_hole == other_config.external_perimeters_hole + && config.external_perimeters_nothole == other_config.external_perimeters_nothole && config.external_perimeter_speed == other_config.external_perimeter_speed && config.extra_perimeters_odd_layers == other_config.extra_perimeters_odd_layers && config.gap_fill == other_config.gap_fill diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index e39c4a720..e33993936 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -588,6 +588,7 @@ void PerimeterGenerator::process() } } // at this point, all loops should be in contours[0] (= contours.front() ) + // collection of loops to add into loops ExtrusionEntityCollection entities; if (config->perimeter_loop.value) { //onlyone_perimter = >fusion all perimeterLoops @@ -614,9 +615,46 @@ void PerimeterGenerator::process() // if brim will be printed, reverse the order of perimeters so that // we continue inwards after having finished the brim // TODO: add test for perimeter order - if (this->config->external_perimeters_first || - (this->layer_id == 0 && this->print_config->brim_width.value > 0)) - entities.reverse(); + if (this->config->external_perimeters_first || + (this->layer_id == 0 && this->print_config->brim_width.value > 0)) { + if (this->config->external_perimeters_nothole.value) { + if (this->config->external_perimeters_hole.value) { + entities.reverse(); + } else { + //reverse only not-hole perimeters + ExtrusionEntityCollection coll2; + for (const auto loop : entities.entities) { + std::cout << loop->is_loop() <<" test " << (((ExtrusionLoop*)loop)->loop_role()) <<" & " << ExtrusionLoopRole::elrHole <<"\n"; + if (loop->is_loop() && !(((ExtrusionLoop*)loop)->loop_role() & ExtrusionLoopRole::elrHole) != 0) { + coll2.entities.push_back(loop); + } + } + coll2.reverse(); + for (const auto loop : entities.entities) { + if (!loop->is_loop() || (((ExtrusionLoop*)loop)->loop_role() & ExtrusionLoopRole::elrHole) != 0) { + coll2.entities.push_back(loop); + } + } + entities = coll2; + } + } else if (this->config->external_perimeters_hole.value) { + //reverse the hole, and put them in first place. + ExtrusionEntityCollection coll2; + for (const auto loop : entities.entities) { + if (loop->is_loop() && (((ExtrusionLoop*)loop)->loop_role() & ExtrusionLoopRole::elrHole) != 0) { + coll2.entities.push_back(loop); + } + } + coll2.reverse(); + for (const auto loop : entities.entities) { + if (!loop->is_loop() || !(((ExtrusionLoop*)loop)->loop_role() & ExtrusionLoopRole::elrHole) != 0) { + coll2.entities.push_back(loop); + } + } + entities = coll2; + } + + } // append perimeters for this slice as a collection if (!entities.empty()) this->loops->append(entities); @@ -708,18 +746,21 @@ ExtrusionEntityCollection PerimeterGenerator::_traverse_loops( bool is_external = loop.is_external(); ExtrusionRole role; - ExtrusionLoopRole loop_role; + ExtrusionLoopRole loop_role = ExtrusionLoopRole::elrDefault; role = is_external ? erExternalPerimeter : erPerimeter; if (loop.is_internal_contour()) { // Note that we set loop role to ContourInternalPerimeter // also when loop is both internal and external (i.e. // there's only one contour loop). - loop_role = elrInternal; - } else { - loop_role = elrDefault; + loop_role = ExtrusionLoopRole::elrInternal; } if (!loop.is_contour) { - loop_role = (ExtrusionLoopRole)(loop_role | elrHole); + loop_role = (ExtrusionLoopRole)(loop_role | ExtrusionLoopRole::elrHole); + } + if (this->config->external_perimeters_vase.value && this->config->external_perimeters_first.value && is_external) { + if ((loop.is_contour && this->config->external_perimeters_nothole.value) || (!loop.is_contour && this->config->external_perimeters_hole.value)) { + loop_role = (ExtrusionLoopRole)(loop_role | ExtrusionLoopRole::elrVase); + } } // detect overhanging/bridging perimeters diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index a07106fba..93994bf6a 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -668,6 +668,25 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->set_default_value(new ConfigOptionBool(false)); + def = this->add("external_perimeters_nothole", coBool); + def->label = L("only for outter side"); + def->full_label = L("ext peri first for outter side"); + def->category = OptionCategory::perimeter; + def->tooltip = L("Only do the vase trick on the external side. Useful when the thikness is too low."); + def->mode = comExpert; + def->set_default_value(new ConfigOptionBool(true)); + + def = this->add("external_perimeters_hole", coBool); + def->label = L("only for inner side"); + def->full_label = L("ext peri first for inner side"); + def->category = OptionCategory::perimeter; + def->tooltip = L("Only do the vase trick on the external side. Useful when you only want to remode seam from screw hole."); + def->mode = comExpert; + def->set_default_value(new ConfigOptionBool(true)); + + ConfigOptionBool external_perimeters_nothole; + ConfigOptionBool external_perimeters_hole; + def = this->add("perimeter_loop", coBool); def->label = L(""); def->full_label = L("Perimeters loop"); @@ -679,7 +698,7 @@ void PrintConfigDef::init_fff_params() def = this->add("perimeter_loop_seam", coEnum); def->label = L("Seam position"); - def->full_label = L("Perimeter loop"); + def->full_label = L("Perimeter loop seam"); def->category = OptionCategory::perimeter; def->tooltip = L("Position of perimeters starting points."); def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 8134928c7..d7fd91f98 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -492,7 +492,6 @@ public: ConfigOptionFloat elefant_foot_compensation; ConfigOptionBool exact_last_layer_height; ConfigOptionFloatOrPercent extrusion_width; - ConfigOptionBool external_perimeters_vase; ConfigOptionFloatOrPercent first_layer_height; ConfigOptionBool infill_only_where_needed; // Force the generation of solid shells between adjacent materials/volumes. @@ -546,7 +545,6 @@ protected: OPT_PTR(elefant_foot_compensation); OPT_PTR(exact_last_layer_height); OPT_PTR(extrusion_width); - OPT_PTR(external_perimeters_vase); OPT_PTR(first_layer_height); OPT_PTR(infill_only_where_needed); OPT_PTR(interface_shells); @@ -611,6 +609,9 @@ public: ConfigOptionFloatOrPercent external_perimeter_extrusion_width; ConfigOptionFloatOrPercent external_perimeter_speed; ConfigOptionBool external_perimeters_first; + ConfigOptionBool external_perimeters_vase; + ConfigOptionBool external_perimeters_nothole; + ConfigOptionBool external_perimeters_hole; ConfigOptionBool extra_perimeters; ConfigOptionBool extra_perimeters_odd_layers; ConfigOptionBool only_one_perimeter_top; @@ -683,6 +684,9 @@ protected: OPT_PTR(external_perimeter_extrusion_width); OPT_PTR(external_perimeter_speed); OPT_PTR(external_perimeters_first); + OPT_PTR(external_perimeters_vase); + OPT_PTR(external_perimeters_nothole); + OPT_PTR(external_perimeters_hole); OPT_PTR(extra_perimeters); OPT_PTR(extra_perimeters_odd_layers); OPT_PTR(only_one_perimeter_top); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index d29983175..252a9178b 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -611,6 +611,9 @@ bool PrintObject::invalidate_state_by_config_options(const std::vectoropt_bool("external_perimeters_first")); for (auto el : { "thin_walls_min_width", "thin_walls_overlap" }) @@ -254,6 +254,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) toggle_field("perimeter_loop_seam", config->opt_bool("perimeter_loop")); + toggle_field("gap_fill_min_area", config->opt_bool("gap_fill")); bool have_infill = config->option("fill_density")->value > 0; // infill_extruder uses the same logic as in Print::extruders() diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index 2526d84d8..68533b774 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -403,8 +403,10 @@ const std::vector& Preset::print_options() "thin_walls", "overhangs", "overhangs_width", "seam_position", - "external_perimeters_first", - "external_perimeters_vase", + "external_perimeters_first", + "external_perimeters_vase", + "external_perimeters_nothole", + "external_perimeters_hole", "fill_density" , "fill_pattern" , "fill_top_flow_ratio" diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index e37076667..57e8c3051 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1557,6 +1557,8 @@ void TabPrint::build() line = { _(L("External Perimeter")), "" }; line.append_option(optgroup->get_option("external_perimeters_first")); line.append_option(optgroup->get_option("external_perimeters_vase")); + line.append_option(optgroup->get_option("external_perimeters_nothole")); + line.append_option(optgroup->get_option("external_perimeters_hole")); optgroup->append_line(line); line = { _(L("Looping perimeter")), "" }; line.append_option(optgroup->get_option("perimeter_loop")); diff --git a/src/test/libslic3r/test_thin.cpp b/src/test/libslic3r/test_thin.cpp index ab32db5ff..859ca1092 100644 --- a/src/test/libslic3r/test_thin.cpp +++ b/src/test/libslic3r/test_thin.cpp @@ -6,10 +6,60 @@ #include "../../libslic3r/ClipperUtils.hpp" #include "../../libslic3r/MedialAxis.hpp" #include "../../libslic3r/SVG.hpp" +#include "../../libslic3r/GCode.hpp" using namespace Slic3r; using namespace Slic3r::Geometry; +using namespace Slic3r::Test; +class ExtrusionVolumeVisitor : public ExtrusionVisitorConst { + double volume = 0; +public: + virtual void use(const ExtrusionPath &path) override { + for (int i = 0; i < path.polyline.size() - 1; i++) volume += path.polyline.points[i].distance_to(path.polyline.points[i + 1]) * path.mm3_per_mm; + }; + virtual void use(const ExtrusionPath3D &path3D) override { std::cout << "error, not supported"; }; + virtual void use(const ExtrusionMultiPath &multipath) override { + for (const ExtrusionPath &path : multipath.paths) use(path); + } + virtual void use(const ExtrusionMultiPath3D &multipath) override { std::cout << "error, not supported"; }; + virtual void use(const ExtrusionLoop &loop) override { + for (const ExtrusionEntity &path : loop.paths) path.visit(*this); + } + virtual void use(const ExtrusionEntityCollection &collection) override { + for (const ExtrusionEntity *path : collection.entities) path->visit(*this); + } + double compute(const ExtrusionEntity &entity) && { + entity.visit(*this); + return volume; + } +}; + + +SCENARIO("extrude_thinwalls") { + GIVEN("ThickLine") { + ExPolygon expolygon; + expolygon.contour = Slic3r::Polygon{ Points{ + Point::new_scale(-0.5, 0), + Point::new_scale(0.5, 0), + Point::new_scale(0.3, 10), + Point::new_scale(-0.3, 10) } }; + ThickPolylines res; + + MedialAxis{ expolygon, scale_(1.1), scale_(0.5), scale_(0.2) }.build(res); + Flow periflow{ 1.1, 0.2, 0.4 }; + ExtrusionEntityCollection gap_fill = thin_variable_width(res, erGapFill, periflow); + + + //std::string gcode = gcodegen.get_visitor_gcode(); + THEN("analyse extrusion.") { + ExtrusionVolumeVisitor vis; + std::cout << " volume is " << ExtrusionVolumeVisitor{}.compute(gap_fill) << "\n"; + std::cout << " wanted volume is " << ((0.6*0.2 * 10) + (0.2*0.2 * 10)) << "\n"; + REQUIRE(std::abs(ExtrusionVolumeVisitor{}.compute(gap_fill) - ((0.6*0.2 * 10) + (0.2*0.2 * 10)))<0.01); + } + } +} SCENARIO("thin walls: ") { @@ -48,7 +98,7 @@ SCENARIO("thin walls: ") } } - GIVEN("narrow rectangle"){ + GIVEN("narrow rectangle") { ExPolygon expolygon; expolygon.contour = Slic3r::Polygon{ Points{ Point::new_scale(100, 100), @@ -67,15 +117,15 @@ SCENARIO("thin walls: ") Point::new_scale(100, 200) } }; Polylines res2; expolygon.medial_axis(scale_(20), scale_(0.5), &res2); - WHEN("creating the medial axis"){ + WHEN("creating the medial axis") { - THEN("medial axis of a narrow rectangle is a single line"){ + THEN("medial axis of a narrow rectangle is a single line") { REQUIRE(res.size() == 1); THEN("medial axis has reasonable length") { REQUIRE(res[0].length() >= scale_(200 - 100 - (120 - 100)) - SCALED_EPSILON); } } - THEN("medial axis of a narrow rectangle with an extra vertex is still a single line"){ + THEN("medial axis of a narrow rectangle with an extra vertex is still a single line") { REQUIRE(res2.size() == 1); THEN("medial axis of a narrow rectangle with an extra vertex has reasonable length") { REQUIRE(res2[0].length() >= scale_(200 - 100 - (120 - 100)) - SCALED_EPSILON);