Fix bug where top surface colors could occasionally be replaced with solid infill
- Add more information to top-surface debug export when environment variable is enabled
This commit is contained in:
@@ -1247,21 +1247,33 @@ static void top_surface_image_debug_write_manifest_locked(const TopSurfaceImageD
|
||||
out << root.dump(2) << '\n';
|
||||
}
|
||||
|
||||
static void top_surface_image_debug_register_layer_file_export(int layer_id,
|
||||
double z_mm,
|
||||
const std::string &phase,
|
||||
TopSurfaceImageDebugFileExport file)
|
||||
{
|
||||
TopSurfaceImageDebugLayerExport entry;
|
||||
entry.layer_id = layer_id;
|
||||
entry.z_mm = z_mm;
|
||||
entry.phase = phase;
|
||||
entry.files.push_back(std::move(file));
|
||||
TopSurfaceImageDebugManifest &manifest = top_surface_image_debug_manifest();
|
||||
std::lock_guard<std::mutex> lock(manifest.mutex);
|
||||
manifest.layers.emplace_back(std::move(entry));
|
||||
top_surface_image_debug_write_manifest_locked(manifest);
|
||||
}
|
||||
|
||||
static void top_surface_image_debug_register_layer_export(int layer_id,
|
||||
double z_mm,
|
||||
const std::string &phase,
|
||||
const std::string &path,
|
||||
const BoundingBox &bbox)
|
||||
{
|
||||
TopSurfaceImageDebugLayerExport entry;
|
||||
entry.layer_id = layer_id;
|
||||
entry.z_mm = z_mm;
|
||||
entry.phase = phase;
|
||||
entry.files.push_back(top_surface_image_debug_file_export("layer_svg", path, bbox));
|
||||
TopSurfaceImageDebugManifest &manifest = top_surface_image_debug_manifest();
|
||||
std::lock_guard<std::mutex> lock(manifest.mutex);
|
||||
manifest.layers.emplace_back(std::move(entry));
|
||||
top_surface_image_debug_write_manifest_locked(manifest);
|
||||
top_surface_image_debug_register_layer_file_export(
|
||||
layer_id,
|
||||
z_mm,
|
||||
phase,
|
||||
top_surface_image_debug_file_export("layer_svg", path, bbox));
|
||||
}
|
||||
|
||||
static void top_surface_image_debug_export_object_mesh(const PrintObject &object)
|
||||
@@ -4046,6 +4058,37 @@ static std::vector<ExPolygons> top_surface_image_contoning_vector_border_shared_
|
||||
return areas;
|
||||
}
|
||||
|
||||
static bool top_surface_image_contoning_areas_exceed_target_partition(const std::vector<ExPolygons> &areas,
|
||||
const std::vector<int> &ids,
|
||||
const std::vector<int> &cell_counts,
|
||||
const ExPolygons &target_area,
|
||||
const ThrowIfCanceled *throw_if_canceled)
|
||||
{
|
||||
const double target_area_abs = top_surface_image_abs_area(target_area);
|
||||
if (target_area_abs <= 0.)
|
||||
return false;
|
||||
|
||||
int total_cells = 0;
|
||||
for (int id : ids)
|
||||
if (id >= 0 && size_t(id) < cell_counts.size())
|
||||
total_cells += cell_counts[size_t(id)];
|
||||
|
||||
double summed_area = 0.;
|
||||
for (int id : ids) {
|
||||
check_canceled(throw_if_canceled);
|
||||
if (id < 0 || size_t(id) >= areas.size())
|
||||
continue;
|
||||
const double area_abs = top_surface_image_abs_area(areas[size_t(id)]);
|
||||
summed_area += area_abs;
|
||||
if (total_cells > 0 && size_t(id) < cell_counts.size() && cell_counts[size_t(id)] > 0) {
|
||||
const double cell_fraction = double(cell_counts[size_t(id)]) / double(total_cells);
|
||||
if (area_abs > target_area_abs * 0.90 && cell_fraction < 0.80)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return summed_area > target_area_abs * 1.10;
|
||||
}
|
||||
|
||||
static std::vector<ExPolygons> top_surface_image_contoning_mid_gaussian_shared_chain_fit_areas(
|
||||
const std::vector<int> &grid,
|
||||
int cols,
|
||||
@@ -4278,21 +4321,28 @@ static std::vector<TopSurfaceImageContoningVectorRegion> top_surface_image_conto
|
||||
effective_polygonization_mode == int(TextureMappingZone::ContoningPolygonizationMarchingSquares);
|
||||
const ExPolygons empty_blocked_area;
|
||||
ExPolygons valid_area;
|
||||
bool valid_area_initialized = false;
|
||||
auto ensure_valid_area = [&]() -> bool {
|
||||
if (!valid_area_initialized) {
|
||||
valid_area = top_surface_image_contoning_area_from_grid_label(valid_grid,
|
||||
cols,
|
||||
rows,
|
||||
1,
|
||||
min_x,
|
||||
min_y,
|
||||
step,
|
||||
bbox,
|
||||
area,
|
||||
empty_blocked_area,
|
||||
min_feature_mm,
|
||||
cleanup_optimizations_enabled,
|
||||
throw_if_canceled);
|
||||
valid_area_initialized = true;
|
||||
}
|
||||
return !valid_area.empty();
|
||||
};
|
||||
if (!raw_partition_hierarchy_convert && !mid_gaussian_shared_chain_fit) {
|
||||
valid_area = top_surface_image_contoning_area_from_grid_label(valid_grid,
|
||||
cols,
|
||||
rows,
|
||||
1,
|
||||
min_x,
|
||||
min_y,
|
||||
step,
|
||||
bbox,
|
||||
area,
|
||||
empty_blocked_area,
|
||||
min_feature_mm,
|
||||
cleanup_optimizations_enabled,
|
||||
throw_if_canceled);
|
||||
if (valid_area.empty())
|
||||
if (!ensure_valid_area())
|
||||
return regions;
|
||||
}
|
||||
|
||||
@@ -4337,6 +4387,29 @@ static std::vector<TopSurfaceImageContoningVectorRegion> top_surface_image_conto
|
||||
step,
|
||||
bbox,
|
||||
throw_if_canceled);
|
||||
const bool has_valid_area = ensure_valid_area();
|
||||
const ExPolygons &partition_target_area = has_valid_area ? valid_area : area;
|
||||
if (has_valid_area &&
|
||||
top_surface_image_contoning_areas_exceed_target_partition(component_areas,
|
||||
component_order,
|
||||
cell_counts,
|
||||
partition_target_area,
|
||||
throw_if_canceled)) {
|
||||
component_areas =
|
||||
top_surface_image_contoning_vector_border_shared_gaussian_partition_areas(component_grid,
|
||||
cols,
|
||||
rows,
|
||||
component_order,
|
||||
size_t(max_component_id) + 1,
|
||||
min_x,
|
||||
min_y,
|
||||
step,
|
||||
bbox,
|
||||
valid_area,
|
||||
min_feature_mm,
|
||||
cleanup_optimizations_enabled,
|
||||
throw_if_canceled);
|
||||
}
|
||||
for (int component_id : component_order) {
|
||||
check_canceled(throw_if_canceled);
|
||||
if (component_id <= 0 || size_t(component_id) >= component_areas.size() ||
|
||||
@@ -4508,6 +4581,26 @@ static std::vector<TopSurfaceImageContoningVectorRegion> top_surface_image_conto
|
||||
step,
|
||||
bbox,
|
||||
throw_if_canceled);
|
||||
if (top_surface_image_contoning_areas_exceed_target_partition(label_areas,
|
||||
label_order,
|
||||
cell_counts,
|
||||
area,
|
||||
throw_if_canceled)) {
|
||||
label_areas =
|
||||
top_surface_image_contoning_vector_border_shared_gaussian_partition_areas(label_grid,
|
||||
cols,
|
||||
rows,
|
||||
label_order,
|
||||
labels.size(),
|
||||
min_x,
|
||||
min_y,
|
||||
step,
|
||||
bbox,
|
||||
area,
|
||||
min_feature_mm,
|
||||
cleanup_optimizations_enabled,
|
||||
throw_if_canceled);
|
||||
}
|
||||
for (int label : label_order) {
|
||||
check_canceled(throw_if_canceled);
|
||||
if (label < 0 || size_t(label) >= label_areas.size() || label_areas[size_t(label)].empty())
|
||||
@@ -5414,6 +5507,7 @@ static std::optional<TopSurfaceImageContoningCellSample> top_surface_image_conto
|
||||
const ExPolygons &normal_filter_bypass_area,
|
||||
int stack_layers,
|
||||
int pattern_filaments,
|
||||
int minimum_solve_layers,
|
||||
int depth,
|
||||
coord_t x0,
|
||||
coord_t y0,
|
||||
@@ -5432,7 +5526,9 @@ static std::optional<TopSurfaceImageContoningCellSample> top_surface_image_conto
|
||||
top_surface_image_contoning_local_stack_layers_at_point(sample_point, source_stack_areas, stack_layers);
|
||||
if (local_stack_layers <= 0 || (depth >= 0 && depth >= local_stack_layers))
|
||||
return;
|
||||
const int solve_layers = std::min({ local_stack_layers, stack_layers, pattern_filaments });
|
||||
int solve_layers = std::min({ local_stack_layers, stack_layers, pattern_filaments });
|
||||
if (minimum_solve_layers > 0)
|
||||
solve_layers = std::max(solve_layers, std::min({ minimum_solve_layers, stack_layers, pattern_filaments }));
|
||||
if (solve_layers <= 0)
|
||||
return;
|
||||
const float sample_x_mm = unscale<float>(sample_point.x());
|
||||
@@ -5623,6 +5719,10 @@ static void top_surface_image_contoning_resolve_merged_grid_regions(
|
||||
std::vector<TopSurfaceImageContoningVectorLabel> resolved_labels;
|
||||
TopSurfaceImageContoningStackLabelMap label_by_stack;
|
||||
std::vector<unsigned char> visited(grid.size(), 0);
|
||||
const int minimum_solve_layers =
|
||||
lower_surface && solver.nearest_measured_sample_mode() ?
|
||||
std::min(stack_layers, pattern_filaments) :
|
||||
0;
|
||||
|
||||
auto append_fallback_label = [&](int source_label) {
|
||||
if (source_label < 0 || source_label >= int(labels.size()))
|
||||
@@ -5700,7 +5800,11 @@ static void top_surface_image_contoning_resolve_merged_grid_regions(
|
||||
float(oklab_sum[2] / sample_weight)
|
||||
};
|
||||
const std::array<float, 3> average_rgb = color_solver_srgb_from_oklab(average_oklab);
|
||||
const int solve_layers = std::min({ visible_layers, stack_layers, pattern_filaments });
|
||||
int solve_layers = std::min({ visible_layers, stack_layers, pattern_filaments });
|
||||
if (minimum_solve_layers > 0) {
|
||||
solve_layers = std::max(solve_layers, minimum_solve_layers);
|
||||
visible_layers = std::max(visible_layers, solve_layers);
|
||||
}
|
||||
if (solve_layers > 0) {
|
||||
std::optional<TopSurfaceImageContoningSolvedLabel> solved =
|
||||
top_surface_image_contoning_solve_label(average_rgb,
|
||||
@@ -5901,6 +6005,10 @@ static void top_surface_image_contoning_solve_anchored_region(
|
||||
const bool lower_surface =
|
||||
source_surface == TopSurfaceImageSourceSurface::Bottom &&
|
||||
plan.contoning_td_adjustment_enabled;
|
||||
const int minimum_solve_layers =
|
||||
lower_surface && solver.nearest_measured_sample_mode() ?
|
||||
std::min(source_context.stack_layers, source_context.pattern_filaments) :
|
||||
0;
|
||||
|
||||
auto label_cell = [&](int row, int col, const TextureMappingContoningStack &stack, int available_depth) {
|
||||
std::optional<TopSurfaceImageContoningSolvedLabel> solved =
|
||||
@@ -5931,6 +6039,7 @@ static void top_surface_image_contoning_solve_anchored_region(
|
||||
source_context.normal_filter_bypass_area,
|
||||
source_context.stack_layers,
|
||||
source_context.pattern_filaments,
|
||||
minimum_solve_layers,
|
||||
-1,
|
||||
x0,
|
||||
y0,
|
||||
@@ -7576,6 +7685,12 @@ static std::vector<TopSurfaceImageContoningVectorRegion> top_surface_image_conto
|
||||
std::vector<int> grid(size_t(cols) * size_t(rows), -1);
|
||||
std::vector<TopSurfaceImageContoningVectorLabel> labels;
|
||||
TopSurfaceImageContoningStackLabelMap label_by_stack;
|
||||
const int minimum_solve_layers =
|
||||
source_surface == TopSurfaceImageSourceSurface::Bottom &&
|
||||
plan.contoning_td_adjustment_enabled &&
|
||||
solver.nearest_measured_sample_mode() ?
|
||||
std::min(source->stack_layers, source->pattern_filaments) :
|
||||
0;
|
||||
|
||||
auto solve_cell = [&](int row, int col, const std::array<float, 3> &target_rgb, int solve_layers, int) {
|
||||
std::optional<TopSurfaceImageContoningSolvedLabel> solved =
|
||||
@@ -7607,6 +7722,7 @@ static std::vector<TopSurfaceImageContoningVectorRegion> top_surface_image_conto
|
||||
source->normal_filter_bypass_area,
|
||||
source->stack_layers,
|
||||
source->pattern_filaments,
|
||||
minimum_solve_layers,
|
||||
depth,
|
||||
x0,
|
||||
y0,
|
||||
@@ -7792,6 +7908,12 @@ static std::shared_ptr<const TopSurfaceImageContoningStackPlan> top_surface_imag
|
||||
out->cells.assign(size_t(cols) * size_t(rows), TopSurfaceImageContoningStackPlanCell());
|
||||
|
||||
TopSurfaceImageContoningStackLabelMap label_by_stack;
|
||||
const int minimum_solve_layers =
|
||||
source_surface == TopSurfaceImageSourceSurface::Bottom &&
|
||||
plan.contoning_td_adjustment_enabled &&
|
||||
solver.nearest_measured_sample_mode() ?
|
||||
std::min(source_context->stack_layers, source_context->pattern_filaments) :
|
||||
0;
|
||||
|
||||
auto solve_cell = [&](int row, int col, const std::array<float, 3> &target_rgb, int solve_layers, int available_depth) {
|
||||
std::optional<TopSurfaceImageContoningSolvedLabel> solved =
|
||||
@@ -7825,6 +7947,7 @@ static std::shared_ptr<const TopSurfaceImageContoningStackPlan> top_surface_imag
|
||||
source_context->normal_filter_bypass_area,
|
||||
source_context->stack_layers,
|
||||
source_context->pattern_filaments,
|
||||
minimum_solve_layers,
|
||||
-1,
|
||||
x0,
|
||||
y0,
|
||||
@@ -8391,15 +8514,16 @@ static void top_surface_image_append_contoning_slices(TopSurfaceImageRegionPlan
|
||||
auto append_regions = [&](const std::vector<TopSurfaceImageContoningVectorRegion> ®ions,
|
||||
bool for_fill,
|
||||
bool for_perimeter) {
|
||||
const ApplySafetyOffset clip_safety_offset =
|
||||
used_raw_top_surface_labels ? ApplySafetyOffset::No : ApplySafetyOffset::Yes;
|
||||
const ApplySafetyOffset clip_safety_offset = ApplySafetyOffset::No;
|
||||
for (const TopSurfaceImageContoningVectorRegion ®ion : regions) {
|
||||
check_canceled(throw_if_canceled);
|
||||
if (depth < 0 || region.bottom_to_top.empty() || region.area.empty())
|
||||
continue;
|
||||
const int pattern_depth = depth % int(region.bottom_to_top.size());
|
||||
const unsigned int component_id =
|
||||
region.bottom_to_top[size_t(int(region.bottom_to_top.size()) - 1 - pattern_depth)];
|
||||
source_surface == TopSurfaceImageSourceSurface::Bottom ?
|
||||
region.bottom_to_top[size_t(pattern_depth)] :
|
||||
region.bottom_to_top[size_t(int(region.bottom_to_top.size()) - 1 - pattern_depth)];
|
||||
if (component_id == 0 || component_id >= by_component.size())
|
||||
continue;
|
||||
if (for_perimeter &&
|
||||
@@ -8618,11 +8742,11 @@ static void top_surface_image_append_contoning_slices(TopSurfaceImageRegionPlan
|
||||
if (!depth_taken.empty() && !component_area.empty())
|
||||
component_area = top_surface_clip_diff_ex(component_area,
|
||||
depth_taken,
|
||||
used_raw_top_surface_labels ? ApplySafetyOffset::No : ApplySafetyOffset::Yes);
|
||||
ApplySafetyOffset::No);
|
||||
if (!perimeter_depth_taken.empty() && !component_perimeter_area.empty())
|
||||
component_perimeter_area = top_surface_clip_diff_ex(component_perimeter_area,
|
||||
perimeter_depth_taken,
|
||||
used_raw_top_surface_labels ? ApplySafetyOffset::No : ApplySafetyOffset::Yes);
|
||||
ApplySafetyOffset::No);
|
||||
if (component_area.empty() && component_perimeter_area.empty())
|
||||
continue;
|
||||
if (!component_area.empty())
|
||||
@@ -11613,6 +11737,201 @@ struct GroupFillsOptions
|
||||
TopSurfaceImageContoningStackPlanCache *contoning_stack_plan_cache { nullptr };
|
||||
};
|
||||
|
||||
static const char* top_surface_image_debug_surface_type_label(SurfaceType type)
|
||||
{
|
||||
switch (type) {
|
||||
case stTop: return "top";
|
||||
case stBottom: return "bottom";
|
||||
case stBottomBridge: return "bottom_bridge";
|
||||
case stInternalAfterExternalBridge: return "internal_after_external_bridge";
|
||||
case stInternal: return "internal";
|
||||
case stInternalSolid: return "internal_solid";
|
||||
case stInternalBridge: return "internal_bridge";
|
||||
case stSecondInternalBridge: return "second_internal_bridge";
|
||||
case stInternalVoid: return "internal_void";
|
||||
case stPerimeter: return "perimeter";
|
||||
case stCount: return "count";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static const char* top_surface_image_debug_extrusion_role_label(ExtrusionRole role)
|
||||
{
|
||||
switch (role) {
|
||||
case erNone: return "none";
|
||||
case erPerimeter: return "perimeter";
|
||||
case erExternalPerimeter: return "external_perimeter";
|
||||
case erOverhangPerimeter: return "overhang_perimeter";
|
||||
case erInternalInfill: return "internal_infill";
|
||||
case erSolidInfill: return "solid_infill";
|
||||
case erTopSolidInfill: return "top_solid_infill";
|
||||
case erBottomSurface: return "bottom_surface";
|
||||
case erIroning: return "ironing";
|
||||
case erBridgeInfill: return "bridge_infill";
|
||||
case erInternalBridgeInfill: return "internal_bridge_infill";
|
||||
case erGapFill: return "gap_fill";
|
||||
case erSkirt: return "skirt";
|
||||
case erBrim: return "brim";
|
||||
case erSupportMaterial: return "support_material";
|
||||
case erSupportMaterialInterface: return "support_material_interface";
|
||||
case erSupportTransition: return "support_transition";
|
||||
case erWipeTower: return "wipe_tower";
|
||||
case erCustom: return "custom";
|
||||
case erMixed: return "mixed";
|
||||
case erCount: return "count";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static double top_surface_image_debug_area_mm2(const ExPolygons &area)
|
||||
{
|
||||
return top_surface_image_scaled_area_mm2(top_surface_image_abs_area(area));
|
||||
}
|
||||
|
||||
static long long top_surface_image_debug_optional_index(size_t idx)
|
||||
{
|
||||
return idx == size_t(-1) ? -1 : static_cast<long long>(idx);
|
||||
}
|
||||
|
||||
struct TopSurfaceImageReplacementTrace
|
||||
{
|
||||
bool enabled { false };
|
||||
bool has_rows { false };
|
||||
std::ostringstream csv;
|
||||
std::vector<std::pair<ExPolygons, SVG::ExPolygonAttributes>> svg_items;
|
||||
|
||||
explicit TopSurfaceImageReplacementTrace(bool enabled)
|
||||
: enabled(enabled)
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
csv << std::fixed << std::setprecision(6);
|
||||
csv << "event,layer_id,z_mm,region_id,surface_index,surface_type,extrusion_role,zone_id,"
|
||||
"slice_begin,slice_end,slice_index,depth,lower_surface,contoning,raw_labels,same_layer_partition,"
|
||||
"component_id,component_index,component_count,slice_area_mm2,slice_perimeter_area_mm2,"
|
||||
"remaining_before_mm2,image_expolygons_mm2,component_intersection_mm2,component_printed_mm2,"
|
||||
"component_intersection_sum_mm2,depth_clip_union_mm2,image_clip_mm2,remaining_after_mm2,"
|
||||
"reservation_overlap_mm2,original_appended_mm2\n";
|
||||
}
|
||||
|
||||
void add_row(const char *event,
|
||||
const Layer &layer,
|
||||
size_t region_id,
|
||||
size_t surface_index,
|
||||
SurfaceType surface_type,
|
||||
ExtrusionRole extrusion_role,
|
||||
unsigned int zone_id,
|
||||
size_t slice_begin,
|
||||
size_t slice_end,
|
||||
size_t slice_index,
|
||||
int depth,
|
||||
bool lower_surface,
|
||||
bool contoning,
|
||||
bool raw_labels,
|
||||
bool same_layer_partition,
|
||||
unsigned int component_id,
|
||||
size_t component_index,
|
||||
size_t component_count,
|
||||
double slice_area_mm2,
|
||||
double slice_perimeter_area_mm2,
|
||||
double remaining_before_mm2,
|
||||
double image_expolygons_mm2,
|
||||
double component_intersection_mm2,
|
||||
double component_printed_mm2,
|
||||
double component_intersection_sum_mm2,
|
||||
double depth_clip_union_mm2,
|
||||
double image_clip_mm2,
|
||||
double remaining_after_mm2,
|
||||
double reservation_overlap_mm2,
|
||||
double original_appended_mm2)
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
has_rows = true;
|
||||
csv << event << ','
|
||||
<< layer.id() << ','
|
||||
<< layer.print_z << ','
|
||||
<< region_id << ','
|
||||
<< surface_index << ','
|
||||
<< top_surface_image_debug_surface_type_label(surface_type) << ','
|
||||
<< top_surface_image_debug_extrusion_role_label(extrusion_role) << ','
|
||||
<< zone_id << ','
|
||||
<< top_surface_image_debug_optional_index(slice_begin) << ','
|
||||
<< top_surface_image_debug_optional_index(slice_end) << ','
|
||||
<< top_surface_image_debug_optional_index(slice_index) << ','
|
||||
<< depth << ','
|
||||
<< (lower_surface ? 1 : 0) << ','
|
||||
<< (contoning ? 1 : 0) << ','
|
||||
<< (raw_labels ? 1 : 0) << ','
|
||||
<< (same_layer_partition ? 1 : 0) << ','
|
||||
<< component_id << ','
|
||||
<< top_surface_image_debug_optional_index(component_index) << ','
|
||||
<< top_surface_image_debug_optional_index(component_count) << ','
|
||||
<< slice_area_mm2 << ','
|
||||
<< slice_perimeter_area_mm2 << ','
|
||||
<< remaining_before_mm2 << ','
|
||||
<< image_expolygons_mm2 << ','
|
||||
<< component_intersection_mm2 << ','
|
||||
<< component_printed_mm2 << ','
|
||||
<< component_intersection_sum_mm2 << ','
|
||||
<< depth_clip_union_mm2 << ','
|
||||
<< image_clip_mm2 << ','
|
||||
<< remaining_after_mm2 << ','
|
||||
<< reservation_overlap_mm2 << ','
|
||||
<< original_appended_mm2 << '\n';
|
||||
}
|
||||
|
||||
void add_svg(ExPolygons area,
|
||||
const std::string &legend,
|
||||
const std::string &fill,
|
||||
float opacity,
|
||||
const std::string &outline)
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
top_surface_image_debug_add_svg_item(svg_items, std::move(area), legend, fill, opacity, outline);
|
||||
}
|
||||
|
||||
void write(const Layer &layer)
|
||||
{
|
||||
if (!enabled || !has_rows)
|
||||
return;
|
||||
|
||||
std::ostringstream stem;
|
||||
stem << "layer_"
|
||||
<< std::setw(5) << std::setfill('0') << layer.id()
|
||||
<< "_z_" << top_surface_image_debug_z_string(layer.print_z)
|
||||
<< "_replacement_trace";
|
||||
|
||||
const std::string csv_filename = stem.str() + ".csv";
|
||||
{
|
||||
const std::filesystem::path path = top_surface_image_debug_output_dir() / csv_filename;
|
||||
std::ofstream out(path.string());
|
||||
if (out) {
|
||||
out << csv.str();
|
||||
top_surface_image_debug_register_layer_file_export(
|
||||
layer.id(),
|
||||
layer.print_z,
|
||||
"replacement_trace",
|
||||
top_surface_image_debug_file_export("replacement_trace_csv", csv_filename));
|
||||
}
|
||||
}
|
||||
|
||||
if (svg_items.empty())
|
||||
return;
|
||||
|
||||
const std::string svg_filename = stem.str() + ".svg";
|
||||
const std::filesystem::path svg_path = top_surface_image_debug_output_dir() / svg_filename;
|
||||
const BoundingBox svg_bbox = top_surface_image_debug_svg_bbox(svg_items);
|
||||
SVG::export_expolygons(svg_path.string(), svg_items);
|
||||
top_surface_image_debug_register_layer_file_export(
|
||||
layer.id(),
|
||||
layer.print_z,
|
||||
"replacement_trace",
|
||||
top_surface_image_debug_file_export("replacement_trace_svg", svg_filename, svg_bbox));
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<SurfaceFill> group_fills(const Layer &layer,
|
||||
LockRegionParam &lock_param,
|
||||
const GroupFillsOptions &options)
|
||||
@@ -11638,6 +11957,16 @@ std::vector<SurfaceFill> group_fills(const Layer &layer,
|
||||
top_surface_replacement_reservations[region_id] =
|
||||
top_surface_image_contoning_replacement_reservation_area(top_surface_plans[region_id]);
|
||||
}
|
||||
TopSurfaceImageReplacementTrace replacement_trace(top_surface_image_debug_enabled() && build_top_surface_plans);
|
||||
auto replacement_trace_legend = [](const char *label, size_t region_id, size_t surface_index, int depth, unsigned int component_id) {
|
||||
std::ostringstream out;
|
||||
out << label << " r" << region_id << " s" << surface_index;
|
||||
if (depth >= 0)
|
||||
out << " d" << depth;
|
||||
if (component_id != 0)
|
||||
out << " c" << component_id;
|
||||
return out.str();
|
||||
};
|
||||
|
||||
auto append_flow_param = [](std::map<Flow, ExPolygons> &flow_params, Flow flow, const ExPolygon &exp) {
|
||||
auto it = flow_params.find(flow);
|
||||
@@ -11817,12 +12146,52 @@ std::vector<SurfaceFill> group_fills(const Layer &layer,
|
||||
if (surface.surface_type != stInternalVoid) {
|
||||
const SurfaceFillParams *params = region_to_surface_params[region_id][&surface - &layerm.fill_surfaces.surfaces.front()];
|
||||
if (params != nullptr) {
|
||||
const size_t surface_index = size_t(&surface - &layerm.fill_surfaces.surfaces.front());
|
||||
ExPolygons remaining = { surface.expolygon };
|
||||
if (region_id < top_surface_plans.size() &&
|
||||
const bool replacement_candidate =
|
||||
region_id < top_surface_plans.size() &&
|
||||
top_surface_plans[region_id].zone != nullptr &&
|
||||
(surface.is_top() || surface.surface_type == stInternalSolid || surface.surface_type == stBottom) &&
|
||||
!surface.is_bridge()) {
|
||||
!surface.is_bridge();
|
||||
if (replacement_candidate) {
|
||||
const TopSurfaceImageRegionPlan &plan = top_surface_plans[region_id];
|
||||
if (replacement_trace.enabled) {
|
||||
replacement_trace.add_row("surface_start",
|
||||
layer,
|
||||
region_id,
|
||||
surface_index,
|
||||
surface.surface_type,
|
||||
params->extrusion_role,
|
||||
plan.zone_id,
|
||||
size_t(-1),
|
||||
size_t(-1),
|
||||
size_t(-1),
|
||||
-1,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
size_t(-1),
|
||||
size_t(-1),
|
||||
0.,
|
||||
0.,
|
||||
top_surface_image_debug_area_mm2(remaining),
|
||||
0.,
|
||||
0.,
|
||||
0.,
|
||||
0.,
|
||||
0.,
|
||||
0.,
|
||||
top_surface_image_debug_area_mm2(remaining),
|
||||
0.,
|
||||
0.);
|
||||
replacement_trace.add_svg(ExPolygons { surface.expolygon },
|
||||
replacement_trace_legend("source surface", region_id, surface_index, -1, 0),
|
||||
"#bdbdbd",
|
||||
0.12f,
|
||||
"#636363");
|
||||
}
|
||||
for (size_t slice_idx = 0; slice_idx < plan.slices.size();) {
|
||||
check_canceled(throw_if_canceled);
|
||||
const TopSurfaceImageStackSlice &slice = plan.slices[slice_idx];
|
||||
@@ -11833,13 +12202,54 @@ std::vector<SurfaceFill> group_fills(const Layer &layer,
|
||||
if (remaining.empty())
|
||||
break;
|
||||
const ApplySafetyOffset slice_safety_offset =
|
||||
slice.raw_top_surface_labels ? ApplySafetyOffset::No : ApplySafetyOffset::Yes;
|
||||
(slice.raw_top_surface_labels || slice.contoning || slice.same_layer_partition) ?
|
||||
ApplySafetyOffset::No :
|
||||
ApplySafetyOffset::Yes;
|
||||
const double remaining_before_mm2 = replacement_trace.enabled ?
|
||||
top_surface_image_debug_area_mm2(remaining) :
|
||||
0.;
|
||||
ExPolygons image_expolygons = top_surface_clip_intersection_ex(remaining, slice.area, slice_safety_offset);
|
||||
if (image_expolygons.empty() && !slice.contoning) {
|
||||
if (replacement_trace.enabled)
|
||||
replacement_trace.add_row("slice_empty_skip",
|
||||
layer,
|
||||
region_id,
|
||||
surface_index,
|
||||
surface.surface_type,
|
||||
params->extrusion_role,
|
||||
plan.zone_id,
|
||||
slice_idx,
|
||||
slice_idx + 1,
|
||||
slice_idx,
|
||||
slice.depth,
|
||||
slice.lower_surface,
|
||||
slice.contoning,
|
||||
slice.raw_top_surface_labels,
|
||||
slice.same_layer_partition,
|
||||
slice.component_id,
|
||||
slice.component_index,
|
||||
slice.component_count,
|
||||
top_surface_image_debug_area_mm2(slice.area),
|
||||
top_surface_image_debug_area_mm2(slice.perimeter_area),
|
||||
remaining_before_mm2,
|
||||
0.,
|
||||
0.,
|
||||
0.,
|
||||
0.,
|
||||
0.,
|
||||
0.,
|
||||
remaining_before_mm2,
|
||||
0.,
|
||||
0.);
|
||||
++slice_idx;
|
||||
continue;
|
||||
}
|
||||
ExPolygons image_clip = image_expolygons;
|
||||
const double image_expolygons_mm2 = replacement_trace.enabled ?
|
||||
top_surface_image_debug_area_mm2(image_expolygons) :
|
||||
0.;
|
||||
double component_intersection_sum_mm2 = 0.;
|
||||
double depth_clip_union_mm2 = 0.;
|
||||
if (slice.same_layer_partition || slice.contoning) {
|
||||
size_t same_depth_end = slice_idx;
|
||||
while (same_depth_end < plan.slices.size() &&
|
||||
@@ -11852,11 +12262,19 @@ std::vector<SurfaceFill> group_fills(const Layer &layer,
|
||||
ExPolygons depth_clip;
|
||||
for (size_t same_idx = slice_idx; same_idx < same_depth_end; ++same_idx) {
|
||||
check_canceled(throw_if_canceled);
|
||||
const TopSurfaceImageStackSlice &same_slice = plan.slices[same_idx];
|
||||
SurfaceFillParams image_params =
|
||||
top_surface_image_params_for_slice(layer, surface, *params, plan, plan.slices[same_idx]);
|
||||
top_surface_image_params_for_slice(layer, surface, *params, plan, same_slice);
|
||||
ExPolygons component_expolygons = slice.same_layer_partition ?
|
||||
image_expolygons :
|
||||
top_surface_clip_intersection_ex(remaining, plan.slices[same_idx].area, slice_safety_offset);
|
||||
top_surface_clip_intersection_ex(remaining, same_slice.area, slice_safety_offset);
|
||||
const double component_intersection_mm2 = replacement_trace.enabled ?
|
||||
top_surface_image_debug_area_mm2(component_expolygons) :
|
||||
0.;
|
||||
component_intersection_sum_mm2 += component_intersection_mm2;
|
||||
ExPolygons debug_component_expolygons =
|
||||
replacement_trace.enabled ? component_expolygons : ExPolygons();
|
||||
double component_printed_mm2 = 0.;
|
||||
if (!component_expolygons.empty()) {
|
||||
append(depth_clip, component_expolygons);
|
||||
if (plan.slices[same_idx].contoning &&
|
||||
@@ -11865,23 +12283,173 @@ std::vector<SurfaceFill> group_fills(const Layer &layer,
|
||||
component_expolygons = top_surface_clip_intersection_ex(component_expolygons,
|
||||
layerm.fill_no_overlap_expolygons,
|
||||
slice_safety_offset);
|
||||
component_printed_mm2 = replacement_trace.enabled ?
|
||||
top_surface_image_debug_area_mm2(component_expolygons) :
|
||||
0.;
|
||||
if (replacement_trace.enabled) {
|
||||
const std::string color = top_surface_image_debug_palette_color(same_slice.component_id);
|
||||
replacement_trace.add_svg(std::move(debug_component_expolygons),
|
||||
replacement_trace_legend("component intersection",
|
||||
region_id,
|
||||
surface_index,
|
||||
same_slice.depth,
|
||||
same_slice.component_id),
|
||||
color,
|
||||
0.22f,
|
||||
color);
|
||||
}
|
||||
if (!component_expolygons.empty()) {
|
||||
SurfaceFill &image_fill = surface_fill_for_params(surface_fills, image_params);
|
||||
append_surface_fill_expolygons(image_fill, region_id, surface, std::move(component_expolygons), layerm);
|
||||
}
|
||||
}
|
||||
if (replacement_trace.enabled)
|
||||
replacement_trace.add_row("component",
|
||||
layer,
|
||||
region_id,
|
||||
surface_index,
|
||||
surface.surface_type,
|
||||
image_params.extrusion_role,
|
||||
plan.zone_id,
|
||||
slice_idx,
|
||||
same_depth_end,
|
||||
same_idx,
|
||||
same_slice.depth,
|
||||
same_slice.lower_surface,
|
||||
same_slice.contoning,
|
||||
same_slice.raw_top_surface_labels,
|
||||
same_slice.same_layer_partition,
|
||||
same_slice.component_id,
|
||||
same_slice.component_index,
|
||||
same_slice.component_count,
|
||||
top_surface_image_debug_area_mm2(same_slice.area),
|
||||
top_surface_image_debug_area_mm2(same_slice.perimeter_area),
|
||||
remaining_before_mm2,
|
||||
image_expolygons_mm2,
|
||||
component_intersection_mm2,
|
||||
component_printed_mm2,
|
||||
0.,
|
||||
0.,
|
||||
0.,
|
||||
0.,
|
||||
0.,
|
||||
0.);
|
||||
}
|
||||
if (!depth_clip.empty())
|
||||
if (!depth_clip.empty()) {
|
||||
image_clip = top_surface_clip_union_ex(depth_clip);
|
||||
depth_clip_union_mm2 = replacement_trace.enabled ?
|
||||
top_surface_image_debug_area_mm2(image_clip) :
|
||||
0.;
|
||||
}
|
||||
const double image_clip_mm2 = replacement_trace.enabled ?
|
||||
top_surface_image_debug_area_mm2(image_clip) :
|
||||
0.;
|
||||
ExPolygons remaining_after = top_surface_clip_diff_ex(remaining, image_clip, slice_safety_offset);
|
||||
const double remaining_after_mm2 = replacement_trace.enabled ?
|
||||
top_surface_image_debug_area_mm2(remaining_after) :
|
||||
0.;
|
||||
if (replacement_trace.enabled) {
|
||||
replacement_trace.add_row("slice_group",
|
||||
layer,
|
||||
region_id,
|
||||
surface_index,
|
||||
surface.surface_type,
|
||||
params->extrusion_role,
|
||||
plan.zone_id,
|
||||
slice_idx,
|
||||
same_depth_end,
|
||||
size_t(-1),
|
||||
slice.depth,
|
||||
slice.lower_surface,
|
||||
slice.contoning,
|
||||
slice.raw_top_surface_labels,
|
||||
slice.same_layer_partition,
|
||||
0,
|
||||
size_t(-1),
|
||||
size_t(-1),
|
||||
top_surface_image_debug_area_mm2(slice.area),
|
||||
top_surface_image_debug_area_mm2(slice.perimeter_area),
|
||||
remaining_before_mm2,
|
||||
image_expolygons_mm2,
|
||||
0.,
|
||||
0.,
|
||||
component_intersection_sum_mm2,
|
||||
depth_clip_union_mm2,
|
||||
image_clip_mm2,
|
||||
remaining_after_mm2,
|
||||
0.,
|
||||
0.);
|
||||
replacement_trace.add_svg(image_clip,
|
||||
replacement_trace_legend("image clip", region_id, surface_index, slice.depth, 0),
|
||||
"#00a65a",
|
||||
0.18f,
|
||||
"#006d2c");
|
||||
replacement_trace.add_svg(remaining_after,
|
||||
replacement_trace_legend("remaining after image", region_id, surface_index, slice.depth, 0),
|
||||
"#fb6a4a",
|
||||
0.26f,
|
||||
"#cb181d");
|
||||
}
|
||||
remaining = std::move(remaining_after);
|
||||
slice_idx = same_depth_end;
|
||||
} else {
|
||||
SurfaceFillParams image_params =
|
||||
top_surface_image_params_for_slice(layer, surface, *params, plan, slice);
|
||||
SurfaceFill &image_fill = surface_fill_for_params(surface_fills, image_params);
|
||||
append_surface_fill_expolygons(image_fill, region_id, surface, std::move(image_expolygons), layerm);
|
||||
const double image_clip_mm2 = replacement_trace.enabled ?
|
||||
top_surface_image_debug_area_mm2(image_clip) :
|
||||
0.;
|
||||
ExPolygons remaining_after = top_surface_clip_diff_ex(remaining, image_clip, slice_safety_offset);
|
||||
const double remaining_after_mm2 = replacement_trace.enabled ?
|
||||
top_surface_image_debug_area_mm2(remaining_after) :
|
||||
0.;
|
||||
if (replacement_trace.enabled) {
|
||||
replacement_trace.add_row("single_slice",
|
||||
layer,
|
||||
region_id,
|
||||
surface_index,
|
||||
surface.surface_type,
|
||||
image_params.extrusion_role,
|
||||
plan.zone_id,
|
||||
slice_idx,
|
||||
slice_idx + 1,
|
||||
slice_idx,
|
||||
slice.depth,
|
||||
slice.lower_surface,
|
||||
slice.contoning,
|
||||
slice.raw_top_surface_labels,
|
||||
slice.same_layer_partition,
|
||||
slice.component_id,
|
||||
slice.component_index,
|
||||
slice.component_count,
|
||||
top_surface_image_debug_area_mm2(slice.area),
|
||||
top_surface_image_debug_area_mm2(slice.perimeter_area),
|
||||
remaining_before_mm2,
|
||||
image_expolygons_mm2,
|
||||
image_clip_mm2,
|
||||
image_clip_mm2,
|
||||
image_clip_mm2,
|
||||
image_clip_mm2,
|
||||
image_clip_mm2,
|
||||
remaining_after_mm2,
|
||||
0.,
|
||||
0.);
|
||||
const std::string color = top_surface_image_debug_palette_color(slice.component_id);
|
||||
replacement_trace.add_svg(image_clip,
|
||||
replacement_trace_legend("image clip", region_id, surface_index, slice.depth, slice.component_id),
|
||||
color,
|
||||
0.22f,
|
||||
color);
|
||||
replacement_trace.add_svg(remaining_after,
|
||||
replacement_trace_legend("remaining after image", region_id, surface_index, slice.depth, 0),
|
||||
"#fb6a4a",
|
||||
0.26f,
|
||||
"#cb181d");
|
||||
}
|
||||
remaining = std::move(remaining_after);
|
||||
++slice_idx;
|
||||
}
|
||||
remaining = top_surface_clip_diff_ex(remaining, image_clip, slice_safety_offset);
|
||||
}
|
||||
}
|
||||
if (!remaining.empty()) {
|
||||
@@ -11889,12 +12457,109 @@ std::vector<SurfaceFill> group_fills(const Layer &layer,
|
||||
!top_surface_replacement_reservations[region_id].empty() &&
|
||||
(surface.is_top() || surface.surface_type == stInternalSolid || surface.surface_type == stBottom) &&
|
||||
!surface.is_bridge()) {
|
||||
remaining = top_surface_clip_diff_ex(remaining,
|
||||
top_surface_replacement_reservations[region_id],
|
||||
ApplySafetyOffset::Yes);
|
||||
ExPolygons reservation_overlap;
|
||||
const double remaining_before_mm2 = replacement_trace.enabled ?
|
||||
top_surface_image_debug_area_mm2(remaining) :
|
||||
0.;
|
||||
if (replacement_trace.enabled)
|
||||
reservation_overlap = top_surface_clip_intersection_ex(remaining,
|
||||
top_surface_replacement_reservations[region_id],
|
||||
ApplySafetyOffset::Yes);
|
||||
ExPolygons remaining_after = top_surface_clip_diff_ex(remaining,
|
||||
top_surface_replacement_reservations[region_id],
|
||||
ApplySafetyOffset::Yes);
|
||||
const double reservation_overlap_mm2 = replacement_trace.enabled ?
|
||||
top_surface_image_debug_area_mm2(reservation_overlap) :
|
||||
0.;
|
||||
const double remaining_after_mm2 = replacement_trace.enabled ?
|
||||
top_surface_image_debug_area_mm2(remaining_after) :
|
||||
0.;
|
||||
if (replacement_trace.enabled && replacement_candidate) {
|
||||
const TopSurfaceImageRegionPlan &plan = top_surface_plans[region_id];
|
||||
replacement_trace.add_row("reservation",
|
||||
layer,
|
||||
region_id,
|
||||
surface_index,
|
||||
surface.surface_type,
|
||||
params->extrusion_role,
|
||||
plan.zone_id,
|
||||
size_t(-1),
|
||||
size_t(-1),
|
||||
size_t(-1),
|
||||
-1,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
size_t(-1),
|
||||
size_t(-1),
|
||||
0.,
|
||||
0.,
|
||||
remaining_before_mm2,
|
||||
0.,
|
||||
0.,
|
||||
0.,
|
||||
0.,
|
||||
0.,
|
||||
0.,
|
||||
remaining_after_mm2,
|
||||
reservation_overlap_mm2,
|
||||
0.);
|
||||
replacement_trace.add_svg(std::move(reservation_overlap),
|
||||
replacement_trace_legend("reservation overlap", region_id, surface_index, -1, 0),
|
||||
"#756bb1",
|
||||
0.30f,
|
||||
"#54278f");
|
||||
replacement_trace.add_svg(remaining_after,
|
||||
replacement_trace_legend("remaining after reservation", region_id, surface_index, -1, 0),
|
||||
"#de2d26",
|
||||
0.32f,
|
||||
"#a50f15");
|
||||
}
|
||||
remaining = std::move(remaining_after);
|
||||
}
|
||||
}
|
||||
if (!remaining.empty()) {
|
||||
if (replacement_trace.enabled && replacement_candidate) {
|
||||
const TopSurfaceImageRegionPlan &plan = top_surface_plans[region_id];
|
||||
const double original_appended_mm2 = top_surface_image_debug_area_mm2(remaining);
|
||||
replacement_trace.add_row("original_appended",
|
||||
layer,
|
||||
region_id,
|
||||
surface_index,
|
||||
surface.surface_type,
|
||||
params->extrusion_role,
|
||||
plan.zone_id,
|
||||
size_t(-1),
|
||||
size_t(-1),
|
||||
size_t(-1),
|
||||
-1,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
size_t(-1),
|
||||
size_t(-1),
|
||||
0.,
|
||||
0.,
|
||||
original_appended_mm2,
|
||||
0.,
|
||||
0.,
|
||||
0.,
|
||||
0.,
|
||||
0.,
|
||||
0.,
|
||||
original_appended_mm2,
|
||||
0.,
|
||||
original_appended_mm2);
|
||||
replacement_trace.add_svg(remaining,
|
||||
replacement_trace_legend("ordinary fill appended", region_id, surface_index, -1, 0),
|
||||
"#ffffff",
|
||||
0.72f,
|
||||
"#000000");
|
||||
}
|
||||
SurfaceFill &fill = surface_fills[params->idx];
|
||||
append_surface_fill_expolygons(fill, region_id, surface, std::move(remaining), layerm);
|
||||
}
|
||||
@@ -11909,6 +12574,8 @@ std::vector<SurfaceFill> group_fills(const Layer &layer,
|
||||
throw_if_canceled);
|
||||
}
|
||||
|
||||
replacement_trace.write(layer);
|
||||
|
||||
{
|
||||
Polygons all_polygons;
|
||||
for (SurfaceFill &fill : surface_fills)
|
||||
@@ -11916,7 +12583,8 @@ std::vector<SurfaceFill> group_fills(const Layer &layer,
|
||||
check_canceled(throw_if_canceled);
|
||||
if (fill.params.texture_mapping_top_surface_same_layer_partition)
|
||||
continue;
|
||||
if (fill.params.texture_mapping_top_surface_raw_labels) {
|
||||
if (fill.params.texture_mapping_top_surface_contoning ||
|
||||
fill.params.texture_mapping_top_surface_raw_labels) {
|
||||
if (fill.expolygons.size() > 1)
|
||||
fill.expolygons = top_surface_clip_union_ex(fill.expolygons);
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user