Add blue noise, phase, angle and supersampling options for top-surface coloring
This commit is contained in:
@@ -433,6 +433,10 @@ struct TopSurfaceImageRegionPlan {
|
||||
bool contoning_replace_top_perimeters_with_infill = false;
|
||||
bool contoning_recolor_surrounding_perimeters = false;
|
||||
int contoning_perimeter_mode = TextureMappingZone::DefaultTopSurfaceContoningPerimeterMode;
|
||||
bool contoning_layer_phase_enabled = false;
|
||||
bool contoning_varied_infill_angles_enabled = false;
|
||||
bool contoning_blue_noise_error_diffusion_enabled = false;
|
||||
bool contoning_supersampled_cells_enabled = false;
|
||||
};
|
||||
|
||||
enum class TopSurfaceImageSourceSurface {
|
||||
@@ -670,6 +674,16 @@ struct TopSurfaceImageContoningVectorRegion {
|
||||
int cell_count { 0 };
|
||||
};
|
||||
|
||||
struct TopSurfaceImageContoningCellSample {
|
||||
std::array<float, 3> rgb { { 0.f, 0.f, 0.f } };
|
||||
int solve_layers { 0 };
|
||||
};
|
||||
|
||||
struct TopSurfaceImageContoningSolvedLabel {
|
||||
int label { -1 };
|
||||
std::array<float, 3> rgb { { 0.f, 0.f, 0.f } };
|
||||
};
|
||||
|
||||
static float top_surface_image_contoning_oklab_error(const std::array<float, 3> &lhs,
|
||||
const std::array<float, 3> &rhs)
|
||||
{
|
||||
@@ -842,6 +856,68 @@ static float top_surface_image_contoning_sample_pitch_mm(const TopSurfaceImageRe
|
||||
return std::clamp(pitch, 0.25f, std::max(0.25f, plan.contoning_min_feature_mm));
|
||||
}
|
||||
|
||||
static float top_surface_image_contoning_angle_rad(int depth, bool varied_angles)
|
||||
{
|
||||
if (!varied_angles)
|
||||
return (depth & 1) ? float(-PI / 4.0) : float(PI / 4.0);
|
||||
switch ((depth % 4 + 4) % 4) {
|
||||
case 0: return float(PI / 4.0);
|
||||
case 1: return float(-PI / 4.0);
|
||||
case 2: return 0.f;
|
||||
default: return float(PI / 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
static coord_t top_surface_image_contoning_grid_min(coord_t value, coord_t step, coord_t phase)
|
||||
{
|
||||
if (step <= 0)
|
||||
return value;
|
||||
const coord_t shifted = value - phase;
|
||||
coord_t quotient = shifted / step;
|
||||
if (shifted < 0 && shifted % step != 0)
|
||||
--quotient;
|
||||
return quotient * step + phase;
|
||||
}
|
||||
|
||||
static std::pair<coord_t, coord_t> top_surface_image_contoning_grid_phase(coord_t step, int depth)
|
||||
{
|
||||
if (step <= 0)
|
||||
return { 0, 0 };
|
||||
static constexpr int phase_x[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
|
||||
static constexpr int phase_y[8] = { 0, 4, 6, 2, 5, 1, 7, 3 };
|
||||
const int idx = (depth % 8 + 8) % 8;
|
||||
return {
|
||||
coord_t((static_cast<long long>(step) * static_cast<long long>(phase_x[idx])) / 8),
|
||||
coord_t((static_cast<long long>(step) * static_cast<long long>(phase_y[idx])) / 8)
|
||||
};
|
||||
}
|
||||
|
||||
static uint32_t top_surface_image_contoning_hash_u32(int col, int row, int depth, int channel)
|
||||
{
|
||||
uint32_t h = 2166136261u;
|
||||
auto mix = [&h](uint32_t value) {
|
||||
h ^= value;
|
||||
h *= 16777619u;
|
||||
};
|
||||
mix(uint32_t(col) * 0x9e3779b9u);
|
||||
mix(uint32_t(row) * 0x85ebca6bu);
|
||||
mix(uint32_t(depth) * 0xc2b2ae35u);
|
||||
mix(uint32_t(channel) * 0x27d4eb2fu);
|
||||
h ^= h >> 16;
|
||||
h *= 0x7feb352du;
|
||||
h ^= h >> 15;
|
||||
h *= 0x846ca68bu;
|
||||
h ^= h >> 16;
|
||||
return h;
|
||||
}
|
||||
|
||||
static float top_surface_image_contoning_jitter(int col, int row, int depth, int channel)
|
||||
{
|
||||
const uint32_t h = top_surface_image_contoning_hash_u32(col, row, depth, channel);
|
||||
const float unit = float(h & 0x00FFFFFFu) / float(0x00FFFFFFu);
|
||||
return (unit - 0.5f) * 0.006f;
|
||||
}
|
||||
|
||||
static bool top_surface_image_contoning_grid_component_printable(int cell_count,
|
||||
int min_col,
|
||||
int max_col,
|
||||
@@ -1028,6 +1104,114 @@ static int top_surface_image_contoning_pattern_filaments(int stack_layers, int c
|
||||
return std::max(1, std::min(clamped_stack_layers, clamped_pattern_filaments));
|
||||
}
|
||||
|
||||
static std::optional<TopSurfaceImageContoningCellSample> top_surface_image_contoning_sample_cell(
|
||||
const TextureMappingOffsetContext &context,
|
||||
const ExPolygons &area,
|
||||
const std::vector<ExPolygons> &source_stack_areas,
|
||||
int stack_layers,
|
||||
int pattern_filaments,
|
||||
int depth,
|
||||
coord_t x0,
|
||||
coord_t y0,
|
||||
coord_t x1,
|
||||
coord_t y1,
|
||||
float threshold_deg,
|
||||
TopSurfaceImageSourceSurface source_surface,
|
||||
bool supersampled)
|
||||
{
|
||||
TopSurfaceImageContoningCellSample out;
|
||||
int sample_count = 0;
|
||||
auto add_sample = [&](const Point &sample_point) {
|
||||
if (!top_surface_image_expolygons_contain_point(area, sample_point))
|
||||
return;
|
||||
const int local_stack_layers =
|
||||
top_surface_image_contoning_local_stack_layers_at_point(sample_point, source_stack_areas, stack_layers);
|
||||
if (depth >= local_stack_layers)
|
||||
return;
|
||||
const int solve_layers = std::min({ local_stack_layers, stack_layers, pattern_filaments });
|
||||
if (solve_layers <= 0)
|
||||
return;
|
||||
const float sample_x_mm = unscale<float>(sample_point.x());
|
||||
const float sample_y_mm = unscale<float>(sample_point.y());
|
||||
if (!top_surface_image_contoning_sample_eligible(context, sample_x_mm, sample_y_mm, threshold_deg, source_surface))
|
||||
return;
|
||||
const std::optional<std::array<float, 3>> rgb =
|
||||
sample_weight_field_rgb(context.weight_field,
|
||||
sample_x_mm,
|
||||
sample_y_mm,
|
||||
context.high_resolution_texture_sampling);
|
||||
if (!rgb)
|
||||
return;
|
||||
out.rgb[0] += (*rgb)[0];
|
||||
out.rgb[1] += (*rgb)[1];
|
||||
out.rgb[2] += (*rgb)[2];
|
||||
out.solve_layers = sample_count == 0 ? solve_layers : std::min(out.solve_layers, solve_layers);
|
||||
++sample_count;
|
||||
};
|
||||
|
||||
if (supersampled) {
|
||||
static constexpr std::array<std::pair<double, double>, 5> offsets {
|
||||
std::pair<double, double>{ 0.5, 0.5 },
|
||||
std::pair<double, double>{ 0.25, 0.25 },
|
||||
std::pair<double, double>{ 0.75, 0.25 },
|
||||
std::pair<double, double>{ 0.25, 0.75 },
|
||||
std::pair<double, double>{ 0.75, 0.75 }
|
||||
};
|
||||
for (const std::pair<double, double> &offset : offsets) {
|
||||
const coord_t x = coord_t(std::llround(double(x0) + double(x1 - x0) * offset.first));
|
||||
const coord_t y = coord_t(std::llround(double(y0) + double(y1 - y0) * offset.second));
|
||||
add_sample(Point(x, y));
|
||||
}
|
||||
} else {
|
||||
add_sample(Point((x0 + x1) / 2, (y0 + y1) / 2));
|
||||
}
|
||||
|
||||
if (sample_count <= 0)
|
||||
return std::nullopt;
|
||||
out.rgb[0] = std::clamp(out.rgb[0] / float(sample_count), 0.f, 1.f);
|
||||
out.rgb[1] = std::clamp(out.rgb[1] / float(sample_count), 0.f, 1.f);
|
||||
out.rgb[2] = std::clamp(out.rgb[2] / float(sample_count), 0.f, 1.f);
|
||||
if (out.solve_layers <= 0)
|
||||
return std::nullopt;
|
||||
return out;
|
||||
}
|
||||
|
||||
static std::optional<TopSurfaceImageContoningSolvedLabel> top_surface_image_contoning_solve_label(
|
||||
const std::array<float, 3> &rgb,
|
||||
int solve_layers,
|
||||
const TextureMappingContoningSolver &solver,
|
||||
const PrintConfig &print_config,
|
||||
std::vector<TopSurfaceImageContoningVectorLabel> &labels,
|
||||
std::map<std::vector<unsigned int>, int> &label_by_stack)
|
||||
{
|
||||
TextureMappingContoningStack stack = solver.solve(rgb, solve_layers);
|
||||
if (stack.bottom_to_top.empty())
|
||||
return std::nullopt;
|
||||
std::optional<std::array<float, 3>> stack_rgb =
|
||||
top_surface_image_contoning_stack_rgb(stack.bottom_to_top, print_config);
|
||||
if (!stack_rgb)
|
||||
return std::nullopt;
|
||||
top_surface_image_contoning_sort_stack_for_top_color(stack.bottom_to_top, *stack_rgb, print_config);
|
||||
top_surface_image_contoning_spread_stack_repeats(stack.bottom_to_top);
|
||||
auto label_it = label_by_stack.find(stack.bottom_to_top);
|
||||
int label = -1;
|
||||
if (label_it == label_by_stack.end()) {
|
||||
TopSurfaceImageContoningVectorLabel label_data;
|
||||
label_data.bottom_to_top = stack.bottom_to_top;
|
||||
label_data.rgb = *stack_rgb;
|
||||
label_data.oklab = color_solver_oklab_from_srgb(*stack_rgb);
|
||||
label = int(labels.size());
|
||||
labels.emplace_back(std::move(label_data));
|
||||
label_by_stack.emplace(labels.back().bottom_to_top, label);
|
||||
} else {
|
||||
label = label_it->second;
|
||||
}
|
||||
TopSurfaceImageContoningSolvedLabel out;
|
||||
out.label = label;
|
||||
out.rgb = *stack_rgb;
|
||||
return out;
|
||||
}
|
||||
|
||||
static std::vector<TopSurfaceImageContoningVectorRegion> top_surface_image_contoning_vector_regions(
|
||||
const TopSurfaceImageRegionPlan &plan,
|
||||
const Layer &source_layer,
|
||||
@@ -1038,6 +1222,7 @@ static std::vector<TopSurfaceImageContoningVectorRegion> top_surface_image_conto
|
||||
int depth,
|
||||
const TextureMappingContoningSolver &solver,
|
||||
TopSurfaceImageSourceSurface source_surface,
|
||||
bool use_blue_noise_error_diffusion,
|
||||
const ThrowIfCanceled *throw_if_canceled)
|
||||
{
|
||||
std::vector<TopSurfaceImageContoningVectorRegion> regions;
|
||||
@@ -1069,8 +1254,14 @@ static std::vector<TopSurfaceImageContoningVectorRegion> top_surface_image_conto
|
||||
|
||||
const float pitch_mm = top_surface_image_contoning_sample_pitch_mm(plan, bbox);
|
||||
const coord_t step = std::max<coord_t>(1, scale_(double(pitch_mm)));
|
||||
const coord_t min_x = (bbox.min.x() / step) * step;
|
||||
const coord_t min_y = (bbox.min.y() / step) * step;
|
||||
const std::pair<coord_t, coord_t> grid_phase =
|
||||
plan.contoning_layer_phase_enabled ? top_surface_image_contoning_grid_phase(step, depth) : std::pair<coord_t, coord_t>{ 0, 0 };
|
||||
const coord_t min_x = plan.contoning_layer_phase_enabled ?
|
||||
top_surface_image_contoning_grid_min(bbox.min.x(), step, grid_phase.first) :
|
||||
(bbox.min.x() / step) * step;
|
||||
const coord_t min_y = plan.contoning_layer_phase_enabled ?
|
||||
top_surface_image_contoning_grid_min(bbox.min.y(), step, grid_phase.second) :
|
||||
(bbox.min.y() / step) * step;
|
||||
const int cols = std::max(0, int(std::ceil(double(bbox.max.x() - min_x) / double(step))));
|
||||
const int rows = std::max(0, int(std::ceil(double(bbox.max.y() - min_y) / double(step))));
|
||||
if (cols <= 0 || rows <= 0)
|
||||
@@ -1091,60 +1282,102 @@ static std::vector<TopSurfaceImageContoningVectorRegion> top_surface_image_conto
|
||||
const std::vector<ExPolygons> source_stack_areas =
|
||||
top_surface_image_contoning_stack_areas(source_layer, plan.zone_id, stack_layers, source_surface, throw_if_canceled);
|
||||
|
||||
auto solve_cell = [&](int row, int col, const std::array<float, 3> &target_rgb, int solve_layers) {
|
||||
std::optional<TopSurfaceImageContoningSolvedLabel> solved =
|
||||
top_surface_image_contoning_solve_label(target_rgb, solve_layers, solver, print_config, labels, label_by_stack);
|
||||
if (!solved)
|
||||
return std::optional<TopSurfaceImageContoningSolvedLabel>();
|
||||
grid[size_t(row * cols + col)] = solved->label;
|
||||
return solved;
|
||||
};
|
||||
|
||||
auto sample_cell = [&](int row, int col) {
|
||||
const coord_t x0 = min_x + coord_t(col) * step;
|
||||
const coord_t y0 = min_y + coord_t(row) * step;
|
||||
const coord_t x1 = std::min<coord_t>(x0 + step, bbox.max.x());
|
||||
const coord_t y1 = std::min<coord_t>(y0 + step, bbox.max.y());
|
||||
if (x1 <= x0 || y1 <= y0)
|
||||
return std::optional<TopSurfaceImageContoningCellSample>();
|
||||
return top_surface_image_contoning_sample_cell(*context,
|
||||
area,
|
||||
source_stack_areas,
|
||||
stack_layers,
|
||||
pattern_filaments,
|
||||
depth,
|
||||
x0,
|
||||
y0,
|
||||
x1,
|
||||
y1,
|
||||
threshold_deg,
|
||||
source_surface,
|
||||
plan.contoning_supersampled_cells_enabled);
|
||||
};
|
||||
|
||||
std::vector<std::optional<TopSurfaceImageContoningCellSample>> cell_samples(grid.size());
|
||||
for (int row = 0; row < rows; ++row) {
|
||||
if ((row & 15) == 0)
|
||||
check_canceled(throw_if_canceled);
|
||||
for (int col = 0; col < cols; ++col) {
|
||||
const coord_t x0 = min_x + coord_t(col) * step;
|
||||
const coord_t y0 = min_y + coord_t(row) * step;
|
||||
const coord_t x1 = std::min<coord_t>(x0 + step, bbox.max.x());
|
||||
const coord_t y1 = std::min<coord_t>(y0 + step, bbox.max.y());
|
||||
if (x1 <= x0 || y1 <= y0)
|
||||
continue;
|
||||
const Point sample_point((x0 + x1) / 2, (y0 + y1) / 2);
|
||||
if (!top_surface_image_expolygons_contain_point(area, sample_point))
|
||||
continue;
|
||||
const int local_stack_layers =
|
||||
top_surface_image_contoning_local_stack_layers_at_point(sample_point, source_stack_areas, stack_layers);
|
||||
if (depth >= local_stack_layers)
|
||||
continue;
|
||||
const int solve_layers = std::min({ local_stack_layers, stack_layers, pattern_filaments });
|
||||
if (solve_layers <= 0)
|
||||
continue;
|
||||
const float sample_x_mm = unscale<float>(sample_point.x());
|
||||
const float sample_y_mm = unscale<float>(sample_point.y());
|
||||
if (!top_surface_image_contoning_sample_eligible(*context, sample_x_mm, sample_y_mm, threshold_deg, source_surface))
|
||||
continue;
|
||||
const std::optional<std::array<float, 3>> rgb =
|
||||
sample_weight_field_rgb(context->weight_field,
|
||||
sample_x_mm,
|
||||
sample_y_mm,
|
||||
context->high_resolution_texture_sampling);
|
||||
if (!rgb)
|
||||
continue;
|
||||
TextureMappingContoningStack stack = solver.solve(*rgb, solve_layers);
|
||||
if (stack.bottom_to_top.empty())
|
||||
continue;
|
||||
std::optional<std::array<float, 3>> stack_rgb =
|
||||
top_surface_image_contoning_stack_rgb(stack.bottom_to_top, print_config);
|
||||
if (!stack_rgb)
|
||||
continue;
|
||||
top_surface_image_contoning_sort_stack_for_top_color(stack.bottom_to_top, *stack_rgb, print_config);
|
||||
top_surface_image_contoning_spread_stack_repeats(stack.bottom_to_top);
|
||||
auto label_it = label_by_stack.find(stack.bottom_to_top);
|
||||
int label = -1;
|
||||
if (label_it == label_by_stack.end()) {
|
||||
TopSurfaceImageContoningVectorLabel label_data;
|
||||
label_data.bottom_to_top = stack.bottom_to_top;
|
||||
label_data.rgb = *stack_rgb;
|
||||
label_data.oklab = color_solver_oklab_from_srgb(*stack_rgb);
|
||||
label = int(labels.size());
|
||||
labels.emplace_back(std::move(label_data));
|
||||
label_by_stack.emplace(labels.back().bottom_to_top, label);
|
||||
} else {
|
||||
label = label_it->second;
|
||||
for (int col = 0; col < cols; ++col)
|
||||
cell_samples[size_t(row * cols + col)] = sample_cell(row, col);
|
||||
}
|
||||
|
||||
if (use_blue_noise_error_diffusion) {
|
||||
std::vector<std::array<float, 3>> errors(grid.size(), std::array<float, 3>{ { 0.f, 0.f, 0.f } });
|
||||
auto add_error = [&](int row, int col, const std::array<float, 3> &error, float factor) {
|
||||
if (row < 0 || row >= rows || col < 0 || col >= cols)
|
||||
return;
|
||||
std::array<float, 3> &dst = errors[size_t(row * cols + col)];
|
||||
dst[0] += error[0] * factor;
|
||||
dst[1] += error[1] * factor;
|
||||
dst[2] += error[2] * factor;
|
||||
};
|
||||
for (int row = 0; row < rows; ++row) {
|
||||
if ((row & 15) == 0)
|
||||
check_canceled(throw_if_canceled);
|
||||
const bool left_to_right = (row & 1) == 0;
|
||||
for (int step_col = 0; step_col < cols; ++step_col) {
|
||||
const int col = left_to_right ? step_col : cols - 1 - step_col;
|
||||
const std::optional<TopSurfaceImageContoningCellSample> &sample = cell_samples[size_t(row * cols + col)];
|
||||
if (!sample)
|
||||
continue;
|
||||
const size_t grid_idx = size_t(row * cols + col);
|
||||
std::array<float, 3> target_rgb {
|
||||
std::clamp(sample->rgb[0] + errors[grid_idx][0] + top_surface_image_contoning_jitter(col, row, depth, 0), 0.f, 1.f),
|
||||
std::clamp(sample->rgb[1] + errors[grid_idx][1] + top_surface_image_contoning_jitter(col, row, depth, 1), 0.f, 1.f),
|
||||
std::clamp(sample->rgb[2] + errors[grid_idx][2] + top_surface_image_contoning_jitter(col, row, depth, 2), 0.f, 1.f)
|
||||
};
|
||||
const std::optional<TopSurfaceImageContoningSolvedLabel> solved =
|
||||
solve_cell(row, col, target_rgb, sample->solve_layers);
|
||||
if (!solved)
|
||||
continue;
|
||||
const std::array<float, 3> error {
|
||||
target_rgb[0] - solved->rgb[0],
|
||||
target_rgb[1] - solved->rgb[1],
|
||||
target_rgb[2] - solved->rgb[2]
|
||||
};
|
||||
if (left_to_right) {
|
||||
add_error(row, col + 1, error, 7.f / 16.f);
|
||||
add_error(row + 1, col - 1, error, 3.f / 16.f);
|
||||
add_error(row + 1, col, error, 5.f / 16.f);
|
||||
add_error(row + 1, col + 1, error, 1.f / 16.f);
|
||||
} else {
|
||||
add_error(row, col - 1, error, 7.f / 16.f);
|
||||
add_error(row + 1, col + 1, error, 3.f / 16.f);
|
||||
add_error(row + 1, col, error, 5.f / 16.f);
|
||||
add_error(row + 1, col - 1, error, 1.f / 16.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int row = 0; row < rows; ++row) {
|
||||
if ((row & 15) == 0)
|
||||
check_canceled(throw_if_canceled);
|
||||
for (int col = 0; col < cols; ++col) {
|
||||
const std::optional<TopSurfaceImageContoningCellSample> &sample = cell_samples[size_t(row * cols + col)];
|
||||
if (!sample)
|
||||
continue;
|
||||
solve_cell(row, col, sample->rgb, sample->solve_layers);
|
||||
}
|
||||
grid[size_t(row * cols + col)] = label;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1233,32 +1466,71 @@ static void top_surface_image_append_contoning_slices(TopSurfaceImageRegionPlan
|
||||
|
||||
std::vector<ExPolygons> by_component(print_config.filament_colour.values.size() + 1);
|
||||
std::vector<ExPolygons> perimeter_by_component(print_config.filament_colour.values.size() + 1);
|
||||
const std::vector<TopSurfaceImageContoningVectorRegion> stack_regions =
|
||||
top_surface_image_contoning_vector_regions(plan,
|
||||
source_layer,
|
||||
perimeter_area,
|
||||
object,
|
||||
zone,
|
||||
print_config,
|
||||
depth,
|
||||
solver,
|
||||
source_surface,
|
||||
throw_if_canceled);
|
||||
for (const TopSurfaceImageContoningVectorRegion ®ion : stack_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)];
|
||||
if (component_id == 0 || component_id >= by_component.size())
|
||||
continue;
|
||||
append(perimeter_by_component[component_id], region.area);
|
||||
if (!area.empty()) {
|
||||
ExPolygons component_area = intersection_ex(region.area, area, ApplySafetyOffset::Yes);
|
||||
if (!component_area.empty())
|
||||
append(by_component[component_id], std::move(component_area));
|
||||
auto append_regions = [&](const std::vector<TopSurfaceImageContoningVectorRegion> ®ions,
|
||||
bool for_fill,
|
||||
bool for_perimeter) {
|
||||
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)];
|
||||
if (component_id == 0 || component_id >= by_component.size())
|
||||
continue;
|
||||
if (for_perimeter)
|
||||
append(perimeter_by_component[component_id], region.area);
|
||||
if (for_fill && !area.empty()) {
|
||||
ExPolygons component_area = intersection_ex(region.area, area, ApplySafetyOffset::Yes);
|
||||
if (!component_area.empty())
|
||||
append(by_component[component_id], std::move(component_area));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (plan.contoning_blue_noise_error_diffusion_enabled) {
|
||||
if (!area.empty()) {
|
||||
const std::vector<TopSurfaceImageContoningVectorRegion> fill_regions =
|
||||
top_surface_image_contoning_vector_regions(plan,
|
||||
source_layer,
|
||||
area,
|
||||
object,
|
||||
zone,
|
||||
print_config,
|
||||
depth,
|
||||
solver,
|
||||
source_surface,
|
||||
true,
|
||||
throw_if_canceled);
|
||||
append_regions(fill_regions, true, false);
|
||||
}
|
||||
const std::vector<TopSurfaceImageContoningVectorRegion> perimeter_regions =
|
||||
top_surface_image_contoning_vector_regions(plan,
|
||||
source_layer,
|
||||
perimeter_area,
|
||||
object,
|
||||
zone,
|
||||
print_config,
|
||||
depth,
|
||||
solver,
|
||||
source_surface,
|
||||
false,
|
||||
throw_if_canceled);
|
||||
append_regions(perimeter_regions, false, true);
|
||||
} else {
|
||||
const std::vector<TopSurfaceImageContoningVectorRegion> stack_regions =
|
||||
top_surface_image_contoning_vector_regions(plan,
|
||||
source_layer,
|
||||
perimeter_area,
|
||||
object,
|
||||
zone,
|
||||
print_config,
|
||||
depth,
|
||||
solver,
|
||||
source_surface,
|
||||
false,
|
||||
throw_if_canceled);
|
||||
append_regions(stack_regions, true, true);
|
||||
}
|
||||
|
||||
ExPolygons depth_taken;
|
||||
@@ -1287,7 +1559,7 @@ static void top_surface_image_append_contoning_slices(TopSurfaceImageRegionPlan
|
||||
slice.component_count = size_t(pattern_filaments);
|
||||
slice.contoning = true;
|
||||
slice.lower_surface = source_surface == TopSurfaceImageSourceSurface::Bottom;
|
||||
slice.angle_rad = (depth & 1) ? float(-PI / 4.0) : float(PI / 4.0);
|
||||
slice.angle_rad = top_surface_image_contoning_angle_rad(depth, plan.contoning_varied_infill_angles_enabled);
|
||||
slice.area = std::move(component_area);
|
||||
slice.perimeter_area = std::move(component_perimeter_area);
|
||||
plan.slices.emplace_back(std::move(slice));
|
||||
@@ -1382,6 +1654,10 @@ static std::vector<TopSurfaceImageRegionPlan> top_surface_image_region_plans(con
|
||||
std::clamp(zone->top_surface_contoning_perimeter_mode,
|
||||
int(TextureMappingZone::ContoningPerimeterSegmentBlocks),
|
||||
int(TextureMappingZone::ContoningPerimeterSegmentInfill));
|
||||
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;
|
||||
plan.contoning_supersampled_cells_enabled = zone->top_surface_contoning_supersampled_cells_enabled;
|
||||
const TextureMappingContoningSolver contoning_solver(*zone, print_config, components);
|
||||
|
||||
const int stack_depth = plan.contoning ?
|
||||
@@ -3111,8 +3387,11 @@ std::vector<SurfaceFill> group_fills(const Layer &layer,
|
||||
params.flow = layerm.flow(frSolidInfill);
|
||||
params.spacing = params.flow.spacing();
|
||||
surface_fills.emplace_back(params);
|
||||
surface_fills.back().region_id = region_id;
|
||||
surface_fills.back().surface.surface_type = stInternalSolid;
|
||||
surface_fills.back().surface.thickness = layer.height;
|
||||
surface_fills.back().region_id_group.push_back(region_id);
|
||||
surface_fills.back().no_overlap_expolygons = layerm.fill_no_overlap_expolygons;
|
||||
surface_fills.back().expolygons = std::move(extensions);
|
||||
} else {
|
||||
append(extensions, std::move(internal_solid_fill->expolygons));
|
||||
@@ -3216,6 +3495,10 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree,
|
||||
|
||||
for (SurfaceFill &surface_fill : surface_fills) {
|
||||
check_canceled(throw_if_canceled_ptr);
|
||||
if (surface_fill.expolygons.empty() ||
|
||||
surface_fill.region_id >= this->m_regions.size() ||
|
||||
this->m_regions[surface_fill.region_id] == nullptr)
|
||||
continue;
|
||||
// Create the filler object.
|
||||
std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(surface_fill.params.pattern));
|
||||
f->set_bounding_box(bbox);
|
||||
|
||||
@@ -1057,6 +1057,10 @@ bool TextureMappingZone::operator==(const TextureMappingZone &rhs) const
|
||||
top_surface_contoning_replace_top_perimeters_with_infill == rhs.top_surface_contoning_replace_top_perimeters_with_infill &&
|
||||
top_surface_contoning_recolor_surrounding_perimeters == rhs.top_surface_contoning_recolor_surrounding_perimeters &&
|
||||
top_surface_contoning_perimeter_mode == rhs.top_surface_contoning_perimeter_mode &&
|
||||
top_surface_contoning_layer_phase_enabled == rhs.top_surface_contoning_layer_phase_enabled &&
|
||||
top_surface_contoning_varied_infill_angles_enabled == rhs.top_surface_contoning_varied_infill_angles_enabled &&
|
||||
top_surface_contoning_blue_noise_error_diffusion_enabled == rhs.top_surface_contoning_blue_noise_error_diffusion_enabled &&
|
||||
top_surface_contoning_supersampled_cells_enabled == rhs.top_surface_contoning_supersampled_cells_enabled &&
|
||||
compact_offset_mode == rhs.compact_offset_mode &&
|
||||
use_legacy_fixed_color_mode == rhs.use_legacy_fixed_color_mode &&
|
||||
high_speed_image_texture_sampling == rhs.high_speed_image_texture_sampling &&
|
||||
@@ -1443,6 +1447,13 @@ std::string TextureMappingManager::serialize_entries()
|
||||
clamp_int(zone.top_surface_contoning_perimeter_mode,
|
||||
int(TextureMappingZone::ContoningPerimeterSegmentBlocks),
|
||||
int(TextureMappingZone::ContoningPerimeterSegmentInfill));
|
||||
texture["top_surface_contoning_layer_phase_enabled"] = zone.top_surface_contoning_layer_phase_enabled;
|
||||
texture["top_surface_contoning_varied_infill_angles_enabled"] =
|
||||
zone.top_surface_contoning_varied_infill_angles_enabled;
|
||||
texture["top_surface_contoning_blue_noise_error_diffusion_enabled"] =
|
||||
zone.top_surface_contoning_blue_noise_error_diffusion_enabled;
|
||||
texture["top_surface_contoning_supersampled_cells_enabled"] =
|
||||
zone.top_surface_contoning_supersampled_cells_enabled;
|
||||
texture["compact_offset_mode"] = zone.compact_offset_mode;
|
||||
texture["use_legacy_fixed_color_mode"] = zone.use_legacy_fixed_color_mode;
|
||||
texture["high_speed_image_texture_sampling"] = true;
|
||||
@@ -1709,6 +1720,18 @@ void TextureMappingManager::load_entries(const std::string &serialized,
|
||||
int(TextureMappingZone::ContoningPerimeterSegmentInfill));
|
||||
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 =
|
||||
texture.value("top_surface_contoning_layer_phase_enabled",
|
||||
TextureMappingZone::DefaultTopSurfaceContoningLayerPhaseEnabled);
|
||||
zone.top_surface_contoning_varied_infill_angles_enabled =
|
||||
texture.value("top_surface_contoning_varied_infill_angles_enabled",
|
||||
TextureMappingZone::DefaultTopSurfaceContoningVariedInfillAnglesEnabled);
|
||||
zone.top_surface_contoning_blue_noise_error_diffusion_enabled =
|
||||
texture.value("top_surface_contoning_blue_noise_error_diffusion_enabled",
|
||||
TextureMappingZone::DefaultTopSurfaceContoningBlueNoiseErrorDiffusionEnabled);
|
||||
zone.top_surface_contoning_supersampled_cells_enabled =
|
||||
texture.value("top_surface_contoning_supersampled_cells_enabled",
|
||||
TextureMappingZone::DefaultTopSurfaceContoningSupersampledCellsEnabled);
|
||||
zone.compact_offset_mode = texture.value("compact_offset_mode", TextureMappingZone::DefaultCompactOffsetMode);
|
||||
zone.use_legacy_fixed_color_mode =
|
||||
texture.value("use_legacy_fixed_color_mode", TextureMappingZone::DefaultUseLegacyFixedColorMode);
|
||||
|
||||
@@ -179,6 +179,10 @@ struct TextureMappingZone
|
||||
static constexpr bool DefaultTopSurfaceContoningReplaceTopPerimetersWithInfill = false;
|
||||
static constexpr bool DefaultTopSurfaceContoningRecolorSurroundingPerimeters = false;
|
||||
static constexpr int DefaultTopSurfaceContoningPerimeterMode = int(ContoningPerimeterDividedLine);
|
||||
static constexpr bool DefaultTopSurfaceContoningLayerPhaseEnabled = false;
|
||||
static constexpr bool DefaultTopSurfaceContoningVariedInfillAnglesEnabled = false;
|
||||
static constexpr bool DefaultTopSurfaceContoningBlueNoiseErrorDiffusionEnabled = false;
|
||||
static constexpr bool DefaultTopSurfaceContoningSupersampledCellsEnabled = false;
|
||||
static constexpr bool DefaultCompactOffsetMode = true;
|
||||
static constexpr bool DefaultUseLegacyFixedColorMode = false;
|
||||
static constexpr bool DefaultHighSpeedImageTextureSampling = true;
|
||||
@@ -282,6 +286,10 @@ struct TextureMappingZone
|
||||
bool top_surface_contoning_replace_top_perimeters_with_infill = DefaultTopSurfaceContoningReplaceTopPerimetersWithInfill;
|
||||
bool top_surface_contoning_recolor_surrounding_perimeters = DefaultTopSurfaceContoningRecolorSurroundingPerimeters;
|
||||
int top_surface_contoning_perimeter_mode = DefaultTopSurfaceContoningPerimeterMode;
|
||||
bool top_surface_contoning_layer_phase_enabled = DefaultTopSurfaceContoningLayerPhaseEnabled;
|
||||
bool top_surface_contoning_varied_infill_angles_enabled = DefaultTopSurfaceContoningVariedInfillAnglesEnabled;
|
||||
bool top_surface_contoning_blue_noise_error_diffusion_enabled = DefaultTopSurfaceContoningBlueNoiseErrorDiffusionEnabled;
|
||||
bool top_surface_contoning_supersampled_cells_enabled = DefaultTopSurfaceContoningSupersampledCellsEnabled;
|
||||
bool compact_offset_mode = DefaultCompactOffsetMode;
|
||||
bool use_legacy_fixed_color_mode = DefaultUseLegacyFixedColorMode;
|
||||
bool high_speed_image_texture_sampling = DefaultHighSpeedImageTextureSampling;
|
||||
@@ -401,6 +409,10 @@ struct TextureMappingZone
|
||||
top_surface_contoning_replace_top_perimeters_with_infill = DefaultTopSurfaceContoningReplaceTopPerimetersWithInfill;
|
||||
top_surface_contoning_recolor_surrounding_perimeters = DefaultTopSurfaceContoningRecolorSurroundingPerimeters;
|
||||
top_surface_contoning_perimeter_mode = DefaultTopSurfaceContoningPerimeterMode;
|
||||
top_surface_contoning_layer_phase_enabled = DefaultTopSurfaceContoningLayerPhaseEnabled;
|
||||
top_surface_contoning_varied_infill_angles_enabled = DefaultTopSurfaceContoningVariedInfillAnglesEnabled;
|
||||
top_surface_contoning_blue_noise_error_diffusion_enabled = DefaultTopSurfaceContoningBlueNoiseErrorDiffusionEnabled;
|
||||
top_surface_contoning_supersampled_cells_enabled = DefaultTopSurfaceContoningSupersampledCellsEnabled;
|
||||
compact_offset_mode = DefaultCompactOffsetMode;
|
||||
use_legacy_fixed_color_mode = DefaultUseLegacyFixedColorMode;
|
||||
high_speed_image_texture_sampling = DefaultHighSpeedImageTextureSampling;
|
||||
|
||||
@@ -1908,6 +1908,10 @@ public:
|
||||
bool top_surface_contoning_replace_top_perimeters_with_infill,
|
||||
bool top_surface_contoning_recolor_surrounding_perimeters,
|
||||
int top_surface_contoning_perimeter_mode,
|
||||
bool top_surface_contoning_layer_phase_enabled,
|
||||
bool top_surface_contoning_varied_infill_angles_enabled,
|
||||
bool top_surface_contoning_blue_noise_error_diffusion_enabled,
|
||||
bool top_surface_contoning_supersampled_cells_enabled,
|
||||
const TextureMappingManager &texture_mapping_zones,
|
||||
const TextureMappingGlobalSettings &global_settings,
|
||||
const TextureMappingPrimeTowerImage &prime_tower_image,
|
||||
@@ -2594,6 +2598,42 @@ public:
|
||||
0,
|
||||
wxEXPAND | wxTOP | wxBOTTOM,
|
||||
gap / 2);
|
||||
m_top_surface_contoning_layer_phase_checkbox =
|
||||
new wxCheckBox(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("Layer phase detail"));
|
||||
m_top_surface_contoning_layer_phase_checkbox->SetValue(top_surface_contoning_layer_phase_enabled);
|
||||
m_top_surface_contoning_layer_phase_checkbox->SetMinSize(
|
||||
wxSize(-1, std::max(m_top_surface_contoning_layer_phase_checkbox->GetBestSize().GetHeight(), FromDIP(24))));
|
||||
contoning_checkboxes_root->Add(m_top_surface_contoning_layer_phase_checkbox,
|
||||
0,
|
||||
wxEXPAND | wxTOP | wxBOTTOM,
|
||||
gap / 2);
|
||||
m_top_surface_contoning_varied_infill_angles_checkbox =
|
||||
new wxCheckBox(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("Varied infill angles"));
|
||||
m_top_surface_contoning_varied_infill_angles_checkbox->SetValue(top_surface_contoning_varied_infill_angles_enabled);
|
||||
m_top_surface_contoning_varied_infill_angles_checkbox->SetMinSize(
|
||||
wxSize(-1, std::max(m_top_surface_contoning_varied_infill_angles_checkbox->GetBestSize().GetHeight(), FromDIP(24))));
|
||||
contoning_checkboxes_root->Add(m_top_surface_contoning_varied_infill_angles_checkbox,
|
||||
0,
|
||||
wxEXPAND | wxTOP | wxBOTTOM,
|
||||
gap / 2);
|
||||
m_top_surface_contoning_blue_noise_error_diffusion_checkbox =
|
||||
new wxCheckBox(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("Blue-noise error diffusion"));
|
||||
m_top_surface_contoning_blue_noise_error_diffusion_checkbox->SetValue(top_surface_contoning_blue_noise_error_diffusion_enabled);
|
||||
m_top_surface_contoning_blue_noise_error_diffusion_checkbox->SetMinSize(
|
||||
wxSize(-1, std::max(m_top_surface_contoning_blue_noise_error_diffusion_checkbox->GetBestSize().GetHeight(), FromDIP(24))));
|
||||
contoning_checkboxes_root->Add(m_top_surface_contoning_blue_noise_error_diffusion_checkbox,
|
||||
0,
|
||||
wxEXPAND | wxTOP | wxBOTTOM,
|
||||
gap / 2);
|
||||
m_top_surface_contoning_supersampled_cells_checkbox =
|
||||
new wxCheckBox(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("Supersampled cell colors"));
|
||||
m_top_surface_contoning_supersampled_cells_checkbox->SetValue(top_surface_contoning_supersampled_cells_enabled);
|
||||
m_top_surface_contoning_supersampled_cells_checkbox->SetMinSize(
|
||||
wxSize(-1, std::max(m_top_surface_contoning_supersampled_cells_checkbox->GetBestSize().GetHeight(), FromDIP(24))));
|
||||
contoning_checkboxes_root->Add(m_top_surface_contoning_supersampled_cells_checkbox,
|
||||
0,
|
||||
wxEXPAND | wxTOP | wxBOTTOM,
|
||||
gap / 2);
|
||||
top_surface_box->Add(m_top_surface_contoning_checkboxes_panel, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP | wxBOTTOM, gap);
|
||||
m_top_surface_contoning_only_color_surface_infill_checkbox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &) {
|
||||
update_top_surface_image_options_visibility(true);
|
||||
@@ -2986,6 +3026,26 @@ public:
|
||||
int(TextureMappingZone::ContoningPerimeterSegmentInfill)) :
|
||||
TextureMappingZone::DefaultTopSurfaceContoningPerimeterMode;
|
||||
}
|
||||
bool top_surface_contoning_layer_phase_enabled() const
|
||||
{
|
||||
return m_top_surface_contoning_layer_phase_checkbox != nullptr &&
|
||||
m_top_surface_contoning_layer_phase_checkbox->GetValue();
|
||||
}
|
||||
bool top_surface_contoning_varied_infill_angles_enabled() const
|
||||
{
|
||||
return m_top_surface_contoning_varied_infill_angles_checkbox != nullptr &&
|
||||
m_top_surface_contoning_varied_infill_angles_checkbox->GetValue();
|
||||
}
|
||||
bool top_surface_contoning_blue_noise_error_diffusion_enabled() const
|
||||
{
|
||||
return m_top_surface_contoning_blue_noise_error_diffusion_checkbox != nullptr &&
|
||||
m_top_surface_contoning_blue_noise_error_diffusion_checkbox->GetValue();
|
||||
}
|
||||
bool top_surface_contoning_supersampled_cells_enabled() const
|
||||
{
|
||||
return m_top_surface_contoning_supersampled_cells_checkbox != nullptr &&
|
||||
m_top_surface_contoning_supersampled_cells_checkbox->GetValue();
|
||||
}
|
||||
bool minimum_visibility_offset_enabled() const
|
||||
{
|
||||
return m_minimum_visibility_offset_checkbox && m_minimum_visibility_offset_checkbox->GetValue();
|
||||
@@ -3457,6 +3517,22 @@ private:
|
||||
m_top_surface_contoning_perimeter_mode_panel->Show(show_perimeter_mode);
|
||||
if (m_top_surface_contoning_perimeter_mode_choice != nullptr)
|
||||
m_top_surface_contoning_perimeter_mode_choice->Enable(show_perimeter_mode);
|
||||
if (m_top_surface_contoning_layer_phase_checkbox != nullptr) {
|
||||
m_top_surface_contoning_layer_phase_checkbox->Show(contoning);
|
||||
m_top_surface_contoning_layer_phase_checkbox->Enable(contoning);
|
||||
}
|
||||
if (m_top_surface_contoning_varied_infill_angles_checkbox != nullptr) {
|
||||
m_top_surface_contoning_varied_infill_angles_checkbox->Show(contoning);
|
||||
m_top_surface_contoning_varied_infill_angles_checkbox->Enable(contoning);
|
||||
}
|
||||
if (m_top_surface_contoning_blue_noise_error_diffusion_checkbox != nullptr) {
|
||||
m_top_surface_contoning_blue_noise_error_diffusion_checkbox->Show(contoning);
|
||||
m_top_surface_contoning_blue_noise_error_diffusion_checkbox->Enable(contoning);
|
||||
}
|
||||
if (m_top_surface_contoning_supersampled_cells_checkbox != nullptr) {
|
||||
m_top_surface_contoning_supersampled_cells_checkbox->Show(contoning);
|
||||
m_top_surface_contoning_supersampled_cells_checkbox->Enable(contoning);
|
||||
}
|
||||
if (m_top_surface_image_fixed_coloring_filaments_checkbox != nullptr) {
|
||||
m_top_surface_image_fixed_coloring_filaments_checkbox->Show(!contoning_selected);
|
||||
m_top_surface_image_fixed_coloring_filaments_checkbox->Enable(enabled && !contoning_selected);
|
||||
@@ -3523,6 +3599,10 @@ private:
|
||||
wxCheckBox *m_top_surface_contoning_recolor_surrounding_perimeters_checkbox {nullptr};
|
||||
wxPanel *m_top_surface_contoning_perimeter_mode_panel {nullptr};
|
||||
wxChoice *m_top_surface_contoning_perimeter_mode_choice {nullptr};
|
||||
wxCheckBox *m_top_surface_contoning_layer_phase_checkbox {nullptr};
|
||||
wxCheckBox *m_top_surface_contoning_varied_infill_angles_checkbox {nullptr};
|
||||
wxCheckBox *m_top_surface_contoning_blue_noise_error_diffusion_checkbox {nullptr};
|
||||
wxCheckBox *m_top_surface_contoning_supersampled_cells_checkbox {nullptr};
|
||||
wxCheckBox *m_use_legacy_fixed_color_mode_checkbox {nullptr};
|
||||
wxCheckBox *m_minimum_visibility_offset_checkbox {nullptr};
|
||||
wxSpinCtrl *m_minimum_visibility_offset_spin {nullptr};
|
||||
@@ -8527,6 +8607,10 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
updated.top_surface_contoning_replace_top_perimeters_with_infill,
|
||||
updated.top_surface_contoning_recolor_surrounding_perimeters,
|
||||
updated.top_surface_contoning_perimeter_mode,
|
||||
updated.top_surface_contoning_layer_phase_enabled,
|
||||
updated.top_surface_contoning_varied_infill_angles_enabled,
|
||||
updated.top_surface_contoning_blue_noise_error_diffusion_enabled,
|
||||
updated.top_surface_contoning_supersampled_cells_enabled,
|
||||
bundle->texture_mapping_zones,
|
||||
bundle->texture_mapping_global_settings,
|
||||
wxGetApp().model().texture_mapping_prime_tower_image,
|
||||
@@ -8587,6 +8671,13 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
updated.top_surface_contoning_recolor_surrounding_perimeters =
|
||||
dlg.top_surface_contoning_recolor_surrounding_perimeters();
|
||||
updated.top_surface_contoning_perimeter_mode = dlg.top_surface_contoning_perimeter_mode();
|
||||
updated.top_surface_contoning_layer_phase_enabled = dlg.top_surface_contoning_layer_phase_enabled();
|
||||
updated.top_surface_contoning_varied_infill_angles_enabled =
|
||||
dlg.top_surface_contoning_varied_infill_angles_enabled();
|
||||
updated.top_surface_contoning_blue_noise_error_diffusion_enabled =
|
||||
dlg.top_surface_contoning_blue_noise_error_diffusion_enabled();
|
||||
updated.top_surface_contoning_supersampled_cells_enabled =
|
||||
dlg.top_surface_contoning_supersampled_cells_enabled();
|
||||
if (updated.top_surface_image_printing_enabled &&
|
||||
updated.top_surface_image_printing_method == int(TextureMappingZone::TopSurfaceImageContoning)) {
|
||||
updated.modulation_mode = int(TextureMappingZone::ModulationPerimeterPathV2);
|
||||
|
||||
Reference in New Issue
Block a user