Add 'Rectilinear with Boundary' infill mode for top surface coloring

This commit is contained in:
sentientstardust
2026-05-27 17:39:40 +01:00
parent 2ea7239849
commit a75b8b69e3
5 changed files with 480 additions and 21 deletions

View File

@@ -2648,7 +2648,7 @@ static std::shared_ptr<const TopSurfaceImageContoningDepthRegionPlan> top_surfac
return;
ExPolygons area = perimeter_area;
if (!plan.contoning_replace_top_perimeters_with_infill) {
if (!plan.contoning_replace_top_perimeters_with_infill && include_perimeter_regions) {
Polygons current_layer_perimeters =
top_surface_image_layer_perimeter_polygons(*target_layer, throw_if_canceled);
if (!current_layer_perimeters.empty())
@@ -3120,7 +3120,7 @@ static std::vector<TopSurfaceImageRegionPlan> top_surface_image_region_plans(
std::clamp(TextureMappingZone::effective_top_surface_contoning_flat_surface_infill_mode(
zone->top_surface_contoning_flat_surface_infill_mode),
int(TextureMappingZone::ContoningFlatSurfaceInfillRectilinear),
int(TextureMappingZone::ContoningFlatSurfaceInfillBoundarySkinHybrid));
int(TextureMappingZone::ContoningFlatSurfaceInfillRectilinearWithBoundary));
plan.contoning_layer_phase_enabled = zone->top_surface_contoning_layer_phase_enabled;
plan.contoning_varied_infill_angles_enabled = zone->top_surface_contoning_varied_infill_angles_enabled;
plan.contoning_blue_noise_error_diffusion_enabled = zone->top_surface_contoning_blue_noise_error_diffusion_enabled;
@@ -3142,8 +3142,11 @@ static std::vector<TopSurfaceImageRegionPlan> top_surface_image_region_plans(
}
if (plan.contoning) {
auto append_contoning_surface = [&](TopSurfaceImageSourceSurface source_surface) {
const bool target_surface_limited =
plan.contoning_replace_top_perimeters_with_infill ||
!plan.contoning_recolor_surrounding_perimeters;
const ExPolygons current_target_surface_area =
plan.contoning_replace_top_perimeters_with_infill ?
target_surface_limited ?
top_surface_image_current_layer_surface_mask(*layerm, source_surface) :
ExPolygons();
std::vector<const Layer *> contoning_depth_layers(size_t(stack_depth), nullptr);
@@ -3160,7 +3163,7 @@ static std::vector<TopSurfaceImageRegionPlan> top_surface_image_region_plans(
source_layer->lower_layer;
if (source_layer == nullptr)
break;
if (plan.contoning_replace_top_perimeters_with_infill &&
if (target_surface_limited &&
!top_surface_image_contoning_depth_within_shell(layer,
*source_layer,
layerm->region().config(),
@@ -3174,12 +3177,14 @@ static std::vector<TopSurfaceImageRegionPlan> top_surface_image_region_plans(
ExPolygons fill_area = source_area;
ExPolygons vector_area = source_area;
ExPolygons perimeter_clip_area = source_area;
if (plan.contoning_replace_top_perimeters_with_infill) {
if (target_surface_limited) {
if (current_target_surface_area.empty())
continue;
fill_area = top_surface_clip_intersection_ex(fill_area, current_target_surface_area, ApplySafetyOffset::Yes);
if (fill_area.empty())
continue;
}
if (plan.contoning_replace_top_perimeters_with_infill) {
vector_area = fill_area;
perimeter_clip_area = current_region_wall_area;
if (!perimeter_clip_area.empty()) {
@@ -3188,8 +3193,6 @@ static std::vector<TopSurfaceImageRegionPlan> top_surface_image_region_plans(
}
}
if (!plan.contoning_replace_top_perimeters_with_infill) {
if (!current_layer_perimeters.empty())
fill_area = top_surface_clip_diff_ex(fill_area, current_layer_perimeters, ApplySafetyOffset::Yes);
if (!plan.contoning_recolor_surrounding_perimeters)
vector_area = fill_area;
}
@@ -3723,6 +3726,449 @@ static void top_surface_image_append_colored_block_loops(LayerRegion &layerm,
layerm.perimeters.entities.emplace_back(collection);
}
static bool top_surface_image_contoning_rectilinear_with_boundary_mode(int mode)
{
return mode == int(TextureMappingZone::ContoningFlatSurfaceInfillRectilinearWithBoundary);
}
struct TopSurfaceImageRectilinearBoundaryKey {
size_t region_id = size_t(-1);
unsigned int zone_id = 0;
int depth = 0;
SurfaceType surface_type = stInternal;
ExtrusionRole extrusion_role = erMixed;
float flow_width = 0.f;
float flow_height = 0.f;
float flow_nozzle = 0.f;
float flow_spacing = 0.f;
bool operator<(const TopSurfaceImageRectilinearBoundaryKey &rhs) const
{
return std::tie(region_id,
zone_id,
depth,
surface_type,
extrusion_role,
flow_width,
flow_height,
flow_nozzle,
flow_spacing) <
std::tie(rhs.region_id,
rhs.zone_id,
rhs.depth,
rhs.surface_type,
rhs.extrusion_role,
rhs.flow_width,
rhs.flow_height,
rhs.flow_nozzle,
rhs.flow_spacing);
}
};
struct TopSurfaceImageRectilinearBoundaryGroup {
SurfaceFillParams params;
ExPolygons area;
std::map<unsigned int, ExPolygons> component_areas;
};
static void top_surface_image_apply_rectilinear_boundary_metadata(ExtrusionEntityCollection &collection,
const SurfaceFillParams &params)
{
collection.texture_mapping_top_surface_image = true;
collection.texture_mapping_top_surface_zone_id = params.texture_mapping_top_surface_zone_id;
collection.texture_mapping_top_surface_stack_depth = params.texture_mapping_top_surface_stack_depth;
collection.texture_mapping_top_surface_fixed_coloring = params.texture_mapping_top_surface_fixed_coloring;
collection.texture_mapping_top_surface_desired_component_id =
collection.texture_mapping_extruder_override >= 0 ?
unsigned(collection.texture_mapping_extruder_override + 1) :
params.texture_mapping_top_surface_component_id;
for (ExtrusionEntity *entity : collection.entities)
if (ExtrusionEntityCollection *child = dynamic_cast<ExtrusionEntityCollection *>(entity))
top_surface_image_apply_rectilinear_boundary_metadata(*child, params);
}
static int top_surface_image_rectilinear_boundary_override_at_point(const Point &point,
const std::vector<TopSurfaceImagePerimeterMask> &masks,
int fallback_override)
{
const int override = top_surface_image_perimeter_override_at_point(point, masks);
return override >= 0 ? override : fallback_override;
}
static void top_surface_image_append_rectilinear_boundary_polyline(ExtrusionEntitiesPtr &collections,
const ExtrusionPath &source,
const Polyline &polyline,
const std::vector<TopSurfaceImagePerimeterMask> &masks,
float sample_step_mm,
int fallback_override)
{
if (polyline.points.size() < 2 || fallback_override < 0)
return;
const double sample_step = std::max(0.02, double(sample_step_mm));
Points current_points;
int current_override = -2;
auto flush = [&]() {
if (current_points.empty())
return;
top_surface_image_append_perimeter_path_piece(collections, source, std::move(current_points), current_override);
current_points.clear();
current_override = -2;
};
for (size_t point_idx = 1; point_idx < polyline.points.size(); ++point_idx) {
const Point &p0 = polyline.points[point_idx - 1];
const Point &p1 = polyline.points[point_idx];
const double len_mm = unscale<double>(p0.distance_to(p1));
if (!std::isfinite(len_mm) || len_mm <= EPSILON)
continue;
const int steps = std::max(1, int(std::ceil(len_mm / sample_step)));
for (int step = 0; step < steps; ++step) {
const double t0 = double(step) / double(steps);
const double t1 = double(step + 1) / double(steps);
const Point q0 = lerp(p0, p1, t0);
const Point q1 = lerp(p0, p1, t1);
if (q0 == q1)
continue;
const Point qm = lerp(p0, p1, 0.5 * (t0 + t1));
const int override = top_surface_image_rectilinear_boundary_override_at_point(qm,
masks,
current_override >= 0 ?
current_override :
fallback_override);
if (current_points.empty()) {
current_override = override;
current_points.emplace_back(q0);
current_points.emplace_back(q1);
} else if (current_override == override && current_points.back() == q0) {
current_points.emplace_back(q1);
} else {
flush();
current_override = override;
current_points.emplace_back(q0);
current_points.emplace_back(q1);
}
}
}
flush();
}
static ExtrusionEntitiesPtr top_surface_image_rectilinear_boundary_collections(
const TopSurfaceImageRectilinearBoundaryGroup &group,
const ThrowIfCanceled *throw_if_canceled)
{
check_canceled(throw_if_canceled);
if (group.area.empty() || group.component_areas.empty())
return {};
ExPolygons boundary_area = top_surface_clip_union_ex(group.area);
if (boundary_area.empty())
return {};
std::vector<TopSurfaceImagePerimeterMask> masks;
masks.reserve(group.component_areas.size());
const float sample_tolerance_mm =
std::clamp(group.params.flow.width() * 0.20f, 0.02f, 0.08f);
int fallback_override = -1;
for (const auto &component_area : group.component_areas) {
check_canceled(throw_if_canceled);
if (component_area.first == 0 || component_area.second.empty())
continue;
ExPolygons area = top_surface_clip_union_ex(component_area.second);
ExPolygons sample_area = top_surface_clip_offset_ex(area, float(scale_(sample_tolerance_mm)));
if (sample_area.empty())
sample_area = std::move(area);
TopSurfaceImagePerimeterMask mask;
mask.component_id = component_area.first;
mask.zone_id = group.params.texture_mapping_top_surface_zone_id;
mask.depth = group.params.texture_mapping_top_surface_stack_depth;
mask.area = std::move(sample_area);
masks.emplace_back(std::move(mask));
if (fallback_override < 0)
fallback_override = int(component_area.first) - 1;
}
if (masks.empty() || fallback_override < 0)
return {};
Polygons loops = to_polygons(boundary_area);
if (loops.empty())
return {};
ExtrusionEntitiesPtr collections;
ExtrusionPath source(group.params.extrusion_role,
group.params.flow.mm3_per_mm(),
group.params.flow.width(),
group.params.flow.height());
const float sample_step_mm =
std::clamp(group.params.flow.width() * 0.50f, 0.05f, 0.25f);
for (const Polygon &loop : loops) {
check_canceled(throw_if_canceled);
if (loop.points.size() < 3)
continue;
Polyline polyline;
polyline.points.reserve(loop.points.size() + 1);
polyline.points.insert(polyline.points.end(), loop.points.begin(), loop.points.end());
polyline.points.emplace_back(loop.points.front());
remove_same_neighbor(polyline);
if (!polyline.is_valid())
continue;
top_surface_image_append_rectilinear_boundary_polyline(collections,
source,
polyline,
masks,
sample_step_mm,
fallback_override);
}
for (ExtrusionEntity *entity : collections)
if (ExtrusionEntityCollection *collection = dynamic_cast<ExtrusionEntityCollection *>(entity))
top_surface_image_apply_rectilinear_boundary_metadata(*collection, group.params);
return collections;
}
static std::map<TopSurfaceImageRectilinearBoundaryKey, TopSurfaceImageRectilinearBoundaryGroup>
top_surface_image_rectilinear_boundary_groups(const Layer &layer,
const std::vector<SurfaceFill> &surface_fills,
const ThrowIfCanceled *throw_if_canceled)
{
std::map<TopSurfaceImageRectilinearBoundaryKey, TopSurfaceImageRectilinearBoundaryGroup> groups;
for (const SurfaceFill &fill : surface_fills) {
check_canceled(throw_if_canceled);
if (fill.expolygons.empty() ||
fill.region_id >= layer.regions().size() ||
!fill.params.texture_mapping_top_surface_image ||
!fill.params.texture_mapping_top_surface_contoning ||
!top_surface_image_contoning_rectilinear_with_boundary_mode(
fill.params.texture_mapping_top_surface_contoning_flat_surface_infill_mode) ||
fill.params.texture_mapping_top_surface_component_id == 0)
continue;
TopSurfaceImageRectilinearBoundaryKey key;
key.region_id = fill.region_id;
key.zone_id = fill.params.texture_mapping_top_surface_zone_id;
key.depth = fill.params.texture_mapping_top_surface_stack_depth;
key.surface_type = fill.surface.surface_type;
key.extrusion_role = fill.params.extrusion_role;
key.flow_width = fill.params.flow.width();
key.flow_height = fill.params.flow.height();
key.flow_nozzle = fill.params.flow.nozzle_diameter();
key.flow_spacing = fill.params.spacing;
TopSurfaceImageRectilinearBoundaryGroup &group = groups[key];
if (group.component_areas.empty()) {
group.params = fill.params;
group.params.texture_mapping_top_surface_component_id = 0;
}
append(group.area, fill.expolygons);
append(group.component_areas[fill.params.texture_mapping_top_surface_component_id], fill.expolygons);
}
return groups;
}
static void top_surface_image_append_rectilinear_boundary_collections(Layer &layer,
const std::map<TopSurfaceImageRectilinearBoundaryKey,
TopSurfaceImageRectilinearBoundaryGroup> &groups,
const ThrowIfCanceled *throw_if_canceled)
{
for (const auto &entry : groups) {
check_canceled(throw_if_canceled);
if (entry.first.region_id >= layer.regions().size() || layer.regions()[entry.first.region_id] == nullptr)
continue;
ExtrusionEntitiesPtr collections =
top_surface_image_rectilinear_boundary_collections(entry.second, throw_if_canceled);
for (ExtrusionEntity *entity : collections)
layer.regions()[entry.first.region_id]->fills.entities.emplace_back(entity);
collections.clear();
}
}
static void top_surface_image_append_rectilinear_repair_loops(ExtrusionEntityCollection &collection,
const ExPolygon &expolygon,
const SurfaceFillParams &params)
{
Polygons loops = to_polygons(ExPolygons { expolygon });
if (loops.empty())
return;
extrusion_entities_append_loops(collection.entities,
std::move(loops),
params.extrusion_role,
float(params.flow.mm3_per_mm()),
float(params.flow.width()),
float(params.flow.height()));
}
static void top_surface_image_append_rectilinear_repair_lines(ExtrusionEntityCollection &collection,
const ExPolygon &expolygon,
const SurfaceFillParams &params,
const ThrowIfCanceled *throw_if_canceled)
{
const BoundingBox bbox = get_extents(expolygon);
if (!bbox.defined)
return;
const double theta = params.angle;
const double cos_t = std::cos(theta);
const double sin_t = std::sin(theta);
double min_u = std::numeric_limits<double>::max();
double min_v = std::numeric_limits<double>::max();
double max_u = -std::numeric_limits<double>::max();
double max_v = -std::numeric_limits<double>::max();
for (size_t i = 0; i < 4; ++i) {
const Point corner = bbox[i];
const double x = unscale<double>(corner.x());
const double y = unscale<double>(corner.y());
const double u = x * cos_t + y * sin_t;
const double v = -x * sin_t + y * cos_t;
min_u = std::min(min_u, u);
max_u = std::max(max_u, u);
min_v = std::min(min_v, v);
max_v = std::max(max_v, v);
}
if (max_u < min_u || max_v < min_v)
return;
const double spacing = std::max(0.05, double(params.flow.spacing()) * 0.75);
const double v_span = std::max(0.0, max_v - min_v);
const int line_count = std::max(1, int(std::ceil(v_span / spacing)));
const double margin = std::max(double(params.flow.spacing()), double(params.flow.width())) * 2.0;
const ExPolygons clip { expolygon };
for (int line_idx = 0; line_idx < line_count; ++line_idx) {
check_canceled(throw_if_canceled);
const double v = line_count == 1 ?
0.5 * (min_v + max_v) :
min_v + (double(line_idx) + 0.5) * v_span / double(line_count);
const double u0 = min_u - margin;
const double u1 = max_u + margin;
Polyline polyline;
polyline.points.emplace_back(Point::new_scale(u0 * cos_t - v * sin_t, u0 * sin_t + v * cos_t));
polyline.points.emplace_back(Point::new_scale(u1 * cos_t - v * sin_t, u1 * sin_t + v * cos_t));
if (!polyline.is_valid())
continue;
ExtrusionPath path(params.extrusion_role,
params.flow.mm3_per_mm(),
params.flow.width(),
params.flow.height());
path.polyline = std::move(polyline);
path.intersect_expolygons(clip, &collection);
}
}
static ExPolygons top_surface_image_rectilinear_repair_leftover(
const Layer &layer,
const TopSurfaceImageRectilinearBoundaryKey &key,
const TopSurfaceImageRectilinearBoundaryGroup &group,
const ThrowIfCanceled *throw_if_canceled)
{
if (key.region_id >= layer.regions().size() || layer.regions()[key.region_id] == nullptr || group.area.empty())
return {};
ExPolygons intended = top_surface_clip_union_ex(group.area);
if (intended.empty())
return {};
Polygons covered_polygons;
const LayerRegion *layerm = layer.regions()[key.region_id];
for (const ExtrusionEntity *entity : layerm->fills.entities) {
check_canceled(throw_if_canceled);
const ExtrusionEntityCollection *collection = dynamic_cast<const ExtrusionEntityCollection *>(entity);
if (collection == nullptr ||
!collection->texture_mapping_top_surface_image ||
collection->texture_mapping_top_surface_zone_id != key.zone_id ||
collection->texture_mapping_top_surface_stack_depth != key.depth)
continue;
const ExtrusionRole role = collection->role();
if (key.extrusion_role != erMixed && role != key.extrusion_role)
continue;
collection->polygons_covered_by_spacing(covered_polygons, float(scale_(0.02)));
}
if (covered_polygons.empty())
return intended;
ExPolygons covered =
top_surface_clip_intersection_ex(top_surface_clip_union_ex(covered_polygons), intended, ApplySafetyOffset::Yes);
return covered.empty() ? intended : top_surface_clip_diff_ex(intended, covered, ApplySafetyOffset::Yes);
}
static ExtrusionEntitiesPtr top_surface_image_rectilinear_repair_collections(
const TopSurfaceImageRectilinearBoundaryGroup &group,
const ExPolygons &leftover,
const ThrowIfCanceled *throw_if_canceled)
{
ExtrusionEntitiesPtr out;
if (leftover.empty() || group.component_areas.empty())
return out;
const float sample_tolerance_mm =
std::clamp(group.params.flow.width() * 0.20f, 0.02f, 0.08f);
ExPolygons taken;
for (const auto &component_area : group.component_areas) {
check_canceled(throw_if_canceled);
if (component_area.first == 0 || component_area.second.empty())
continue;
ExPolygons sample_area = top_surface_clip_union_ex(component_area.second);
sample_area = top_surface_clip_offset_ex(sample_area, float(scale_(sample_tolerance_mm)));
if (sample_area.empty())
sample_area = top_surface_clip_union_ex(component_area.second);
ExPolygons area = top_surface_clip_intersection_ex(leftover, sample_area, ApplySafetyOffset::Yes);
if (!taken.empty())
area = top_surface_clip_diff_ex(area, taken, ApplySafetyOffset::Yes);
if (!area.empty())
area = top_surface_clip_union_ex(area);
if (area.empty())
continue;
append(taken, area);
SurfaceFillParams params = group.params;
params.texture_mapping_top_surface_component_id = component_area.first;
ExtrusionEntityCollection *collection = new ExtrusionEntityCollection();
collection->no_sort = true;
collection->texture_mapping_extruder_override = int(component_area.first) - 1;
for (const ExPolygon &expolygon : area) {
check_canceled(throw_if_canceled);
top_surface_image_append_rectilinear_repair_lines(*collection, expolygon, params, throw_if_canceled);
}
Polygons line_covered_polygons;
collection->polygons_covered_by_spacing(line_covered_polygons, float(scale_(0.02)));
ExPolygons loop_area = area;
if (!line_covered_polygons.empty()) {
ExPolygons line_covered =
top_surface_clip_intersection_ex(top_surface_clip_union_ex(line_covered_polygons), area, ApplySafetyOffset::Yes);
if (!line_covered.empty())
loop_area = top_surface_clip_diff_ex(area, line_covered, ApplySafetyOffset::Yes);
}
for (const ExPolygon &expolygon : loop_area) {
check_canceled(throw_if_canceled);
top_surface_image_append_rectilinear_repair_loops(*collection, expolygon, params);
}
if (collection->empty()) {
delete collection;
} else {
top_surface_image_apply_rectilinear_boundary_metadata(*collection, params);
out.emplace_back(collection);
}
}
return out;
}
static void top_surface_image_append_rectilinear_repair_collections(Layer &layer,
const std::map<TopSurfaceImageRectilinearBoundaryKey,
TopSurfaceImageRectilinearBoundaryGroup> &groups,
const ThrowIfCanceled *throw_if_canceled)
{
std::vector<std::pair<size_t, ExtrusionEntitiesPtr>> repairs;
for (const auto &entry : groups) {
check_canceled(throw_if_canceled);
ExPolygons leftover = top_surface_image_rectilinear_repair_leftover(layer,
entry.first,
entry.second,
throw_if_canceled);
if (leftover.empty())
continue;
ExtrusionEntitiesPtr collections =
top_surface_image_rectilinear_repair_collections(entry.second, leftover, throw_if_canceled);
if (!collections.empty())
repairs.emplace_back(entry.first.region_id, std::move(collections));
}
for (auto &repair : repairs) {
check_canceled(throw_if_canceled);
if (repair.first >= layer.regions().size() || layer.regions()[repair.first] == nullptr) {
top_surface_image_delete_entities(repair.second);
continue;
}
for (ExtrusionEntity *entity : repair.second)
layer.regions()[repair.first]->fills.entities.emplace_back(entity);
repair.second.clear();
}
}
static double top_surface_image_perimeter_infill_adjacency_score(const SurfaceFill &fill,
const TopSurfaceImagePerimeterMask &mask,
int flat_mode,
@@ -5737,6 +6183,10 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree,
}
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
const std::map<TopSurfaceImageRectilinearBoundaryKey, TopSurfaceImageRectilinearBoundaryGroup> rectilinear_boundary_groups =
top_surface_image_rectilinear_boundary_groups(*this, surface_fills, throw_if_canceled_ptr);
top_surface_image_append_rectilinear_boundary_collections(*this, rectilinear_boundary_groups, throw_if_canceled_ptr);
for (SurfaceFill &surface_fill : surface_fills) {
check_canceled(throw_if_canceled_ptr);
if (surface_fill.expolygons.empty() ||
@@ -6030,8 +6480,10 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree,
apply_top_surface_image_collection_metadata(*collection, surface_fill.params, top_surface_image_context, throw_if_canceled_ptr);
}
}
}
}
}
}
top_surface_image_append_rectilinear_repair_collections(*this, rectilinear_boundary_groups, throw_if_canceled_ptr);
// add thin fill regions
// Unpacks the collection, creates multiple collections per path.

View File

@@ -837,26 +837,27 @@ void PrintObject::infill()
const auto objects = m_print->objects();
const auto object_it = std::find(objects.begin(), objects.end(), this);
const size_t object_index = object_it == objects.end() ? 0 : size_t(object_it - objects.begin());
Print *print = m_print;
std::atomic<size_t> completed_layers { 0 };
auto set_infill_progress = [this, total_layers, object_index](size_t completed) {
auto set_infill_progress = [print, total_layers, object_index](size_t completed) {
const std::string message_prefix = Slic3r::format("%1% %2%", L("Generating infill toolpath"), object_index + 1);
if (total_layers == 0)
m_print->set_status(35, message_prefix);
print->set_status(35, message_prefix);
else
m_print->set_status(35, Slic3r::format("%1% (%2%/%3%)", message_prefix, completed, total_layers));
print->set_status(35, Slic3r::format("%1% (%2%/%3%)", message_prefix, completed, total_layers));
};
set_infill_progress(0);
const auto& adaptive_fill_octree = this->m_adaptive_fill_octrees.first;
const auto& support_fill_octree = this->m_adaptive_fill_octrees.second;
const std::function<void()> throw_if_canceled = [this]() { m_print->throw_if_canceled(); };
const std::function<void()> throw_if_canceled = [print]() { print->throw_if_canceled(); };
auto contoning_stack_plan_cache = make_top_surface_image_contoning_stack_plan_cache();
BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - start";
tbb::parallel_for(
tbb::blocked_range<size_t>(0, m_layers.size()),
[this, &adaptive_fill_octree = adaptive_fill_octree, &support_fill_octree = support_fill_octree, &throw_if_canceled, &completed_layers, &set_infill_progress, contoning_stack_plan_cache](const tbb::blocked_range<size_t>& range) {
[this, print, &adaptive_fill_octree = adaptive_fill_octree, &support_fill_octree = support_fill_octree, &throw_if_canceled, &completed_layers, &set_infill_progress, contoning_stack_plan_cache](const tbb::blocked_range<size_t>& range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
m_print->throw_if_canceled();
print->throw_if_canceled();
m_layers[layer_idx]->make_fills(adaptive_fill_octree.get(), support_fill_octree.get(), this->m_lightning_generator.get(), throw_if_canceled, contoning_stack_plan_cache.get());
const size_t completed = completed_layers.fetch_add(1, std::memory_order_relaxed) + 1;
set_infill_progress(completed);

View File

@@ -688,9 +688,11 @@ static std::string top_surface_contoning_flat_surface_infill_mode_name(int mode)
{
switch (clamp_int(mode,
int(TextureMappingZone::ContoningFlatSurfaceInfillDefault),
int(TextureMappingZone::ContoningFlatSurfaceInfillBoundarySkinHybrid))) {
int(TextureMappingZone::ContoningFlatSurfaceInfillRectilinearWithBoundary))) {
case int(TextureMappingZone::ContoningFlatSurfaceInfillRectilinear):
return "rectilinear";
case int(TextureMappingZone::ContoningFlatSurfaceInfillRectilinearWithBoundary):
return "rectilinear_with_boundary";
case int(TextureMappingZone::ContoningFlatSurfaceInfillConcentric):
return "concentric";
case int(TextureMappingZone::ContoningFlatSurfaceInfillBoundarySkinFixed):
@@ -710,6 +712,8 @@ static int top_surface_contoning_flat_surface_infill_mode_from_name(const std::s
{
if (name == "rectilinear")
return int(TextureMappingZone::ContoningFlatSurfaceInfillRectilinear);
if (name == "rectilinear_with_boundary" || name == "rectilinear_boundary")
return int(TextureMappingZone::ContoningFlatSurfaceInfillRectilinearWithBoundary);
if (name == "concentric")
return int(TextureMappingZone::ContoningFlatSurfaceInfillConcentric);
if (name == "boundary_skin" || name == "boundary_skin_variable")
@@ -1769,9 +1773,9 @@ void TextureMappingManager::load_entries(const std::string &serialized,
top_surface_contoning_flat_surface_infill_mode_from_name(flat_surface_infill_mode_it->get<std::string>()) :
clamp_int(flat_surface_infill_mode_it != texture.end() && flat_surface_infill_mode_it->is_number_integer() ?
flat_surface_infill_mode_it->get<int>() :
TextureMappingZone::DefaultTopSurfaceContoningFlatSurfaceInfillMode,
TextureMappingZone::DefaultTopSurfaceContoningFlatSurfaceInfillMode,
int(TextureMappingZone::ContoningFlatSurfaceInfillDefault),
int(TextureMappingZone::ContoningFlatSurfaceInfillBoundarySkinHybrid));
int(TextureMappingZone::ContoningFlatSurfaceInfillRectilinearWithBoundary));
if (zone.top_surface_contoning_replace_top_perimeters_with_infill)
zone.top_surface_contoning_recolor_surrounding_perimeters = false;
zone.top_surface_contoning_layer_phase_enabled =

View File

@@ -85,7 +85,8 @@ struct TextureMappingZone
ContoningFlatSurfaceInfillBoundarySkinFixed = 3,
ContoningFlatSurfaceInfillBoundarySkinVariable = 4,
ContoningFlatSurfaceInfillSpiral = 5,
ContoningFlatSurfaceInfillBoundarySkinHybrid = 6
ContoningFlatSurfaceInfillBoundarySkinHybrid = 6,
ContoningFlatSurfaceInfillRectilinearWithBoundary = 7
};
enum FilamentColorMode : uint8_t {

View File

@@ -2546,12 +2546,13 @@ public:
contoning_flat_infill_choices.Add(_L("Boundary Skin (variable width)"));
contoning_flat_infill_choices.Add(_L("Spiral"));
contoning_flat_infill_choices.Add(_L("Boundary Skin Hybrid"));
contoning_flat_infill_choices.Add(_L("Rectilinear with Boundary"));
m_top_surface_contoning_flat_surface_infill_choice =
new wxChoice(m_top_surface_contoning_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, contoning_flat_infill_choices);
m_top_surface_contoning_flat_surface_infill_choice->SetSelection(
std::clamp(top_surface_contoning_flat_surface_infill_mode,
int(TextureMappingZone::ContoningFlatSurfaceInfillDefault),
int(TextureMappingZone::ContoningFlatSurfaceInfillBoundarySkinHybrid)));
int(TextureMappingZone::ContoningFlatSurfaceInfillRectilinearWithBoundary)));
contoning_flat_infill_row->Add(m_top_surface_contoning_flat_surface_infill_choice, 1, wxEXPAND);
top_surface_contoning_root->Add(contoning_flat_infill_row, 0, wxEXPAND | wxTOP, gap);
top_surface_box->Add(m_top_surface_contoning_panel, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, gap);
@@ -3063,7 +3064,7 @@ public:
return m_top_surface_contoning_flat_surface_infill_choice != nullptr ?
std::clamp(m_top_surface_contoning_flat_surface_infill_choice->GetSelection(),
int(TextureMappingZone::ContoningFlatSurfaceInfillDefault),
int(TextureMappingZone::ContoningFlatSurfaceInfillBoundarySkinHybrid)) :
int(TextureMappingZone::ContoningFlatSurfaceInfillRectilinearWithBoundary)) :
TextureMappingZone::DefaultTopSurfaceContoningFlatSurfaceInfillMode;
}
bool top_surface_contoning_layer_phase_enabled() const