Add TD correction support for top-surface coloring
This commit is contained in:
@@ -124,7 +124,8 @@ int build_color_solver_kd_tree(const std::vector<float> &coor
|
||||
return build_color_solver_kd_tree(coords, nodes, indices, 0, candidate_count, uint8_t(0));
|
||||
}
|
||||
|
||||
void build_color_solver_kd_trees(ColorSolverCandidateSet &candidates)
|
||||
template <class CandidateSet>
|
||||
void build_color_solver_kd_trees(CandidateSet &candidates)
|
||||
{
|
||||
candidates.kd_root = build_color_solver_kd_tree(candidates.rgbs, candidates.kd_nodes);
|
||||
if (candidates.perceptual_coords.size() == candidates.rgbs.size()) {
|
||||
@@ -159,7 +160,8 @@ void update_color_solver_nearest_result(ColorSolverNearestResult &result, size_t
|
||||
}
|
||||
}
|
||||
|
||||
float color_solver_candidate_error(const ColorSolverCandidateSet &candidates,
|
||||
template <class CandidateSet>
|
||||
float color_solver_candidate_error(const CandidateSet &candidates,
|
||||
size_t candidate_idx,
|
||||
const std::array<float, 3> &target_rgb)
|
||||
{
|
||||
@@ -170,7 +172,8 @@ float color_solver_candidate_error(const ColorSolverCandidateSet &candidates,
|
||||
return dr * dr + dg * dg + db * db;
|
||||
}
|
||||
|
||||
ColorSolverNearestResult nearest_color_solver_candidates_linear(const ColorSolverCandidateSet &candidates,
|
||||
template <class CandidateSet>
|
||||
ColorSolverNearestResult nearest_color_solver_candidates_linear(const CandidateSet &candidates,
|
||||
const std::array<float, 3> &target_rgb)
|
||||
{
|
||||
ColorSolverNearestResult result;
|
||||
@@ -184,7 +187,8 @@ ColorSolverNearestResult nearest_color_solver_candidates_linear(const ColorSolve
|
||||
return result;
|
||||
}
|
||||
|
||||
void query_color_solver_kd_tree(const ColorSolverCandidateSet &candidates,
|
||||
template <class CandidateSet>
|
||||
void query_color_solver_kd_tree(const CandidateSet &candidates,
|
||||
const std::array<float, 3> &target_rgb,
|
||||
int node_idx,
|
||||
ColorSolverNearestResult &result)
|
||||
@@ -216,7 +220,8 @@ void query_color_solver_kd_tree(const ColorSolverCandidateSet &candidates,
|
||||
query_color_solver_kd_tree(candidates, target_rgb, far_node, result);
|
||||
}
|
||||
|
||||
ColorSolverNearestResult nearest_color_solver_candidates(const ColorSolverCandidateSet &candidates,
|
||||
template <class CandidateSet>
|
||||
ColorSolverNearestResult nearest_color_solver_candidates(const CandidateSet &candidates,
|
||||
const std::array<float, 3> &target_rgb)
|
||||
{
|
||||
ColorSolverNearestResult result;
|
||||
@@ -228,7 +233,8 @@ ColorSolverNearestResult nearest_color_solver_candidates(const ColorSolverCandid
|
||||
return result;
|
||||
}
|
||||
|
||||
float color_solver_candidate_perceptual_error(const ColorSolverCandidateSet &candidates,
|
||||
template <class CandidateSet>
|
||||
float color_solver_candidate_perceptual_error(const CandidateSet &candidates,
|
||||
size_t candidate_idx,
|
||||
const std::array<float, 3> &target_oklab,
|
||||
const std::array<float, 3> &axis_weights)
|
||||
@@ -240,7 +246,8 @@ float color_solver_candidate_perceptual_error(const ColorSolverCandidateSet &can
|
||||
return axis_weights[0] * dl * dl + axis_weights[1] * da * da + axis_weights[2] * db * db;
|
||||
}
|
||||
|
||||
ColorSolverNearestResult nearest_color_solver_candidates_perceptual_linear(const ColorSolverCandidateSet &candidates,
|
||||
template <class CandidateSet>
|
||||
ColorSolverNearestResult nearest_color_solver_candidates_perceptual_linear(const CandidateSet &candidates,
|
||||
const std::array<float, 3> &target_oklab,
|
||||
const std::array<float, 3> &axis_weights)
|
||||
{
|
||||
@@ -254,7 +261,8 @@ ColorSolverNearestResult nearest_color_solver_candidates_perceptual_linear(const
|
||||
return result;
|
||||
}
|
||||
|
||||
void query_color_solver_perceptual_kd_tree(const ColorSolverCandidateSet &candidates,
|
||||
template <class CandidateSet>
|
||||
void query_color_solver_perceptual_kd_tree(const CandidateSet &candidates,
|
||||
const std::array<float, 3> &target_oklab,
|
||||
const std::array<float, 3> &axis_weights,
|
||||
int node_idx,
|
||||
@@ -287,7 +295,8 @@ void query_color_solver_perceptual_kd_tree(const ColorSolverCandidateSet &candid
|
||||
query_color_solver_perceptual_kd_tree(candidates, target_oklab, axis_weights, far_node, result);
|
||||
}
|
||||
|
||||
ColorSolverNearestResult nearest_color_solver_candidates_perceptual(const ColorSolverCandidateSet &candidates,
|
||||
template <class CandidateSet>
|
||||
ColorSolverNearestResult nearest_color_solver_candidates_perceptual(const CandidateSet &candidates,
|
||||
const std::array<float, 3> &target_rgb)
|
||||
{
|
||||
ColorSolverNearestResult result;
|
||||
@@ -304,6 +313,48 @@ ColorSolverNearestResult nearest_color_solver_candidates_perceptual(const ColorS
|
||||
return result;
|
||||
}
|
||||
|
||||
std::array<float, 3> mix_ordered_stack_with_buffers(const std::vector<std::array<float, 3>> &colors_with_background,
|
||||
std::vector<float> &weights,
|
||||
const std::vector<uint16_t> &surface_to_deep,
|
||||
const std::vector<float> &layer_opacities)
|
||||
{
|
||||
if (colors_with_background.empty() || surface_to_deep.empty())
|
||||
return colors_with_background.empty() ? std::array<float, 3>{ { 0.f, 0.f, 0.f } } : colors_with_background.back();
|
||||
|
||||
const size_t component_count = colors_with_background.size() - 1;
|
||||
weights.assign(colors_with_background.size(), 0.f);
|
||||
float transmission = 1.f;
|
||||
for (uint16_t component_idx : surface_to_deep) {
|
||||
if (size_t(component_idx) >= component_count)
|
||||
continue;
|
||||
const float opacity =
|
||||
size_t(component_idx) < layer_opacities.size() && std::isfinite(layer_opacities[size_t(component_idx)]) ?
|
||||
std::clamp(layer_opacities[size_t(component_idx)], 1e-4f, 0.9999f) :
|
||||
0.5f;
|
||||
weights[size_t(component_idx)] += transmission * opacity;
|
||||
transmission *= 1.f - opacity;
|
||||
if (transmission <= 1e-5f)
|
||||
break;
|
||||
}
|
||||
weights.back() = std::max(0.f, transmission);
|
||||
return pigment_painter::mix_srgb(colors_with_background, weights);
|
||||
}
|
||||
|
||||
size_t ordered_stack_candidate_count(size_t component_count, int stack_depth, size_t candidate_limit)
|
||||
{
|
||||
if (component_count == 0 || stack_depth <= 0)
|
||||
return 0;
|
||||
size_t count = 1;
|
||||
for (int idx = 0; idx < stack_depth; ++idx) {
|
||||
if (candidate_limit > 0 && count > candidate_limit / component_count)
|
||||
return 0;
|
||||
if (count > std::numeric_limits<size_t>::max() / component_count)
|
||||
return 0;
|
||||
count *= component_count;
|
||||
}
|
||||
return candidate_limit > 0 && count > candidate_limit ? 0 : count;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ColorSolverMixModel color_solver_mix_model_from_index(int model)
|
||||
@@ -362,6 +413,22 @@ std::array<float, 3> mix_color_solver_components(const std::vector<std::array<fl
|
||||
return pigment_painter::mix_srgb(component_colors, safe_weights);
|
||||
}
|
||||
|
||||
std::array<float, 3> mix_color_solver_ordered_stack(const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<uint16_t> &surface_to_deep,
|
||||
const std::vector<float> &layer_opacities,
|
||||
const std::array<float, 3> &background_rgb,
|
||||
ColorSolverMixModel mix_model)
|
||||
{
|
||||
(void) mix_model;
|
||||
if (component_colors.empty() || surface_to_deep.empty())
|
||||
return background_rgb;
|
||||
|
||||
std::vector<std::array<float, 3>> colors = component_colors;
|
||||
colors.emplace_back(background_rgb);
|
||||
std::vector<float> weights;
|
||||
return mix_ordered_stack_with_buffers(colors, weights, surface_to_deep, layer_opacities);
|
||||
}
|
||||
|
||||
std::array<float, 3> color_solver_oklab_from_srgb(const std::array<float, 3> &rgb)
|
||||
{
|
||||
return oklab_from_srgb(rgb);
|
||||
@@ -480,4 +547,145 @@ std::vector<float> solve_color_solver_weights_for_target(const ColorSolverCandid
|
||||
return weights;
|
||||
}
|
||||
|
||||
std::string color_solver_ordered_stack_candidate_cache_key(const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<float> &layer_opacities,
|
||||
const std::array<float, 3> &background_rgb,
|
||||
ColorSolverMixModel mix_model,
|
||||
int stack_depth,
|
||||
size_t candidate_limit)
|
||||
{
|
||||
std::ostringstream key;
|
||||
key << component_colors.size();
|
||||
key << "|mx" << mix_model_index(mix_model);
|
||||
key << "|sd" << stack_depth;
|
||||
key << "|lim" << candidate_limit;
|
||||
key << "|bg"
|
||||
<< int(std::lround(clamp01(background_rgb[0]) * 65535.f)) << ','
|
||||
<< int(std::lround(clamp01(background_rgb[1]) * 65535.f)) << ','
|
||||
<< int(std::lround(clamp01(background_rgb[2]) * 65535.f));
|
||||
for (const std::array<float, 3> &color : component_colors) {
|
||||
key << '|'
|
||||
<< int(std::lround(clamp01(color[0]) * 65535.f)) << ','
|
||||
<< int(std::lround(clamp01(color[1]) * 65535.f)) << ','
|
||||
<< int(std::lround(clamp01(color[2]) * 65535.f));
|
||||
}
|
||||
key << "|op";
|
||||
for (size_t idx = 0; idx < component_colors.size(); ++idx) {
|
||||
const float opacity =
|
||||
idx < layer_opacities.size() && std::isfinite(layer_opacities[idx]) ?
|
||||
std::clamp(layer_opacities[idx], 1e-4f, 0.9999f) :
|
||||
0.5f;
|
||||
key << ',' << int(std::lround(opacity * 1000000.f));
|
||||
}
|
||||
return key.str();
|
||||
}
|
||||
|
||||
ColorSolverOrderedStackCandidateSet build_color_solver_ordered_stack_candidates(
|
||||
const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<float> &layer_opacities,
|
||||
const std::array<float, 3> &background_rgb,
|
||||
ColorSolverMixModel mix_model,
|
||||
int stack_depth,
|
||||
size_t candidate_limit)
|
||||
{
|
||||
(void) mix_model;
|
||||
ColorSolverOrderedStackCandidateSet candidates;
|
||||
if (component_colors.empty() || stack_depth <= 0 || component_colors.size() > size_t(std::numeric_limits<uint16_t>::max()))
|
||||
return candidates;
|
||||
|
||||
const size_t component_count = component_colors.size();
|
||||
const size_t candidate_count = ordered_stack_candidate_count(component_count, stack_depth, candidate_limit);
|
||||
if (candidate_count == 0)
|
||||
return candidates;
|
||||
|
||||
candidates.component_count = component_count;
|
||||
candidates.stack_depth = stack_depth;
|
||||
candidates.rgbs.reserve(candidate_count * 3);
|
||||
candidates.perceptual_coords.reserve(candidate_count * 3);
|
||||
candidates.stacks.reserve(candidate_count * size_t(stack_depth));
|
||||
|
||||
std::vector<std::array<float, 3>> colors_with_background = component_colors;
|
||||
colors_with_background.emplace_back(background_rgb);
|
||||
std::vector<float> weights(colors_with_background.size(), 0.f);
|
||||
std::vector<uint16_t> surface_to_deep(size_t(stack_depth), 0);
|
||||
|
||||
std::function<void(int)> recurse = [&](int depth_idx) {
|
||||
if (depth_idx == stack_depth) {
|
||||
const std::array<float, 3> mixed =
|
||||
mix_ordered_stack_with_buffers(colors_with_background, weights, surface_to_deep, layer_opacities);
|
||||
const std::array<float, 3> perceptual = oklab_from_srgb(mixed);
|
||||
candidates.rgbs.emplace_back(mixed[0]);
|
||||
candidates.rgbs.emplace_back(mixed[1]);
|
||||
candidates.rgbs.emplace_back(mixed[2]);
|
||||
candidates.perceptual_coords.emplace_back(perceptual[0]);
|
||||
candidates.perceptual_coords.emplace_back(perceptual[1]);
|
||||
candidates.perceptual_coords.emplace_back(perceptual[2]);
|
||||
candidates.stacks.insert(candidates.stacks.end(), surface_to_deep.begin(), surface_to_deep.end());
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t component_idx = 0; component_idx < component_count; ++component_idx) {
|
||||
surface_to_deep[size_t(depth_idx)] = uint16_t(component_idx);
|
||||
recurse(depth_idx + 1);
|
||||
}
|
||||
};
|
||||
recurse(0);
|
||||
build_color_solver_kd_trees(candidates);
|
||||
return candidates;
|
||||
}
|
||||
|
||||
const ColorSolverOrderedStackCandidateSet &color_solver_ordered_stack_candidates(
|
||||
ColorSolverOrderedStackCandidateCache &cache,
|
||||
const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<float> &layer_opacities,
|
||||
const std::array<float, 3> &background_rgb,
|
||||
ColorSolverMixModel mix_model,
|
||||
int stack_depth,
|
||||
size_t candidate_limit)
|
||||
{
|
||||
const std::string key =
|
||||
color_solver_ordered_stack_candidate_cache_key(component_colors,
|
||||
layer_opacities,
|
||||
background_rgb,
|
||||
mix_model,
|
||||
stack_depth,
|
||||
candidate_limit);
|
||||
auto it = cache.find(key);
|
||||
if (it != cache.end())
|
||||
return it->second;
|
||||
return cache.emplace(
|
||||
key,
|
||||
build_color_solver_ordered_stack_candidates(component_colors,
|
||||
layer_opacities,
|
||||
background_rgb,
|
||||
mix_model,
|
||||
stack_depth,
|
||||
candidate_limit)).first->second;
|
||||
}
|
||||
|
||||
std::vector<uint16_t> solve_color_solver_ordered_stack_for_target(
|
||||
const ColorSolverOrderedStackCandidateSet &candidates,
|
||||
const std::array<float, 3> &target_rgb,
|
||||
ColorSolverMode solver_mode)
|
||||
{
|
||||
if (candidates.empty())
|
||||
return {};
|
||||
|
||||
const size_t candidate_count = candidates.rgbs.size() / 3;
|
||||
ColorSolverNearestResult nearest =
|
||||
solver_mode == ColorSolverMode::V2 ?
|
||||
nearest_color_solver_candidates_perceptual(candidates, target_rgb) :
|
||||
nearest_color_solver_candidates(candidates, target_rgb);
|
||||
if (nearest.best_idx >= candidate_count && solver_mode == ColorSolverMode::V2)
|
||||
nearest = nearest_color_solver_candidates(candidates, target_rgb);
|
||||
if (nearest.best_idx >= candidate_count)
|
||||
return {};
|
||||
|
||||
const size_t stack_begin = nearest.best_idx * size_t(candidates.stack_depth);
|
||||
if (stack_begin + size_t(candidates.stack_depth) > candidates.stacks.size())
|
||||
return {};
|
||||
return std::vector<uint16_t>(candidates.stacks.begin() + stack_begin,
|
||||
candidates.stacks.begin() + stack_begin + candidates.stack_depth);
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -69,6 +69,28 @@ struct ColorSolverCandidateSet {
|
||||
|
||||
using ColorSolverCandidateCache = std::map<std::string, ColorSolverCandidateSet>;
|
||||
|
||||
struct ColorSolverOrderedStackCandidateSet {
|
||||
using KdNode = ColorSolverCandidateSet::KdNode;
|
||||
|
||||
size_t component_count { 0 };
|
||||
int stack_depth { 0 };
|
||||
std::vector<float> rgbs;
|
||||
std::vector<float> perceptual_coords;
|
||||
std::vector<uint16_t> stacks;
|
||||
std::vector<KdNode> kd_nodes;
|
||||
std::vector<KdNode> perceptual_kd_nodes;
|
||||
int kd_root { -1 };
|
||||
int perceptual_kd_root { -1 };
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return component_count == 0 || stack_depth <= 0 || rgbs.empty() || rgbs.size() % 3 != 0 ||
|
||||
stacks.size() != (rgbs.size() / 3) * size_t(stack_depth);
|
||||
}
|
||||
};
|
||||
|
||||
using ColorSolverOrderedStackCandidateCache = std::map<std::string, ColorSolverOrderedStackCandidateSet>;
|
||||
|
||||
ColorSolverMixModel color_solver_mix_model_from_index(int model);
|
||||
ColorSolverLookupMode color_solver_lookup_mode_from_index(int mode);
|
||||
ColorSolverMode color_solver_mode_from_index(int mode);
|
||||
@@ -82,6 +104,11 @@ std::array<float, 3> mix_color_solver_components(const std::vector<std::array<fl
|
||||
std::array<float, 3> mix_color_solver_components(const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<float> &weights,
|
||||
ColorSolverMixModel mix_model);
|
||||
std::array<float, 3> mix_color_solver_ordered_stack(const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<uint16_t> &surface_to_deep,
|
||||
const std::vector<float> &layer_opacities,
|
||||
const std::array<float, 3> &background_rgb,
|
||||
ColorSolverMixModel mix_model);
|
||||
std::array<float, 3> color_solver_oklab_from_srgb(const std::array<float, 3> &rgb);
|
||||
|
||||
std::string color_solver_candidate_cache_key(const std::vector<std::array<float, 3>> &component_colors,
|
||||
@@ -98,6 +125,31 @@ std::vector<float> solve_color_solver_weights_for_target(const ColorSolverCandid
|
||||
const std::array<float, 3> &target_rgb,
|
||||
ColorSolverLookupMode lookup_mode,
|
||||
ColorSolverMode solver_mode);
|
||||
std::string color_solver_ordered_stack_candidate_cache_key(const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<float> &layer_opacities,
|
||||
const std::array<float, 3> &background_rgb,
|
||||
ColorSolverMixModel mix_model,
|
||||
int stack_depth,
|
||||
size_t candidate_limit = 0);
|
||||
ColorSolverOrderedStackCandidateSet build_color_solver_ordered_stack_candidates(
|
||||
const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<float> &layer_opacities,
|
||||
const std::array<float, 3> &background_rgb,
|
||||
ColorSolverMixModel mix_model,
|
||||
int stack_depth,
|
||||
size_t candidate_limit = 0);
|
||||
const ColorSolverOrderedStackCandidateSet &color_solver_ordered_stack_candidates(
|
||||
ColorSolverOrderedStackCandidateCache &cache,
|
||||
const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<float> &layer_opacities,
|
||||
const std::array<float, 3> &background_rgb,
|
||||
ColorSolverMixModel mix_model,
|
||||
int stack_depth,
|
||||
size_t candidate_limit = 0);
|
||||
std::vector<uint16_t> solve_color_solver_ordered_stack_for_target(
|
||||
const ColorSolverOrderedStackCandidateSet &candidates,
|
||||
const std::array<float, 3> &target_rgb,
|
||||
ColorSolverMode solver_mode);
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
|
||||
@@ -504,6 +504,7 @@ struct TopSurfaceImageRegionPlan {
|
||||
bool contoning_polygonize_color_regions_enabled = false;
|
||||
int contoning_polygonize_resolution = TextureMappingZone::DefaultTopSurfaceContoningPolygonizeResolution;
|
||||
bool contoning_surface_anchored_stacks_enabled = false;
|
||||
bool contoning_td_adjustment_enabled = TextureMappingZone::DefaultTopSurfaceContoningTdAdjustmentEnabled;
|
||||
int contoning_flat_surface_infill_mode = TextureMappingZone::SlicerDefaultTopSurfaceContoningFlatSurfaceInfillMode;
|
||||
};
|
||||
|
||||
@@ -1166,6 +1167,7 @@ struct TopSurfaceImageContoningStackPlanKey {
|
||||
bool blue_noise { false };
|
||||
bool polygonize { false };
|
||||
int polygonize_resolution { 1 };
|
||||
bool td_adjustment { false };
|
||||
|
||||
bool operator<(const TopSurfaceImageContoningStackPlanKey &rhs) const
|
||||
{
|
||||
@@ -1192,7 +1194,8 @@ struct TopSurfaceImageContoningStackPlanKey {
|
||||
supersampled,
|
||||
blue_noise,
|
||||
polygonize,
|
||||
polygonize_resolution) <
|
||||
polygonize_resolution,
|
||||
td_adjustment) <
|
||||
std::tie(rhs.source_layer,
|
||||
rhs.source_layer_id,
|
||||
rhs.target_layer,
|
||||
@@ -1216,7 +1219,8 @@ struct TopSurfaceImageContoningStackPlanKey {
|
||||
rhs.supersampled,
|
||||
rhs.blue_noise,
|
||||
rhs.polygonize,
|
||||
rhs.polygonize_resolution);
|
||||
rhs.polygonize_resolution,
|
||||
rhs.td_adjustment);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1320,29 +1324,6 @@ static float top_surface_image_contoning_oklab_error(const std::array<float, 3>
|
||||
return dl * dl + 4.f * da * da + 4.f * db * db;
|
||||
}
|
||||
|
||||
static std::optional<std::array<float, 3>> top_surface_image_contoning_stack_rgb(
|
||||
const std::vector<unsigned int> &bottom_to_top,
|
||||
const PrintConfig &print_config)
|
||||
{
|
||||
if (bottom_to_top.empty())
|
||||
return std::nullopt;
|
||||
std::vector<std::array<float, 3>> colors;
|
||||
std::vector<float> weights;
|
||||
colors.reserve(bottom_to_top.size());
|
||||
weights.reserve(bottom_to_top.size());
|
||||
const float weight = 1.f / float(bottom_to_top.size());
|
||||
for (unsigned int component_id : bottom_to_top) {
|
||||
if (component_id == 0 || component_id > print_config.filament_colour.values.size())
|
||||
return std::nullopt;
|
||||
ColorRGB color;
|
||||
if (!decode_color(print_config.filament_colour.get_at(size_t(component_id - 1)), color))
|
||||
return std::nullopt;
|
||||
colors.push_back({ color.r(), color.g(), color.b() });
|
||||
weights.emplace_back(weight);
|
||||
}
|
||||
return mix_color_solver_components(colors, weights, ColorSolverMixModel::PigmentPainter);
|
||||
}
|
||||
|
||||
static float top_surface_image_contoning_sample_pitch_mm(const TopSurfaceImageRegionPlan &plan,
|
||||
const BoundingBox &bbox)
|
||||
{
|
||||
@@ -1704,6 +1685,7 @@ static std::vector<TopSurfaceImageContoningVectorRegion> top_surface_image_conto
|
||||
const ExPolygons &area,
|
||||
float min_feature_mm,
|
||||
bool polygonize_color_regions,
|
||||
bool lower_surface,
|
||||
const ThrowIfCanceled *throw_if_canceled)
|
||||
{
|
||||
std::vector<TopSurfaceImageContoningVectorRegion> regions;
|
||||
@@ -1729,7 +1711,9 @@ static std::vector<TopSurfaceImageContoningVectorRegion> top_surface_image_conto
|
||||
continue;
|
||||
const int pattern_depth = depth % int(bottom_to_top.size());
|
||||
const unsigned int component_id =
|
||||
bottom_to_top[size_t(int(bottom_to_top.size()) - 1 - pattern_depth)];
|
||||
lower_surface ?
|
||||
bottom_to_top[size_t(pattern_depth)] :
|
||||
bottom_to_top[size_t(int(bottom_to_top.size()) - 1 - pattern_depth)];
|
||||
if (component_id == 0 || component_id > max_component_id)
|
||||
continue;
|
||||
component_grid[idx] = int(component_id);
|
||||
@@ -1969,15 +1953,15 @@ static std::optional<TopSurfaceImageContoningSolvedLabel> top_surface_image_cont
|
||||
const std::array<float, 3> &rgb,
|
||||
int solve_layers,
|
||||
const TextureMappingContoningSolver &solver,
|
||||
const PrintConfig &print_config,
|
||||
bool lower_surface,
|
||||
std::vector<TopSurfaceImageContoningVectorLabel> &labels,
|
||||
std::map<std::vector<unsigned int>, int> &label_by_stack)
|
||||
{
|
||||
TextureMappingContoningStack stack = solver.solve(rgb, solve_layers);
|
||||
TextureMappingContoningStack stack = solver.solve(rgb, solve_layers, lower_surface);
|
||||
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);
|
||||
solver.stack_rgb(stack.bottom_to_top, lower_surface);
|
||||
if (!stack_rgb)
|
||||
return std::nullopt;
|
||||
auto label_it = label_by_stack.find(stack.bottom_to_top);
|
||||
@@ -2124,7 +2108,13 @@ static std::vector<TopSurfaceImageContoningVectorRegion> top_surface_image_conto
|
||||
|
||||
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);
|
||||
top_surface_image_contoning_solve_label(target_rgb,
|
||||
solve_layers,
|
||||
solver,
|
||||
source_surface == TopSurfaceImageSourceSurface::Bottom &&
|
||||
plan.contoning_td_adjustment_enabled,
|
||||
labels,
|
||||
label_by_stack);
|
||||
if (!solved)
|
||||
return std::optional<TopSurfaceImageContoningSolvedLabel>();
|
||||
grid[size_t(row * cols + col)] = solved->label;
|
||||
@@ -2247,6 +2237,8 @@ static std::vector<TopSurfaceImageContoningVectorRegion> top_surface_image_conto
|
||||
area,
|
||||
plan.contoning_min_feature_mm,
|
||||
plan.contoning_polygonize_color_regions_enabled,
|
||||
source_surface == TopSurfaceImageSourceSurface::Bottom &&
|
||||
plan.contoning_td_adjustment_enabled,
|
||||
throw_if_canceled);
|
||||
}
|
||||
|
||||
@@ -2306,7 +2298,13 @@ static std::shared_ptr<const TopSurfaceImageContoningStackPlan> top_surface_imag
|
||||
|
||||
auto solve_cell = [&](int row, int col, const std::array<float, 3> &target_rgb, int solve_layers, int available_depth) {
|
||||
std::optional<TopSurfaceImageContoningSolvedLabel> solved =
|
||||
top_surface_image_contoning_solve_label(target_rgb, solve_layers, solver, print_config, out->labels, label_by_stack);
|
||||
top_surface_image_contoning_solve_label(target_rgb,
|
||||
solve_layers,
|
||||
solver,
|
||||
source_surface == TopSurfaceImageSourceSurface::Bottom &&
|
||||
plan.contoning_td_adjustment_enabled,
|
||||
out->labels,
|
||||
label_by_stack);
|
||||
if (!solved)
|
||||
return std::optional<TopSurfaceImageContoningSolvedLabel>();
|
||||
TopSurfaceImageContoningStackPlanCell &cell = out->cells[size_t(row * cols + col)];
|
||||
@@ -2470,6 +2468,7 @@ static TopSurfaceImageContoningStackPlanKey top_surface_image_contoning_stack_pl
|
||||
key.polygonize_resolution = plan.contoning_polygonize_color_regions_enabled ?
|
||||
TextureMappingZone::normalize_top_surface_contoning_polygonize_resolution(plan.contoning_polygonize_resolution) :
|
||||
1;
|
||||
key.td_adjustment = plan.contoning_td_adjustment_enabled;
|
||||
return key;
|
||||
}
|
||||
|
||||
@@ -2511,6 +2510,7 @@ static std::vector<TopSurfaceImageContoningVectorRegion> top_surface_image_conto
|
||||
const TopSurfaceImageContoningStackPlan &stack_plan,
|
||||
const ExPolygons &area,
|
||||
int depth,
|
||||
TopSurfaceImageSourceSurface source_surface,
|
||||
const ThrowIfCanceled *throw_if_canceled)
|
||||
{
|
||||
std::vector<TopSurfaceImageContoningVectorRegion> regions;
|
||||
@@ -2550,6 +2550,8 @@ static std::vector<TopSurfaceImageContoningVectorRegion> top_surface_image_conto
|
||||
area,
|
||||
plan.contoning_min_feature_mm,
|
||||
plan.contoning_polygonize_color_regions_enabled,
|
||||
source_surface == TopSurfaceImageSourceSurface::Bottom &&
|
||||
plan.contoning_td_adjustment_enabled,
|
||||
throw_if_canceled);
|
||||
}
|
||||
|
||||
@@ -2889,7 +2891,12 @@ static void top_surface_image_append_contoning_slices(TopSurfaceImageRegionPlan
|
||||
stack_area_extensions_ptr,
|
||||
throw_if_canceled);
|
||||
const std::vector<TopSurfaceImageContoningVectorRegion> stack_regions =
|
||||
top_surface_image_contoning_vector_regions_from_stack_plan(plan, *stack_plan, vector_area, depth, throw_if_canceled);
|
||||
top_surface_image_contoning_vector_regions_from_stack_plan(plan,
|
||||
*stack_plan,
|
||||
vector_area,
|
||||
depth,
|
||||
source_surface,
|
||||
throw_if_canceled);
|
||||
append_regions(stack_regions, true, include_perimeter_regions);
|
||||
}
|
||||
} else if (plan.contoning_blue_noise_error_diffusion_enabled) {
|
||||
@@ -3122,7 +3129,8 @@ static std::vector<TopSurfaceImageRegionPlan> top_surface_image_region_plans(
|
||||
TextureMappingZone::normalize_top_surface_contoning_polygonize_resolution(zone->top_surface_contoning_polygonize_resolution);
|
||||
plan.contoning_surface_anchored_stacks_enabled =
|
||||
zone->effective_top_surface_contoning_surface_anchored_stacks_enabled();
|
||||
const TextureMappingContoningSolver contoning_solver(*zone, print_config, components);
|
||||
plan.contoning_td_adjustment_enabled = zone->top_surface_contoning_td_adjustment_enabled;
|
||||
const TextureMappingContoningSolver contoning_solver(*zone, print_config, components, float(layer.height));
|
||||
|
||||
const int stack_depth = plan.contoning ?
|
||||
plan.contoning_stack_layers :
|
||||
|
||||
@@ -528,7 +528,10 @@ static std::optional<PerimeterTextureRecolorSampler> perimeter_texture_make_reco
|
||||
if (zone.top_surface_contoning_perimeters_active()) {
|
||||
sampler.contoning = true;
|
||||
sampler.contoning_solver =
|
||||
TextureMappingContoningSolver(zone, print_config, sampler.image_context->component_ids);
|
||||
TextureMappingContoningSolver(zone,
|
||||
print_config,
|
||||
sampler.image_context->component_ids,
|
||||
layer != nullptr ? float(layer->height) : 0.f);
|
||||
sampler.contoning_stack_layers =
|
||||
std::clamp(zone.top_surface_contoning_stack_layers,
|
||||
TextureMappingZone::MinTopSurfaceContoningStackLayers,
|
||||
|
||||
@@ -1148,6 +1148,7 @@ bool TextureMappingZone::operator==(const TextureMappingZone &rhs) const
|
||||
TextureMappingZone::normalize_top_surface_contoning_polygonize_resolution(top_surface_contoning_polygonize_resolution) ==
|
||||
TextureMappingZone::normalize_top_surface_contoning_polygonize_resolution(rhs.top_surface_contoning_polygonize_resolution) &&
|
||||
effective_top_surface_contoning_surface_anchored_stacks_enabled() == rhs.effective_top_surface_contoning_surface_anchored_stacks_enabled() &&
|
||||
top_surface_contoning_td_adjustment_enabled == rhs.top_surface_contoning_td_adjustment_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 &&
|
||||
@@ -1548,6 +1549,8 @@ std::string TextureMappingManager::serialize_entries()
|
||||
TextureMappingZone::normalize_top_surface_contoning_polygonize_resolution(zone.top_surface_contoning_polygonize_resolution);
|
||||
texture["top_surface_contoning_surface_anchored_stacks_enabled"] =
|
||||
zone.effective_top_surface_contoning_surface_anchored_stacks_enabled();
|
||||
texture["top_surface_contoning_td_adjustment_enabled"] =
|
||||
zone.top_surface_contoning_td_adjustment_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;
|
||||
@@ -1844,6 +1847,9 @@ void TextureMappingManager::load_entries(const std::string &serialized,
|
||||
zone.top_surface_contoning_surface_anchored_stacks_enabled =
|
||||
texture.value("top_surface_contoning_surface_anchored_stacks_enabled",
|
||||
TextureMappingZone::DefaultTopSurfaceContoningSurfaceAnchoredStacksEnabled);
|
||||
zone.top_surface_contoning_td_adjustment_enabled =
|
||||
texture.value("top_surface_contoning_td_adjustment_enabled",
|
||||
TextureMappingZone::DefaultTopSurfaceContoningTdAdjustmentEnabled);
|
||||
zone.apply_top_surface_contoning_experimental_defaults();
|
||||
zone.compact_offset_mode = texture.value("compact_offset_mode", TextureMappingZone::DefaultCompactOffsetMode);
|
||||
zone.use_legacy_fixed_color_mode =
|
||||
|
||||
@@ -204,6 +204,7 @@ struct TextureMappingZone
|
||||
static constexpr bool DefaultTopSurfaceContoningPolygonizeColorRegionsEnabled = true;
|
||||
static constexpr int DefaultTopSurfaceContoningPolygonizeResolution = 4;
|
||||
static constexpr bool DefaultTopSurfaceContoningSurfaceAnchoredStacksEnabled = false;
|
||||
static constexpr bool DefaultTopSurfaceContoningTdAdjustmentEnabled = true;
|
||||
static constexpr bool DefaultCompactOffsetMode = true;
|
||||
static constexpr bool DefaultUseLegacyFixedColorMode = false;
|
||||
static constexpr bool DefaultHighSpeedImageTextureSampling = true;
|
||||
@@ -362,6 +363,7 @@ struct TextureMappingZone
|
||||
bool top_surface_contoning_polygonize_color_regions_enabled = DefaultTopSurfaceContoningPolygonizeColorRegionsEnabled;
|
||||
int top_surface_contoning_polygonize_resolution = DefaultTopSurfaceContoningPolygonizeResolution;
|
||||
bool top_surface_contoning_surface_anchored_stacks_enabled = DefaultTopSurfaceContoningSurfaceAnchoredStacksEnabled;
|
||||
bool top_surface_contoning_td_adjustment_enabled = DefaultTopSurfaceContoningTdAdjustmentEnabled;
|
||||
bool compact_offset_mode = DefaultCompactOffsetMode;
|
||||
bool use_legacy_fixed_color_mode = DefaultUseLegacyFixedColorMode;
|
||||
bool high_speed_image_texture_sampling = DefaultHighSpeedImageTextureSampling;
|
||||
@@ -553,6 +555,7 @@ struct TextureMappingZone
|
||||
top_surface_contoning_polygonize_color_regions_enabled = DefaultTopSurfaceContoningPolygonizeColorRegionsEnabled;
|
||||
top_surface_contoning_polygonize_resolution = DefaultTopSurfaceContoningPolygonizeResolution;
|
||||
top_surface_contoning_surface_anchored_stacks_enabled = DefaultTopSurfaceContoningSurfaceAnchoredStacksEnabled;
|
||||
top_surface_contoning_td_adjustment_enabled = DefaultTopSurfaceContoningTdAdjustmentEnabled;
|
||||
compact_offset_mode = DefaultCompactOffsetMode;
|
||||
use_legacy_fixed_color_mode = DefaultUseLegacyFixedColorMode;
|
||||
high_speed_image_texture_sampling = DefaultHighSpeedImageTextureSampling;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <numeric>
|
||||
|
||||
@@ -17,6 +18,7 @@ namespace {
|
||||
|
||||
constexpr float OPAQUE_CONTONING_TD_THRESHOLD_MM = 0.5f;
|
||||
constexpr float INFERRED_BLACK_TD_MM = 0.1f;
|
||||
constexpr size_t MAX_TD_ORDERED_CONTONING_CANDIDATES = 2500000;
|
||||
|
||||
float clamp01(float value)
|
||||
{
|
||||
@@ -81,9 +83,16 @@ bool is_black_color_filament(const PrintConfig &config, unsigned int component_i
|
||||
return max_channel <= 0.20f && luminance <= 0.12f && max_channel - min_channel <= 0.08f;
|
||||
}
|
||||
|
||||
float estimated_transmission_distance_mm(const PrintConfig &config, unsigned int component_id)
|
||||
{
|
||||
const float luminance = std::clamp(filament_luminance(config, component_id), 0.f, 1.f);
|
||||
return std::clamp(0.1f + 2.9f * std::pow(luminance, 1.35f), 0.12f, 3.f);
|
||||
}
|
||||
|
||||
std::vector<float> effective_transmission_distances_mm(const TextureMappingZone &zone,
|
||||
const PrintConfig &config,
|
||||
const std::vector<unsigned int> &component_ids)
|
||||
const std::vector<unsigned int> &component_ids,
|
||||
bool estimate_missing)
|
||||
{
|
||||
std::vector<float> out(component_ids.size(), 0.f);
|
||||
for (size_t idx = 0; idx < component_ids.size(); ++idx) {
|
||||
@@ -93,11 +102,20 @@ std::vector<float> effective_transmission_distances_mm(const TextureMappingZone
|
||||
} else if (black_role_component(zone.filament_color_mode, idx, component_ids.size()) ||
|
||||
is_black_color_filament(config, component_ids[idx])) {
|
||||
out[idx] = INFERRED_BLACK_TD_MM;
|
||||
} else if (estimate_missing) {
|
||||
out[idx] = estimated_transmission_distance_mm(config, component_ids[idx]);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
float layer_opacity_from_td(float td_mm, float layer_height_mm)
|
||||
{
|
||||
const float safe_td = std::clamp(td_mm, 0.01f, 50.f);
|
||||
const float safe_layer_height = std::clamp(layer_height_mm, 0.01f, 2.f);
|
||||
return std::clamp(1.f - std::pow(0.05f, safe_layer_height / safe_td), 1e-4f, 0.9999f);
|
||||
}
|
||||
|
||||
float effective_transmission_distance_for_component(const std::vector<unsigned int> &component_ids,
|
||||
const std::vector<float> &effective_tds,
|
||||
unsigned int component_id)
|
||||
@@ -263,7 +281,8 @@ std::vector<unsigned int> texture_mapping_contoning_components_bottom_to_top(
|
||||
return component_ids;
|
||||
|
||||
const std::vector<unsigned int> td_component_ids = component_ids;
|
||||
const std::vector<float> effective_tds = effective_transmission_distances_mm(zone, config, td_component_ids);
|
||||
const std::vector<float> effective_tds =
|
||||
effective_transmission_distances_mm(zone, config, td_component_ids, zone.top_surface_contoning_td_adjustment_enabled);
|
||||
const bool has_complete_td =
|
||||
std::all_of(effective_tds.begin(), effective_tds.end(), [](float td) { return std::isfinite(td) && td > 0.f; });
|
||||
if (has_complete_td) {
|
||||
@@ -327,8 +346,14 @@ bool texture_mapping_contoning_normal_eligible(float normal_z, float threshold_d
|
||||
|
||||
TextureMappingContoningSolver::TextureMappingContoningSolver(const TextureMappingZone &zone,
|
||||
const PrintConfig &config,
|
||||
std::vector<unsigned int> component_ids)
|
||||
std::vector<unsigned int> component_ids,
|
||||
float layer_height_mm)
|
||||
{
|
||||
m_td_adjustment_enabled = zone.top_surface_contoning_td_adjustment_enabled;
|
||||
m_layer_height_mm = std::isfinite(layer_height_mm) && layer_height_mm > 0.f ? layer_height_mm : 0.2f;
|
||||
if (!std::isfinite(m_layer_height_mm) || m_layer_height_mm <= 0.f)
|
||||
m_layer_height_mm = 0.2f;
|
||||
|
||||
component_ids.erase(std::remove_if(component_ids.begin(), component_ids.end(), [&config](unsigned int id) {
|
||||
return id == 0 || id > config.filament_colour.values.size();
|
||||
}), component_ids.end());
|
||||
@@ -342,7 +367,13 @@ TextureMappingContoningSolver::TextureMappingContoningSolver(const TextureMappin
|
||||
m_component_luminance.reserve(m_component_ids.size());
|
||||
for (const unsigned int id : m_component_ids)
|
||||
m_component_luminance.emplace_back(filament_luminance(config, id));
|
||||
m_effective_transmission_distances_mm = effective_transmission_distances_mm(zone, config, m_component_ids);
|
||||
std::vector<float> background_weights(m_component_colors.size(), 1.f / float(m_component_colors.size()));
|
||||
m_background_rgb = mix_color_solver_components(m_component_colors, background_weights, ColorSolverMixModel::PigmentPainter);
|
||||
m_effective_transmission_distances_mm =
|
||||
effective_transmission_distances_mm(zone, config, m_component_ids, m_td_adjustment_enabled);
|
||||
m_component_layer_opacity.reserve(m_effective_transmission_distances_mm.size());
|
||||
for (float td_mm : m_effective_transmission_distances_mm)
|
||||
m_component_layer_opacity.emplace_back(layer_opacity_from_td(td_mm > 0.f ? td_mm : 3.f, m_layer_height_mm));
|
||||
m_components_bottom_to_top = texture_mapping_contoning_components_bottom_to_top(zone, config, m_component_ids);
|
||||
}
|
||||
|
||||
@@ -381,6 +412,63 @@ TextureMappingContoningSolver::candidates_for_depth(int stack_layers) const
|
||||
return m_candidates_by_depth.emplace(depth, std::move(candidates)).first->second;
|
||||
}
|
||||
|
||||
std::optional<size_t> TextureMappingContoningSolver::component_index(unsigned int component_id) const
|
||||
{
|
||||
const auto it = std::find(m_component_ids.begin(), m_component_ids.end(), component_id);
|
||||
if (it == m_component_ids.end())
|
||||
return std::nullopt;
|
||||
return size_t(it - m_component_ids.begin());
|
||||
}
|
||||
|
||||
std::optional<std::array<float, 3>> TextureMappingContoningSolver::stack_rgb(
|
||||
const std::vector<unsigned int> &bottom_to_top,
|
||||
bool lower_surface) const
|
||||
{
|
||||
if (bottom_to_top.empty() || !valid())
|
||||
return std::nullopt;
|
||||
|
||||
if (!m_td_adjustment_enabled) {
|
||||
std::vector<std::array<float, 3>> colors;
|
||||
std::vector<float> weights;
|
||||
colors.reserve(bottom_to_top.size());
|
||||
weights.reserve(bottom_to_top.size());
|
||||
const float weight = 1.f / float(bottom_to_top.size());
|
||||
for (unsigned int component_id : bottom_to_top) {
|
||||
const std::optional<size_t> idx = component_index(component_id);
|
||||
if (!idx || *idx >= m_component_colors.size())
|
||||
return std::nullopt;
|
||||
colors.emplace_back(m_component_colors[*idx]);
|
||||
weights.emplace_back(weight);
|
||||
}
|
||||
return mix_color_solver_components(colors, weights, ColorSolverMixModel::PigmentPainter);
|
||||
}
|
||||
|
||||
std::vector<uint16_t> surface_to_deep;
|
||||
surface_to_deep.reserve(bottom_to_top.size());
|
||||
auto append_component = [this, &surface_to_deep](unsigned int component_id) {
|
||||
const std::optional<size_t> idx = component_index(component_id);
|
||||
if (!idx || *idx > size_t(std::numeric_limits<uint16_t>::max()))
|
||||
return false;
|
||||
surface_to_deep.emplace_back(uint16_t(*idx));
|
||||
return true;
|
||||
};
|
||||
if (lower_surface) {
|
||||
for (unsigned int component_id : bottom_to_top)
|
||||
if (!append_component(component_id))
|
||||
return std::nullopt;
|
||||
} else {
|
||||
for (auto it = bottom_to_top.rbegin(); it != bottom_to_top.rend(); ++it)
|
||||
if (!append_component(*it))
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return mix_color_solver_ordered_stack(m_component_colors,
|
||||
surface_to_deep,
|
||||
m_component_layer_opacity,
|
||||
m_background_rgb,
|
||||
ColorSolverMixModel::PigmentPainter);
|
||||
}
|
||||
|
||||
void TextureMappingContoningSolver::arrange_stack_for_light_path(std::vector<unsigned int> &bottom_to_top,
|
||||
const std::array<float, 3> &target_rgb) const
|
||||
{
|
||||
@@ -446,7 +534,9 @@ void TextureMappingContoningSolver::arrange_stack_for_light_path(std::vector<uns
|
||||
bottom_to_top.emplace_back(*it);
|
||||
}
|
||||
|
||||
TextureMappingContoningStack TextureMappingContoningSolver::solve(const std::array<float, 3> &target_rgb, int stack_layers) const
|
||||
TextureMappingContoningStack TextureMappingContoningSolver::solve(const std::array<float, 3> &target_rgb,
|
||||
int stack_layers,
|
||||
bool lower_surface) const
|
||||
{
|
||||
TextureMappingContoningStack out;
|
||||
if (!valid())
|
||||
@@ -455,6 +545,39 @@ TextureMappingContoningStack TextureMappingContoningSolver::solve(const std::arr
|
||||
const int depth = std::clamp(stack_layers,
|
||||
TextureMappingZone::MinTopSurfaceContoningStackLayers,
|
||||
TextureMappingZone::MaxTopSurfaceContoningStackLayers);
|
||||
if (m_td_adjustment_enabled) {
|
||||
const ColorSolverOrderedStackCandidateSet *ordered_candidates = nullptr;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(*m_ordered_candidate_cache_mutex);
|
||||
ordered_candidates =
|
||||
&color_solver_ordered_stack_candidates(*m_ordered_candidate_cache,
|
||||
m_component_colors,
|
||||
m_component_layer_opacity,
|
||||
m_background_rgb,
|
||||
ColorSolverMixModel::PigmentPainter,
|
||||
depth,
|
||||
MAX_TD_ORDERED_CONTONING_CANDIDATES);
|
||||
}
|
||||
const std::vector<uint16_t> surface_to_deep =
|
||||
solve_color_solver_ordered_stack_for_target(*ordered_candidates, target_rgb, ColorSolverMode::V2);
|
||||
if (!surface_to_deep.empty()) {
|
||||
out.bottom_to_top.reserve(surface_to_deep.size());
|
||||
auto append_component = [this, &out](uint16_t component_idx) {
|
||||
if (size_t(component_idx) < m_component_ids.size())
|
||||
out.bottom_to_top.emplace_back(m_component_ids[size_t(component_idx)]);
|
||||
};
|
||||
if (lower_surface) {
|
||||
for (uint16_t component_idx : surface_to_deep)
|
||||
append_component(component_idx);
|
||||
} else {
|
||||
for (auto it = surface_to_deep.rbegin(); it != surface_to_deep.rend(); ++it)
|
||||
append_component(*it);
|
||||
}
|
||||
if (!out.bottom_to_top.empty())
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<Candidate> &candidates = candidates_for_depth(depth);
|
||||
if (candidates.empty())
|
||||
return out;
|
||||
@@ -492,18 +615,23 @@ TextureMappingContoningStack TextureMappingContoningSolver::solve(const std::arr
|
||||
if (int(out.bottom_to_top.size()) > depth)
|
||||
out.bottom_to_top.resize(size_t(depth));
|
||||
arrange_stack_for_light_path(out.bottom_to_top, target_rgb);
|
||||
if (lower_surface && m_td_adjustment_enabled)
|
||||
std::reverse(out.bottom_to_top.begin(), out.bottom_to_top.end());
|
||||
return out;
|
||||
}
|
||||
|
||||
unsigned int TextureMappingContoningSolver::component_for_depth(const std::array<float, 3> &target_rgb,
|
||||
int stack_layers,
|
||||
int depth_from_top) const
|
||||
int depth_from_top,
|
||||
bool lower_surface) const
|
||||
{
|
||||
TextureMappingContoningStack stack = solve(target_rgb, stack_layers);
|
||||
TextureMappingContoningStack stack = solve(target_rgb, stack_layers, lower_surface);
|
||||
if (stack.bottom_to_top.empty())
|
||||
return 0;
|
||||
const int depth = int(stack.bottom_to_top.size());
|
||||
const int idx = std::clamp(depth - 1 - depth_from_top, 0, depth - 1);
|
||||
const int idx = lower_surface ?
|
||||
std::clamp(depth_from_top, 0, depth - 1) :
|
||||
std::clamp(depth - 1 - depth_from_top, 0, depth - 1);
|
||||
return stack.bottom_to_top[size_t(idx)];
|
||||
}
|
||||
|
||||
|
||||
@@ -3,10 +3,14 @@
|
||||
#ifndef slic3r_TextureMappingContoning_hpp_
|
||||
#define slic3r_TextureMappingContoning_hpp_
|
||||
|
||||
#include "ColorSolver.hpp"
|
||||
#include "TextureMapping.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
@@ -24,14 +28,16 @@ public:
|
||||
TextureMappingContoningSolver() = default;
|
||||
TextureMappingContoningSolver(const TextureMappingZone &zone,
|
||||
const PrintConfig &config,
|
||||
std::vector<unsigned int> component_ids);
|
||||
std::vector<unsigned int> component_ids,
|
||||
float layer_height_mm = 0.f);
|
||||
|
||||
bool valid() const { return !m_component_ids.empty() && m_component_ids.size() == m_component_colors.size(); }
|
||||
const std::vector<unsigned int>& component_ids() const { return m_component_ids; }
|
||||
const std::vector<unsigned int>& components_bottom_to_top() const { return m_components_bottom_to_top; }
|
||||
|
||||
TextureMappingContoningStack solve(const std::array<float, 3> &target_rgb, int stack_layers) const;
|
||||
unsigned int component_for_depth(const std::array<float, 3> &target_rgb, int stack_layers, int depth_from_top) const;
|
||||
TextureMappingContoningStack solve(const std::array<float, 3> &target_rgb, int stack_layers, bool lower_surface = false) const;
|
||||
unsigned int component_for_depth(const std::array<float, 3> &target_rgb, int stack_layers, int depth_from_top, bool lower_surface = false) const;
|
||||
std::optional<std::array<float, 3>> stack_rgb(const std::vector<unsigned int> &bottom_to_top, bool lower_surface = false) const;
|
||||
|
||||
private:
|
||||
struct Candidate {
|
||||
@@ -44,13 +50,20 @@ private:
|
||||
const std::vector<Candidate>& candidates_for_depth(int stack_layers) const;
|
||||
void arrange_stack_for_light_path(std::vector<unsigned int> &bottom_to_top,
|
||||
const std::array<float, 3> &target_rgb) const;
|
||||
std::optional<size_t> component_index(unsigned int component_id) const;
|
||||
|
||||
std::vector<unsigned int> m_component_ids;
|
||||
std::vector<unsigned int> m_components_bottom_to_top;
|
||||
std::vector<std::array<float, 3>> m_component_colors;
|
||||
std::array<float, 3> m_background_rgb { { 0.f, 0.f, 0.f } };
|
||||
std::vector<float> m_component_luminance;
|
||||
std::vector<float> m_effective_transmission_distances_mm;
|
||||
std::vector<float> m_component_layer_opacity;
|
||||
float m_layer_height_mm { 0.2f };
|
||||
bool m_td_adjustment_enabled { false };
|
||||
mutable std::map<int, std::vector<Candidate>> m_candidates_by_depth;
|
||||
mutable std::shared_ptr<ColorSolverOrderedStackCandidateCache> m_ordered_candidate_cache { std::make_shared<ColorSolverOrderedStackCandidateCache>() };
|
||||
mutable std::shared_ptr<std::mutex> m_ordered_candidate_cache_mutex { std::make_shared<std::mutex>() };
|
||||
};
|
||||
|
||||
std::vector<unsigned int> texture_mapping_contoning_components_bottom_to_top(const TextureMappingZone &zone,
|
||||
|
||||
@@ -45,8 +45,10 @@ constexpr size_t k_temporary_simulated_texture_preview_min_source_pixels = k_tem
|
||||
constexpr size_t k_surface_gradient_preview_max_components = 10;
|
||||
constexpr size_t k_surface_gradient_preview_lut_size = 33;
|
||||
constexpr size_t k_contoning_flat_surface_preview_max_candidates = 250000;
|
||||
constexpr size_t k_contoning_flat_surface_preview_max_ordered_candidates = 2500000;
|
||||
constexpr double k_contoning_top_surface_preview_lod_max_samples = 350000.0;
|
||||
constexpr const char *TEXTURE_MAPPING_BACKGROUND_COLOR_CONFIG_KEY = "texture_mapping_background_color";
|
||||
constexpr float k_contoning_preview_inferred_black_td_mm = 0.1f;
|
||||
|
||||
struct TexturePreviewMixCandidate
|
||||
{
|
||||
@@ -90,9 +92,13 @@ struct TexturePreviewSimulationSettings
|
||||
int generic_solver_mix_model = TextureMappingZone::DefaultGenericSolverMixModel;
|
||||
bool contoning_flat_surface_quantization = false;
|
||||
bool contoning_flat_surface_pattern_blend = false;
|
||||
bool contoning_flat_surface_td_adjustment = false;
|
||||
int contoning_flat_surface_pattern_filaments = TextureMappingZone::DefaultTopSurfaceContoningPatternFilaments;
|
||||
bool simulate_top_surface_lod = false;
|
||||
float top_surface_lod_pitch_mm = 0.f;
|
||||
float contoning_flat_surface_layer_height_mm = 0.2f;
|
||||
std::array<float, 3> contoning_flat_surface_background_rgb { { 0.f, 0.f, 0.f } };
|
||||
std::vector<float> contoning_flat_surface_layer_opacities;
|
||||
float minimum_visibility_offset_factor = 0.f;
|
||||
std::vector<unsigned int> component_ids;
|
||||
std::vector<std::array<float, 3>> component_colors;
|
||||
@@ -521,6 +527,82 @@ float contoning_flat_surface_lod_pitch_for_texture_preview(const TextureMappingZ
|
||||
return std::clamp(pitch, 0.25f, std::max(0.25f, min_feature));
|
||||
}
|
||||
|
||||
float texture_preview_layer_height_mm()
|
||||
{
|
||||
return std::clamp(texture_preview_config_float("layer_height", 0.2f), 0.01f, 2.f);
|
||||
}
|
||||
|
||||
float texture_preview_filament_luminance(const std::array<float, 3> &color)
|
||||
{
|
||||
return 0.2126f * clamp01(color[0]) + 0.7152f * clamp01(color[1]) + 0.0722f * clamp01(color[2]);
|
||||
}
|
||||
|
||||
bool texture_preview_black_role_component(int filament_color_mode, size_t component_idx, size_t component_count)
|
||||
{
|
||||
switch (std::clamp(filament_color_mode,
|
||||
int(TextureMappingZone::FilamentColorAny),
|
||||
int(TextureMappingZone::FilamentColorRGBKW))) {
|
||||
case int(TextureMappingZone::FilamentColorCMYK):
|
||||
case int(TextureMappingZone::FilamentColorRGBK):
|
||||
return component_count == 4 && component_idx == 3;
|
||||
case int(TextureMappingZone::FilamentColorBW):
|
||||
return component_count == 2 && component_idx == 0;
|
||||
case int(TextureMappingZone::FilamentColorCMYKW):
|
||||
case int(TextureMappingZone::FilamentColorRGBKW):
|
||||
return component_count == 5 && component_idx == 3;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool texture_preview_black_color_filament(const std::array<float, 3> &color)
|
||||
{
|
||||
const float r = clamp01(color[0]);
|
||||
const float g = clamp01(color[1]);
|
||||
const float b = clamp01(color[2]);
|
||||
const float max_channel = std::max({ r, g, b });
|
||||
const float min_channel = std::min({ r, g, b });
|
||||
const float luminance = texture_preview_filament_luminance(color);
|
||||
return max_channel <= 0.20f && luminance <= 0.12f && max_channel - min_channel <= 0.08f;
|
||||
}
|
||||
|
||||
float texture_preview_estimated_transmission_distance_mm(const std::array<float, 3> &color)
|
||||
{
|
||||
return std::clamp(0.1f + 2.9f * std::pow(texture_preview_filament_luminance(color), 1.35f), 0.12f, 3.f);
|
||||
}
|
||||
|
||||
float texture_preview_layer_opacity_from_td(float td_mm, float layer_height_mm)
|
||||
{
|
||||
const float safe_td = std::clamp(td_mm, 0.01f, 50.f);
|
||||
const float safe_layer_height = std::clamp(layer_height_mm, 0.01f, 2.f);
|
||||
return std::clamp(1.f - std::pow(0.05f, safe_layer_height / safe_td), 1e-4f, 0.9999f);
|
||||
}
|
||||
|
||||
std::vector<float> contoning_flat_surface_preview_layer_opacities(
|
||||
const TextureMappingZone &zone,
|
||||
const TexturePreviewSimulationSettings &settings)
|
||||
{
|
||||
std::vector<float> out;
|
||||
out.reserve(settings.component_ids.size());
|
||||
for (size_t idx = 0; idx < settings.component_ids.size() && idx < settings.component_colors.size(); ++idx) {
|
||||
const unsigned int component_id = settings.component_ids[idx];
|
||||
float td_mm = 0.f;
|
||||
if (component_id > 0 && size_t(component_id - 1) < zone.filament_transmission_distances_mm.size()) {
|
||||
const float explicit_td = zone.filament_transmission_distances_mm[size_t(component_id - 1)];
|
||||
if (std::isfinite(explicit_td) && explicit_td > 0.f)
|
||||
td_mm = explicit_td;
|
||||
}
|
||||
if (td_mm <= 0.f &&
|
||||
(texture_preview_black_role_component(zone.filament_color_mode, idx, settings.component_ids.size()) ||
|
||||
texture_preview_black_color_filament(settings.component_colors[idx])))
|
||||
td_mm = k_contoning_preview_inferred_black_td_mm;
|
||||
if (td_mm <= 0.f)
|
||||
td_mm = texture_preview_estimated_transmission_distance_mm(settings.component_colors[idx]);
|
||||
out.emplace_back(texture_preview_layer_opacity_from_td(td_mm, settings.contoning_flat_surface_layer_height_mm));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::array<float, 2> raw_offset_visibility_factors_for_texture_preview(const TextureMappingZone &zone)
|
||||
{
|
||||
const float base_outer_width_mm =
|
||||
@@ -2401,12 +2483,23 @@ std::array<float, 3> fallback_contoning_flat_surface_rgb_for_texture_preview(
|
||||
std::array<float, 3> contoning_flat_surface_rgb_for_texture_preview(
|
||||
const TexturePreviewSimulationSettings &settings,
|
||||
const std::array<float, 4> &sample_rgba,
|
||||
const ColorSolverOrderedStackCandidateSet &ordered_candidates,
|
||||
const std::vector<TexturePreviewMixCandidate> &candidates,
|
||||
const std::vector<TexturePreviewMixCandidateKdNode> &nodes,
|
||||
int root,
|
||||
int total_units)
|
||||
{
|
||||
const std::array<float, 3> target_rgb = texture_preview_target_rgb(settings, sample_rgba);
|
||||
if (settings.contoning_flat_surface_td_adjustment && !ordered_candidates.empty()) {
|
||||
const std::vector<uint16_t> surface_to_deep =
|
||||
solve_color_solver_ordered_stack_for_target(ordered_candidates, target_rgb, ColorSolverMode::V2);
|
||||
if (!surface_to_deep.empty())
|
||||
return mix_color_solver_ordered_stack(settings.component_colors,
|
||||
surface_to_deep,
|
||||
settings.contoning_flat_surface_layer_opacities,
|
||||
settings.contoning_flat_surface_background_rgb,
|
||||
ColorSolverMixModel::PigmentPainter);
|
||||
}
|
||||
if (!candidates.empty()) {
|
||||
const TexturePreviewMixNearestResult nearest =
|
||||
nearest_contoning_flat_surface_mix_candidate(candidates, nodes, root, target_rgb);
|
||||
@@ -2544,6 +2637,7 @@ std::optional<TexturePreviewSimulationSettings> texture_preview_simulation_setti
|
||||
int(TextureMappingZone::GenericSolverLegacy),
|
||||
int(TextureMappingZone::GenericSolverV2));
|
||||
settings.generic_solver_mix_model = TextureMappingZone::DefaultGenericSolverMixModel;
|
||||
settings.contoning_flat_surface_layer_height_mm = texture_preview_layer_height_mm();
|
||||
if (zone->top_surface_image_printing_enabled) {
|
||||
const int stack_layers =
|
||||
std::clamp(zone->top_surface_contoning_stack_layers,
|
||||
@@ -2554,6 +2648,8 @@ std::optional<TexturePreviewSimulationSettings> texture_preview_simulation_setti
|
||||
TextureMappingZone::MinTopSurfaceContoningPatternFilaments,
|
||||
TextureMappingZone::MaxTopSurfaceContoningPatternFilaments);
|
||||
settings.contoning_flat_surface_pattern_filaments = std::max(1, std::min(stack_layers, pattern_filaments));
|
||||
settings.contoning_flat_surface_td_adjustment =
|
||||
zone->top_surface_contoning_active() && zone->top_surface_contoning_td_adjustment_enabled;
|
||||
}
|
||||
settings.minimum_visibility_offset_factor = zone->minimum_visibility_offset_enabled ?
|
||||
std::clamp((std::isfinite(zone->minimum_visibility_offset_pct) ?
|
||||
@@ -2597,6 +2693,16 @@ std::optional<TexturePreviewSimulationSettings> texture_preview_simulation_setti
|
||||
settings.component_minimum_offset_factors.emplace_back(std::clamp(safe_minimum_offset_pct / 100.f, 0.f, 1.f));
|
||||
}
|
||||
|
||||
if (settings.contoning_flat_surface_td_adjustment && !settings.component_colors.empty()) {
|
||||
std::vector<float> background_weights(settings.component_colors.size(), 1.f / float(settings.component_colors.size()));
|
||||
settings.contoning_flat_surface_background_rgb =
|
||||
mix_color_solver_components(settings.component_colors, background_weights, ColorSolverMixModel::PigmentPainter);
|
||||
settings.contoning_flat_surface_layer_opacities =
|
||||
contoning_flat_surface_preview_layer_opacities(*zone, settings);
|
||||
if (settings.contoning_flat_surface_layer_opacities.size() != settings.component_colors.size())
|
||||
settings.contoning_flat_surface_td_adjustment = false;
|
||||
}
|
||||
|
||||
const std::array<float, 2> raw_offset_visibility_factors = raw_offset_visibility_factors_for_texture_preview(*zone);
|
||||
settings.raw_offset_base_visibility_factor = raw_offset_visibility_factors[0];
|
||||
settings.raw_offset_visibility_range_factor = raw_offset_visibility_factors[1];
|
||||
@@ -2632,12 +2738,18 @@ size_t texture_preview_simulation_signature(const ModelVolume &model_volume,
|
||||
mix(std::hash<int>{}(settings.generic_solver_mix_model));
|
||||
mix(std::hash<int>{}(settings.contoning_flat_surface_quantization ? 1 : 0));
|
||||
mix(std::hash<int>{}(settings.contoning_flat_surface_pattern_blend ? 1 : 0));
|
||||
mix(std::hash<int>{}(settings.contoning_flat_surface_td_adjustment ? 1 : 0));
|
||||
if (settings.contoning_flat_surface_quantization) {
|
||||
mix(std::hash<int>{}(settings.contoning_flat_surface_pattern_filaments));
|
||||
mix(std::hash<int>{}(settings.simulate_top_surface_lod ? 1 : 0));
|
||||
if (settings.simulate_top_surface_lod)
|
||||
mix(std::hash<int>{}(int(std::lround(settings.top_surface_lod_pitch_mm * 100000.f))));
|
||||
}
|
||||
if (settings.contoning_flat_surface_td_adjustment) {
|
||||
mix(std::hash<int>{}(int(std::lround(settings.contoning_flat_surface_layer_height_mm * 100000.f))));
|
||||
for (const float opacity : settings.contoning_flat_surface_layer_opacities)
|
||||
mix(std::hash<int>{}(int(std::lround(opacity * 1000000.f))));
|
||||
}
|
||||
mix(std::hash<int>{}(int(std::lround(settings.contrast_pct * 100.f))));
|
||||
mix(std::hash<int>{}(int(std::lround(settings.tone_gamma * 1000.f))));
|
||||
mix(std::hash<int>{}(int(std::lround(settings.minimum_visibility_offset_factor * 100000.f))));
|
||||
@@ -2709,8 +2821,21 @@ TexturePreviewSimulationResult build_simulated_texture_preview_result(size_t sig
|
||||
settings.mapping_mode != int(TextureMappingZone::TextureMappingRawValues) &&
|
||||
!settings.component_colors.empty() &&
|
||||
contoning_flat_surface_pattern_filaments > 0;
|
||||
const bool use_contoning_flat_surface_ordered_quantization =
|
||||
use_contoning_flat_surface_quantization &&
|
||||
settings.contoning_flat_surface_td_adjustment &&
|
||||
settings.contoning_flat_surface_layer_opacities.size() == settings.component_colors.size();
|
||||
const ColorSolverOrderedStackCandidateSet contoning_flat_surface_ordered_candidates =
|
||||
use_contoning_flat_surface_ordered_quantization ?
|
||||
build_color_solver_ordered_stack_candidates(settings.component_colors,
|
||||
settings.contoning_flat_surface_layer_opacities,
|
||||
settings.contoning_flat_surface_background_rgb,
|
||||
ColorSolverMixModel::PigmentPainter,
|
||||
contoning_flat_surface_pattern_filaments,
|
||||
k_contoning_flat_surface_preview_max_ordered_candidates) :
|
||||
ColorSolverOrderedStackCandidateSet{};
|
||||
const std::vector<TexturePreviewMixCandidate> contoning_flat_surface_candidates =
|
||||
use_contoning_flat_surface_quantization ?
|
||||
use_contoning_flat_surface_quantization && contoning_flat_surface_ordered_candidates.empty() ?
|
||||
build_contoning_flat_surface_mix_candidates(settings.component_colors, contoning_flat_surface_pattern_filaments) :
|
||||
std::vector<TexturePreviewMixCandidate>{};
|
||||
std::vector<TexturePreviewMixCandidateKdNode> contoning_flat_surface_nodes;
|
||||
@@ -2928,6 +3053,7 @@ TexturePreviewSimulationResult build_simulated_texture_preview_result(size_t sig
|
||||
forced_simulated_rgb =
|
||||
contoning_flat_surface_rgb_for_texture_preview(settings,
|
||||
sample_rgba,
|
||||
contoning_flat_surface_ordered_candidates,
|
||||
contoning_flat_surface_candidates,
|
||||
contoning_flat_surface_nodes,
|
||||
contoning_flat_surface_root,
|
||||
@@ -5513,6 +5639,7 @@ static size_t texture_preview_settings_signature_impl(size_t num_physical,
|
||||
signature_mix(std::hash<int>{}(zone.top_surface_contoning_stack_layers));
|
||||
signature_mix(std::hash<int>{}(zone.top_surface_contoning_pattern_filaments));
|
||||
signature_mix(std::hash<int>{}(zone.top_surface_contoning_color_lower_surfaces ? 1 : 0));
|
||||
signature_mix(std::hash<int>{}(zone.top_surface_contoning_td_adjustment_enabled ? 1 : 0));
|
||||
signature_mix(std::hash<int>{}(zone.nonlinear_offset_adjustment ? 1 : 0));
|
||||
signature_mix(std::hash<int>{}(zone.compact_offset_mode ? 1 : 0));
|
||||
signature_mix(std::hash<int>{}(zone.use_legacy_fixed_color_mode ? 1 : 0));
|
||||
@@ -5533,6 +5660,8 @@ static size_t texture_preview_settings_signature_impl(size_t num_physical,
|
||||
signature_mix_float(strength_pct, 100.f);
|
||||
for (const float minimum_offset_pct : zone.filament_minimum_offsets_pct)
|
||||
signature_mix_float(minimum_offset_pct, 100.f);
|
||||
for (const float td_mm : zone.filament_transmission_distances_mm)
|
||||
signature_mix_float(td_mm, 1000.f);
|
||||
}
|
||||
return signature;
|
||||
}
|
||||
@@ -5663,6 +5792,7 @@ static void texture_preview_mix_zone_baked_model_settings(size_t &signature,
|
||||
signature_mix(std::hash<int>{}(zone.top_surface_contoning_stack_layers));
|
||||
signature_mix(std::hash<int>{}(zone.top_surface_contoning_pattern_filaments));
|
||||
signature_mix(std::hash<int>{}(zone.top_surface_contoning_color_lower_surfaces ? 1 : 0));
|
||||
signature_mix(std::hash<int>{}(zone.top_surface_contoning_td_adjustment_enabled ? 1 : 0));
|
||||
signature_mix(std::hash<int>{}(zone.nonlinear_offset_adjustment ? 1 : 0));
|
||||
signature_mix(std::hash<int>{}(zone.compact_offset_mode ? 1 : 0));
|
||||
signature_mix(std::hash<int>{}(zone.use_legacy_fixed_color_mode ? 1 : 0));
|
||||
@@ -5687,6 +5817,8 @@ static void texture_preview_mix_zone_baked_model_settings(size_t &signature,
|
||||
signature_mix_float(strength_pct, 100.f);
|
||||
for (const float minimum_offset_pct : zone.filament_minimum_offsets_pct)
|
||||
signature_mix_float(minimum_offset_pct, 100.f);
|
||||
for (const float td_mm : zone.filament_transmission_distances_mm)
|
||||
signature_mix_float(td_mm, 1000.f);
|
||||
|
||||
if (zone.is_surface_gradient()) {
|
||||
signature_mix_float(texture_preview_config_float("texture_mapping_outer_wall_gradient_global_strength", 100.f), 100.f);
|
||||
|
||||
@@ -1984,6 +1984,7 @@ public:
|
||||
bool top_surface_contoning_polygonize_color_regions_enabled,
|
||||
int top_surface_contoning_polygonize_resolution,
|
||||
bool top_surface_contoning_surface_anchored_stacks_enabled,
|
||||
bool top_surface_contoning_td_adjustment_enabled,
|
||||
const TextureMappingManager &texture_mapping_zones,
|
||||
const TextureMappingGlobalSettings &global_settings,
|
||||
const TextureMappingPrimeTowerImage &prime_tower_image,
|
||||
@@ -2199,7 +2200,7 @@ public:
|
||||
auto *filament_calibration_note =
|
||||
new wxStaticText(filament_page,
|
||||
wxID_ANY,
|
||||
_L("NOTE: Filament/TD calibration is not currently used in top-surface coloring"),
|
||||
_L("NOTE: TD calibration is used by overhang modulation and Contoning TD adjustment"),
|
||||
wxDefaultPosition,
|
||||
wxSize(FromDIP(390), -1));
|
||||
filament_calibration_note->Wrap(FromDIP(390));
|
||||
@@ -2662,6 +2663,15 @@ public:
|
||||
0,
|
||||
wxEXPAND | wxTOP | wxBOTTOM,
|
||||
gap / 2);
|
||||
m_top_surface_contoning_td_adjustment_checkbox =
|
||||
new wxCheckBox(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("TD adjustment"));
|
||||
m_top_surface_contoning_td_adjustment_checkbox->SetValue(top_surface_contoning_td_adjustment_enabled);
|
||||
m_top_surface_contoning_td_adjustment_checkbox->SetMinSize(
|
||||
wxSize(-1, std::max(m_top_surface_contoning_td_adjustment_checkbox->GetBestSize().GetHeight(), FromDIP(24))));
|
||||
contoning_checkboxes_root->Add(m_top_surface_contoning_td_adjustment_checkbox,
|
||||
0,
|
||||
wxEXPAND | wxTOP | wxBOTTOM,
|
||||
gap / 2);
|
||||
m_top_surface_contoning_only_one_perimeter_around_shell_infill_checkbox =
|
||||
new wxCheckBox(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("Only one perimeter around shell infill"));
|
||||
m_top_surface_contoning_only_one_perimeter_around_shell_infill_checkbox->SetValue(
|
||||
@@ -3267,6 +3277,12 @@ public:
|
||||
TextureMappingZone::DefaultTopSurfaceContoningSurfaceAnchoredStacksEnabled :
|
||||
m_top_surface_contoning_surface_anchored_stacks_checkbox->GetValue();
|
||||
}
|
||||
bool top_surface_contoning_td_adjustment_enabled() const
|
||||
{
|
||||
return m_top_surface_contoning_td_adjustment_checkbox == nullptr ?
|
||||
TextureMappingZone::DefaultTopSurfaceContoningTdAdjustmentEnabled :
|
||||
m_top_surface_contoning_td_adjustment_checkbox->GetValue();
|
||||
}
|
||||
bool minimum_visibility_offset_enabled() const
|
||||
{
|
||||
return m_minimum_visibility_offset_checkbox && m_minimum_visibility_offset_checkbox->GetValue();
|
||||
@@ -3723,6 +3739,10 @@ private:
|
||||
m_top_surface_contoning_color_lower_surfaces_checkbox->Show(contoning);
|
||||
m_top_surface_contoning_color_lower_surfaces_checkbox->Enable(contoning);
|
||||
}
|
||||
if (m_top_surface_contoning_td_adjustment_checkbox != nullptr) {
|
||||
m_top_surface_contoning_td_adjustment_checkbox->Show(contoning);
|
||||
m_top_surface_contoning_td_adjustment_checkbox->Enable(contoning);
|
||||
}
|
||||
if (m_top_surface_contoning_only_one_perimeter_around_shell_infill_checkbox != nullptr) {
|
||||
m_top_surface_contoning_only_one_perimeter_around_shell_infill_checkbox->Show(contoning);
|
||||
m_top_surface_contoning_only_one_perimeter_around_shell_infill_checkbox->Enable(contoning);
|
||||
@@ -3856,6 +3876,7 @@ private:
|
||||
wxPanel *m_top_surface_contoning_polygonize_resolution_panel {nullptr};
|
||||
wxChoice *m_top_surface_contoning_polygonize_resolution_choice {nullptr};
|
||||
wxCheckBox *m_top_surface_contoning_surface_anchored_stacks_checkbox {nullptr};
|
||||
wxCheckBox *m_top_surface_contoning_td_adjustment_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};
|
||||
@@ -8880,6 +8901,7 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
updated.top_surface_contoning_polygonize_color_regions_enabled,
|
||||
updated.top_surface_contoning_polygonize_resolution,
|
||||
updated.top_surface_contoning_surface_anchored_stacks_enabled,
|
||||
updated.top_surface_contoning_td_adjustment_enabled,
|
||||
bundle->texture_mapping_zones,
|
||||
bundle->texture_mapping_global_settings,
|
||||
wxGetApp().model().texture_mapping_prime_tower_image,
|
||||
@@ -8955,6 +8977,8 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
dlg.top_surface_contoning_polygonize_resolution();
|
||||
updated.top_surface_contoning_surface_anchored_stacks_enabled =
|
||||
dlg.top_surface_contoning_surface_anchored_stacks_enabled();
|
||||
updated.top_surface_contoning_td_adjustment_enabled =
|
||||
dlg.top_surface_contoning_td_adjustment_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