From cfbafe43224776f8ec2bddf9d3dd23add6fb3f6b Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 20 Feb 2019 17:22:03 +0100 Subject: [PATCH] Sawtooth infill : may be useful for support interface (idea by e3D) add a setting to select the support interface. need some tests to see if it works. --- src/libslic3r/Fill/FillBase.cpp | 1 + src/libslic3r/Fill/FillRectilinear2.cpp | 131 ++++++++++++- src/libslic3r/Fill/FillRectilinear2.hpp | 10 + src/libslic3r/GCode.cpp | 238 ++++++++++++++++-------- src/libslic3r/GCode.hpp | 27 ++- src/libslic3r/PrintConfig.cpp | 23 +++ src/libslic3r/PrintConfig.hpp | 7 +- src/libslic3r/PrintObject.cpp | 1 + src/libslic3r/SupportMaterial.cpp | 12 +- src/libslic3r/TriangleMesh.cpp | 8 +- src/slic3r/GUI/Field.cpp | 39 ++-- src/slic3r/GUI/GUI.cpp | 2 + src/slic3r/GUI/GUI_ObjectList.cpp | 2 +- src/slic3r/GUI/OptionsGroup.cpp | 3 + src/slic3r/GUI/Preset.cpp | 1 + src/slic3r/GUI/Tab.cpp | 17 +- 16 files changed, 391 insertions(+), 131 deletions(-) diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index 27cf1fc11..3a3b83bf9 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -42,6 +42,7 @@ Fill* Fill::new_from_type(const InfillPattern type) case ipSmoothTriple: return new FillSmoothTriple(); case ipSmoothHilbert: return new FillSmoothHilbert(); case ipRectiWithPerimeter: return new FillRectilinear2Peri(); + case ipSawtooth: return new FillRectilinearSawtooth(); default: throw std::invalid_argument("unknown type"); } } diff --git a/src/libslic3r/Fill/FillRectilinear2.cpp b/src/libslic3r/Fill/FillRectilinear2.cpp index 8c1e866ea..face63d84 100644 --- a/src/libslic3r/Fill/FillRectilinear2.cpp +++ b/src/libslic3r/Fill/FillRectilinear2.cpp @@ -1260,7 +1260,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP } skip = params.dont_connect || (link_max_length > 0 && (take_next ? distNext : distPrev) > link_max_length); if (skip) { - //"skip" the connection but continue to do as it was printed + //"skip" the connection but continue to print something as it was connected //also, add a bit of extrusion at the tip, to not under-extrude //TODO: supermerill: don't output polyline but Extrusion entiyt, to be able to extrude a small line here (gap-fill style) instead of big bits. Point last_point = Point(seg.pos, intrsctn->pos()); @@ -1269,17 +1269,17 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP //compute angle to see where it's possible to extrude a bit float coeff_before = 0.5f; if (!polyline_current->points.empty()) coeff_before = 1 - std::abs(((last_point.ccw_angle(polyline_current->points.back(), next_point)) / PI) - 1); - if (coeff_before < 0.2) coeff_before = 0.0; - if (coeff_before > 0.8) coeff_before = 1.0; + if (coeff_before < 0.5) coeff_before = 0.0; + if (coeff_before > 0.5) coeff_before = 1.0; //now add the points at the end of the current polyline polyline_current->points.push_back(last_point); if (coeff_before > 0.0) - polyline_current->points.push_back(last_point.interpolate(coeff_before * scale_(this->spacing) / ( (take_next ? distNext : distPrev)), next_point)); + polyline_current->points.push_back(last_point.interpolate(coeff_before * scale_(this->spacing * 0.7) / ( (take_next ? distNext : distPrev)), next_point)); //now create & add the points at the start of the new polyline polylines_out.push_back(Polyline()); polyline_current = &polylines_out.back(); if (coeff_before < 1.0) - polyline_current->points.push_back(next_point.interpolate((1 - coeff_before) * scale_(this->spacing) / ( (take_next ? distNext : distPrev)), last_point)); + polyline_current->points.push_back(next_point.interpolate((1 - coeff_before) * scale_(this->spacing * 0.7) / ((take_next ? distNext : distPrev)), last_point)); polyline_current->points.push_back(next_point); } else { polyline_current->points.push_back(Point(seg.pos, intrsctn->pos())); @@ -1667,4 +1667,125 @@ std::vector FillScatteredRectilinear::_vert_lines_for } +void +FillRectilinearSawtooth::fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, ExtrusionEntitiesPtr &out) { + const coord_t scaled_nozzle_diam = scale_(params.flow->nozzle_diameter); + const coord_t clearance = scaled_nozzle_diam * 2; + const coord_t tooth_spacing_min = scaled_nozzle_diam ; + const coord_t tooth_spacing_max = scaled_nozzle_diam * 3; + const coord_t tooth_zhop = scaled_nozzle_diam; + Polylines polylines_out; + if (!fill_surface_by_lines(surface, params, 0.f, 0.f, polylines_out)) { + printf("FillRectilinear2::fill_surface() failed to fill a region.\n"); + } + if (!polylines_out.empty()) { + ExtrusionEntityCollection *eec = new ExtrusionEntityCollection(); + /// pass the no_sort attribute to the extrusion path + eec->no_sort = this->no_sort(); + + ExtrusionRole good_role = params.role; + if (good_role == erNone || good_role == erCustom) { + good_role = params.flow->bridge ? + erBridgeInfill : + (surface->is_solid() ? + ((surface->is_top()) ? erTopSolidInfill : erSolidInfill) : + erInternalInfill); + } + for (Polyline poly : polylines_out) { + if (!poly.is_valid()) continue; + + ExtrusionMultiPath3D *extrusions = new ExtrusionMultiPath3D(); + extrusions->paths.push_back(ExtrusionPath3D(good_role, params.flow->mm3_per_mm() * params.flow_mult, params.flow->width * params.flow_mult, params.flow->height)); + ExtrusionPath3D *current_extrusion = &(extrusions->paths.back()); + Points &pts = poly.points; + coord_t next_zhop = tooth_spacing_min + (coord_t) abs((rand() / (float)RAND_MAX) * (tooth_spacing_max - tooth_spacing_min)); + size_t idx = 1; + + current_extrusion->push_back(pts[0], 0); + Point last = pts[0]; + coord_t line_length = (coord_t)pts[idx - 1].distance_to(pts[idx]); + coord_t maxLength = poly.length(); + while (idx < poly.size() && maxLength > tooth_spacing_max) { + //go next hop line + //do not use the "return" line nor the tangent ones. + while (idx < poly.size() && maxLength > tooth_spacing_min && (next_zhop >= line_length || line_length < clearance + || (std::abs(std::abs((int)(this->angle * 180 / PI) % 180) - 90) > 45 ? pts[idx].y() < pts[idx - 1].y() : pts[idx].x() < pts[idx - 1].x()))) { + if (line_length < clearance || pts[idx].x() < pts[idx - 1].x()) { + + } else { + next_zhop -= line_length; + } + maxLength -= line_length; + current_extrusion->push_back(pts[idx], 0); + last = pts[idx]; + idx++; + if (idx < poly.size()) line_length = (coord_t)last.distance_to(pts[idx]); + } + if (idx < poly.size() && maxLength > clearance) { + //do z-hop + //keep some room for the mouv + if (next_zhop > line_length - scaled_nozzle_diam * 2) next_zhop -= line_length - scaled_nozzle_diam * 2.5; + last = last.interpolate(next_zhop / (double)line_length, pts[idx]); + //Create point at pos + if (last != pts[idx - 1]) { + current_extrusion->push_back(last, 0); + } + + //add new extrusion that go up with nozzle_flow + extrusions->paths.push_back(ExtrusionPath3D(good_role, params.flow->nozzle_diameter * params.flow->nozzle_diameter * PI / 4, params.flow->nozzle_diameter, params.flow->nozzle_diameter)); + current_extrusion = &(extrusions->paths.back()); + current_extrusion->push_back(last, 0); + current_extrusion->push_back(last, tooth_zhop); + + //add new extrusion that move a bit to let the palce for the nozzle tip + extrusions->paths.push_back(ExtrusionPath3D(good_role, 0, params.flow->nozzle_diameter / 10, params.flow->nozzle_diameter / 10)); + current_extrusion = &(extrusions->paths.back()); + current_extrusion->push_back(last, tooth_zhop); + //add next point + line_length = (coord_t)last.distance_to(pts[idx]); + last = last.interpolate(scaled_nozzle_diam / (double)line_length, pts[idx]); + current_extrusion->push_back(last, tooth_zhop); + + // add new extrusion that go down with no nozzle_flow / sqrt(2) + extrusions->paths.push_back(ExtrusionPath3D(good_role, params.flow->mm3_per_mm() / std::sqrt(2), params.flow->width / std::sqrt(2), params.flow->height)); + current_extrusion = &(extrusions->paths.back()); + current_extrusion->push_back(last, tooth_zhop); + //add next point + line_length = (coord_t)last.distance_to(pts[idx]); + last = last.interpolate(scaled_nozzle_diam / (double)line_length, pts[idx]); + current_extrusion->push_back(last, 0); + + // now go back to normal flow + extrusions->paths.push_back(ExtrusionPath3D(good_role, params.flow->mm3_per_mm() * params.flow_mult, params.flow->width * params.flow_mult, params.flow->height)); + current_extrusion = &(extrusions->paths.back()); + current_extrusion->push_back(last, 0); + line_length = (coord_t)last.distance_to(pts[idx]); + + //re-init + next_zhop = tooth_spacing_min + (coord_t) abs((rand() / (float)RAND_MAX) * (tooth_spacing_max - tooth_spacing_min)); + } + } + while (idx < poly.size()) { + current_extrusion->push_back(pts[idx], 0); + idx++; + } + if (current_extrusion->size() < 2) extrusions->paths.pop_back(); + ExtrusionPrinter print; extrusions->visit(print); + if (!extrusions->paths.empty()) eec->entities.push_back(extrusions); + else delete extrusions; + } + // === end === + if (!eec->empty()) { + out.push_back(eec); + ExtrusionPrinter print; eec->visit(print); + } else { + delete eec; + } + } + + +} + + + } // namespace Slic3r diff --git a/src/libslic3r/Fill/FillRectilinear2.hpp b/src/libslic3r/Fill/FillRectilinear2.hpp index 879fbbfa4..e91ecdb08 100644 --- a/src/libslic3r/Fill/FillRectilinear2.hpp +++ b/src/libslic3r/Fill/FillRectilinear2.hpp @@ -100,6 +100,16 @@ protected: virtual coord_t _line_spacing_for_density(float density) const; }; +class FillRectilinearSawtooth : public FillRectilinear2 { +public: + // require bridge flow since it's a pre-bridge over very sparse infill + virtual bool use_bridge_flow() const { return true; } + + virtual Fill* clone() const { return new FillRectilinearSawtooth(*this); }; + virtual ~FillRectilinearSawtooth() {} + virtual void fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, ExtrusionEntitiesPtr &out) override; + +}; }; // namespace Slic3r diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 461eaa3b1..6a757ee9e 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1992,10 +1992,11 @@ std::vector polygon_angles_at_vertices(const Polygon &polygon, const std: return angles; } -std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, double speed, std::unique_ptr *lower_layer_edge_grid) +std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::string &description, double speed, std::unique_ptr *lower_layer_edge_grid) { // 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; if (m_layer->lower_layer != nullptr && lower_layer_edge_grid != nullptr) { if (! *lower_layer_edge_grid) { @@ -2277,8 +2278,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou return gcode; } -std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, std::string description, double speed) -{ +std::string GCode::extrude_multi_path(const ExtrusionMultiPath &multipath, const std::string &description, double speed) { // extrude along the path std::string gcode; for (ExtrusionPath path : multipath.paths) { @@ -2296,34 +2296,99 @@ std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, std::string return gcode; } -std::string GCode::extrude_entity(const ExtrusionEntity &entity, std::string description, double speed, std::unique_ptr *lower_layer_edge_grid) -{ - if (const ExtrusionPath* path = dynamic_cast(&entity)) - return this->extrude_path(*path, description, speed); - else if (const ExtrusionMultiPath* multipath = dynamic_cast(&entity)) - return this->extrude_multi_path(*multipath, description, speed); - else if (const ExtrusionLoop* loop = dynamic_cast(&entity)) - return this->extrude_loop(*loop, description, speed, lower_layer_edge_grid); - else if (const ExtrusionEntityCollection* coll = dynamic_cast(&entity)){ - std::string gcode; - ExtrusionEntityCollection chained; - if (coll->no_sort) chained = *coll; - else chained = coll->chained_path_from(m_last_pos, false); - for (ExtrusionEntity *next_entity : chained.entities) { - gcode += extrude_entity(*next_entity, description, speed, lower_layer_edge_grid); +std::string GCode::extrude_multi_path3D(const ExtrusionMultiPath3D &multipath3D, const std::string &description, double speed) { + // extrude along the path + std::string gcode; + for (const ExtrusionPath3D &path : multipath3D.paths) { + + gcode += this->_before_extrude(path, description, speed); + + // calculate extrusion length per distance unit + double e_per_mm = m_writer.extruder()->e_per_mm3() * path.mm3_per_mm; + if (m_writer.extrusion_axis().empty()) e_per_mm = 0; + double path_length = 0.; + { + std::string comment = m_config.gcode_comments ? description : ""; + //for (const Line &line : path.polyline.lines()) { + for (size_t i = 0; i < path.polyline.points.size() - 1; i++) { + Line line(path.polyline.points[i], path.polyline.points[i + 1]); + const double line_length = line.length() * SCALING_FACTOR; + path_length += line_length; + gcode += m_writer.extrude_to_xyz( + this->point_to_gcode(line.b, path.z_offsets.size()>i+1 ? path.z_offsets[i+1] : 0), + e_per_mm * line_length, + comment); + } } - return gcode; - } else { - throw std::invalid_argument("Invalid argument supplied to extrude()"); - return ""; + gcode += this->_after_extrude(path); + } + if (m_wipe.enable) { + m_wipe.path = std::move(multipath3D.paths.back().polyline); // TODO: don't limit wipe to last path + m_wipe.path.reverse(); + } + // reset acceleration + gcode += m_writer.set_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5)); + return gcode; +} + +std::string GCode::extrude_entity(const ExtrusionEntity &entity, const std::string &description, double speed, std::unique_ptr *lower_layer_edge_grid) +{ + this->visitor_gcode.clear(); + this->visitor_comment = description; + this->visitor_speed = speed; + this->visitor_lower_layer_edge_grid = lower_layer_edge_grid; + entity.visit(*this); + return this->visitor_gcode; +} + +void GCode::use(const ExtrusionEntityCollection &collection) { + ExtrusionEntityCollection chained; + if (collection.no_sort) chained = collection; + else chained = collection.chained_path_from(m_last_pos, false); + for (const ExtrusionEntity *next_entity : chained.entities) { + next_entity->visit(*this); } } -std::string GCode::extrude_path(ExtrusionPath path, std::string description, double speed) -{ -// description += ExtrusionRole2String(path.role()); - path.simplify(SCALED_RESOLUTION); - std::string gcode = this->_extrude(path, description, speed); +std::string GCode::extrude_path(const ExtrusionPath &path, const std::string &description, double speed) { + // description += ExtrusionRole2String(path.role()); + ExtrusionPath simplifed_path = path; + simplifed_path.simplify(SCALED_RESOLUTION); + std::string gcode = this->_extrude(simplifed_path, description, speed); + + if (m_wipe.enable) { + m_wipe.path = std::move(simplifed_path.polyline); + m_wipe.path.reverse(); + } + // reset acceleration + gcode += m_writer.set_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5)); + return gcode; +} + +std::string GCode::extrude_path_3D(const ExtrusionPath3D &path, const std::string &description, double speed) { + // description += ExtrusionRole2String(path.role()); + //path.simplify(SCALED_RESOLUTION); + std::string gcode = this->_before_extrude(path, description, speed); + + // calculate extrusion length per distance unit + double e_per_mm = m_writer.extruder()->e_per_mm3() * path.mm3_per_mm; + if (m_writer.extrusion_axis().empty()) e_per_mm = 0; + double path_length = 0.; + { + std::string comment = m_config.gcode_comments ? description : ""; + //for (const Line &line : path.polyline.lines()) { + for (size_t i = 0; i < path.polyline.points.size()-1;i++) { + Line line(path.polyline.points[i], path.polyline.points[i + 1]); + const double line_length = line.length() * SCALING_FACTOR; + path_length += line_length; + gcode += m_writer.extrude_to_xyz( + this->point_to_gcode(line.b, path.z_offsets.size()>i ? path.z_offsets[i] : 0), + e_per_mm * line_length, + comment); + } + } + gcode += this->_after_extrude(path); + if (m_wipe.enable) { m_wipe.path = std::move(path.polyline); m_wipe.path.reverse(); @@ -2369,22 +2434,19 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill const double support_interface_speed = m_config.support_material_interface_speed.get_abs_value(support_speed); for (const ExtrusionEntity *ee : support_fills.entities) { ExtrusionRole role = ee->role(); - assert(role == erSupportMaterial || role == erSupportMaterialInterface); + assert(role == erSupportMaterial || role == erSupportMaterialInterface || role == erMixed); if (const ExtrusionEntityCollection* coll = dynamic_cast(ee)) { gcode += extrude_support(*coll); continue; } const char *label = (role == erSupportMaterial) ? support_label : support_interface_label; const double speed = (role == erSupportMaterial) ? support_speed : support_interface_speed; - const ExtrusionPath *path = dynamic_cast(ee); - if (path) - gcode += this->extrude_path(*path, label, speed); - else { - const ExtrusionMultiPath *multipath = dynamic_cast(ee); - assert(multipath != nullptr); - if (multipath) - gcode += this->extrude_multi_path(*multipath, label, speed); - } + visitor_gcode = ""; + visitor_comment = label; + visitor_speed = speed; + visitor_lower_layer_edge_grid = nullptr; + ee->visit(*this); + gcode += visitor_gcode; } } return gcode; @@ -2443,22 +2505,45 @@ void GCode::_write_format(FILE* file, const char* format, ...) va_end(args); } -std::string GCode::_extrude(const ExtrusionPath &path, std::string description, double speed) -{ +std::string GCode::_extrude(const ExtrusionPath &path, const std::string &description, double speed) { + + std::string gcode = this->_before_extrude(path, description, speed); + + // calculate extrusion length per distance unit + double e_per_mm = m_writer.extruder()->e_per_mm3() * path.mm3_per_mm; + if (m_writer.extrusion_axis().empty()) e_per_mm = 0; + double path_length = 0.; + { + std::string comment = m_config.gcode_comments ? description : ""; + for (const Line &line : path.polyline.lines()) { + const double line_length = line.length() * SCALING_FACTOR; + path_length += line_length; + gcode += m_writer.extrude_to_xy( + this->point_to_gcode(line.b), + e_per_mm * line_length, + comment); + } + } + gcode += this->_after_extrude(path); + + return gcode; +} + +std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string &description, double speed) { std::string gcode; - + // go to first point of extrusion path if (!m_last_pos_defined || m_last_pos != path.first_point()) { gcode += this->travel_to( path.first_point(), path.role(), "move to first " + description + " point" - ); + ); } - + // compensate retraction gcode += this->unretract(); - + // adjust acceleration { double acceleration; @@ -2475,11 +2560,8 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, } gcode += m_writer.set_acceleration((unsigned int)floor(acceleration + 0.5)); } - - // calculate extrusion length per distance unit - double e_per_mm = m_writer.extruder()->e_per_mm3() * path.mm3_per_mm; - if (m_writer.extrusion_axis().empty()) e_per_mm = 0; - + + // set speed if (speed == -1) { if (path.role() == erPerimeter) { @@ -2514,24 +2596,21 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, speed = std::min( speed, m_config.max_volumetric_speed.value / path.mm3_per_mm - ); + ); } if (EXTRUDER_CONFIG(filament_max_volumetric_speed) > 0) { // cap speed with max_volumetric_speed anyway (even if user is not using autospeed) speed = std::min( speed, EXTRUDER_CONFIG(filament_max_volumetric_speed) / path.mm3_per_mm - ); + ); } double F = speed * 60; // convert mm/sec to mm/min - + // extrude arc or line - if (m_enable_extrusion_role_markers) - { - if (path.role() != m_last_extrusion_role) - { - if (m_enable_extrusion_role_markers) - { + if (m_enable_extrusion_role_markers) { + if (path.role() != m_last_extrusion_role) { + if (m_enable_extrusion_role_markers) { char buf[32]; sprintf(buf, ";_EXTRUSION_ROLE:%d\n", int(path.role())); gcode += buf; @@ -2541,18 +2620,15 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, m_last_extrusion_role = path.role(); // adds analyzer tags and updates analyzer's tracking data - if (m_enable_analyzer) - { - if (path.role() != m_last_analyzer_extrusion_role) - { + if (m_enable_analyzer) { + if (path.role() != m_last_analyzer_extrusion_role) { m_last_analyzer_extrusion_role = path.role(); char buf[32]; sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), int(m_last_analyzer_extrusion_role)); gcode += buf; } - if (m_last_mm3_per_mm != path.mm3_per_mm) - { + if (m_last_mm3_per_mm != path.mm3_per_mm) { m_last_mm3_per_mm = path.mm3_per_mm; char buf[32]; @@ -2560,8 +2636,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, gcode += buf; } - if (m_last_width != path.width) - { + if (m_last_width != path.width) { m_last_width = path.width; char buf[32]; @@ -2569,8 +2644,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, gcode += buf; } - if (m_last_height != path.height) - { + if (m_last_height != path.height) { m_last_height = path.height; char buf[32]; @@ -2590,21 +2664,13 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, if (path.role() == erExternalPerimeter) comment += ";_EXTERNAL_PERIMETER"; } - // F is mm per minute. gcode += m_writer.set_speed(F, "", comment); - double path_length = 0.; - { - std::string comment = m_config.gcode_comments ? description : ""; - for (const Line &line : path.polyline.lines()) { - const double line_length = line.length() * SCALING_FACTOR; - path_length += line_length; - gcode += m_writer.extrude_to_xy( - this->point_to_gcode(line.b), - e_per_mm * line_length, - comment); - } - } + + return gcode; +} +std::string GCode::_after_extrude(const ExtrusionPath &path) { + std::string gcode; if (m_enable_cooling_markers) if (is_bridge(path.role())) gcode += ";_BRIDGE_FAN_END\n"; @@ -2783,12 +2849,20 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z) } // convert a model-space scaled point into G-code coordinates -Vec2d GCode::point_to_gcode(const Point &point) const -{ +Vec2d GCode::point_to_gcode(const Point &point) const { Vec2d extruder_offset = EXTRUDER_CONFIG(extruder_offset); return unscale(point) + m_origin - extruder_offset; } +// convert a model-space scaled point into G-code coordinates +Vec3d GCode::point_to_gcode(const Point &point, const coord_t z_offset) const { + Vec2d extruder_offset = EXTRUDER_CONFIG(extruder_offset); + Vec3d ret_vec(unscale_(point.x()) + m_origin.x() - extruder_offset.x(), + unscale_(point.y()) + m_origin.y() - extruder_offset.y(), + unscale_(z_offset)); + return ret_vec; +} + // convert a model-space scaled point into G-code coordinates Point GCode::gcode_to_point(const Vec2d &point) const { diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 1bd112de5..15c0c5748 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -126,7 +126,7 @@ private: bool i_have_brim = false; }; -class GCode { +class GCode : ExtrusionVisitor { public: GCode() : m_origin(Vec2d::Zero()), @@ -163,6 +163,7 @@ public: void set_origin(const coordf_t x, const coordf_t y) { this->set_origin(Vec2d(x, y)); } const Point& last_pos() const { return m_last_pos; } Vec2d point_to_gcode(const Point &point) const; + Vec3d point_to_gcode(const Point &point, coord_t z_offset) const; Point gcode_to_point(const Vec2d &point) const; const FullPrintConfig &config() const { return m_config; } const Layer* layer() const { return m_layer; } @@ -213,10 +214,22 @@ protected: void set_extruders(const std::vector &extruder_ids); std::string preamble(); std::string change_layer(coordf_t print_z); - std::string extrude_entity(const ExtrusionEntity &entity, std::string description = "", double speed = -1., std::unique_ptr *lower_layer_edge_grid = nullptr); - std::string extrude_loop(ExtrusionLoop loop, std::string description, double speed = -1., std::unique_ptr *lower_layer_edge_grid = nullptr); - std::string extrude_multi_path(ExtrusionMultiPath multipath, std::string description = "", double speed = -1.); - std::string extrude_path(ExtrusionPath path, std::string description = "", double speed = -1.); + std::string visitor_gcode; + std::string visitor_comment; + double visitor_speed; + std::unique_ptr *visitor_lower_layer_edge_grid; + virtual void use(const ExtrusionPath &path) override { visitor_gcode += extrude_path(path, visitor_comment, visitor_speed); }; + virtual void use(const ExtrusionPath3D &path3D) override { visitor_gcode += extrude_path_3D(path3D, visitor_comment, visitor_speed); }; + virtual void use(const ExtrusionMultiPath &multipath) override { visitor_gcode += extrude_multi_path(multipath, visitor_comment, visitor_speed); }; + virtual void use(const ExtrusionMultiPath3D &multipath) override { visitor_gcode += extrude_multi_path3D(multipath, visitor_comment, visitor_speed); }; + virtual void use(const ExtrusionLoop &loop) override { visitor_gcode += extrude_loop(loop, visitor_comment, visitor_speed, visitor_lower_layer_edge_grid); }; + virtual void use(const ExtrusionEntityCollection &collection) override; + std::string extrude_entity(const ExtrusionEntity &entity, const std::string &description, double speed = -1., std::unique_ptr *lower_layer_edge_grid = nullptr); + std::string extrude_loop(const ExtrusionLoop &loop, const std::string &description, double speed = -1., std::unique_ptr *lower_layer_edge_grid = nullptr); + std::string extrude_multi_path(const ExtrusionMultiPath &multipath, const std::string &description, double speed = -1.); + std::string extrude_multi_path3D(const ExtrusionMultiPath3D &multipath, const std::string &description, double speed = -1.); + std::string extrude_path(const ExtrusionPath &path, const std::string &description, double speed = -1.); + std::string extrude_path_3D(const ExtrusionPath3D &path, const std::string &description, double speed = -1.); typedef std::vector ExtruderPerCopy; // Extruding multiple objects with soluble / non-soluble / combined supports @@ -349,7 +362,9 @@ protected: // Formats and write into a file the given data. void _write_format(FILE* file, const char* format, ...); - std::string _extrude(const ExtrusionPath &path, std::string description = "", double speed = -1); + std::string _extrude(const ExtrusionPath &path, const std::string &description, double speed = -1); + std::string _before_extrude(const ExtrusionPath &path, const std::string &description, double speed = -1); + std::string _after_extrude(const ExtrusionPath &path); void print_machine_envelope(FILE *file, Print &print); void _print_first_layer_bed_temperature(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait); void _print_first_layer_extruder_temperatures(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 05b99d1b2..9f0baa7a1 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -417,6 +417,7 @@ void PrintConfigDef::init_fff_params() def->enum_values.push_back("hilbertcurve"); def->enum_values.push_back("archimedeanchords"); def->enum_values.push_back("octagramspiral"); + def->enum_values.push_back("sawtooth"); def->enum_values.push_back("smooth"); def->enum_values.push_back("smoothtriple"); def->enum_values.push_back("smoothhilbert"); @@ -426,6 +427,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->enum_labels.push_back(L("Sawtooth")); def->enum_labels.push_back(L("Ironing")); def->default_value = new ConfigOptionEnum(ipRectilinear); @@ -2390,6 +2392,27 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->default_value = new ConfigOptionEnum(smpRectilinear); + def = this->add("support_material_interface_pattern", coEnum); + def->label = L("Pattern"); + def->category = L("Support material"); + def->tooltip = L("Pattern for interface layer."); + def->cli = "support-material-interface-pattern=s"; + def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + def->enum_values.push_back("rectilinear"); + def->enum_values.push_back("concentric"); + def->enum_values.push_back("concentricgapfill"); + def->enum_values.push_back("hilbertcurve"); + def->enum_values.push_back("sawtooth"); + def->enum_values.push_back("smooth"); + def->enum_labels.push_back(L("Rectilinear")); + def->enum_labels.push_back(L("Concentric")); + def->enum_labels.push_back(L("Concentric (filled)")); + def->enum_labels.push_back(L("Hilbert Curve")); + def->enum_labels.push_back(L("Sawtooth")); + def->enum_labels.push_back(L("Ironing")); + def->mode = comAdvanced; + def->default_value = new ConfigOptionEnum(ipRectilinear); + def = this->add("support_material_spacing", coFloat); def->label = L("Pattern spacing"); def->category = L("Support material"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 26ce58387..bfd353bb3 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -51,7 +51,7 @@ enum PrintHostType { enum InfillPattern { ipRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb, ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipSmooth, ipSmoothHilbert, ipSmoothTriple, - ipRectiWithPerimeter, ipConcentricGapFill, ipScatteredRectilinear + ipRectiWithPerimeter, ipConcentricGapFill, ipScatteredRectilinear, ipSawtooth }; enum SupportMaterialPattern { @@ -152,7 +152,8 @@ template<> inline const t_config_enum_values& ConfigOptionEnum::g keys_map["smoothtriple"] = ipSmoothTriple; keys_map["smoothhilbert"] = ipSmoothHilbert; keys_map["rectiwithperimeter"] = ipRectiWithPerimeter; - keys_map["scatteredrectilinear"]= ipScatteredRectilinear; + keys_map["scatteredrectilinear"] = ipScatteredRectilinear; + keys_map["sawtooth"] = ipSawtooth; } return keys_map; } @@ -467,6 +468,7 @@ public: // Spacing between interface lines (the hatching distance). Set zero to get a solid interface. ConfigOptionFloat support_material_interface_spacing; ConfigOptionFloatOrPercent support_material_interface_speed; + ConfigOptionEnum support_material_interface_pattern; ConfigOptionEnum support_material_pattern; // Spacing between support material lines (the hatching distance). ConfigOptionFloat support_material_spacing; @@ -514,6 +516,7 @@ protected: OPT_PTR(support_material_interface_layers); OPT_PTR(support_material_interface_spacing); OPT_PTR(support_material_interface_speed); + OPT_PTR(support_material_interface_pattern); OPT_PTR(support_material_pattern); OPT_PTR(support_material_spacing); OPT_PTR(support_material_speed); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index a531729e4..53780adc8 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -501,6 +501,7 @@ bool PrintObject::invalidate_state_by_config_options(const std::vectorsupport_material_interface_pattern; BoundingBox bbox_object(Point(-scale_(1.), -scale_(1.0)), Point(scale_(1.), scale_(1.))); // const coordf_t link_max_length_factor = 3.; @@ -3002,7 +3003,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( size_t n_raft_layers = size_t(std::max(0, int(m_slicing_params.raft_layers()) - 1)); tbb::parallel_for(tbb::blocked_range(0, n_raft_layers), [this, &object, &raft_layers, - infill_pattern, &bbox_object, support_density, interface_density, raft_angle_1st_layer, raft_angle_base, raft_angle_interface, link_max_length_factor, with_sheath] + infill_pattern, interface_pattern, &bbox_object, support_density, interface_density, raft_angle_1st_layer, raft_angle_base, raft_angle_interface, link_max_length_factor, with_sheath] (const tbb::blocked_range& range) { for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id) { @@ -3011,7 +3012,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( assert(support_layer.support_fills.entities.empty()); MyLayer &raft_layer = *raft_layers[support_layer_id]; - std::unique_ptr filler_interface = std::unique_ptr(Fill::new_from_type(ipRectilinear)); + std::unique_ptr filler_interface = std::unique_ptr(Fill::new_from_type(interface_pattern)); std::unique_ptr filler_support = std::unique_ptr(Fill::new_from_type(infill_pattern)); std::unique_ptr filler_dense = std::unique_ptr(Fill::new_from_type(ipRectiWithPerimeter)); filler_interface->set_bounding_box(bbox_object); @@ -3114,14 +3115,15 @@ void PrintObjectSupportMaterial::generate_toolpaths( tbb::parallel_for(tbb::blocked_range(n_raft_layers, object.support_layers().size()), [this, &object, &bottom_contacts, &top_contacts, &intermediate_layers, &interface_layers, &layer_caches, &loop_interface_processor, - infill_pattern, &bbox_object, support_density, interface_density, interface_angle, &angles, link_max_length_factor, with_sheath] + infill_pattern, interface_pattern, &bbox_object, support_density, interface_density, interface_angle, &angles, link_max_length_factor, with_sheath] (const tbb::blocked_range& range) { // Indices of the 1st layer in their respective container at the support layer height. size_t idx_layer_bottom_contact = size_t(-1); size_t idx_layer_top_contact = size_t(-1); size_t idx_layer_intermediate = size_t(-1); size_t idx_layer_inteface = size_t(-1); - std::unique_ptr filler_interface = std::unique_ptr(Fill::new_from_type(m_slicing_params.soluble_interface ? ipRectilinear : ipRectilinear)); + std::unique_ptr filler_interface = std::unique_ptr(Fill::new_from_type(interface_pattern)); + std::unique_ptr filler_intermediate_interface = std::unique_ptr(Fill::new_from_type(ipRectilinear)); std::unique_ptr filler_support = std::unique_ptr(Fill::new_from_type(infill_pattern)); std::unique_ptr filler_solid = std::unique_ptr(Fill::new_from_type(ipRectiWithPerimeter)); filler_interface->set_bounding_box(bbox_object); @@ -3198,7 +3200,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( float(layer_ex.layer->height), m_support_material_interface_flow.nozzle_diameter, layer_ex.layer->bridging); - Fill *filler = filler_interface.get(); + Fill *filler = i == 2 ? filler_intermediate_interface.get() : filler_interface.get(); float density = interface_density; //if first layer and solid first layer : draw concentric with 100% density if (support_layer.id() == 0 && this->m_object_config->support_material_solid_first_layer.value) { diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index c2722ccb0..1236209d4 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -619,10 +619,10 @@ void TriangleMesh::require_shared_vertices() const int *vertices = stl.v_indices[facet_idx].vertex; for (int nbr_idx = 0; nbr_idx < 3; ++nbr_idx) { int nbr_face = this->stl.neighbors_start[facet_idx].neighbor[nbr_idx]; - if (nbr_face != -1) { - assert(stl.v_indices[nbr_face].vertex[(nbr.which_vertex_not[nbr_idx] + 1) % 3] == vertices[(nbr_idx + 1) % 3]); - assert(stl.v_indices[nbr_face].vertex[(nbr.which_vertex_not[nbr_idx] + 2) % 3] == vertices[nbr_idx]); - } + //if (nbr_face != -1) { + // assert(stl.v_indices[nbr_face].vertex[(nbr.which_vertex_not[nbr_idx] + 1) % 3] == vertices[(nbr_idx + 1) % 3]); + // assert(stl.v_indices[nbr_face].vertex[(nbr.which_vertex_not[nbr_idx] + 2) % 3] == vertices[nbr_idx]); + //} } } #endif /* _DEBUG */ diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 18f36aef5..94a407dc1 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -725,26 +725,27 @@ boost::any& Choice::get_value() if (m_opt_id == rp_option) return m_value = boost::any(ret_str); - if (m_opt.type == coEnum) - { - int ret_enum = static_cast(window)->GetSelection(); - if (m_opt_id.compare("top_fill_pattern") == 0 || m_opt_id.compare("bottom_fill_pattern") == 0 || m_opt_id.compare("solid_fill_pattern") == 0) - { - if (!m_opt.enum_values.empty()) { - std::string key = m_opt.enum_values[ret_enum]; - t_config_enum_values map_names = ConfigOptionEnum::get_enum_values(); - int value = map_names.at(key); + if (m_opt.type == coEnum) + { + int ret_enum = static_cast(window)->GetSelection(); + if (m_opt_id.compare("top_fill_pattern") == 0 || m_opt_id.compare("bottom_fill_pattern") == 0 + || m_opt_id.compare("solid_fill_pattern") == 0 || m_opt_id.compare("support_material_interface_pattern") == 0) + { + if (!m_opt.enum_values.empty()) { + std::string key = m_opt.enum_values[ret_enum]; + t_config_enum_values map_names = ConfigOptionEnum::get_enum_values(); + int value = map_names.at(key); - m_value = static_cast(value); - } - else - m_value = static_cast(0); - } - if (m_opt_id.compare("fill_pattern") == 0) - m_value = static_cast(ret_enum); - else if (m_opt_id.compare("gcode_flavor") == 0) - m_value = static_cast(ret_enum); - else if (m_opt_id.compare("support_material_pattern") == 0) + m_value = static_cast(value); + } + else + m_value = static_cast(0); + } + if (m_opt_id.compare("fill_pattern") == 0) + m_value = static_cast(ret_enum); + else if (m_opt_id.compare("gcode_flavor") == 0) + m_value = static_cast(ret_enum); + else if (m_opt_id.compare("support_material_pattern") == 0) m_value = static_cast(ret_enum); else if (m_opt_id.compare("seam_position") == 0) m_value = static_cast(ret_enum); diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index e8d5974d4..093a9601c 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -216,6 +216,8 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); else if (opt_key.compare("gcode_flavor") == 0) config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); + else if (opt_key.compare("support_material_interface_pattern") == 0) + config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); else if (opt_key.compare("support_material_pattern") == 0) config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); else if (opt_key.compare("seam_position") == 0 || opt_key.compare("perimeter_loop_seam") == 0) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index f243143da..97d46c814 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -27,7 +27,7 @@ FreqSettingsBundle FREQ_SETTINGS_BUNDLE_FFF = { L("Layers and Perimeters"), { "layer_height" , "perimeters", "top_solid_layers", "bottom_solid_layers" } }, { L("Infill") , { "fill_density", "fill_pattern" } }, { L("Support material") , { "support_material", "support_material_auto", "support_material_threshold", - "support_material_pattern", "support_material_buildplate_only", + "support_material_pattern", "support_material_interface_pattern", "support_material_buildplate_only", "support_material_spacing" } }, { L("Extruders") , { "wipe_into_infill", "wipe_into_objects" } } }; diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 94d86b201..71398e8a7 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -545,6 +545,9 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config else if (opt_key.compare("gcode_flavor") == 0 ) { ret = static_cast(config.option>(opt_key)->value); } + else if (opt_key.compare("support_material_interface_pattern") == 0) { + ret = static_cast(config.option>(opt_key)->value); + } else if (opt_key.compare("support_material_pattern") == 0) { ret = static_cast(config.option>(opt_key)->value); } diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index 8a5c7fec8..d58e3e4a7 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -338,6 +338,7 @@ const std::vector& Preset::print_options() "min_skirt_length", "brim_width", "brim_ears", "brim_ears_max_angle", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers", "raft_layers", "support_material_pattern", "support_material_with_sheath", "support_material_spacing", + "support_material_interface_pattern", "support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers", "support_material_interface_spacing", "support_material_interface_contact_loops" , "support_material_contact_distance_type" diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 3c630f0cd..f7ee5977a 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1037,15 +1037,18 @@ void TabPrint::build() optgroup->append_line(line); optgroup->append_single_option_line("support_material_pattern"); optgroup->append_single_option_line("support_material_with_sheath"); - optgroup->append_single_option_line("support_material_spacing"); - optgroup->append_single_option_line("support_material_angle"); + optgroup->append_single_option_line("support_material_spacing"); + optgroup->append_single_option_line("support_material_angle"); + optgroup->append_single_option_line("support_material_buildplate_only"); + optgroup->append_single_option_line("support_material_xy_spacing"); + optgroup->append_single_option_line("dont_support_bridges"); + optgroup->append_single_option_line("support_material_synchronize_layers"); + + optgroup = page->new_optgroup(_(L("Options for support material interface"))); + optgroup->append_single_option_line("support_material_interface_pattern"); optgroup->append_single_option_line("support_material_interface_layers"); optgroup->append_single_option_line("support_material_interface_spacing"); optgroup->append_single_option_line("support_material_interface_contact_loops"); - optgroup->append_single_option_line("support_material_buildplate_only"); - optgroup->append_single_option_line("support_material_xy_spacing"); - optgroup->append_single_option_line("dont_support_bridges"); - optgroup->append_single_option_line("support_material_synchronize_layers"); page = add_options_page(_(L("Speed")), "time.png"); optgroup = page->new_optgroup(_(L("Speed for print moves"))); @@ -1444,7 +1447,7 @@ void TabPrint::update() "support_material_spacing", "support_material_angle", "support_material_interface_layers", "dont_support_bridges", "support_material_extrusion_width", "support_material_contact_distance_type", - "support_material_xy_spacing" }) + "support_material_xy_spacing", "support_material_interface_pattern" }) get_field(el)->toggle(have_support_material); get_field("support_material_threshold")->toggle(have_support_material_auto); for (auto el : { "support_material_contact_distance_top",