#393 don't connect now differentiate with holes & outer perimeters

but it works only for half of rectilinear2: because it go over a new polyline start always from the same direction.
So it needs a difficult to do change to rectilinear2. (TODO)
This commit is contained in:
supermerill 2020-09-20 03:10:04 +02:00
parent 2022e3fbd6
commit 89ec89e682
16 changed files with 128 additions and 50 deletions

View File

@ -266,7 +266,7 @@ infill_dense_algo = autosmall
infill_every_layers = 1
infill_extruder = 1
infill_first = 0
infill_not_connected = 0
infill_connection = connected
infill_only_where_needed = 0
infill_overlap = 20%
interface_shells = 0

View File

@ -104,7 +104,7 @@ group:Infill
end_line
line:Pattern
setting:label_width$5:label$_:fill_pattern
setting:label$Don't connect:infill_not_connected
setting:width$19:label$_:infill_connection
end_line
line:External patterns
setting:label_width$5:top_fill_pattern

View File

@ -241,7 +241,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
params.density = float(0.01 * density);
params.dont_adjust = false;
params.fill_exactly = layerm.region()->config().enforce_full_fill_volume.getBool();
params.dont_connect = layerm.region()->config().infill_not_connected.getBool();
params.connection = layerm.region()->config().infill_connection.value;
//adjust flow (to over-extrude when needed)
float flow_percent = 1;
if (surface.has_pos_top()) flow_percent *= layerm.region()->config().fill_top_flow_ratio.get_abs_value(1);

View File

@ -168,7 +168,7 @@ void Fill3DHoneycomb::_fill_surface_single(
// connect lines if needed
if (! polylines_chained.empty()) {
if (params.dont_connect)
if (params.connection == icNotConnected)
append(polylines_out, std::move(polylines_chained));
else
this->connect_infill(std::move(polylines_chained), expolygon, polylines_out, this->spacing, params);

View File

@ -1011,6 +1011,7 @@ void Fill::connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary_
[&boundary](const std::pair<size_t, size_t> &contour_point) {
return contour_point.first < boundary.size() && contour_point.second < boundary[contour_point.first].size();
}));
assert(boundary_data.size() == boundary_src.holes.size() + 1);
#endif /* NDEBUG */
}
@ -1065,6 +1066,20 @@ void Fill::connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary_
}
std::sort(connections_sorted.begin(), connections_sorted.end(), [](const ConnectionCost& l, const ConnectionCost& r) { return l.cost < r.cost; });
//mark point as used depends of connection parameter
if (params.connection == icOuterShell) {
for (auto it = boundary_data.begin() + 1; it != boundary_data.end(); ++it) {
for (ContourPointData& pt : *it) {
pt.point_consumed = true;
}
}
} else if (params.connection == icHoles) {
for (ContourPointData& pt : boundary_data[0]) {
pt.point_consumed = true;
}
}
assert(boundary_data.size() == boundary_src.holes.size() + 1);
size_t idx_chain_last = 0;
for (ConnectionCost &connection_cost : connections_sorted) {
const std::pair<size_t, size_t> *cp1 = &map_infill_end_point_to_boundary[connection_cost.idx_first * 2 + 1];

View File

@ -38,7 +38,7 @@ struct FillParams
float flow_mult { 1.0f };
// Don't connect the fill lines around the inner perimeter.
bool dont_connect{ false };
InfillConnection connection{ icConnected };
// Don't adjust spacing to fill the space evenly.
bool dont_adjust { true };

View File

@ -193,15 +193,16 @@ void FillGyroid::_fill_surface_single(
polylines = chain_polylines(polylines);
// connect lines
size_t polylines_out_first_idx = polylines_out.size();
if (params.dont_connect)
append(polylines_out, std::move(polylines));
else
if (params.connection == icNotConnected){
append(polylines_out, std::move(polylines));
} else {
this->connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params);
// new paths must be rotated back
if (abs(infill_angle) >= EPSILON) {
for (auto it = polylines_out.begin() + polylines_out_first_idx; it != polylines_out.end(); ++ it)
it->rotate(infill_angle);
}
}
// new paths must be rotated back
if (abs(infill_angle) >= EPSILON) {
for (auto it = polylines_out.begin() + polylines_out_first_idx; it != polylines_out.end(); ++ it)
it->rotate(infill_angle);
}
}
}

View File

@ -89,16 +89,31 @@ void FillRectilinear::_fill_surface_single(
// offset the expolygon by max(min_spacing/2, extra)
ExPolygon expolygon_off;
{
ExPolygons expolygons_off = offset_ex(expolygon, this->_min_spacing/2);
if (! expolygons_off.empty()) {
// When expanding a polygon, the number of islands could only shrink. Therefore the offset_ex shall generate exactly one expanded island for one input island.
assert(expolygons_off.size() == 1);
std::swap(expolygon_off, expolygons_off.front());
if (params.connection == icConnected || params.connection == icHoles) {
ExPolygons expolygons_off = offset_ex(expolygon, this->_min_spacing / 2);
if (!expolygons_off.empty()) {
// When expanding a polygon, the number of islands could only shrink. Therefore the offset_ex shall generate exactly one expanded island for one input island.
assert(expolygons_off.size() == 1);
std::swap(expolygon_off, expolygons_off.front());
}
//restore contour for hole-only.
if (params.connection == icHoles) {
expolygon_off.contour = expolygon.contour;
}
} else if (params.connection == icOuterShell) {
// shrink only the contour
expolygon_off = expolygon;
Polygons bigcontour = offset(expolygon_off.contour, this->_min_spacing / 2);
if (!bigcontour.empty()) {
// When expanding a polygon, the number of islands could only shrink. Therefore the offset_ex shall generate exactly one expanded island for one input island.
assert(bigcontour.size() == 1);
std::swap(expolygon_off.contour, bigcontour.front());
}
}
}
bool first = true;
for (Polyline &polyline : chain_polylines(std::move(polylines))) {
if (!params.dont_connect && !first) {
if (params.connection != icNotConnected && !first) {
// Try to connect the lines.
Points &pts_end = polylines_out.back().points;
const Point &first_point = polyline.points.front();

View File

@ -123,6 +123,8 @@ struct SegmentIntersection
int64_t pos_p{ 0 };
uint32_t pos_q{ 1 };
bool is_hole{ false };
coord_t pos() const {
// Division rounds both positive and negative down to zero.
// Add half of q for an arithmetic rounding effect.
@ -591,8 +593,8 @@ static inline void emit_perimeter_prev_next_segment(
}
static inline coordf_t measure_perimeter_segment_on_vertical_line_length(
const ExPolygonWithOffset &poly_with_offset,
const std::vector<SegmentedIntersectionLine> &segs,
const ExPolygonWithOffset& poly_with_offset,
const std::vector<SegmentedIntersectionLine>& segs,
size_t iVerticalLine,
size_t iIntersection,
size_t iIntersection2,
@ -759,6 +761,7 @@ std::vector<SegmentedIntersectionLine> FillRectilinear2::_vert_lines_for_polygon
}
for (size_t iContour = 0; iContour < poly_with_offset.n_contours; ++ iContour) {
const Points &contour = poly_with_offset.contour(iContour).points;
bool is_hole = poly_with_offset.contour(iContour).is_clockwise();
if (contour.size() < 2)
continue;
// For each segment
@ -791,6 +794,7 @@ std::vector<SegmentedIntersectionLine> FillRectilinear2::_vert_lines_for_polygon
SegmentIntersection is;
is.iContour = iContour;
is.iSegment = iSegment;
is.is_hole = is_hole;
assert(l <= this_x);
assert(r >= this_x);
// Calculate the intersection position in y axis. x is known.
@ -1064,8 +1068,10 @@ static void connect_segment_intersections_by_contours(
itsct.next_on_contour_quality = SegmentIntersection::LinkQuality::Invalid;
}
}
if (params.dont_connect) {
if (params.connection == icNotConnected
|| (params.connection == icOuterShell && itsct.is_hole) // not: don't work as expected because the algo only start from top and go bottom.
|| (params.connection == icHoles && !itsct.is_hole)
) {
if (itsct.prev_on_contour_quality == SegmentIntersection::LinkQuality::Valid)
itsct.prev_on_contour_quality = SegmentIntersection::LinkQuality::TooLong;
if (itsct.next_on_contour_quality == SegmentIntersection::LinkQuality::Valid)
@ -1082,8 +1088,8 @@ static void connect_segment_intersections_by_contours(
measure_perimeter_segment_on_vertical_line_length(poly_with_offset, segs, i_vline, i_intersection, inext, forward) :
measure_perimeter_horizontal_segment_length(poly_with_offset, segs, i_vline, i_intersection, inext)) > link_max_length)
itsct.next_on_contour_quality = SegmentIntersection::LinkQuality::TooLong;
}
}
}
// Make the LinkQuality::Invalid symmetric on vertical connections.
for (size_t i_intersection = 0; i_intersection < il.intersections.size(); ++i_intersection) {
@ -1092,7 +1098,7 @@ static void connect_segment_intersections_by_contours(
SegmentIntersection& it2 = il.intersections[it.left_vertical()];
assert(it2.left_vertical() == i_intersection);
it2.prev_on_contour_quality = SegmentIntersection::LinkQuality::Invalid;
}
}
if (it.has_right_vertical() && it.next_on_contour_quality == SegmentIntersection::LinkQuality::Invalid) {
SegmentIntersection& it2 = il.intersections[it.right_vertical()];
assert(it2.right_vertical() == i_intersection);
@ -2704,7 +2710,7 @@ Polylines FillTriangles::fill_surface(const Surface *surface, const FillParams &
FillParams params2 = params;
params2.density *= 0.333333333f;
FillParams params3 = params2;
params3.dont_connect = true;
params3.connection = icNotConnected;
Polylines polylines_out;
if (! fill_surface_by_lines(surface, params2, 0.f, 0., polylines_out) ||
! fill_surface_by_lines(surface, params2, float(M_PI / 3.), 0., polylines_out) ||
@ -2720,7 +2726,7 @@ Polylines FillStars::fill_surface(const Surface *surface, const FillParams &para
FillParams params2 = params;
params2.density *= 0.333333333f;
FillParams params3 = params2;
params3.dont_connect = true;
params3.connection = icNotConnected;
Polylines polylines_out;
if (! fill_surface_by_lines(surface, params2, 0.f, 0.f, polylines_out) ||
! fill_surface_by_lines(surface, params2, float(M_PI / 3.), 0.f, polylines_out) ||
@ -2736,7 +2742,7 @@ Polylines FillCubic::fill_surface(const Surface *surface, const FillParams &para
FillParams params2 = params;
params2.density *= 0.333333333f;
FillParams params3 = params2;
params3.dont_connect = true;
params3.connection = icNotConnected;
Polylines polylines_out;
coordf_t dx = sqrt(0.5) * z;
if (! fill_surface_by_lines(surface, params2, 0.f, float(dx), polylines_out) ||

View File

@ -1361,7 +1361,7 @@ static bool fill_hatching_segments_legacy(
(distNext < distPrev) :
intrsctn_type_next == INTERSECTION_TYPE_OTHER_VLINE_OK;
assert(intrsctn->is_inner());
bool skip = params.dont_connect || (link_max_length > 0 && (take_next ? distNext : distPrev) > link_max_length);
bool skip = params.connection == icNotConnected || (link_max_length > 0 && (take_next ? distNext : distPrev) > link_max_length);
if (skip) {
// Just skip the connecting contour and start a new path.
goto dont_connect;
@ -1423,7 +1423,7 @@ static bool fill_hatching_segments_legacy(
distance_of_segmens(poly, intrsctn->iSegment, iSegNext, false)) :
(vert_seg_dir_valid_mask == DIR_FORWARD);
// Skip this perimeter line?
bool skip = params.dont_connect;
bool skip = params.connection == icNotConnected;
if (! skip && link_max_length > 0) {
coordf_t link_length = measure_perimeter_segment_on_vertical_line_length(
poly_with_offset, segs, i_vline, intrsctn->iContour, i_intersection, iNext, dir_forward);

View File

@ -1763,12 +1763,23 @@ void PrintConfigDef::init_fff_params()
def->mode = comSimple;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("infill_not_connected", coBool);
def = this->add("infill_connection", coEnum);
def->label = L("Do not connect infill lines to each other");
def->category = OptionCategory::infill;
def->tooltip = L("If checked, the infill algorithm will try to not connect the lines near the infill. Can be useful for art or with high infill/perimeter overlap.");
def->tooltip = L("Give to the infill algorithm if the infill needs to be connected, and on which periemters"
" Can be useful for art or with high infill/perimeter overlap."
" The result amy varies between infill typers.");
def->enum_keys_map = &ConfigOptionEnum<InfillConnection>::get_enum_values();
def->enum_values.push_back("connected");
def->enum_values.push_back("holes");
def->enum_values.push_back("outershell");
def->enum_values.push_back("notconnected");
def->enum_labels.push_back(L("Connected"));
def->enum_labels.push_back(L("Connected to hole perimeters"));
def->enum_labels.push_back(L("Connected to outer perimeters"));
def->enum_labels.push_back(L("Not connected"));
def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(false));
def->set_default_value(new ConfigOptionEnum<InfillConnection>(icConnected));
def = this->add("infill_dense_algo", coEnum);
def->label = L("Algorithm");
@ -4566,6 +4577,12 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
opt_key = "z_step";
float v = boost::lexical_cast<float>(value);
value = boost::lexical_cast<std::string>(1/v);
} else if (opt_key == "infill_not_connected") {
opt_key = "infill_connection";
if (value == "1")
value = "notconnected";
else
value = "connected";
}
// Ignore the following obsolete configuration keys:
@ -4575,10 +4592,11 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
"standby_temperature", "scale", "rotate", "duplicate", "duplicate_grid",
"start_perimeters_at_concave_points", "start_perimeters_at_non_overhang", "randomize_start",
"seal_position", "vibration_limit", "bed_size",
"print_center", "g0", "threads", "pressure_advance", "wipe_tower_per_color_wipe"
"print_center", "g0", "threads", "pressure_advance", "wipe_tower_per_color_wipe",
#ifndef HAS_PRESSURE_EQUALIZER
, "max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative"
"max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative",
#endif /* HAS_PRESSURE_EQUALIZER */
"cooling"
};
if (ignore.find(opt_key) != ignore.end()) {

View File

@ -98,6 +98,10 @@ enum NoPerimeterUnsupportedAlgo {
npuaNone, npuaNoPeri, npuaBridges, npuaBridgesOverhangs, npuaFilled,
};
enum InfillConnection {
icConnected, icHoles, icOuterShell, icNotConnected,
};
enum SupportZDistanceType {
zdFilament, zdPlane, zdNone,
};
@ -247,6 +251,16 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<NoPerimeterUnsupp
return keys_map;
}
template<> inline const t_config_enum_values& ConfigOptionEnum<InfillConnection>::get_enum_values() {
static const t_config_enum_values keys_map = {
{ "connected", icConnected },
{ "holes", icHoles },
{ "outershell", icOuterShell },
{ "notconnected", icNotConnected }
};
return keys_map;
}
template<> inline const t_config_enum_values& ConfigOptionEnum<SupportZDistanceType>::get_enum_values() {
static const t_config_enum_values keys_map = {
{ "filament", zdFilament },
@ -672,7 +686,7 @@ public:
ConfigOptionInt infill_every_layers;
ConfigOptionFloatOrPercent infill_overlap;
ConfigOptionFloat infill_speed;
ConfigOptionBool infill_not_connected;
ConfigOptionEnum<InfillConnection> infill_connection;
ConfigOptionBool infill_dense;
ConfigOptionEnum<DenseInfillAlgo> infill_dense_algo;
ConfigOptionBool infill_first;
@ -763,7 +777,7 @@ protected:
OPT_PTR(infill_overlap);
OPT_PTR(infill_speed);
OPT_PTR(infill_dense);
OPT_PTR(infill_not_connected);
OPT_PTR(infill_connection);
OPT_PTR(infill_dense_algo);
OPT_PTR(infill_first);
OPT_PTR(milling_after_z);

View File

@ -1004,6 +1004,8 @@ void Choice::set_value(const boost::any& value, bool change_event)
val = idx_from_enum_value<DenseInfillAlgo>(val);
else if (m_opt_id.compare("no_perimeter_unsupported_algo") == 0)
val = idx_from_enum_value<NoPerimeterUnsupportedAlgo>(val);
else if (m_opt_id.compare("infill_connection") == 0)
val = idx_from_enum_value<InfillConnection>(val);
else if (m_opt_id.compare("wipe_advanced_algo") == 0)
val = idx_from_enum_value<WipeAlgo>(val);
else if (m_opt_id.compare("support_material_contact_distance_type") == 0)
@ -1089,6 +1091,8 @@ boost::any& Choice::get_value()
convert_to_enum_value<DenseInfillAlgo>(ret_enum);
else if (m_opt_id.compare("no_perimeter_unsupported_algo") == 0)
convert_to_enum_value<NoPerimeterUnsupportedAlgo>(ret_enum);
else if (m_opt_id.compare("infill_connection") == 0)
convert_to_enum_value<InfillConnection>(ret_enum);
else if (m_opt_id.compare("wipe_advanced_algo") == 0)
convert_to_enum_value<WipeAlgo>(ret_enum);
else if (m_opt_id.compare("support_material_contact_distance_type") == 0)

View File

@ -200,18 +200,20 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt
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)
config.set_key_value(opt_key, new ConfigOptionEnum<SeamPosition>(boost::any_cast<SeamPosition>(value)));
else if (opt_key.compare("host_type") == 0)
else if (opt_key.compare("host_type") == 0)
config.set_key_value(opt_key, new ConfigOptionEnum<PrintHostType>(boost::any_cast<PrintHostType>(value)));
else if (opt_key.compare("infill_dense_algo") == 0)
config.set_key_value(opt_key, new ConfigOptionEnum<DenseInfillAlgo>(boost::any_cast<DenseInfillAlgo>(value)));
else if (opt_key.compare("no_perimeter_unsupported_algo") == 0)
config.set_key_value(opt_key, new ConfigOptionEnum<NoPerimeterUnsupportedAlgo>(boost::any_cast<NoPerimeterUnsupportedAlgo>(value)));
config.set_key_value(opt_key, new ConfigOptionEnum<DenseInfillAlgo>(boost::any_cast<DenseInfillAlgo>(value)));
else if (opt_key.compare("infill_connection") == 0)
config.set_key_value(opt_key, new ConfigOptionEnum<InfillConnection>(boost::any_cast<InfillConnection>(value)));
else if (opt_key.compare("wipe_advanced_algo") == 0)
config.set_key_value(opt_key, new ConfigOptionEnum<WipeAlgo>(boost::any_cast<WipeAlgo>(value)));
else if (opt_key.compare("support_material_contact_distance_type") == 0)
config.set_key_value(opt_key, new ConfigOptionEnum<SupportZDistanceType>(boost::any_cast<SupportZDistanceType>(value)));
else if (opt_key.compare("display_orientation") == 0)
config.set_key_value(opt_key, new ConfigOptionEnum<SLADisplayOrientation>(boost::any_cast<SLADisplayOrientation>(value)));
else if (opt_key.compare("display_orientation") == 0)
config.set_key_value(opt_key, new ConfigOptionEnum<SLADisplayOrientation>(boost::any_cast<SLADisplayOrientation>(value)));
else if(opt_key.compare("support_pillar_connection_mode") == 0)
config.set_key_value(opt_key, new ConfigOptionEnum<SLAPillarConnectionMode>(boost::any_cast<SLAPillarConnectionMode>(value)));
}

View File

@ -774,6 +774,9 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config
else if (opt_key.compare("no_perimeter_unsupported_algo") == 0){
ret = static_cast<int>(config.option<ConfigOptionEnum<NoPerimeterUnsupportedAlgo>>(opt_key)->value);
}
else if (opt_key.compare("infill_connection") == 0) {
ret = static_cast<int>(config.option<ConfigOptionEnum<InfillConnection>>(opt_key)->value);
}
else if (opt_key.compare("wipe_advanced_algo") == 0){
ret = static_cast<int>(config.option<ConfigOptionEnum<WipeAlgo>>(opt_key)->value);
}

View File

@ -523,15 +523,15 @@ const std::vector<std::string>& Preset::print_options()
"compatible_printers", "compatible_printers_condition", "inherits",
"infill_dense", "infill_dense_algo",
"no_perimeter_unsupported_algo",
"support_material_solid_first_layer"
, "exact_last_layer_height"
, "perimeter_loop"
, "perimeter_loop_seam"
, "seam_travel"
, "infill_not_connected"
, "first_layer_infill_speed"
, "thin_walls_min_width"
, "thin_walls_overlap",
"support_material_solid_first_layer",
"exact_last_layer_height",
"perimeter_loop",
"perimeter_loop_seam",
"seam_travel",
"infill_connection",
"first_layer_infill_speed",
"thin_walls_min_width",
"thin_walls_overlap",
"thin_walls_speed"
, "model_precision"
, "curve_smoothing_precision"