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.
This commit is contained in:
supermerill 2019-02-20 17:22:03 +01:00
parent edad0da724
commit cfbafe4322
16 changed files with 391 additions and 131 deletions

View File

@ -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");
}
}

View File

@ -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<SegmentedIntersectionLine> FillScatteredRectilinear::_vert_lines_for
}
void
FillRectilinearSawtooth::fill_surface_extrusion(const Surface *surface, const FillParams &params, 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

View File

@ -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 &params, ExtrusionEntitiesPtr &out) override;
};
}; // namespace Slic3r

View File

@ -1992,10 +1992,11 @@ std::vector<float> 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<EdgeGrid::Grid> *lower_layer_edge_grid)
std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::string &description, double speed, std::unique_ptr<EdgeGrid::Grid> *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<EdgeGrid::Grid> *lower_layer_edge_grid)
{
if (const ExtrusionPath* path = dynamic_cast<const ExtrusionPath*>(&entity))
return this->extrude_path(*path, description, speed);
else if (const ExtrusionMultiPath* multipath = dynamic_cast<const ExtrusionMultiPath*>(&entity))
return this->extrude_multi_path(*multipath, description, speed);
else if (const ExtrusionLoop* loop = dynamic_cast<const ExtrusionLoop*>(&entity))
return this->extrude_loop(*loop, description, speed, lower_layer_edge_grid);
else if (const ExtrusionEntityCollection* coll = dynamic_cast<const ExtrusionEntityCollection*>(&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<EdgeGrid::Grid> *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<const ExtrusionEntityCollection*>(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<const ExtrusionPath*>(ee);
if (path)
gcode += this->extrude_path(*path, label, speed);
else {
const ExtrusionMultiPath *multipath = dynamic_cast<const ExtrusionMultiPath*>(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
{

View File

@ -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<unsigned int> &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<EdgeGrid::Grid> *lower_layer_edge_grid = nullptr);
std::string extrude_loop(ExtrusionLoop loop, std::string description, double speed = -1., std::unique_ptr<EdgeGrid::Grid> *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<EdgeGrid::Grid> *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<EdgeGrid::Grid> *lower_layer_edge_grid = nullptr);
std::string extrude_loop(const ExtrusionLoop &loop, const std::string &description, double speed = -1., std::unique_ptr<EdgeGrid::Grid> *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<int> 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);

View File

@ -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<InfillPattern>(ipRectilinear);
@ -2390,6 +2392,27 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->default_value = new ConfigOptionEnum<SupportMaterialPattern>(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<InfillPattern>::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<InfillPattern>(ipRectilinear);
def = this->add("support_material_spacing", coFloat);
def->label = L("Pattern spacing");
def->category = L("Support material");

View File

@ -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<InfillPattern>::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<InfillPattern> support_material_interface_pattern;
ConfigOptionEnum<SupportMaterialPattern> 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);

View File

@ -501,6 +501,7 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
|| opt_key == "support_material_interface_extruder"
|| opt_key == "support_material_interface_spacing"
|| opt_key == "support_material_pattern"
|| opt_key == "support_material_interface_pattern"
|| opt_key == "support_material_xy_spacing"
|| opt_key == "support_material_spacing"
|| opt_key == "support_material_synchronize_layers"

View File

@ -2966,6 +2966,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
infill_pattern = ipHoneycomb;
break;
}
InfillPattern interface_pattern = m_object_config->support_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<size_t>(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<size_t>& 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<Fill> filler_interface = std::unique_ptr<Fill>(Fill::new_from_type(ipRectilinear));
std::unique_ptr<Fill> filler_interface = std::unique_ptr<Fill>(Fill::new_from_type(interface_pattern));
std::unique_ptr<Fill> filler_support = std::unique_ptr<Fill>(Fill::new_from_type(infill_pattern));
std::unique_ptr<Fill> filler_dense = std::unique_ptr<Fill>(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<size_t>(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<size_t>& 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<Fill> filler_interface = std::unique_ptr<Fill>(Fill::new_from_type(m_slicing_params.soluble_interface ? ipRectilinear : ipRectilinear));
std::unique_ptr<Fill> filler_interface = std::unique_ptr<Fill>(Fill::new_from_type(interface_pattern));
std::unique_ptr<Fill> filler_intermediate_interface = std::unique_ptr<Fill>(Fill::new_from_type(ipRectilinear));
std::unique_ptr<Fill> filler_support = std::unique_ptr<Fill>(Fill::new_from_type(infill_pattern));
std::unique_ptr<Fill> filler_solid = std::unique_ptr<Fill>(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) {

View File

@ -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 */

View File

@ -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<wxComboBox*>(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<InfillPattern>::get_enum_values();
int value = map_names.at(key);
if (m_opt.type == coEnum)
{
int ret_enum = static_cast<wxComboBox*>(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<InfillPattern>::get_enum_values();
int value = map_names.at(key);
m_value = static_cast<InfillPattern>(value);
}
else
m_value = static_cast<InfillPattern>(0);
}
if (m_opt_id.compare("fill_pattern") == 0)
m_value = static_cast<InfillPattern>(ret_enum);
else if (m_opt_id.compare("gcode_flavor") == 0)
m_value = static_cast<GCodeFlavor>(ret_enum);
else if (m_opt_id.compare("support_material_pattern") == 0)
m_value = static_cast<InfillPattern>(value);
}
else
m_value = static_cast<InfillPattern>(0);
}
if (m_opt_id.compare("fill_pattern") == 0)
m_value = static_cast<InfillPattern>(ret_enum);
else if (m_opt_id.compare("gcode_flavor") == 0)
m_value = static_cast<GCodeFlavor>(ret_enum);
else if (m_opt_id.compare("support_material_pattern") == 0)
m_value = static_cast<SupportMaterialPattern>(ret_enum);
else if (m_opt_id.compare("seam_position") == 0)
m_value = static_cast<SeamPosition>(ret_enum);

View File

@ -216,6 +216,8 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt
config.set_key_value(opt_key, new ConfigOptionEnum<InfillPattern>(boost::any_cast<InfillPattern>(value)));
else if (opt_key.compare("gcode_flavor") == 0)
config.set_key_value(opt_key, new ConfigOptionEnum<GCodeFlavor>(boost::any_cast<GCodeFlavor>(value)));
else if (opt_key.compare("support_material_interface_pattern") == 0)
config.set_key_value(opt_key, new ConfigOptionEnum<InfillPattern>(boost::any_cast<InfillPattern>(value)));
else if (opt_key.compare("support_material_pattern") == 0)
config.set_key_value(opt_key, new ConfigOptionEnum<SupportMaterialPattern>(boost::any_cast<SupportMaterialPattern>(value)));
else if (opt_key.compare("seam_position") == 0 || opt_key.compare("perimeter_loop_seam") == 0)

View File

@ -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" } }
};

View File

@ -545,6 +545,9 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config
else if (opt_key.compare("gcode_flavor") == 0 ) {
ret = static_cast<int>(config.option<ConfigOptionEnum<GCodeFlavor>>(opt_key)->value);
}
else if (opt_key.compare("support_material_interface_pattern") == 0) {
ret = static_cast<int>(config.option<ConfigOptionEnum<InfillPattern>>(opt_key)->value);
}
else if (opt_key.compare("support_material_pattern") == 0) {
ret = static_cast<int>(config.option<ConfigOptionEnum<SupportMaterialPattern>>(opt_key)->value);
}

View File

@ -338,6 +338,7 @@ const std::vector<std::string>& 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"

View File

@ -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",