mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-07-13 04:41:46 +08:00
Fill "connect" update
* re-add the 2.2 algo * allow to choose connection method also for solid/top/bottom
This commit is contained in:
parent
eb06db506a
commit
7a10e8220c
@ -41,12 +41,12 @@ group:Quality
|
||||
end_line
|
||||
group:label_width$12:Overhangs
|
||||
line:threshold for
|
||||
setting:label$Bridge speed and fan:width$5:overhangs_width_speed
|
||||
setting:label$Bridge flow:width$5:overhangs_width
|
||||
setting:label$Bridge speed and fan:width$5:sidetext_width$0:overhangs_width_speed
|
||||
setting:label_width$12:label$Bridge flow:width$5:overhangs_width
|
||||
end_line
|
||||
line:Extrusion direction
|
||||
setting:sidetext_width$1:overhangs_reverse
|
||||
setting:width$5:overhangs_reverse_threshold
|
||||
setting:sidetext_width$2:overhangs_reverse
|
||||
setting:label_width$12:width$5:overhangs_reverse_threshold
|
||||
end_line
|
||||
group:Advanced
|
||||
setting:width$25:no_perimeter_unsupported_algo
|
||||
@ -55,13 +55,13 @@ group:Advanced
|
||||
setting:width$5:gap_fill_min_area
|
||||
end_line
|
||||
line:Seam
|
||||
setting:sidetext_width$2:seam_position
|
||||
setting:label_width$10:width$3:sidetext_width$2:seam_angle_cost
|
||||
setting:label_width$10:width$3:sidetext_width$2:seam_travel_cost
|
||||
setting:label_width$12:sidetext_width$0:seam_position
|
||||
setting:width$3:sidetext_width$0:seam_angle_cost
|
||||
setting:width$3:sidetext_width$0:seam_travel_cost
|
||||
end_line
|
||||
line:One-loop perimeters
|
||||
setting:perimeter_loop
|
||||
setting:perimeter_loop_seam
|
||||
setting:sidetext_width$0:perimeter_loop
|
||||
setting:label_width$5:label$Seam:perimeter_loop_seam
|
||||
end_line
|
||||
group: External perimeter first
|
||||
setting:label$Activate:external_perimeters_first
|
||||
@ -102,28 +102,31 @@ group:Other
|
||||
setting:allow_empty_layers
|
||||
|
||||
page:Infill:infill
|
||||
group:Infill
|
||||
line:Fill density
|
||||
setting:label_width$5:label$_:fill_density
|
||||
setting:width$19:label$_:infill_connection
|
||||
setting:infill_anchor
|
||||
group:title_width$8:Infill
|
||||
line:Sparse
|
||||
setting:width$5:label$_:sidetext_width$1:fill_density
|
||||
setting:label_width$1:label$_:fill_pattern
|
||||
setting:label$_:width$18:infill_connection
|
||||
setting:sidetext_width$7:infill_anchor
|
||||
end_line
|
||||
line:Pattern
|
||||
setting:label_width$5:label$_:fill_pattern
|
||||
line:Solid
|
||||
setting:label_width$11:label$_:solid_fill_pattern
|
||||
setting:label$_:width$18:infill_connection_solid
|
||||
end_line
|
||||
line:External patterns
|
||||
setting:label_width$5:top_fill_pattern
|
||||
setting:label_width$5:bottom_fill_pattern
|
||||
line:Top
|
||||
setting:label_width$11:label$_:top_fill_pattern
|
||||
setting:label$_:width$18:infill_connection_top
|
||||
end_line
|
||||
line:Solid pattern
|
||||
setting:label_width$5:label$_:solid_fill_pattern
|
||||
line:Bottom
|
||||
setting:label_width$11:label$_:bottom_fill_pattern
|
||||
setting:label$_:width$18:infill_connection_bottom
|
||||
end_line
|
||||
group:Reducing printing time
|
||||
setting:infill_every_layers
|
||||
setting:infill_only_where_needed
|
||||
line:Supporting dense layer
|
||||
setting:sidetext_width$0:infill_dense
|
||||
setting:infill_dense_algo
|
||||
setting:width$20:infill_dense_algo
|
||||
end_line
|
||||
group:sidetext_width$3:Advanced
|
||||
setting:solid_infill_every_layers
|
||||
@ -144,13 +147,13 @@ group:Advanced Infill options
|
||||
setting:label_width$8:width$5:fill_smooth_distribution
|
||||
setting:label_width$26:label$Spacing between ironing lines:width$5:sidetext_width$7:fill_smooth_width
|
||||
end_line
|
||||
group:Ironing post-process (This will go on top of infills and perimeters)
|
||||
group:title_width$19:Ironing post-process (This will go on top of infills and perimeters)
|
||||
line:Enable ironing post-process
|
||||
setting:label$_:sidetext_width$0:ironing
|
||||
setting:label$On:ironing_type
|
||||
end_line
|
||||
line:Tuning ironing
|
||||
setting:label_width$8:width$5:ironing_flowrate
|
||||
setting:label_width$9:width$5:ironing_flowrate
|
||||
setting:label_width$26:width$5:ironing_spacing
|
||||
end_line
|
||||
|
||||
@ -183,7 +186,7 @@ group:Raft
|
||||
setting:raft_layers
|
||||
group:Options for support material and raft
|
||||
line:Z-offset
|
||||
setting:width$12:support_material_contact_distance_type
|
||||
setting:width$11:support_material_contact_distance_type
|
||||
setting:width$6:support_material_contact_distance_top
|
||||
setting:width$6:support_material_contact_distance_bottom
|
||||
end_line
|
||||
|
@ -115,16 +115,25 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
||||
params.pattern = region_config.fill_pattern.value;
|
||||
params.density = float(region_config.fill_density) / 100.f;
|
||||
params.dont_adjust = false;
|
||||
params.connection = region_config.infill_connection.value;
|
||||
|
||||
if (surface.has_fill_solid()) {
|
||||
params.density = 1.f;
|
||||
params.pattern = ipRectilinear;
|
||||
params.connection = region_config.infill_connection_solid.value;
|
||||
if (surface.has_pos_top())
|
||||
params.connection = region_config.infill_connection_top.value;
|
||||
if (surface.has_pos_bottom())
|
||||
params.connection = region_config.infill_connection_bottom.value;
|
||||
if (is_bridge)
|
||||
params.connection = InfillConnection::icConnected;
|
||||
if (surface.has_pos_external() && !is_bridge)
|
||||
params.pattern = surface.has_pos_top() ? region_config.top_fill_pattern.value : region_config.bottom_fill_pattern.value;
|
||||
else if (!is_bridge)
|
||||
params.pattern = region_config.solid_fill_pattern.value;
|
||||
} else {
|
||||
|
||||
if (is_bridge)
|
||||
params.connection = InfillConnection::icConnected;
|
||||
if (region_config.infill_dense.getBool()
|
||||
&& region_config.fill_density < 40
|
||||
&& surface.maxNbSolidLayersOnTop == 1) {
|
||||
@ -132,6 +141,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
||||
is_denser = true;
|
||||
is_bridge = true;
|
||||
params.pattern = ipRectiWithPerimeter;
|
||||
params.connection = InfillConnection::icConnected;
|
||||
}
|
||||
if (params.density <= 0)
|
||||
continue;
|
||||
@ -156,7 +166,6 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
||||
}
|
||||
}
|
||||
params.fill_exactly = region_config.enforce_full_fill_volume.getBool();
|
||||
params.connection = region_config.infill_connection.value;
|
||||
params.bridge_angle = float(surface.bridge_angle);
|
||||
if (is_denser) {
|
||||
params.angle = 0;
|
||||
@ -186,7 +195,8 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
||||
if (surface.has_fill_solid() || is_bridge) {
|
||||
params.spacing = params.flow.spacing();
|
||||
// Don't limit anchor length for solid or bridging infill.
|
||||
params.anchor_length = 1000.f;
|
||||
// use old algo to prevent possible weird stuff from sparse bridging
|
||||
params.anchor_length = is_bridge?0:1000.f;
|
||||
} else {
|
||||
// it's internal infill, so we can calculate a generic flow spacing
|
||||
// for all layers, for avoiding the ugly effect of
|
||||
@ -204,8 +214,6 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
||||
params.anchor_length = float(region_config.infill_anchor);
|
||||
if (region_config.infill_anchor.percent)
|
||||
params.anchor_length *= 0.01 * params.spacing;
|
||||
// Don't limit anchor length for solid or bridging infill.
|
||||
//FIXEME: totest params.anchor_length = 1000.f;
|
||||
}
|
||||
|
||||
auto it_params = set_surface_params.find(params);
|
||||
|
@ -212,12 +212,66 @@ coord_t Fill::_line_spacing_for_density(float density) const
|
||||
return coord_t(scale_(this->get_spacing()) / density);
|
||||
}
|
||||
|
||||
//FIXME: add recent improvmeent from perimetergenerator: avoid thick gapfill
|
||||
void
|
||||
Fill::do_gap_fill(const ExPolygons& gapfill_areas, const FillParams& params, ExtrusionEntitiesPtr& coll_out) const {
|
||||
|
||||
ThickPolylines polylines_gapfill;
|
||||
double min = 0.4 * scale_(params.flow.nozzle_diameter) * (1 - INSET_OVERLAP_TOLERANCE);
|
||||
double max = 2. * params.flow.scaled_width();
|
||||
// collapse
|
||||
//be sure we don't gapfill where the perimeters are already touching each other (negative spacing).
|
||||
min = std::max(min, double(Flow::new_from_spacing((float)EPSILON, (float)params.flow.nozzle_diameter, (float)params.flow.height, false).scaled_width()));
|
||||
//ExPolygons gapfill_areas_collapsed = diff_ex(
|
||||
// offset2_ex(gapfill_areas, double(-min / 2), double(+min / 2)),
|
||||
// offset2_ex(gapfill_areas, double(-max / 2), double(+max / 2)),
|
||||
// true);
|
||||
ExPolygons gapfill_areas_collapsed = offset2_ex(gapfill_areas, double(-min / 2), double(+min / 2));
|
||||
double minarea = params.flow.scaled_width() * params.flow.scaled_width();
|
||||
if (params.config != nullptr) minarea = scale_(params.config->gap_fill_min_area.get_abs_value(params.flow.width)) * params.flow.scaled_width();
|
||||
for (const ExPolygon& ex : gapfill_areas_collapsed) {
|
||||
//remove too small gaps that are too hard to fill.
|
||||
//ie one that are smaller than an extrusion with width of min and a length of max.
|
||||
if (ex.area() > minarea) {
|
||||
MedialAxis{ ex, params.flow.scaled_width() * 2, params.flow.scaled_width() / 5, coord_t(params.flow.height) }.build(polylines_gapfill);
|
||||
}
|
||||
}
|
||||
if (!polylines_gapfill.empty() && params.role != erBridgeInfill && params.role != erInternalBridgeInfill) {
|
||||
//test
|
||||
#ifdef _DEBUG
|
||||
for (ThickPolyline poly : polylines_gapfill) {
|
||||
for (coordf_t width : poly.width) {
|
||||
if (width > params.flow.scaled_width() * 2.2) {
|
||||
std::cerr << "ERRROR!!!! gapfill width = " << unscaled(width) << " > max_width = " << (params.flow.width * 2) << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ExtrusionEntityCollection gap_fill = thin_variable_width(polylines_gapfill, erGapFill, params.flow);
|
||||
//set role if needed
|
||||
/*if (params.role != erSolidInfill) {
|
||||
ExtrusionSetRole set_good_role(params.role);
|
||||
gap_fill.visit(set_good_role);
|
||||
}*/
|
||||
//move them into the collection
|
||||
if (!gap_fill.entities.empty()) {
|
||||
ExtrusionEntityCollection* coll_gapfill = new ExtrusionEntityCollection();
|
||||
coll_gapfill->no_sort = this->no_sort();
|
||||
coll_gapfill->append(std::move(gap_fill.entities));
|
||||
coll_out.push_back(coll_gapfill);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace NaiveConnect {
|
||||
|
||||
/// cut poly between poly.point[idx_1] & poly.point[idx_1+1]
|
||||
/// add p1+-width to one part and p2+-width to the other one.
|
||||
/// add the "new" polyline to polylines (to part cut from poly)
|
||||
/// p1 & p2 have to be between poly.point[idx_1] & poly.point[idx_1+1]
|
||||
/// if idx_1 is ==0 or == size-1, then we don't need to create a new polyline.
|
||||
void cut_polyline(Polyline &poly, Polylines &polylines, size_t idx_1, Point p1, Point p2) {
|
||||
void cut_polyline(Polyline& poly, Polylines& polylines, size_t idx_1, Point p1, Point p2) {
|
||||
//reorder points
|
||||
if (p1.distance_to_square(poly.points[idx_1]) > p2.distance_to_square(poly.points[idx_1])) {
|
||||
Point temp = p2;
|
||||
@ -245,7 +299,7 @@ void cut_polyline(Polyline &poly, Polylines &polylines, size_t idx_1, Point p1,
|
||||
}
|
||||
|
||||
/// the poly is like a polygon but with first_point != last_point (already removed)
|
||||
void cut_polygon(Polyline &poly, size_t idx_1, Point p1, Point p2) {
|
||||
void cut_polygon(Polyline& poly, size_t idx_1, Point p1, Point p2) {
|
||||
//reorder points
|
||||
if (p1.distance_to_square(poly.points[idx_1]) > p2.distance_to_square(poly.points[idx_1])) {
|
||||
Point temp = p2;
|
||||
@ -267,15 +321,15 @@ void cut_polygon(Polyline &poly, size_t idx_1, Point p1, Point p2) {
|
||||
/// it use equally_spaced_points with width/2 precision, so don't worry with pts_to_check number of points.
|
||||
/// it use the given polylines_blocker points, be sure to put enough of them to be reliable.
|
||||
/// complexity : N(pts_to_check.equally_spaced_points(width / 2)) x N(polylines_blocker.points)
|
||||
bool collision(const Points &pts_to_check, const Polylines &polylines_blocker, const coord_t width) {
|
||||
bool collision(const Points& pts_to_check, const Polylines& polylines_blocker, const coord_t width) {
|
||||
//check if it's not too close to a polyline
|
||||
//convert to double to allow ² operation
|
||||
double min_dist_square = (double)width * (double)width * 0.9 - SCALED_EPSILON;
|
||||
Polyline better_polylines(pts_to_check);
|
||||
Points better_pts = better_polylines.equally_spaced_points(double(width / 2));
|
||||
for (const Point &p : better_pts) {
|
||||
for (const Polyline &poly2 : polylines_blocker) {
|
||||
for (const Point &p2 : poly2.points) {
|
||||
for (const Point& p : better_pts) {
|
||||
for (const Polyline& poly2 : polylines_blocker) {
|
||||
for (const Point& p2 : poly2.points) {
|
||||
if (p.distance_to_square(p2) < min_dist_square) {
|
||||
return true;
|
||||
}
|
||||
@ -291,9 +345,9 @@ bool collision(const Points &pts_to_check, const Polylines &polylines_blocker, c
|
||||
/// complexity: N(polylines.points) + a collision check after that if we finded a path: N(2(p2-p1)/width) x N(polylines_blocker.points)
|
||||
/// @param width is scaled
|
||||
/// @param max_size is scaled
|
||||
Points getFrontier(Polylines &polylines, const Point& p1, const Point& p2, const coord_t width, const Polylines &polylines_blockers, coord_t max_size = -1) {
|
||||
Points getFrontier(Polylines& polylines, const Point& p1, const Point& p2, const coord_t width, const Polylines& polylines_blockers, coord_t max_size = -1) {
|
||||
for (size_t idx_poly = 0; idx_poly < polylines.size(); ++idx_poly) {
|
||||
Polyline &poly = polylines[idx_poly];
|
||||
Polyline& poly = polylines[idx_poly];
|
||||
if (poly.size() <= 1) continue;
|
||||
|
||||
//loop?
|
||||
@ -333,7 +387,7 @@ Points getFrontier(Polylines &polylines, const Point& p1, const Point& p2, const
|
||||
Points ret_1_to_2;
|
||||
double dist_1_to_2 = p1.distance_to(poly.points[idx_12]);
|
||||
ret_1_to_2.push_back(poly.points[idx_12]);
|
||||
size_t max = idx_12 <= idx_21 ? idx_21+1 : poly.points.size();
|
||||
size_t max = idx_12 <= idx_21 ? idx_21 + 1 : poly.points.size();
|
||||
for (size_t i = idx_12 + 1; i < max; i++) {
|
||||
dist_1_to_2 += poly.points[i - 1].distance_to(poly.points[i]);
|
||||
ret_1_to_2.push_back(poly.points[i]);
|
||||
@ -469,15 +523,14 @@ Points getFrontier(Polylines &polylines, const Point& p1, const Point& p2, const
|
||||
/// return the connected polylines in polylines_out. Can output polygons (stored as polylines with first_point = last_point).
|
||||
/// complexity: worst: N(infill_ordered.points) x N(boundary.points)
|
||||
/// typical: N(infill_ordered) x ( N(boundary.points) + N(infill_ordered.points) )
|
||||
void
|
||||
Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const FillParams ¶ms) const {
|
||||
void connect_infill(const Polylines& infill_ordered, const ExPolygon& boundary, Polylines& polylines_out, const double spacing, const FillParams& params) {
|
||||
|
||||
//TODO: fallback to the quick & dirty old algorithm when n(points) is too high.
|
||||
Polylines polylines_frontier = to_polylines(((Polygons)boundary));
|
||||
|
||||
Polylines polylines_blocker;
|
||||
coord_t clip_size = scale_(this->get_spacing()) * 2;
|
||||
for (const Polyline &polyline : infill_ordered) {
|
||||
coord_t clip_size = scale_(spacing) * 2;
|
||||
for (const Polyline& polyline : infill_ordered) {
|
||||
if (polyline.length() > 2.01 * clip_size) {
|
||||
polylines_blocker.push_back(polyline);
|
||||
polylines_blocker.back().clip_end((double)clip_size);
|
||||
@ -486,18 +539,18 @@ Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary,
|
||||
}
|
||||
|
||||
//length between two lines
|
||||
coordf_t ideal_length = (1 / params.density) * this->get_spacing();
|
||||
coordf_t ideal_length = (1 / params.density) * spacing;
|
||||
|
||||
Polylines polylines_connected_first;
|
||||
bool first = true;
|
||||
for (const Polyline &polyline : infill_ordered) {
|
||||
for (const Polyline& polyline : infill_ordered) {
|
||||
if (!first) {
|
||||
// Try to connect the lines.
|
||||
Points &pts_end = polylines_connected_first.back().points;
|
||||
const Point &last_point = pts_end.back();
|
||||
const Point &first_point = polyline.points.front();
|
||||
if (last_point.distance_to(first_point) < scale_(this->get_spacing()) * 10) {
|
||||
Points pts_frontier = getFrontier(polylines_frontier, last_point, first_point, scale_(this->get_spacing()), polylines_blocker, scale_(ideal_length) * 2);
|
||||
Points& pts_end = polylines_connected_first.back().points;
|
||||
const Point& last_point = pts_end.back();
|
||||
const Point& first_point = polyline.points.front();
|
||||
if (last_point.distance_to(first_point) < scale_(spacing) * 10) {
|
||||
Points pts_frontier = getFrontier(polylines_frontier, last_point, first_point, scale_(spacing), polylines_blocker, scale_(ideal_length) * 2);
|
||||
if (!pts_frontier.empty()) {
|
||||
// The lines can be connected.
|
||||
pts_end.insert(pts_end.end(), pts_frontier.begin(), pts_frontier.end());
|
||||
@ -514,15 +567,15 @@ Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary,
|
||||
|
||||
Polylines polylines_connected;
|
||||
first = true;
|
||||
for (const Polyline &polyline : polylines_connected_first) {
|
||||
for (const Polyline& polyline : polylines_connected_first) {
|
||||
if (!first) {
|
||||
// Try to connect the lines.
|
||||
Points &pts_end = polylines_connected.back().points;
|
||||
const Point &last_point = pts_end.back();
|
||||
const Point &first_point = polyline.points.front();
|
||||
Points& pts_end = polylines_connected.back().points;
|
||||
const Point& last_point = pts_end.back();
|
||||
const Point& first_point = polyline.points.front();
|
||||
|
||||
Polylines before = polylines_frontier;
|
||||
Points pts_frontier = getFrontier(polylines_frontier, last_point, first_point, scale_(this->get_spacing()), polylines_blocker);
|
||||
Points pts_frontier = getFrontier(polylines_frontier, last_point, first_point, scale_(spacing), polylines_blocker);
|
||||
if (!pts_frontier.empty()) {
|
||||
// The lines can be connected.
|
||||
pts_end.insert(pts_end.end(), pts_frontier.begin(), pts_frontier.end());
|
||||
@ -555,15 +608,15 @@ Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary,
|
||||
min_length = min;
|
||||
}
|
||||
}
|
||||
if (min_idx > idx1 && min_idx < polylines_connected.size()){
|
||||
Points pts_frontier = getFrontier(polylines_frontier,
|
||||
switch_id1 ? polylines_connected[idx1].first_point() : polylines_connected[idx1].last_point(),
|
||||
if (min_idx > idx1&& min_idx < polylines_connected.size()) {
|
||||
Points pts_frontier = getFrontier(polylines_frontier,
|
||||
switch_id1 ? polylines_connected[idx1].first_point() : polylines_connected[idx1].last_point(),
|
||||
switch_id2 ? polylines_connected[min_idx].last_point() : polylines_connected[min_idx].first_point(),
|
||||
scale_(this->get_spacing()), polylines_blocker);
|
||||
scale_(spacing), polylines_blocker);
|
||||
if (!pts_frontier.empty()) {
|
||||
if (switch_id1) polylines_connected[idx1].reverse();
|
||||
if (switch_id2) polylines_connected[min_idx].reverse();
|
||||
Points &pts_end = polylines_connected[idx1].points;
|
||||
Points& pts_end = polylines_connected[idx1].points;
|
||||
pts_end.insert(pts_end.end(), pts_frontier.begin(), pts_frontier.end());
|
||||
pts_end.insert(pts_end.end(), polylines_connected[min_idx].points.begin(), polylines_connected[min_idx].points.end());
|
||||
polylines_connected.erase(polylines_connected.begin() + min_idx);
|
||||
@ -572,8 +625,8 @@ Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary,
|
||||
}
|
||||
|
||||
//try to create some loops if possible
|
||||
for (Polyline &polyline : polylines_connected) {
|
||||
Points pts_frontier = getFrontier(polylines_frontier, polyline.last_point(), polyline.first_point(), scale_(this->get_spacing()), polylines_blocker);
|
||||
for (Polyline& polyline : polylines_connected) {
|
||||
Points pts_frontier = getFrontier(polylines_frontier, polyline.last_point(), polyline.first_point(), scale_(spacing), polylines_blocker);
|
||||
if (!pts_frontier.empty()) {
|
||||
polyline.points.insert(polyline.points.end(), pts_frontier.begin(), pts_frontier.end());
|
||||
polyline.points.insert(polyline.points.begin(), polyline.points.back());
|
||||
@ -582,59 +635,513 @@ Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace PrusaSimpleConnect {
|
||||
|
||||
void
|
||||
Fill::do_gap_fill(const ExPolygons &gapfill_areas, const FillParams ¶ms, ExtrusionEntitiesPtr &coll_out) const {
|
||||
struct ContourPointData {
|
||||
ContourPointData(float param) : param(param) {}
|
||||
// Eucleidean position of the contour point along the contour.
|
||||
float param = 0.f;
|
||||
// Was the segment starting with this contour point extruded?
|
||||
bool segment_consumed = false;
|
||||
// Was this point extruded over?
|
||||
bool point_consumed = false;
|
||||
};
|
||||
|
||||
ThickPolylines polylines_gapfill;
|
||||
double min = 0.4 * scale_(params.flow.nozzle_diameter) * (1 - INSET_OVERLAP_TOLERANCE);
|
||||
double max = 2. * params.flow.scaled_width();
|
||||
// collapse
|
||||
//be sure we don't gapfill where the perimeters are already touching each other (negative spacing).
|
||||
min = std::max(min, double(Flow::new_from_spacing((float)EPSILON, (float)params.flow.nozzle_diameter, (float)params.flow.height, false).scaled_width()));
|
||||
//ExPolygons gapfill_areas_collapsed = diff_ex(
|
||||
// offset2_ex(gapfill_areas, double(-min / 2), double(+min / 2)),
|
||||
// offset2_ex(gapfill_areas, double(-max / 2), double(+max / 2)),
|
||||
// true);
|
||||
ExPolygons gapfill_areas_collapsed = offset2_ex(gapfill_areas, double(-min / 2), double(+min / 2));
|
||||
double minarea = params.flow.scaled_width() * params.flow.scaled_width();
|
||||
if (params.config != nullptr) minarea = scale_(params.config->gap_fill_min_area.get_abs_value(params.flow.width)) * params.flow.scaled_width();
|
||||
for (const ExPolygon &ex : gapfill_areas_collapsed) {
|
||||
//remove too small gaps that are too hard to fill.
|
||||
//ie one that are smaller than an extrusion with width of min and a length of max.
|
||||
if (ex.area() > minarea) {
|
||||
MedialAxis{ ex, params.flow.scaled_width() * 2, params.flow.scaled_width() / 5, coord_t(params.flow.height) }.build(polylines_gapfill);
|
||||
// Verify whether the contour from point idx_start to point idx_end could be taken (whether all segments along the contour were not yet extruded).
|
||||
static bool could_take(const std::vector<ContourPointData>& contour_data, size_t idx_start, size_t idx_end)
|
||||
{
|
||||
assert(idx_start != idx_end);
|
||||
for (size_t i = idx_start; i != idx_end; ) {
|
||||
if (contour_data[i].segment_consumed || contour_data[i].point_consumed)
|
||||
return false;
|
||||
if (++i == contour_data.size())
|
||||
i = 0;
|
||||
}
|
||||
return !contour_data[idx_end].point_consumed;
|
||||
}
|
||||
if (!polylines_gapfill.empty() && params.role != erBridgeInfill && params.role != erInternalBridgeInfill) {
|
||||
//test
|
||||
#ifdef _DEBUG
|
||||
for (ThickPolyline poly : polylines_gapfill) {
|
||||
for (coordf_t width : poly.width) {
|
||||
if (width > params.flow.scaled_width() * 2.2) {
|
||||
std::cerr << "ERRROR!!!! gapfill width = " << unscaled(width) << " > max_width = " << (params.flow.width * 2) << "\n";
|
||||
|
||||
// Connect end of pl1 to the start of pl2 using the perimeter contour.
|
||||
// The idx_start and idx_end are ordered so that the connecting polyline points will be taken with increasing indices.
|
||||
static void take(Polyline& pl1, Polyline&& pl2, const Points& contour, std::vector<ContourPointData>& contour_data, size_t idx_start, size_t idx_end, bool reversed)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
size_t num_points_initial = pl1.points.size();
|
||||
assert(idx_start != idx_end);
|
||||
#endif /* NDEBUG */
|
||||
|
||||
{
|
||||
// Reserve memory at pl1 for the connecting contour and pl2.
|
||||
int new_points = int(idx_end) - int(idx_start) - 1;
|
||||
if (new_points < 0)
|
||||
new_points += int(contour.size());
|
||||
pl1.points.reserve(pl1.points.size() + size_t(new_points) + pl2.points.size());
|
||||
}
|
||||
|
||||
contour_data[idx_start].point_consumed = true;
|
||||
contour_data[idx_start].segment_consumed = true;
|
||||
contour_data[idx_end].point_consumed = true;
|
||||
|
||||
if (reversed) {
|
||||
size_t i = (idx_end == 0) ? contour_data.size() - 1 : idx_end - 1;
|
||||
while (i != idx_start) {
|
||||
contour_data[i].point_consumed = true;
|
||||
contour_data[i].segment_consumed = true;
|
||||
pl1.points.emplace_back(contour[i]);
|
||||
if (i == 0)
|
||||
i = contour_data.size();
|
||||
--i;
|
||||
}
|
||||
} else {
|
||||
size_t i = idx_start;
|
||||
if (++i == contour_data.size())
|
||||
i = 0;
|
||||
while (i != idx_end) {
|
||||
contour_data[i].point_consumed = true;
|
||||
contour_data[i].segment_consumed = true;
|
||||
pl1.points.emplace_back(contour[i]);
|
||||
if (++i == contour_data.size())
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
append(pl1.points, std::move(pl2.points));
|
||||
}
|
||||
|
||||
// Return an index of start of a segment and a point of the clipping point at distance from the end of polyline.
|
||||
struct SegmentPoint {
|
||||
// Segment index, defining a line <idx_segment, idx_segment + 1).
|
||||
size_t idx_segment = std::numeric_limits<size_t>::max();
|
||||
// Parameter of point in <0, 1) along the line <idx_segment, idx_segment + 1)
|
||||
double t;
|
||||
Vec2d point;
|
||||
|
||||
bool valid() const { return idx_segment != std::numeric_limits<size_t>::max(); }
|
||||
};
|
||||
|
||||
static inline SegmentPoint clip_start_segment_and_point(const Points& polyline, double distance)
|
||||
{
|
||||
assert(polyline.size() >= 2);
|
||||
assert(distance > 0.);
|
||||
// Initialized to "invalid".
|
||||
SegmentPoint out;
|
||||
if (polyline.size() >= 2) {
|
||||
Vec2d pt_prev = polyline.front().cast<double>();
|
||||
for (size_t i = 1; i < polyline.size(); ++i) {
|
||||
Vec2d pt = polyline[i].cast<double>();
|
||||
Vec2d v = pt - pt_prev;
|
||||
double l2 = v.squaredNorm();
|
||||
if (l2 > distance* distance) {
|
||||
out.idx_segment = i;
|
||||
out.t = distance / sqrt(l2);
|
||||
out.point = pt_prev + out.t * v;
|
||||
break;
|
||||
}
|
||||
distance -= sqrt(l2);
|
||||
pt_prev = pt;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline SegmentPoint clip_end_segment_and_point(const Points& polyline, double distance)
|
||||
{
|
||||
assert(polyline.size() >= 2);
|
||||
assert(distance > 0.);
|
||||
// Initialized to "invalid".
|
||||
SegmentPoint out;
|
||||
if (polyline.size() >= 2) {
|
||||
Vec2d pt_next = polyline.back().cast<double>();
|
||||
for (int i = int(polyline.size()) - 2; i >= 0; --i) {
|
||||
Vec2d pt = polyline[i].cast<double>();
|
||||
Vec2d v = pt - pt_next;
|
||||
double l2 = v.squaredNorm();
|
||||
if (l2 > distance* distance) {
|
||||
out.idx_segment = i;
|
||||
out.t = distance / sqrt(l2);
|
||||
out.point = pt_next + out.t * v;
|
||||
// Store the parameter referenced to the starting point of a segment.
|
||||
out.t = 1. - out.t;
|
||||
break;
|
||||
}
|
||||
distance -= sqrt(l2);
|
||||
pt_next = pt;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Optimized version with the precalculated v1 = p1b - p1a and l1_2 = v1.squaredNorm().
|
||||
// Assumption: l1_2 < EPSILON.
|
||||
static inline double segment_point_distance_squared(const Vec2d& p1a, const Vec2d& p1b, const Vec2d& v1, const double l1_2, const Vec2d& p2)
|
||||
{
|
||||
assert(l1_2 > EPSILON);
|
||||
Vec2d v12 = p2 - p1a;
|
||||
double t = v12.dot(v1);
|
||||
return (t <= 0.) ? v12.squaredNorm() :
|
||||
(t >= l1_2) ? (p2 - p1a).squaredNorm() :
|
||||
((t / l1_2) * v1 - v12).squaredNorm();
|
||||
}
|
||||
|
||||
static inline double segment_point_distance_squared(const Vec2d& p1a, const Vec2d& p1b, const Vec2d& p2)
|
||||
{
|
||||
const Vec2d v = p1b - p1a;
|
||||
const double l2 = v.squaredNorm();
|
||||
if (l2 < EPSILON)
|
||||
// p1a == p1b
|
||||
return (p2 - p1a).squaredNorm();
|
||||
return segment_point_distance_squared(p1a, p1b, v, v.squaredNorm(), p2);
|
||||
}
|
||||
|
||||
// Distance to the closest point of line.
|
||||
static inline double min_distance_of_segments(const Vec2d& p1a, const Vec2d& p1b, const Vec2d& p2a, const Vec2d& p2b)
|
||||
{
|
||||
Vec2d v1 = p1b - p1a;
|
||||
double l1_2 = v1.squaredNorm();
|
||||
if (l1_2 < EPSILON)
|
||||
// p1a == p1b: Return distance of p1a from the (p2a, p2b) segment.
|
||||
return segment_point_distance_squared(p2a, p2b, p1a);
|
||||
|
||||
Vec2d v2 = p2b - p2a;
|
||||
double l2_2 = v2.squaredNorm();
|
||||
if (l2_2 < EPSILON)
|
||||
// p2a == p2b: Return distance of p2a from the (p1a, p1b) segment.
|
||||
return segment_point_distance_squared(p1a, p1b, v1, l1_2, p2a);
|
||||
|
||||
return std::min(
|
||||
std::min(segment_point_distance_squared(p1a, p1b, v1, l1_2, p2a), segment_point_distance_squared(p1a, p1b, v1, l1_2, p2b)),
|
||||
std::min(segment_point_distance_squared(p2a, p2b, v2, l2_2, p1a), segment_point_distance_squared(p2a, p2b, v2, l2_2, p1b)));
|
||||
}
|
||||
|
||||
// Mark the segments of split boundary as consumed if they are very close to some of the infill line.
|
||||
void mark_boundary_segments_touching_infill(
|
||||
const std::vector<Points>& boundary,
|
||||
std::vector<std::vector<ContourPointData>>& boundary_data,
|
||||
const BoundingBox& boundary_bbox,
|
||||
const Polylines& infill,
|
||||
const double clip_distance,
|
||||
const double distance_colliding)
|
||||
{
|
||||
EdgeGrid::Grid grid;
|
||||
grid.set_bbox(boundary_bbox.inflated(distance_colliding * 1.43));
|
||||
// Inflate the bounding box by a thick line width.
|
||||
grid.create(boundary, coord_t(clip_distance + scale_(10.)));
|
||||
|
||||
struct Visitor {
|
||||
Visitor(const EdgeGrid::Grid& grid, const std::vector<Points>& boundary, std::vector<std::vector<ContourPointData>>& boundary_data, const double dist2_max) :
|
||||
grid(grid), boundary(boundary), boundary_data(boundary_data), dist2_max(dist2_max) {}
|
||||
|
||||
void init(const Vec2d& pt1, const Vec2d& pt2) {
|
||||
this->pt1 = &pt1;
|
||||
this->pt2 = &pt2;
|
||||
}
|
||||
|
||||
bool operator()(coord_t iy, coord_t ix) {
|
||||
// Called with a row and colum of the grid cell, which is intersected by a line.
|
||||
auto cell_data_range = this->grid.cell_data_range(iy, ix);
|
||||
for (auto it_contour_and_segment = cell_data_range.first; it_contour_and_segment != cell_data_range.second; ++it_contour_and_segment) {
|
||||
// End points of the line segment and their vector.
|
||||
auto segment = this->grid.segment(*it_contour_and_segment);
|
||||
const Vec2d seg_pt1 = segment.first.cast<double>();
|
||||
const Vec2d seg_pt2 = segment.second.cast<double>();
|
||||
if (min_distance_of_segments(seg_pt1, seg_pt2, *this->pt1, *this->pt2) < this->dist2_max) {
|
||||
// Mark this boundary segment as touching the infill line.
|
||||
ContourPointData& bdp = boundary_data[it_contour_and_segment->first][it_contour_and_segment->second];
|
||||
bdp.segment_consumed = true;
|
||||
// There is no need for checking seg_pt2 as it will be checked the next time.
|
||||
bool point_touching = false;
|
||||
if (segment_point_distance_squared(*this->pt1, *this->pt2, seg_pt1) < this->dist2_max) {
|
||||
point_touching = true;
|
||||
bdp.point_consumed = true;
|
||||
}
|
||||
#if 0
|
||||
{
|
||||
static size_t iRun = 0;
|
||||
ExPolygon expoly(Polygon(*grid.contours().front()));
|
||||
for (size_t i = 1; i < grid.contours().size(); ++i)
|
||||
expoly.holes.emplace_back(Polygon(*grid.contours()[i]));
|
||||
SVG svg(debug_out_path("%s-%d.svg", "FillBase-mark_boundary_segments_touching_infill", iRun++).c_str(), get_extents(expoly));
|
||||
svg.draw(expoly, "green");
|
||||
svg.draw(Line(segment.first, segment.second), "red");
|
||||
svg.draw(Line(this->pt1->cast<coord_t>(), this->pt2->cast<coord_t>()), "magenta");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
// Continue traversing the grid along the edge.
|
||||
return true;
|
||||
}
|
||||
|
||||
const EdgeGrid::Grid& grid;
|
||||
const std::vector<Points>& boundary;
|
||||
std::vector<std::vector<ContourPointData>>& boundary_data;
|
||||
// Maximum distance between the boundary and the infill line allowed to consider the boundary not touching the infill line.
|
||||
const double dist2_max;
|
||||
|
||||
const Vec2d* pt1;
|
||||
const Vec2d* pt2;
|
||||
} visitor(grid, boundary, boundary_data, distance_colliding * distance_colliding);
|
||||
|
||||
BoundingBoxf bboxf(boundary_bbox.min.cast<double>(), boundary_bbox.max.cast<double>());
|
||||
bboxf.offset(coordf_t(-SCALED_EPSILON));
|
||||
|
||||
for (const Polyline& polyline : infill) {
|
||||
// Clip the infill polyline by the Eucledian distance along the polyline.
|
||||
SegmentPoint start_point = clip_start_segment_and_point(polyline.points, clip_distance);
|
||||
SegmentPoint end_point = clip_end_segment_and_point(polyline.points, clip_distance);
|
||||
if (start_point.valid() && end_point.valid() &&
|
||||
(start_point.idx_segment < end_point.idx_segment || (start_point.idx_segment == end_point.idx_segment && start_point.t < end_point.t))) {
|
||||
// The clipped polyline is non-empty.
|
||||
for (size_t point_idx = start_point.idx_segment; point_idx <= end_point.idx_segment; ++point_idx) {
|
||||
//FIXME extend the EdgeGrid to suport tracing a thick line.
|
||||
#if 0
|
||||
Point pt1, pt2;
|
||||
Vec2d pt1d, pt2d;
|
||||
if (point_idx == start_point.idx_segment) {
|
||||
pt1d = start_point.point;
|
||||
pt1 = pt1d.cast<coord_t>();
|
||||
} else {
|
||||
pt1 = polyline.points[point_idx];
|
||||
pt1d = pt1.cast<double>();
|
||||
}
|
||||
if (point_idx == start_point.idx_segment) {
|
||||
pt2d = end_point.point;
|
||||
pt2 = pt1d.cast<coord_t>();
|
||||
} else {
|
||||
pt2 = polyline.points[point_idx];
|
||||
pt2d = pt2.cast<double>();
|
||||
}
|
||||
visitor.init(pt1d, pt2d);
|
||||
grid.visit_cells_intersecting_thick_line(pt1, pt2, distance_colliding, visitor);
|
||||
#else
|
||||
Vec2d pt1 = (point_idx == start_point.idx_segment) ? start_point.point : polyline.points[point_idx].cast<double>();
|
||||
Vec2d pt2 = (point_idx == end_point.idx_segment) ? end_point.point : polyline.points[point_idx + 1].cast<double>();
|
||||
#if 0
|
||||
{
|
||||
static size_t iRun = 0;
|
||||
ExPolygon expoly(Polygon(*grid.contours().front()));
|
||||
for (size_t i = 1; i < grid.contours().size(); ++i)
|
||||
expoly.holes.emplace_back(Polygon(*grid.contours()[i]));
|
||||
SVG svg(debug_out_path("%s-%d.svg", "FillBase-mark_boundary_segments_touching_infill0", iRun++).c_str(), get_extents(expoly));
|
||||
svg.draw(expoly, "green");
|
||||
svg.draw(polyline, "blue");
|
||||
svg.draw(Line(pt1.cast<coord_t>(), pt2.cast<coord_t>()), "magenta", scale_(0.1));
|
||||
}
|
||||
#endif
|
||||
visitor.init(pt1, pt2);
|
||||
// Simulate tracing of a thick line. This only works reliably if distance_colliding <= grid cell size.
|
||||
Vec2d v = (pt2 - pt1).normalized() * distance_colliding;
|
||||
Vec2d vperp(-v.y(), v.x());
|
||||
Vec2d a = pt1 - v - vperp;
|
||||
Vec2d b = pt1 + v - vperp;
|
||||
if (Geometry::liang_barsky_line_clipping(a, b, bboxf))
|
||||
grid.visit_cells_intersecting_line(a.cast<coord_t>(), b.cast<coord_t>(), visitor);
|
||||
a = pt1 - v + vperp;
|
||||
b = pt1 + v + vperp;
|
||||
if (Geometry::liang_barsky_line_clipping(a, b, bboxf))
|
||||
grid.visit_cells_intersecting_line(a.cast<coord_t>(), b.cast<coord_t>(), visitor);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ExtrusionEntityCollection gap_fill = thin_variable_width(polylines_gapfill, erGapFill, params.flow);
|
||||
//set role if needed
|
||||
/*if (params.role != erSolidInfill) {
|
||||
ExtrusionSetRole set_good_role(params.role);
|
||||
gap_fill.visit(set_good_role);
|
||||
}*/
|
||||
//move them into the collection
|
||||
if (!gap_fill.entities.empty()) {
|
||||
ExtrusionEntityCollection *coll_gapfill = new ExtrusionEntityCollection();
|
||||
coll_gapfill->no_sort = this->no_sort();
|
||||
coll_gapfill->append(std::move(gap_fill.entities));
|
||||
coll_out.push_back(coll_gapfill);
|
||||
void connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary_src, Polylines &polylines_out, const double spacing, const FillParams ¶ms)
|
||||
{
|
||||
assert(!infill_ordered.empty());
|
||||
assert(!boundary_src.contour.points.empty());
|
||||
|
||||
BoundingBox bbox = get_extents(boundary_src.contour);
|
||||
bbox.offset(coordf_t(SCALED_EPSILON));
|
||||
|
||||
// 1) Add the end points of infill_ordered to boundary_src.
|
||||
std::vector<Points> boundary;
|
||||
std::vector<std::vector<ContourPointData>> boundary_data;
|
||||
boundary.assign(boundary_src.holes.size() + 1, Points());
|
||||
boundary_data.assign(boundary_src.holes.size() + 1, std::vector<ContourPointData>());
|
||||
// Mapping the infill_ordered end point to a (contour, point) of boundary.
|
||||
std::vector<std::pair<size_t, size_t>> map_infill_end_point_to_boundary;
|
||||
static constexpr auto boundary_idx_unconnected = std::numeric_limits<size_t>::max();
|
||||
map_infill_end_point_to_boundary.assign(infill_ordered.size() * 2, std::pair<size_t, size_t>(boundary_idx_unconnected, boundary_idx_unconnected));
|
||||
{
|
||||
// Project the infill_ordered end points onto boundary_src.
|
||||
std::vector<std::pair<EdgeGrid::Grid::ClosestPointResult, size_t>> intersection_points;
|
||||
{
|
||||
EdgeGrid::Grid grid;
|
||||
grid.set_bbox(bbox);
|
||||
grid.create(boundary_src, scale_(10.));
|
||||
intersection_points.reserve(infill_ordered.size() * 2);
|
||||
for (const Polyline& pl : infill_ordered)
|
||||
for (const Point* pt : { &pl.points.front(), &pl.points.back() }) {
|
||||
EdgeGrid::Grid::ClosestPointResult cp = grid.closest_point(*pt, SCALED_EPSILON);
|
||||
if (cp.valid()) {
|
||||
// The infill end point shall lie on the contour.
|
||||
assert(cp.distance < 2.);
|
||||
intersection_points.emplace_back(cp, (&pl - infill_ordered.data()) * 2 + (pt == &pl.points.front() ? 0 : 1));
|
||||
}
|
||||
}
|
||||
std::sort(intersection_points.begin(), intersection_points.end(), [](const std::pair<EdgeGrid::Grid::ClosestPointResult, size_t>& cp1, const std::pair<EdgeGrid::Grid::ClosestPointResult, size_t>& cp2) {
|
||||
return cp1.first.contour_idx < cp2.first.contour_idx ||
|
||||
(cp1.first.contour_idx == cp2.first.contour_idx &&
|
||||
(cp1.first.start_point_idx < cp2.first.start_point_idx ||
|
||||
(cp1.first.start_point_idx == cp2.first.start_point_idx && cp1.first.t < cp2.first.t)));
|
||||
});
|
||||
}
|
||||
auto it = intersection_points.begin();
|
||||
auto it_end = intersection_points.end();
|
||||
for (size_t idx_contour = 0; idx_contour <= boundary_src.holes.size(); ++idx_contour) {
|
||||
const Polygon& contour_src = (idx_contour == 0) ? boundary_src.contour : boundary_src.holes[idx_contour - 1];
|
||||
Points& contour_dst = boundary[idx_contour];
|
||||
for (size_t idx_point = 0; idx_point < contour_src.points.size(); ++idx_point) {
|
||||
contour_dst.emplace_back(contour_src.points[idx_point]);
|
||||
for (; it != it_end && it->first.contour_idx == idx_contour && it->first.start_point_idx == idx_point; ++it) {
|
||||
// Add these points to the destination contour.
|
||||
const Vec2d pt1 = contour_src[idx_point].cast<double>();
|
||||
const Vec2d pt2 = (idx_point + 1 == contour_src.size() ? contour_src.points.front() : contour_src.points[idx_point + 1]).cast<double>();
|
||||
const Vec2d pt = lerp(pt1, pt2, it->first.t);
|
||||
map_infill_end_point_to_boundary[it->second] = std::make_pair(idx_contour, contour_dst.size());
|
||||
contour_dst.emplace_back(pt.cast<coord_t>());
|
||||
}
|
||||
}
|
||||
// Parametrize the curve.
|
||||
std::vector<ContourPointData>& contour_data = boundary_data[idx_contour];
|
||||
contour_data.reserve(contour_dst.size());
|
||||
contour_data.emplace_back(ContourPointData(0.f));
|
||||
for (size_t i = 1; i < contour_dst.size(); ++i)
|
||||
contour_data.emplace_back(contour_data.back().param + (contour_dst[i].cast<float>() - contour_dst[i - 1].cast<float>()).norm());
|
||||
contour_data.front().param = contour_data.back().param + (contour_dst.back().cast<float>() - contour_dst.front().cast<float>()).norm();
|
||||
}
|
||||
|
||||
assert(boundary.size() == boundary_src.num_contours());
|
||||
#if 0
|
||||
// Adaptive Cubic Infill produces infill lines, which not always end at the outer boundary.
|
||||
assert(std::all_of(map_infill_end_point_to_boundary.begin(), map_infill_end_point_to_boundary.end(),
|
||||
[&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
|
||||
}
|
||||
|
||||
// Mark the points and segments of split boundary as consumed if they are very close to some of the infill line.
|
||||
{
|
||||
// @supermerill used 2. * scale_(spacing)
|
||||
const double clip_distance = 3. * scale_(spacing);
|
||||
const double distance_colliding = 1.1 * scale_(spacing);
|
||||
mark_boundary_segments_touching_infill(boundary, boundary_data, bbox, infill_ordered, clip_distance, distance_colliding);
|
||||
}
|
||||
|
||||
// Connection from end of one infill line to the start of another infill line.
|
||||
//const float length_max = scale_(spacing);
|
||||
// const float length_max = scale_((2. / params.density) * spacing);
|
||||
const coord_t length_max = scale_((1000. / params.density) * spacing);
|
||||
std::vector<size_t> merged_with(infill_ordered.size());
|
||||
for (size_t i = 0; i < merged_with.size(); ++i)
|
||||
merged_with[i] = i;
|
||||
struct ConnectionCost {
|
||||
ConnectionCost(size_t idx_first, double cost, bool reversed) : idx_first(idx_first), cost(cost), reversed(reversed) {}
|
||||
size_t idx_first;
|
||||
double cost;
|
||||
bool reversed;
|
||||
};
|
||||
std::vector<ConnectionCost> connections_sorted;
|
||||
connections_sorted.reserve(infill_ordered.size() * 2 - 2);
|
||||
for (size_t idx_chain = 1; idx_chain < infill_ordered.size(); ++idx_chain) {
|
||||
const Polyline& pl1 = infill_ordered[idx_chain - 1];
|
||||
const Polyline& pl2 = infill_ordered[idx_chain];
|
||||
const std::pair<size_t, size_t>* cp1 = &map_infill_end_point_to_boundary[(idx_chain - 1) * 2 + 1];
|
||||
const std::pair<size_t, size_t>* cp2 = &map_infill_end_point_to_boundary[idx_chain * 2];
|
||||
if (cp1->first != boundary_idx_unconnected && cp1->first == cp2->first) {
|
||||
// End points on the same contour. Try to connect them.
|
||||
const std::vector<ContourPointData>& contour_data = boundary_data[cp1->first];
|
||||
float param_lo = (cp1->second == 0) ? 0.f : contour_data[cp1->second].param;
|
||||
float param_hi = (cp2->second == 0) ? 0.f : contour_data[cp2->second].param;
|
||||
float param_end = contour_data.front().param;
|
||||
bool reversed = false;
|
||||
if (param_lo > param_hi) {
|
||||
std::swap(param_lo, param_hi);
|
||||
reversed = true;
|
||||
}
|
||||
assert(param_lo >= 0.f && param_lo <= param_end);
|
||||
assert(param_hi >= 0.f && param_hi <= param_end);
|
||||
coord_t len = coord_t(param_hi - param_lo);
|
||||
if (len < length_max)
|
||||
connections_sorted.emplace_back(idx_chain - 1, len, reversed);
|
||||
len = coord_t(param_lo + param_end - param_hi);
|
||||
if (len < length_max)
|
||||
connections_sorted.emplace_back(idx_chain - 1, len, !reversed);
|
||||
}
|
||||
}
|
||||
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];
|
||||
const std::pair<size_t, size_t>* cp1prev = cp1 - 1;
|
||||
const std::pair<size_t, size_t>* cp2 = &map_infill_end_point_to_boundary[(connection_cost.idx_first + 1) * 2];
|
||||
const std::pair<size_t, size_t>* cp2next = cp2 + 1;
|
||||
assert(cp1->first == cp2->first && cp1->first != boundary_idx_unconnected);
|
||||
std::vector<ContourPointData>& contour_data = boundary_data[cp1->first];
|
||||
if (connection_cost.reversed)
|
||||
std::swap(cp1, cp2);
|
||||
// Mark the the other end points of the segments to be taken as consumed temporarily, so they will not be crossed
|
||||
// by the new connection line.
|
||||
bool prev_marked = false;
|
||||
bool next_marked = false;
|
||||
if (cp1prev->first == cp1->first && !contour_data[cp1prev->second].point_consumed) {
|
||||
contour_data[cp1prev->second].point_consumed = true;
|
||||
prev_marked = true;
|
||||
}
|
||||
if (cp2next->first == cp1->first && !contour_data[cp2next->second].point_consumed) {
|
||||
contour_data[cp2next->second].point_consumed = true;
|
||||
next_marked = true;
|
||||
}
|
||||
if (could_take(contour_data, cp1->second, cp2->second)) {
|
||||
// Indices of the polygons to be connected.
|
||||
size_t idx_first = connection_cost.idx_first;
|
||||
size_t idx_second = idx_first + 1;
|
||||
for (size_t last = idx_first;;) {
|
||||
size_t lower = merged_with[last];
|
||||
if (lower == last) {
|
||||
merged_with[idx_first] = lower;
|
||||
idx_first = lower;
|
||||
break;
|
||||
}
|
||||
last = lower;
|
||||
}
|
||||
// Connect the two polygons using the boundary contour.
|
||||
take(infill_ordered[idx_first], std::move(infill_ordered[idx_second]), boundary[cp1->first], contour_data, cp1->second, cp2->second, connection_cost.reversed);
|
||||
// Mark the second polygon as merged with the first one.
|
||||
merged_with[idx_second] = merged_with[idx_first];
|
||||
}
|
||||
if (prev_marked)
|
||||
contour_data[cp1prev->second].point_consumed = false;
|
||||
if (next_marked)
|
||||
contour_data[cp2next->second].point_consumed = false;
|
||||
}
|
||||
polylines_out.reserve(polylines_out.size() + std::count_if(infill_ordered.begin(), infill_ordered.end(), [](const Polyline& pl) { return !pl.empty(); }));
|
||||
for (Polyline& pl : infill_ordered)
|
||||
if (!pl.empty())
|
||||
polylines_out.emplace_back(std::move(pl));
|
||||
}
|
||||
}
|
||||
|
||||
namespace FakePerimeterConnect {
|
||||
|
||||
// A single T joint of an infill line to a closed contour or one of its holes.
|
||||
struct ContourIntersectionPoint {
|
||||
@ -1529,7 +2036,8 @@ void mark_boundary_segments_touching_infill(
|
||||
assert(validate_boundary_intersections(boundary_intersections));
|
||||
}
|
||||
|
||||
void Fill::connect_infill(Polylines&& infill_ordered, const ExPolygon& boundary_src, Polylines& polylines_out, const double spacing, const FillParams& params)
|
||||
|
||||
void connect_infill(Polylines&& infill_ordered, const ExPolygon& boundary_src, Polylines& polylines_out, const double spacing, const FillParams& params)
|
||||
{
|
||||
assert(!boundary_src.contour.points.empty());
|
||||
auto polygons_src = reserve_vector<const Polygon*>(boundary_src.holes.size() + 1);
|
||||
@ -1542,7 +2050,7 @@ void Fill::connect_infill(Polylines&& infill_ordered, const ExPolygon& boundary_
|
||||
connect_infill(std::move(infill_ordered), polygons_src, get_extents(boundary_src.contour), polylines_out, spacing, params);
|
||||
}
|
||||
|
||||
void Fill::connect_infill(Polylines&& infill_ordered, const Polygons& boundary_src, const BoundingBox& bbox, Polylines& polylines_out, const double spacing, const FillParams& params)
|
||||
void connect_infill(Polylines&& infill_ordered, const Polygons& boundary_src, const BoundingBox& bbox, Polylines& polylines_out, const double spacing, const FillParams& params)
|
||||
{
|
||||
auto polygons_src = reserve_vector<const Polygon*>(boundary_src.size());
|
||||
for (const Polygon& polygon : boundary_src)
|
||||
@ -1551,7 +2059,7 @@ void Fill::connect_infill(Polylines&& infill_ordered, const Polygons& boundary_s
|
||||
connect_infill(std::move(infill_ordered), polygons_src, bbox, polylines_out, spacing, params);
|
||||
}
|
||||
|
||||
void Fill::connect_infill(Polylines&& infill_ordered, const std::vector<const Polygon*>& boundary_src, const BoundingBox& bbox, Polylines& polylines_out, const double spacing, const FillParams& params)
|
||||
void connect_infill(Polylines&& infill_ordered, const std::vector<const Polygon*>& boundary_src, const BoundingBox& bbox, Polylines& polylines_out, const double spacing, const FillParams& params)
|
||||
{
|
||||
assert(!infill_ordered.empty());
|
||||
assert(params.anchor_length >= 0.01f);
|
||||
@ -1914,5 +2422,21 @@ void Fill::connect_infill(Polylines&& infill_ordered, const std::vector<const Po
|
||||
polylines_out.emplace_back(std::move(pl));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Fill::connect_infill(Polylines&& infill_ordered, const ExPolygon& boundary, Polylines& polylines_out, const double spacing, const FillParams& params) {
|
||||
if (params.anchor_length == 0) {
|
||||
PrusaSimpleConnect::connect_infill(std::move(infill_ordered), boundary, polylines_out, spacing, params);
|
||||
} else {
|
||||
FakePerimeterConnect::connect_infill(std::move(infill_ordered), boundary, polylines_out, spacing, params);
|
||||
}
|
||||
}
|
||||
void Fill::connect_infill(Polylines&& infill_ordered, const ExPolygon& boundary, const Polygons& polygons_src, Polylines& polylines_out, const double spacing, const FillParams& params) {
|
||||
if (params.anchor_length == 0) {
|
||||
PrusaSimpleConnect::connect_infill(std::move(infill_ordered), boundary, polylines_out, spacing, params);
|
||||
} else {
|
||||
FakePerimeterConnect::connect_infill(std::move(infill_ordered), polygons_src, get_extents(boundary.contour), polylines_out, spacing, params);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -156,8 +156,6 @@ protected:
|
||||
|
||||
virtual std::pair<float, Point> _infill_direction(const Surface *surface) const;
|
||||
|
||||
void connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const FillParams ¶ms) const;
|
||||
|
||||
void do_gap_fill(const ExPolygons &gapfill_areas, const FillParams ¶ms, ExtrusionEntitiesPtr &coll_out) const;
|
||||
|
||||
ExtrusionRole getRoleFromSurfaceType(const FillParams ¶ms, const Surface *surface) const {
|
||||
@ -172,9 +170,9 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
static void connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const double spacing, const FillParams ¶ms);
|
||||
static void connect_infill(Polylines &&infill_ordered, const Polygons &boundary, const BoundingBox& bbox, Polylines &polylines_out, const double spacing, const FillParams ¶ms);
|
||||
static void connect_infill(Polylines &&infill_ordered, const std::vector<const Polygon*> &boundary, const BoundingBox &bbox, Polylines &polylines_out, double spacing, const FillParams ¶ms);
|
||||
static void connect_infill(Polylines&& infill_ordered, const ExPolygon& boundary, Polylines& polylines_out, const double spacing, const FillParams& params);
|
||||
//for rectilinear
|
||||
static void connect_infill(Polylines&& infill_ordered, const ExPolygon& boundary, const Polygons& polygons_src, Polylines& polylines_out, const double spacing, const FillParams& params);
|
||||
|
||||
static coord_t _adjust_solid_spacing(const coord_t width, const coord_t distance);
|
||||
|
||||
@ -198,6 +196,17 @@ public:
|
||||
{ return Point(_align_to_grid(coord(0), spacing(0), base(0)), _align_to_grid(coord(1), spacing(1), base(1))); }
|
||||
};
|
||||
|
||||
namespace FakePerimeterConnect {
|
||||
void connect_infill(Polylines&& infill_ordered, const ExPolygon& boundary, Polylines& polylines_out, const double spacing, const FillParams& params);
|
||||
void connect_infill(Polylines&& infill_ordered, const Polygons& boundary, const BoundingBox& bbox, Polylines& polylines_out, const double spacing, const FillParams& params);
|
||||
void connect_infill(Polylines&& infill_ordered, const std::vector<const Polygon*>& boundary, const BoundingBox& bbox, Polylines& polylines_out, double spacing, const FillParams& params);
|
||||
}
|
||||
namespace PrusaSimpleConnect {
|
||||
void connect_infill(Polylines& infill_ordered, const ExPolygon& boundary, Polylines& polylines_out, const double spacing, const FillParams& params);
|
||||
}
|
||||
namespace NaiveConnect {
|
||||
void connect_infill(Polylines&& infill_ordered, const ExPolygon& boundary, Polylines& polylines_out, const double spacing, const FillParams& params);
|
||||
}
|
||||
|
||||
class ExtrusionSetRole : public ExtrusionVisitor {
|
||||
ExtrusionRole new_role;
|
||||
|
@ -194,7 +194,7 @@ void FillGyroid::_fill_surface_single(
|
||||
if (params.connection == icNotConnected){
|
||||
append(polylines_out, chain_polylines(polylines));
|
||||
} else {
|
||||
this->connect_infill(std::move(polylines), expolygon, polylines_out, this->get_spacing(), params);
|
||||
this->connect_infill(chain_polylines(polylines), expolygon, polylines_out, this->get_spacing(), params);
|
||||
}
|
||||
// new paths must be rotated back
|
||||
if (std::abs(infill_angle) >= EPSILON) {
|
||||
|
@ -2889,7 +2889,8 @@ bool FillRectilinear::fill_surface_by_multilines(const Surface* surface, FillPar
|
||||
fill_lines = chain_polylines(std::move(fill_lines));
|
||||
append(polylines_out, std::move(fill_lines));
|
||||
} else
|
||||
connect_infill(std::move(fill_lines), poly_with_offset_base.polygons_outer, get_extents(surface->expolygon.contour), polylines_out, this->get_spacing(), params);
|
||||
//connect_infill(std::move(fill_lines), poly_with_offset_base.polygons_outer, get_extents(surface->expolygon.contour), polylines_out, this->get_spacing(), params);
|
||||
connect_infill(std::move(fill_lines), surface->expolygon, poly_with_offset_base.polygons_outer, polylines_out, this->get_spacing(), params);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -559,7 +559,7 @@ const std::vector<std::string>& Preset::print_options()
|
||||
"perimeter_loop_seam",
|
||||
"seam_angle_cost",
|
||||
"seam_travel_cost",
|
||||
"infill_connection",
|
||||
"infill_connection", "infill_connection_solid", "infill_connection_top", "infill_connection_bottom",
|
||||
"first_layer_infill_speed",
|
||||
"thin_walls_min_width",
|
||||
"thin_walls_overlap",
|
||||
|
@ -1876,7 +1876,8 @@ void PrintConfigDef::init_fff_params()
|
||||
def->label = L("Length of the infill anchor");
|
||||
def->category = OptionCategory::infill;
|
||||
def->tooltip = L("Connect an infill line to an internal perimeter with a short segment of an additional perimeter. "
|
||||
"If expressed as percentage (example: 15%) it is calculated over infill extrusion width.");
|
||||
"If expressed as percentage (example: 15%) it is calculated over infill extrusion width."
|
||||
"\nIf set to 0, it will use a simpler algo that don't try to create a fake perimeter.");
|
||||
def->sidetext = L("mm or %");
|
||||
def->ratio_over = "infill_extrusion_width";
|
||||
def->gui_type = "f_enum_open";
|
||||
@ -1886,15 +1887,15 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_values.push_back("5");
|
||||
def->enum_values.push_back("10");
|
||||
def->enum_values.push_back("1000");
|
||||
def->enum_labels.push_back(L("0 (not anchored)"));
|
||||
def->enum_labels.push_back(L("0 (Simple connect)"));
|
||||
def->enum_labels.push_back("1 mm");
|
||||
def->enum_labels.push_back("2 mm");
|
||||
def->enum_labels.push_back("5 mm");
|
||||
def->enum_labels.push_back("10 mm");
|
||||
def->enum_labels.push_back(L("1000 (unlimited)"));
|
||||
def->mode = comAdvanced;
|
||||
// def->set_default_value(new ConfigOptionFloatOrPercent(300, true));
|
||||
def->set_default_value(new ConfigOptionFloatOrPercent(1000, false));
|
||||
// def->set_default_value(new ConfigOptionFloatOrPercent(300, true));
|
||||
def->set_default_value(new ConfigOptionFloatOrPercent(0, false));
|
||||
|
||||
def = this->add("infill_dense", coBool);
|
||||
def->label = ("");
|
||||
@ -1922,6 +1923,60 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_labels.push_back(L("Not connected"));
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionEnum<InfillConnection>(icConnected));
|
||||
|
||||
def = this->add("infill_connection_top", coEnum);
|
||||
def->label = L("Do not connect infill lines to each other");
|
||||
def->category = OptionCategory::infill;
|
||||
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 ConfigOptionEnum<InfillConnection>(icConnected));
|
||||
|
||||
def = this->add("infill_connection_bottom", coEnum);
|
||||
def->label = L("Do not connect infill lines to each other");
|
||||
def->category = OptionCategory::infill;
|
||||
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 ConfigOptionEnum<InfillConnection>(icConnected));
|
||||
|
||||
def = this->add("infill_connection_solid", coEnum);
|
||||
def->label = L("Do not connect infill lines to each other");
|
||||
def->category = OptionCategory::infill;
|
||||
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 ConfigOptionEnum<InfillConnection>(icConnected));
|
||||
|
||||
def = this->add("infill_dense_algo", coEnum);
|
||||
def->label = L("Algorithm");
|
||||
@ -3967,7 +4022,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
|
||||
def = this->add("hole_size_compensation", coFloat);
|
||||
def->label = L("Holes");
|
||||
def->label = L("XY compensation");
|
||||
def->full_label = L("XY holes compensation");
|
||||
def->category = OptionCategory::slicing;
|
||||
def->tooltip = L("The convex holes will be grown / shrunk in the XY plane by the configured value"
|
||||
@ -3979,7 +4034,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
|
||||
def = this->add("hole_size_threshold", coFloat);
|
||||
def->label = L("Holes");
|
||||
def->label = L("Threshold");
|
||||
def->full_label = L("XY holes threshold");
|
||||
def->category = OptionCategory::slicing;
|
||||
def->tooltip = L("Maximum area for the hole where the hole_size_compensation will apply fully."
|
||||
|
@ -754,13 +754,17 @@ public:
|
||||
ConfigOptionFloatOrPercent gap_fill_min_area;
|
||||
ConfigOptionPercent gap_fill_overlap;
|
||||
ConfigOptionFloat gap_fill_speed;
|
||||
ConfigOptionFloatOrPercent infill_anchor; ConfigOptionBool hole_to_polyhole;
|
||||
ConfigOptionFloatOrPercent infill_anchor;
|
||||
ConfigOptionBool hole_to_polyhole;
|
||||
ConfigOptionInt infill_extruder;
|
||||
ConfigOptionFloatOrPercent infill_extrusion_width;
|
||||
ConfigOptionInt infill_every_layers;
|
||||
ConfigOptionFloatOrPercent infill_overlap;
|
||||
ConfigOptionFloat infill_speed;
|
||||
ConfigOptionEnum<InfillConnection> infill_connection;
|
||||
ConfigOptionEnum<InfillConnection> infill_connection_solid;
|
||||
ConfigOptionEnum<InfillConnection> infill_connection_top;
|
||||
ConfigOptionEnum<InfillConnection> infill_connection_bottom;
|
||||
ConfigOptionBool infill_dense;
|
||||
ConfigOptionEnum<DenseInfillAlgo> infill_dense_algo;
|
||||
ConfigOptionBool infill_first;
|
||||
@ -859,7 +863,8 @@ protected:
|
||||
OPT_PTR(gap_fill_min_area);
|
||||
OPT_PTR(gap_fill_overlap);
|
||||
OPT_PTR(gap_fill_speed);
|
||||
OPT_PTR(infill_anchor); OPT_PTR(hole_to_polyhole);
|
||||
OPT_PTR(infill_anchor);
|
||||
OPT_PTR(hole_to_polyhole);
|
||||
OPT_PTR(infill_extruder);
|
||||
OPT_PTR(infill_extrusion_width);
|
||||
OPT_PTR(infill_every_layers);
|
||||
@ -867,6 +872,9 @@ protected:
|
||||
OPT_PTR(infill_speed);
|
||||
OPT_PTR(infill_dense);
|
||||
OPT_PTR(infill_connection);
|
||||
OPT_PTR(infill_connection_solid);
|
||||
OPT_PTR(infill_connection_top);
|
||||
OPT_PTR(infill_connection_bottom);
|
||||
OPT_PTR(infill_dense_algo);
|
||||
OPT_PTR(infill_first);
|
||||
OPT_PTR(ironing);
|
||||
|
@ -783,6 +783,10 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
|
||||
|| opt_key == "fill_smooth_distribution"
|
||||
|| opt_key == "first_layer_extrusion_width"
|
||||
|| opt_key == "infill_anchor"
|
||||
|| opt_key == "infill_connection"
|
||||
|| opt_key == "infill_connection_solid"
|
||||
|| opt_key == "infill_connection_top"
|
||||
|| opt_key == "infill_connection_bottom"
|
||||
|| opt_key == "top_infill_extrusion_width") {
|
||||
steps.emplace_back(posInfill);
|
||||
} else if (
|
||||
|
@ -1050,7 +1050,8 @@ void Choice::set_value(const boost::any& value, bool change_event)
|
||||
val = idx_from_enum_value<GCodeFlavor>(val);
|
||||
else if (m_opt_id.compare("host_type") == 0)
|
||||
val = idx_from_enum_value<PrintHostType>(val);
|
||||
else if (m_opt_id.compare("infill_connection") == 0)
|
||||
else if (m_opt_id =="infill_connection" || m_opt_id =="infill_connection_solid"
|
||||
|| m_opt_id =="infill_connection_top" || m_opt_id =="infill_connection_bottom")
|
||||
val = idx_from_enum_value<InfillConnection>(val);
|
||||
else if (m_opt_id.compare("infill_dense_algo") == 0)
|
||||
val = idx_from_enum_value<DenseInfillAlgo>(val);
|
||||
@ -1164,7 +1165,8 @@ boost::any& Choice::get_value()
|
||||
convert_to_enum_value<GCodeFlavor>(ret_enum);
|
||||
else if (m_opt_id.compare("host_type") == 0)
|
||||
convert_to_enum_value<PrintHostType>(ret_enum);
|
||||
else if (m_opt_id.compare("infill_connection") == 0)
|
||||
else if (m_opt_id =="infill_connection" || m_opt_id =="infill_connection_solid"
|
||||
|| m_opt_id =="infill_connection_top" || m_opt_id =="infill_connection_bottom")
|
||||
convert_to_enum_value<InfillConnection>(ret_enum);
|
||||
else if (m_opt_id.compare("infill_dense_algo") == 0)
|
||||
convert_to_enum_value<DenseInfillAlgo>(ret_enum);
|
||||
|
@ -944,7 +944,8 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config
|
||||
ret = static_cast<int>(config.option<ConfigOptionEnum<GCodeFlavor>>(opt_key)->value);
|
||||
} else if (opt_key == "host_type") {
|
||||
ret = static_cast<int>(config.option<ConfigOptionEnum<PrintHostType>>(opt_key)->value);
|
||||
} else if (opt_key == "infill_connection") {
|
||||
} else if (opt_key =="infill_connection" || opt_key =="infill_connection_solid"
|
||||
|| opt_key =="infill_connection_top" || opt_key =="infill_connection_bottom") {
|
||||
ret = static_cast<int>(config.option<ConfigOptionEnum<InfillConnection>>(opt_key)->value);
|
||||
} else if (opt_key == "infill_dense_algo") {
|
||||
ret = static_cast<int>(config.option<ConfigOptionEnum<DenseInfillAlgo>>(opt_key)->value);
|
||||
|
@ -951,7 +951,8 @@ static wxString get_string_value(std::string opt_key, const DynamicPrintConfig&
|
||||
return get_string_from_enum<GCodeFlavor>(opt_key, config);
|
||||
if (opt_key == "host_type")
|
||||
return get_string_from_enum<PrintHostType>(opt_key, config);
|
||||
if (opt_key == "infill_connection")
|
||||
if (opt_key =="infill_connection" || opt_key =="infill_connection_solid"
|
||||
|| opt_key =="infill_connection_top" || opt_key =="infill_connection_bottom")
|
||||
return get_string_from_enum<InfillConnection>(opt_key, config);
|
||||
if (opt_key == "infill_dense_algo")
|
||||
return get_string_from_enum<DenseInfillAlgo>(opt_key, config);
|
||||
|
Loading…
x
Reference in New Issue
Block a user