Support loading side-surface calibration JSON
- Move ColorSolver library to deps_src
This commit is contained in:
@@ -31,6 +31,7 @@ add_subdirectory(miniz)
|
||||
add_subdirectory(minilzo)
|
||||
add_subdirectory(pigment-painter)
|
||||
add_subdirectory(prusa-fdm-mixer)
|
||||
add_subdirectory(colorsolver)
|
||||
add_subdirectory(qhull)
|
||||
add_subdirectory(qoi)
|
||||
add_subdirectory(semver) # Semver static library
|
||||
|
||||
11
deps_src/colorsolver/CMakeLists.txt
Normal file
11
deps_src/colorsolver/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(colorsolver)
|
||||
|
||||
add_library(colorsolver STATIC
|
||||
ColorSolver.cpp
|
||||
ColorSolver.hpp
|
||||
)
|
||||
|
||||
target_include_directories(colorsolver PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_compile_features(colorsolver PUBLIC cxx_std_17)
|
||||
target_link_libraries(colorsolver PUBLIC pigment_painter prusa_fdm_mixer)
|
||||
@@ -1637,6 +1637,11 @@ ColorSolverCandidateSet build_color_solver_candidates(const std::vector<std::arr
|
||||
return candidates;
|
||||
}
|
||||
|
||||
void build_color_solver_candidate_kd_trees(ColorSolverCandidateSet &candidates)
|
||||
{
|
||||
build_color_solver_kd_trees(candidates);
|
||||
}
|
||||
|
||||
const ColorSolverCandidateSet &color_solver_candidates(ColorSolverCandidateCache &cache,
|
||||
const std::vector<std::array<float, 3>> &component_colors,
|
||||
ColorSolverMixModel mix_model,
|
||||
@@ -169,6 +169,7 @@ std::string color_solver_candidate_cache_key(const std::vector<std::array<float,
|
||||
ColorSolverCandidateSet build_color_solver_candidates(const std::vector<std::array<float, 3>> &component_colors,
|
||||
ColorSolverMixModel mix_model,
|
||||
int total_units = 0);
|
||||
void build_color_solver_candidate_kd_trees(ColorSolverCandidateSet &candidates);
|
||||
const ColorSolverCandidateSet &color_solver_candidates(ColorSolverCandidateCache &cache,
|
||||
const std::vector<std::array<float, 3>> &component_colors,
|
||||
ColorSolverMixModel mix_model,
|
||||
@@ -148,8 +148,6 @@ set(lisbslic3r_sources
|
||||
Feature/Interlocking/VoxelUtils.cpp
|
||||
Feature/Interlocking/VoxelUtils.hpp
|
||||
FileParserError.hpp
|
||||
ColorSolver.cpp
|
||||
ColorSolver.hpp
|
||||
Fill/Fill3DHoneycomb.cpp
|
||||
Fill/Fill3DHoneycomb.hpp
|
||||
Fill/FillAdaptive.cpp
|
||||
@@ -608,8 +606,7 @@ target_link_libraries(libslic3r
|
||||
libnest2d
|
||||
miniz
|
||||
opencv_world
|
||||
pigment_painter
|
||||
prusa_fdm_mixer
|
||||
colorsolver
|
||||
PRIVATE
|
||||
${CMAKE_DL_LIBS}
|
||||
${EXPAT_LIBRARIES}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#endif
|
||||
#include "../ClipperUtils.hpp"
|
||||
#include "../Color.hpp"
|
||||
#include "../ColorSolver.hpp"
|
||||
#include "ColorSolver.hpp"
|
||||
#include "../Geometry.hpp"
|
||||
#include "../Layer.hpp"
|
||||
#include "../MarchingSquares.hpp"
|
||||
@@ -12418,8 +12418,8 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree,
|
||||
FillParams fallback_params = params;
|
||||
fallback_params.flow = fallback_flow;
|
||||
fallback_params.pattern = ipRectilinear;
|
||||
fallback_params.no_edge_overlap =
|
||||
!surface_fill.params.texture_mapping_top_surface_contoning_partition_color_regions;
|
||||
fallback_params.no_edge_overlap = true;
|
||||
fallback_params.edge_overlap_width_factor = 0.5f;
|
||||
ExtrusionEntitiesPtr hybrid_interior_entities;
|
||||
if (!hybrid_boundary_skin && collection && !collection->empty()) {
|
||||
apply_top_surface_image_collection_metadata(*collection, surface_fill.params, std::nullopt, throw_if_canceled_ptr);
|
||||
|
||||
@@ -98,6 +98,7 @@ struct FillParams
|
||||
bool dont_sort{ false }; // do not sort the lines, just simply connect them
|
||||
bool can_reverse{true};
|
||||
bool no_edge_overlap{false};
|
||||
float edge_overlap_width_factor{1.0f};
|
||||
|
||||
float horiz_move{0.0}; //move infill to get cross zag pattern
|
||||
bool symmetric_infill_y_axis{false};
|
||||
|
||||
@@ -2768,7 +2768,9 @@ bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillPa
|
||||
assert(params.density > 0.0001f && params.density <= 1.f);
|
||||
coord_t line_spacing = coord_t(scale_(this->spacing) / params.density);
|
||||
const coordf_t edge_width = std::max<coordf_t>(this->spacing, coordf_t(params.flow.width()));
|
||||
const coordf_t edge_overlap_width = std::min<coordf_t>(0.075 * edge_width, coordf_t(0.05));
|
||||
const coordf_t edge_overlap_width =
|
||||
std::clamp<coordf_t>(params.edge_overlap_width_factor, coordf_t(0.0), coordf_t(1.0)) *
|
||||
std::min<coordf_t>(0.075 * edge_width, coordf_t(0.05));
|
||||
const coordf_t outer_clearance = params.no_edge_overlap ?
|
||||
std::max<coordf_t>(0.5 * edge_width - edge_overlap_width, coordf_t(0.0)) :
|
||||
(0.5f - INFILL_OVERLAP_OVER_SPACING) * this->spacing;
|
||||
|
||||
@@ -6122,8 +6122,10 @@ static TransmissionDistanceCalibrationContextForGCode transmission_distance_cali
|
||||
TransmissionDistanceCalibrationContextForGCode context;
|
||||
context.mode = std::clamp(zone.transmission_distance_calibration_mode,
|
||||
int(TextureMappingZone::TDCalibrationNone),
|
||||
int(TextureMappingZone::TDCalibrationNeighbor));
|
||||
if (context.mode == int(TextureMappingZone::TDCalibrationNone) || component_ids.empty())
|
||||
int(TextureMappingZone::TDCalibrationCalibratedNearestMeasuredSample));
|
||||
if (context.mode == int(TextureMappingZone::TDCalibrationNone) ||
|
||||
context.mode == int(TextureMappingZone::TDCalibrationCalibratedNearestMeasuredSample) ||
|
||||
component_ids.empty())
|
||||
return context;
|
||||
|
||||
std::vector<float> explicit_tds(component_ids.size(), 0.f);
|
||||
@@ -8272,6 +8274,7 @@ static VertexColorOverhangWeightField build_vertex_color_weight_field_for_gcode(
|
||||
float halftone_dot_size_mm,
|
||||
const std::vector<float> &component_strength_factors,
|
||||
const std::vector<float> &component_minimum_offset_factors,
|
||||
const GCodeGenericMixCandidateSet *calibrated_side_candidates,
|
||||
std::map<std::string, GCodeGenericMixCandidateSet> *generic_mix_candidate_cache,
|
||||
std::map<const PrintObject*, GCodeUVTextureTriangleCache> *uv_texture_triangle_cache,
|
||||
float texture_contrast_pct,
|
||||
@@ -8800,8 +8803,11 @@ static VertexColorOverhangWeightField build_vertex_color_weight_field_for_gcode(
|
||||
int(TextureMappingZone::DitheringClosest),
|
||||
int(TextureMappingZone::DitheringHalftoneV2));
|
||||
std::vector<uint32_t> binary_dither_masks;
|
||||
const bool has_calibrated_side_candidates =
|
||||
calibrated_side_candidates != nullptr && !calibrated_side_candidates->empty();
|
||||
const bool can_binary_dither =
|
||||
dithering_enabled &&
|
||||
!has_calibrated_side_candidates &&
|
||||
!raw_values_mode &&
|
||||
!is_halftone_dithering_method_for_gcode(clamped_binary_dither_method) &&
|
||||
component_count > 0 &&
|
||||
@@ -8958,7 +8964,7 @@ static VertexColorOverhangWeightField build_vertex_color_weight_field_for_gcode(
|
||||
const size_t sample_count = samples.size();
|
||||
GCodeGenericMixCandidateSet local_generic_mix_candidates;
|
||||
const GCodeGenericMixCandidateSet *generic_mix_candidates = nullptr;
|
||||
if (!raw_values_mode) {
|
||||
if (!raw_values_mode && !has_calibrated_side_candidates) {
|
||||
std::vector<float> optimized_probe;
|
||||
if (!use_fixed_color_generic_solver) {
|
||||
const std::array<float, 3> probe_target { 0.f, 0.f, 0.f };
|
||||
@@ -9038,6 +9044,14 @@ static VertexColorOverhangWeightField build_vertex_color_weight_field_for_gcode(
|
||||
for (size_t channel_idx = 0; channel_idx < channel_count; ++channel_idx)
|
||||
desired[channel_idx] = clamp01f_for_gcode(channels[channel_idx]);
|
||||
mapped_component_count = channel_count;
|
||||
} else if (has_calibrated_side_candidates) {
|
||||
std::vector<float> calibrated =
|
||||
best_component_mix_weights_for_target_for_gcode(*calibrated_side_candidates,
|
||||
target,
|
||||
int(TextureMappingZone::GenericSolverClosestMix),
|
||||
effective_solver_mode);
|
||||
if (calibrated.size() == component_count)
|
||||
desired = std::move(calibrated);
|
||||
} else {
|
||||
std::vector<float> optimized;
|
||||
if (!use_fixed_color_generic_solver)
|
||||
@@ -9061,7 +9075,7 @@ static VertexColorOverhangWeightField build_vertex_color_weight_field_for_gcode(
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_binary_dither && !has_raw_component_weights && std::abs(contrast_factor - 1.f) > 1e-5f)
|
||||
if (!has_binary_dither && !has_raw_component_weights && !has_calibrated_side_candidates && std::abs(contrast_factor - 1.f) > 1e-5f)
|
||||
apply_texture_contrast_to_mapped_components_for_gcode(desired, contrast_factor, mapped_component_count);
|
||||
|
||||
for (size_t component_idx = 0; component_idx < component_count; ++component_idx) {
|
||||
@@ -9550,9 +9564,18 @@ std::optional<PreferredSeamPoint> GCode::texture_mapping_seam_hiding_hint(const
|
||||
std::clamp(zone->tone_gamma, 0.5f, 3.f);
|
||||
const bool high_resolution_texture_sampling = zone->high_resolution_sampling || dithering_enabled;
|
||||
const bool high_speed_image_texture_sampling = zone->high_speed_image_texture_sampling;
|
||||
const std::vector<float> component_strength_factors = overhang_component_strength_factors_for_gcode(*zone, component_ids);
|
||||
const std::vector<float> component_minimum_offset_factors =
|
||||
overhang_component_minimum_offset_factors_for_gcode(*zone, component_ids);
|
||||
const bool calibrated_side_mode =
|
||||
vertex_color_match_mode &&
|
||||
!raw_texture_mapping_mode &&
|
||||
zone->transmission_distance_calibration_mode == int(TextureMappingZone::TDCalibrationCalibratedNearestMeasuredSample);
|
||||
std::vector<float> component_strength_factors;
|
||||
component_strength_factors.reserve(component_ids.size());
|
||||
std::vector<float> component_minimum_offset_factors;
|
||||
component_minimum_offset_factors.reserve(component_ids.size());
|
||||
for (const unsigned int id : component_ids) {
|
||||
component_strength_factors.emplace_back(calibrated_side_mode ? 1.f : overhang_filament_strength_factor_for_gcode(*zone, id));
|
||||
component_minimum_offset_factors.emplace_back(calibrated_side_mode ? 0.f : overhang_filament_minimum_offset_factor_for_gcode(*zone, id));
|
||||
}
|
||||
|
||||
std::vector<std::array<float, 3>> component_colors;
|
||||
component_colors.reserve(component_ids.size());
|
||||
@@ -9579,6 +9602,26 @@ std::optional<PreferredSeamPoint> GCode::texture_mapping_seam_hiding_hint(const
|
||||
(missing_component_color || component_colors.size() != component_ids.size() || component_colors.empty()))
|
||||
return std::nullopt;
|
||||
|
||||
std::vector<float> component_transmission_distances_mm;
|
||||
component_transmission_distances_mm.reserve(component_ids.size());
|
||||
for (const unsigned int id : component_ids) {
|
||||
const size_t idx = id > 0 ? size_t(id - 1) : size_t(-1);
|
||||
const float value = idx < zone->filament_transmission_distances_mm.size() ?
|
||||
zone->filament_transmission_distances_mm[idx] :
|
||||
0.f;
|
||||
component_transmission_distances_mm.emplace_back(std::isfinite(value) && value > 0.f ? std::clamp(value, 0.01f, 50.f) : 0.f);
|
||||
}
|
||||
std::optional<GCodeGenericMixCandidateSet> calibrated_side_candidates;
|
||||
const GCodeGenericMixCandidateSet *calibrated_side_candidates_ptr = nullptr;
|
||||
if (calibrated_side_mode) {
|
||||
calibrated_side_candidates =
|
||||
texture_mapping_side_surface_color_calibrated_candidates(*zone,
|
||||
component_colors,
|
||||
component_transmission_distances_mm);
|
||||
if (calibrated_side_candidates && !calibrated_side_candidates->empty())
|
||||
calibrated_side_candidates_ptr = &*calibrated_side_candidates;
|
||||
}
|
||||
|
||||
const TransmissionDistanceCalibrationContextForGCode td_calibration_context =
|
||||
transmission_distance_calibration_context_for_gcode(*zone,
|
||||
component_ids,
|
||||
@@ -9613,6 +9656,8 @@ std::optional<PreferredSeamPoint> GCode::texture_mapping_seam_hiding_hint(const
|
||||
component_key_stream << "|tg" << int(std::lround(texture_tone_gamma * 100.f));
|
||||
component_key_stream << "|hr" << (high_resolution_texture_sampling ? 1 : 0);
|
||||
component_key_stream << "|hs" << (high_speed_image_texture_sampling ? 1 : 0);
|
||||
if (calibrated_side_mode)
|
||||
component_key_stream << "|sc" << std::hash<std::string>{}(zone->side_surface_color_calibration_json);
|
||||
const std::string component_key_prefix = component_key_stream.str();
|
||||
|
||||
struct SeamLayerTextureState {
|
||||
@@ -9683,6 +9728,7 @@ std::optional<PreferredSeamPoint> GCode::texture_mapping_seam_hiding_hint(const
|
||||
halftone_dot_size_mm,
|
||||
component_strength_factors,
|
||||
component_minimum_offset_factors,
|
||||
calibrated_side_candidates_ptr,
|
||||
&m_generic_solver_mix_candidate_cache,
|
||||
&m_uv_texture_triangle_cache,
|
||||
texture_contrast_pct,
|
||||
@@ -9712,9 +9758,9 @@ std::optional<PreferredSeamPoint> GCode::texture_mapping_seam_hiding_hint(const
|
||||
active_component_id,
|
||||
active_component_idx,
|
||||
weight_field,
|
||||
texture_mapping_offset_filament_strength_factor(*zone, active_component_id),
|
||||
texture_mapping_offset_filament_minimum_offset_factor(*zone, active_component_id),
|
||||
transmission_distance_width_factor_for_gcode(td_calibration_context, active_component_idx, previous_component_idx),
|
||||
calibrated_side_mode ? 1.f : texture_mapping_offset_filament_strength_factor(*zone, active_component_id),
|
||||
calibrated_side_mode ? 0.f : texture_mapping_offset_filament_minimum_offset_factor(*zone, active_component_id),
|
||||
calibrated_side_mode ? 1.f : transmission_distance_width_factor_for_gcode(td_calibration_context, active_component_idx, previous_component_idx),
|
||||
signed_fade_factor,
|
||||
fade_factor
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#include "libslic3r/ColorSolver.hpp"
|
||||
#include "ColorSolver.hpp"
|
||||
#include "libslic3r/TextureMapping.hpp"
|
||||
#include "libslic3r/Polyline.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
|
||||
@@ -1125,20 +1125,31 @@ static std::string transmission_distance_calibration_mode_name(int mode)
|
||||
{
|
||||
switch (clamp_int(mode,
|
||||
int(TextureMappingZone::TDCalibrationNone),
|
||||
int(TextureMappingZone::TDCalibrationNeighbor))) {
|
||||
int(TextureMappingZone::TDCalibrationCalibratedNearestMeasuredSample))) {
|
||||
case int(TextureMappingZone::TDCalibrationNone): return "none";
|
||||
case int(TextureMappingZone::TDCalibrationNeighbor): return "neighbor";
|
||||
case int(TextureMappingZone::TDCalibrationCalibratedNearestMeasuredSample):
|
||||
return "calibrated_nearest_measured_sample";
|
||||
default: return "absolute";
|
||||
}
|
||||
}
|
||||
|
||||
static int transmission_distance_calibration_mode_from_name(std::string name)
|
||||
{
|
||||
std::transform(name.begin(), name.end(), name.begin(), [](unsigned char c) { return char(std::tolower(c)); });
|
||||
std::transform(name.begin(), name.end(), name.begin(), [](unsigned char c) {
|
||||
const char lowered = char(std::tolower(c));
|
||||
return lowered == '-' || lowered == ' ' ? '_' : lowered;
|
||||
});
|
||||
if (name == "none" || name == "off" || name == "disabled")
|
||||
return int(TextureMappingZone::TDCalibrationNone);
|
||||
if (name == "neighbor" || name == "neighbour")
|
||||
if (name == "neighbor" || name == "neighbour" || name == "neighbor_td" || name == "neighbour_td")
|
||||
return int(TextureMappingZone::TDCalibrationNeighbor);
|
||||
if (name == "calibrated_nearest_measured_sample" ||
|
||||
name == "nearest_measured_sample" ||
|
||||
name == "nearest_measured_sample_global" ||
|
||||
name == "measured_sample" ||
|
||||
name == "measured_samples")
|
||||
return int(TextureMappingZone::TDCalibrationCalibratedNearestMeasuredSample);
|
||||
return int(TextureMappingZone::TDCalibrationAbsolute);
|
||||
}
|
||||
|
||||
@@ -1151,7 +1162,7 @@ static int transmission_distance_calibration_mode_from_json(const nlohmann::json
|
||||
if (mode_it->is_number_integer() || mode_it->is_number_unsigned())
|
||||
return clamp_int(mode_it->get<int>(),
|
||||
int(TextureMappingZone::TDCalibrationNone),
|
||||
int(TextureMappingZone::TDCalibrationNeighbor));
|
||||
int(TextureMappingZone::TDCalibrationCalibratedNearestMeasuredSample));
|
||||
if (mode_it->is_boolean())
|
||||
return mode_it->get<bool>() ?
|
||||
int(TextureMappingZone::TDCalibrationAbsolute) :
|
||||
@@ -1334,6 +1345,11 @@ bool TextureMappingColorCalibration::has_mode(int mode) const
|
||||
}
|
||||
}
|
||||
|
||||
bool TextureMappingSideSurfaceColorCalibration::has_nearest_measured_sample() const
|
||||
{
|
||||
return !nearest_measured_sample.empty();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
static const nlohmann::json *calibration_model_json(const nlohmann::json &models, const char *base_key)
|
||||
@@ -1348,6 +1364,37 @@ static const nlohmann::json *calibration_model_json(const nlohmann::json &models
|
||||
return it != models.end() ? &*it : nullptr;
|
||||
}
|
||||
|
||||
static const nlohmann::json *surface_calibration_json(const nlohmann::json &root, const char *surface_key)
|
||||
{
|
||||
if (!root.is_object())
|
||||
return nullptr;
|
||||
auto surfaces_it = root.find("surface_calibrations");
|
||||
if (surfaces_it != root.end() && surfaces_it->is_object()) {
|
||||
auto surface_it = surfaces_it->find(surface_key);
|
||||
if (surface_it != surfaces_it->end() && surface_it->is_object())
|
||||
return &*surface_it;
|
||||
}
|
||||
auto root_surface_it = root.find(surface_key);
|
||||
if (root_surface_it != root.end() && root_surface_it->is_object())
|
||||
return &*root_surface_it;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static nlohmann::json calibration_models_from_root_or_surface(const nlohmann::json &root, const nlohmann::json *surface)
|
||||
{
|
||||
if (root.contains("weights") && root["weights"].is_object() && !root["weights"].empty())
|
||||
return root["weights"];
|
||||
if (root.contains("models") && root["models"].is_object() && !root["models"].empty())
|
||||
return root["models"];
|
||||
if (surface != nullptr) {
|
||||
if (surface->contains("weights") && (*surface)["weights"].is_object())
|
||||
return (*surface)["weights"];
|
||||
if (surface->contains("models") && (*surface)["models"].is_object())
|
||||
return (*surface)["models"];
|
||||
}
|
||||
return nlohmann::json::object();
|
||||
}
|
||||
|
||||
static ColorSolverCalibratedStackModel calibration_current_linear_affine_model(const nlohmann::json &raw)
|
||||
{
|
||||
ColorSolverCalibratedStackModel model;
|
||||
@@ -1617,6 +1664,78 @@ static std::vector<TextureMappingColorCalibrationFilament> calibration_filaments
|
||||
return filaments;
|
||||
}
|
||||
|
||||
static std::vector<float> side_surface_swatch_weights_from_json(const nlohmann::json &raw, size_t component_count)
|
||||
{
|
||||
std::vector<float> weights = json_float_vector_or_empty(raw, { "raw_offsets", "raw_filament_offsets" });
|
||||
if (!weights.empty()) {
|
||||
if (weights.size() < component_count)
|
||||
return {};
|
||||
weights.resize(component_count);
|
||||
for (float &value : weights)
|
||||
value = std::clamp((std::isfinite(value) ? value : 0.f) / 255.f, 0.f, 1.f);
|
||||
return weights;
|
||||
}
|
||||
|
||||
weights = json_float_vector_or_empty(raw, { "normalized_weights", "weights", "component_weights" });
|
||||
if (weights.size() < component_count)
|
||||
return {};
|
||||
weights.resize(component_count);
|
||||
for (float &value : weights)
|
||||
value = std::clamp(std::isfinite(value) ? value : 0.f, 0.f, 1.f);
|
||||
return weights;
|
||||
}
|
||||
|
||||
static ColorSolverCandidateSet side_surface_nearest_measured_sample_candidates(const nlohmann::json &surface,
|
||||
size_t fallback_component_count)
|
||||
{
|
||||
ColorSolverCandidateSet candidates;
|
||||
if (!surface.is_object())
|
||||
return candidates;
|
||||
auto swatches_it = surface.find("swatches");
|
||||
if (swatches_it == surface.end() || !swatches_it->is_array())
|
||||
return candidates;
|
||||
|
||||
size_t component_count = fallback_component_count;
|
||||
if (component_count == 0) {
|
||||
for (const nlohmann::json &swatch : *swatches_it) {
|
||||
const std::vector<float> raw_offsets =
|
||||
json_float_vector_or_empty(swatch, { "raw_offsets", "raw_filament_offsets", "normalized_weights", "weights", "component_weights" });
|
||||
if (!raw_offsets.empty()) {
|
||||
component_count = raw_offsets.size();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (component_count == 0)
|
||||
return candidates;
|
||||
|
||||
candidates.component_count = component_count;
|
||||
candidates.rgbs.reserve(swatches_it->size() * 3);
|
||||
candidates.perceptual_coords.reserve(swatches_it->size() * 3);
|
||||
candidates.weights.reserve(swatches_it->size() * component_count);
|
||||
for (const nlohmann::json &swatch : *swatches_it) {
|
||||
std::optional<std::array<float, 3>> rgb = calibration_measured_sample_rgb_from_json(swatch);
|
||||
if (!rgb)
|
||||
continue;
|
||||
std::vector<float> weights = side_surface_swatch_weights_from_json(swatch, component_count);
|
||||
if (weights.size() != component_count)
|
||||
continue;
|
||||
const std::array<float, 3> perceptual = color_solver_oklab_from_srgb(*rgb);
|
||||
candidates.rgbs.emplace_back((*rgb)[0]);
|
||||
candidates.rgbs.emplace_back((*rgb)[1]);
|
||||
candidates.rgbs.emplace_back((*rgb)[2]);
|
||||
candidates.perceptual_coords.emplace_back(perceptual[0]);
|
||||
candidates.perceptual_coords.emplace_back(perceptual[1]);
|
||||
candidates.perceptual_coords.emplace_back(perceptual[2]);
|
||||
candidates.weights.insert(candidates.weights.end(), weights.begin(), weights.end());
|
||||
}
|
||||
|
||||
if (candidates.empty())
|
||||
return {};
|
||||
build_color_solver_candidate_kd_trees(candidates);
|
||||
return candidates;
|
||||
}
|
||||
|
||||
static const ColorSolverCalibratedStackModel &calibration_model_for_mode(const TextureMappingColorCalibration &calibration,
|
||||
int mode)
|
||||
{
|
||||
@@ -1654,7 +1773,8 @@ static float calibration_color_distance(const std::array<float, 3> &lhs, const s
|
||||
static TextureMappingCalibrationMatch match_calibration_filaments(const TextureMappingColorCalibration &calibration,
|
||||
const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<float> &component_tds_mm,
|
||||
int filament_color_mode)
|
||||
int filament_color_mode,
|
||||
const char *warning_prefix = "Top-surface color calibration")
|
||||
{
|
||||
TextureMappingCalibrationMatch match;
|
||||
match.calibration_index_by_component.assign(component_colors.size(), size_t(-1));
|
||||
@@ -1742,7 +1862,7 @@ static TextureMappingCalibrationMatch match_calibration_filaments(const TextureM
|
||||
if (!match.complete)
|
||||
notes.emplace_back("the calibration file does not contain enough matching filaments");
|
||||
if (!notes.empty()) {
|
||||
match.warning = "Top-surface color calibration mismatch: ";
|
||||
match.warning = std::string(warning_prefix != nullptr ? warning_prefix : "Calibration") + " mismatch: ";
|
||||
for (size_t idx = 0; idx < notes.size(); ++idx) {
|
||||
if (idx > 0)
|
||||
match.warning += "; ";
|
||||
@@ -1874,6 +1994,41 @@ static std::optional<ColorSolverCalibratedStackModel> remap_calibration_model(
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
static std::optional<ColorSolverCandidateSet> remap_side_surface_candidate_set(
|
||||
const ColorSolverCandidateSet &source,
|
||||
const TextureMappingCalibrationMatch &match,
|
||||
size_t target_component_count)
|
||||
{
|
||||
if (source.empty() || !match.complete || target_component_count == 0)
|
||||
return std::nullopt;
|
||||
|
||||
ColorSolverCandidateSet out;
|
||||
out.component_count = target_component_count;
|
||||
const size_t source_component_count = source.component_count;
|
||||
const size_t candidate_count = source.rgbs.size() / 3;
|
||||
if (source_component_count == 0 ||
|
||||
source.weights.size() != candidate_count * source_component_count ||
|
||||
source.perceptual_coords.size() != source.rgbs.size())
|
||||
return std::nullopt;
|
||||
|
||||
out.rgbs = source.rgbs;
|
||||
out.perceptual_coords = source.perceptual_coords;
|
||||
out.weights.assign(candidate_count * target_component_count, 0.f);
|
||||
for (size_t candidate_idx = 0; candidate_idx < candidate_count; ++candidate_idx) {
|
||||
const size_t src_begin = candidate_idx * source_component_count;
|
||||
const size_t dst_begin = candidate_idx * target_component_count;
|
||||
for (size_t component_idx = 0; component_idx < target_component_count; ++component_idx) {
|
||||
const size_t source_idx = match.calibration_index_by_component[component_idx];
|
||||
if (source_idx >= source_component_count)
|
||||
return std::nullopt;
|
||||
out.weights[dst_begin + component_idx] = source.weights[src_begin + source_idx];
|
||||
}
|
||||
}
|
||||
|
||||
build_color_solver_candidate_kd_trees(out);
|
||||
return out.empty() ? std::nullopt : std::optional<ColorSolverCandidateSet>(out);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::optional<TextureMappingColorCalibration> texture_mapping_parse_top_surface_color_calibration(
|
||||
@@ -1893,11 +2048,12 @@ std::optional<TextureMappingColorCalibration> texture_mapping_parse_top_surface_
|
||||
}
|
||||
|
||||
TextureMappingColorCalibration calibration;
|
||||
const nlohmann::json *top_surface = surface_calibration_json(root, "top_surface");
|
||||
calibration.display_name = json_string_or_empty(root, { "display_name", "name", "profile_id" });
|
||||
if (calibration.display_name.empty() && top_surface != nullptr)
|
||||
calibration.display_name = json_string_or_empty(*top_surface, { "display_name", "name", "profile_id" });
|
||||
calibration.filaments = calibration_filaments_from_json(root);
|
||||
const nlohmann::json models = root.contains("weights") && root["weights"].is_object() ?
|
||||
root["weights"] :
|
||||
root.value("models", nlohmann::json::object());
|
||||
const nlohmann::json models = calibration_models_from_root_or_surface(root, top_surface);
|
||||
|
||||
if (const nlohmann::json *raw = calibration_model_json(models, "current_linear_affine"))
|
||||
calibration.current_linear_affine = calibration_current_linear_affine_model(*raw);
|
||||
@@ -1927,6 +2083,46 @@ std::optional<TextureMappingColorCalibration> texture_mapping_parse_top_surface_
|
||||
return calibration;
|
||||
}
|
||||
|
||||
std::optional<TextureMappingSideSurfaceColorCalibration> texture_mapping_parse_side_surface_color_calibration(
|
||||
const std::string &json_text,
|
||||
std::string *error)
|
||||
{
|
||||
if (error != nullptr)
|
||||
error->clear();
|
||||
if (json_text.empty())
|
||||
return std::nullopt;
|
||||
|
||||
nlohmann::json root = nlohmann::json::parse(json_text, nullptr, false);
|
||||
if (root.is_discarded() || !root.is_object()) {
|
||||
if (error != nullptr)
|
||||
*error = "The calibration file is not valid JSON.";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const nlohmann::json *side_surface = surface_calibration_json(root, "side_surface");
|
||||
if (side_surface == nullptr) {
|
||||
if (error != nullptr)
|
||||
*error = "The calibration file does not contain side-surface calibration data.";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
TextureMappingSideSurfaceColorCalibration calibration;
|
||||
calibration.display_name = json_string_or_empty(root, { "display_name", "name", "profile_id" });
|
||||
if (calibration.display_name.empty())
|
||||
calibration.display_name = json_string_or_empty(*side_surface, { "display_name", "name", "profile_id" });
|
||||
calibration.filaments = calibration_filaments_from_json(root);
|
||||
calibration.nearest_measured_sample =
|
||||
side_surface_nearest_measured_sample_candidates(*side_surface, calibration.filaments.size());
|
||||
|
||||
if (!calibration.has_nearest_measured_sample()) {
|
||||
if (error != nullptr)
|
||||
*error = "The side-surface calibration does not contain supported measured swatches.";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return calibration;
|
||||
}
|
||||
|
||||
std::vector<int> texture_mapping_top_surface_color_calibration_supported_modes(const std::string &json_text)
|
||||
{
|
||||
std::vector<int> out;
|
||||
@@ -1983,6 +2179,13 @@ std::string texture_mapping_top_surface_color_calibration_display_name(const std
|
||||
return calibration ? calibration->display_name : std::string();
|
||||
}
|
||||
|
||||
std::string texture_mapping_side_surface_color_calibration_display_name(const std::string &json_text)
|
||||
{
|
||||
std::optional<TextureMappingSideSurfaceColorCalibration> calibration =
|
||||
texture_mapping_parse_side_surface_color_calibration(json_text);
|
||||
return calibration ? calibration->display_name : std::string();
|
||||
}
|
||||
|
||||
std::string texture_mapping_top_surface_color_calibration_warning(const TextureMappingZone &zone,
|
||||
const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<float> &component_tds_mm)
|
||||
@@ -2007,6 +2210,30 @@ std::string texture_mapping_top_surface_color_calibration_warning(const TextureM
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string texture_mapping_side_surface_color_calibration_warning(const TextureMappingZone &zone,
|
||||
const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<float> &component_tds_mm)
|
||||
{
|
||||
if (zone.side_surface_color_calibration_json.empty())
|
||||
return std::string();
|
||||
std::string error;
|
||||
std::optional<TextureMappingSideSurfaceColorCalibration> side_calibration =
|
||||
texture_mapping_parse_side_surface_color_calibration(zone.side_surface_color_calibration_json, &error);
|
||||
if (!side_calibration)
|
||||
return error.empty() ? "Side-surface color calibration could not be loaded." : error;
|
||||
|
||||
TextureMappingColorCalibration calibration;
|
||||
calibration.display_name = side_calibration->display_name;
|
||||
calibration.filaments = side_calibration->filaments;
|
||||
const TextureMappingCalibrationMatch match =
|
||||
match_calibration_filaments(calibration,
|
||||
component_colors,
|
||||
component_tds_mm,
|
||||
zone.filament_color_mode,
|
||||
"Side-surface color calibration");
|
||||
return match.warning;
|
||||
}
|
||||
|
||||
std::optional<ColorSolverCalibratedStackModel> texture_mapping_top_surface_color_calibrated_model(
|
||||
const TextureMappingZone &zone,
|
||||
int mode,
|
||||
@@ -2035,6 +2262,62 @@ std::optional<ColorSolverCalibratedStackModel> texture_mapping_top_surface_color
|
||||
return remap_calibration_model(source, mode, match, component_colors.size());
|
||||
}
|
||||
|
||||
std::optional<ColorSolverCandidateSet> texture_mapping_side_surface_color_calibrated_candidates(
|
||||
const TextureMappingZone &zone,
|
||||
const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<float> &component_tds_mm,
|
||||
std::string *warning)
|
||||
{
|
||||
if (warning != nullptr)
|
||||
warning->clear();
|
||||
std::string error;
|
||||
std::optional<TextureMappingSideSurfaceColorCalibration> side_calibration =
|
||||
texture_mapping_parse_side_surface_color_calibration(zone.side_surface_color_calibration_json, &error);
|
||||
if (!side_calibration) {
|
||||
if (warning != nullptr)
|
||||
*warning = error;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
TextureMappingColorCalibration calibration;
|
||||
calibration.display_name = side_calibration->display_name;
|
||||
calibration.filaments = side_calibration->filaments;
|
||||
const TextureMappingCalibrationMatch match =
|
||||
match_calibration_filaments(calibration,
|
||||
component_colors,
|
||||
component_tds_mm,
|
||||
zone.filament_color_mode,
|
||||
"Side-surface color calibration");
|
||||
if (warning != nullptr)
|
||||
*warning = match.warning;
|
||||
return remap_side_surface_candidate_set(side_calibration->nearest_measured_sample,
|
||||
match,
|
||||
component_colors.size());
|
||||
}
|
||||
|
||||
std::vector<float> texture_mapping_calibration_component_transmission_distances(
|
||||
const std::vector<TextureMappingColorCalibrationFilament> &filaments,
|
||||
const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<float> &component_tds_mm,
|
||||
int filament_color_mode)
|
||||
{
|
||||
TextureMappingColorCalibration calibration;
|
||||
calibration.filaments = filaments;
|
||||
const TextureMappingCalibrationMatch match =
|
||||
match_calibration_filaments(calibration, component_colors, component_tds_mm, filament_color_mode);
|
||||
std::vector<float> out(component_colors.size(), 0.f);
|
||||
if (!match.complete)
|
||||
return out;
|
||||
for (size_t component_idx = 0; component_idx < component_colors.size(); ++component_idx) {
|
||||
const size_t calibration_idx = match.calibration_index_by_component[component_idx];
|
||||
if (calibration_idx < filaments.size() &&
|
||||
std::isfinite(filaments[calibration_idx].td_mm) &&
|
||||
filaments[calibration_idx].td_mm > 0.f)
|
||||
out[component_idx] = std::clamp(filaments[calibration_idx].td_mm, 0.01f, 50.f);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
bool TextureMappingZone::operator==(const TextureMappingZone &rhs) const
|
||||
{
|
||||
constexpr float eps = 1e-6f;
|
||||
@@ -2154,6 +2437,8 @@ bool TextureMappingZone::operator==(const TextureMappingZone &rhs) const
|
||||
effective_top_surface_contoning_beam_search_stack_expansion_enabled() == rhs.effective_top_surface_contoning_beam_search_stack_expansion_enabled() &&
|
||||
top_surface_color_calibration_name == rhs.top_surface_color_calibration_name &&
|
||||
top_surface_color_calibration_json == rhs.top_surface_color_calibration_json &&
|
||||
side_surface_color_calibration_name == rhs.side_surface_color_calibration_name &&
|
||||
side_surface_color_calibration_json == rhs.side_surface_color_calibration_json &&
|
||||
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 &&
|
||||
@@ -2584,6 +2869,12 @@ std::string TextureMappingManager::serialize_entries()
|
||||
texture["top_surface_color_calibration"] =
|
||||
calibration.is_discarded() ? nlohmann::json(zone.top_surface_color_calibration_json) : std::move(calibration);
|
||||
}
|
||||
if (!zone.side_surface_color_calibration_json.empty()) {
|
||||
texture["side_surface_color_calibration_name"] = zone.side_surface_color_calibration_name;
|
||||
nlohmann::json calibration = nlohmann::json::parse(zone.side_surface_color_calibration_json, nullptr, false);
|
||||
texture["side_surface_color_calibration"] =
|
||||
calibration.is_discarded() ? nlohmann::json(zone.side_surface_color_calibration_json) : std::move(calibration);
|
||||
}
|
||||
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;
|
||||
@@ -2949,6 +3240,19 @@ void TextureMappingManager::load_entries(const std::string &serialized,
|
||||
zone.top_surface_contoning_color_prediction_mode =
|
||||
texture_mapping_top_surface_color_calibration_first_supported_mode(zone.top_surface_color_calibration_json);
|
||||
}
|
||||
zone.side_surface_color_calibration_name =
|
||||
texture.value("side_surface_color_calibration_name", std::string());
|
||||
zone.side_surface_color_calibration_json.clear();
|
||||
auto side_color_calibration_it = texture.find("side_surface_color_calibration");
|
||||
if (side_color_calibration_it != texture.end()) {
|
||||
zone.side_surface_color_calibration_json =
|
||||
side_color_calibration_it->is_string() ?
|
||||
side_color_calibration_it->get<std::string>() :
|
||||
side_color_calibration_it->dump();
|
||||
if (zone.side_surface_color_calibration_name.empty())
|
||||
zone.side_surface_color_calibration_name =
|
||||
texture_mapping_side_surface_color_calibration_display_name(zone.side_surface_color_calibration_json);
|
||||
}
|
||||
zone.apply_top_surface_contoning_experimental_defaults();
|
||||
zone.compact_offset_mode = texture.value("compact_offset_mode", TextureMappingZone::DefaultCompactOffsetMode);
|
||||
zone.use_legacy_fixed_color_mode =
|
||||
@@ -2984,6 +3288,11 @@ void TextureMappingManager::load_entries(const std::string &serialized,
|
||||
zone.high_resolution_sampling = true;
|
||||
zone.tone_gamma = normalize_tone_gamma(texture.value("tone_gamma", 1.f));
|
||||
zone.transmission_distance_calibration_mode = transmission_distance_calibration_mode_from_json(texture);
|
||||
if (zone.transmission_distance_calibration_mode == int(TextureMappingZone::TDCalibrationCalibratedNearestMeasuredSample) &&
|
||||
!texture_mapping_parse_side_surface_color_calibration(zone.side_surface_color_calibration_json)) {
|
||||
zone.transmission_distance_calibration_mode =
|
||||
TextureMappingZone::DefaultTransmissionDistanceCalibrationMode;
|
||||
}
|
||||
zone.auto_adjust_filament_selection = texture.value("auto_adjust_filaments", true);
|
||||
zone.filament_strengths_pct = normalize_strengths(floats_from_json(texture.value("strength_pct", nlohmann::json::array())));
|
||||
zone.filament_minimum_offsets_pct =
|
||||
|
||||
@@ -154,7 +154,8 @@ struct TextureMappingZone
|
||||
enum TransmissionDistanceCalibrationMode : uint8_t {
|
||||
TDCalibrationNone = 0,
|
||||
TDCalibrationAbsolute = 1,
|
||||
TDCalibrationNeighbor = 2
|
||||
TDCalibrationNeighbor = 2,
|
||||
TDCalibrationCalibratedNearestMeasuredSample = 3
|
||||
};
|
||||
|
||||
static constexpr int DefaultSurfacePattern = int(ImageTexture);
|
||||
@@ -518,6 +519,8 @@ struct TextureMappingZone
|
||||
bool top_surface_contoning_beam_search_stack_expansion_enabled = DefaultTopSurfaceContoningBeamSearchStackExpansionEnabled;
|
||||
std::string top_surface_color_calibration_name;
|
||||
std::string top_surface_color_calibration_json;
|
||||
std::string side_surface_color_calibration_name;
|
||||
std::string side_surface_color_calibration_json;
|
||||
bool compact_offset_mode = DefaultCompactOffsetMode;
|
||||
bool use_legacy_fixed_color_mode = DefaultUseLegacyFixedColorMode;
|
||||
bool high_speed_image_texture_sampling = DefaultHighSpeedImageTextureSampling;
|
||||
@@ -823,6 +826,8 @@ struct TextureMappingZone
|
||||
top_surface_contoning_beam_search_stack_expansion_enabled = DefaultTopSurfaceContoningBeamSearchStackExpansionEnabled;
|
||||
top_surface_color_calibration_name.clear();
|
||||
top_surface_color_calibration_json.clear();
|
||||
side_surface_color_calibration_name.clear();
|
||||
side_surface_color_calibration_json.clear();
|
||||
compact_offset_mode = DefaultCompactOffsetMode;
|
||||
use_legacy_fixed_color_mode = DefaultUseLegacyFixedColorMode;
|
||||
high_speed_image_texture_sampling = DefaultHighSpeedImageTextureSampling;
|
||||
@@ -893,21 +898,46 @@ struct TextureMappingColorCalibration {
|
||||
bool has_mode(int mode) const;
|
||||
};
|
||||
|
||||
struct TextureMappingSideSurfaceColorCalibration {
|
||||
std::string display_name;
|
||||
std::vector<TextureMappingColorCalibrationFilament> filaments;
|
||||
ColorSolverCandidateSet nearest_measured_sample;
|
||||
|
||||
bool has_nearest_measured_sample() const;
|
||||
};
|
||||
|
||||
std::optional<TextureMappingColorCalibration> texture_mapping_parse_top_surface_color_calibration(
|
||||
const std::string &json_text,
|
||||
std::string *error = nullptr);
|
||||
std::optional<TextureMappingSideSurfaceColorCalibration> texture_mapping_parse_side_surface_color_calibration(
|
||||
const std::string &json_text,
|
||||
std::string *error = nullptr);
|
||||
std::vector<int> texture_mapping_top_surface_color_calibration_supported_modes(const std::string &json_text);
|
||||
int texture_mapping_top_surface_color_calibration_first_supported_mode(const std::string &json_text);
|
||||
std::string texture_mapping_top_surface_color_calibration_display_name(const std::string &json_text);
|
||||
std::string texture_mapping_side_surface_color_calibration_display_name(const std::string &json_text);
|
||||
std::string texture_mapping_top_surface_color_calibration_warning(const TextureMappingZone &zone,
|
||||
const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<float> &component_tds_mm);
|
||||
std::string texture_mapping_side_surface_color_calibration_warning(const TextureMappingZone &zone,
|
||||
const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<float> &component_tds_mm);
|
||||
std::optional<ColorSolverCalibratedStackModel> texture_mapping_top_surface_color_calibrated_model(
|
||||
const TextureMappingZone &zone,
|
||||
int mode,
|
||||
const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<float> &component_tds_mm,
|
||||
std::string *warning = nullptr);
|
||||
std::optional<ColorSolverCandidateSet> texture_mapping_side_surface_color_calibrated_candidates(
|
||||
const TextureMappingZone &zone,
|
||||
const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<float> &component_tds_mm,
|
||||
std::string *warning = nullptr);
|
||||
std::vector<float> texture_mapping_calibration_component_transmission_distances(
|
||||
const std::vector<TextureMappingColorCalibrationFilament> &filaments,
|
||||
const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<float> &component_tds_mm,
|
||||
int filament_color_mode);
|
||||
|
||||
struct TextureMappingPrimeTowerImage
|
||||
{
|
||||
|
||||
@@ -1630,11 +1630,14 @@ std::vector<float> component_weights_for_sample(const WeightedTextureSample &sam
|
||||
float contrast_factor,
|
||||
float tone_gamma,
|
||||
const std::vector<std::array<float, 3>> &component_colors,
|
||||
const ColorSolverCandidateSet *generic_mix_candidates)
|
||||
const ColorSolverCandidateSet *generic_mix_candidates,
|
||||
const ColorSolverCandidateSet *calibrated_side_candidates)
|
||||
{
|
||||
std::vector<float> desired(component_count, 0.f);
|
||||
size_t mapped_component_count = component_count;
|
||||
const bool has_raw_component_weights = sample.raw_component_weights.size() == component_count;
|
||||
const bool has_calibrated_side_candidates =
|
||||
calibrated_side_candidates != nullptr && !calibrated_side_candidates->empty();
|
||||
const int effective_solver_mode = TextureMappingZone::effective_generic_solver_mode(generic_solver_mode);
|
||||
if (has_raw_component_weights) {
|
||||
float raw_activity = 0.f;
|
||||
@@ -1662,6 +1665,14 @@ std::vector<float> component_weights_for_sample(const WeightedTextureSample &sam
|
||||
for (size_t channel_idx = 0; channel_idx < channel_count; ++channel_idx)
|
||||
desired[channel_idx] = clamp01f(channels[channel_idx]);
|
||||
mapped_component_count = channel_count;
|
||||
} else if (has_calibrated_side_candidates) {
|
||||
std::vector<float> calibrated =
|
||||
solve_color_solver_weights_for_target(*calibrated_side_candidates,
|
||||
target,
|
||||
ColorSolverLookupMode::ClosestMix,
|
||||
color_solver_mode_from_index(effective_solver_mode));
|
||||
if (calibrated.size() == component_count)
|
||||
desired = std::move(calibrated);
|
||||
} else {
|
||||
std::vector<float> optimized;
|
||||
if (!use_fixed_color_generic_solver)
|
||||
@@ -1684,7 +1695,7 @@ std::vector<float> component_weights_for_sample(const WeightedTextureSample &sam
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_raw_component_weights && std::abs(contrast_factor - 1.f) > 1e-5f)
|
||||
if (!has_raw_component_weights && !has_calibrated_side_candidates && std::abs(contrast_factor - 1.f) > 1e-5f)
|
||||
apply_texture_contrast_to_components(desired, contrast_factor, mapped_component_count);
|
||||
for (float &v : desired)
|
||||
v = clamp01f(v);
|
||||
@@ -1717,6 +1728,7 @@ TextureMappingOffsetWeightField build_texture_mapping_offset_weight_field(const
|
||||
bool high_speed_image_texture_sampling,
|
||||
std::optional<float> texture_sample_pitch_mm_override,
|
||||
std::optional<std::array<float, 4>> image_background_rgba_override,
|
||||
const ColorSolverCandidateSet *calibrated_side_candidates,
|
||||
std::optional<int> raw_top_surface_depth_override)
|
||||
{
|
||||
TextureMappingOffsetWeightField weight_field;
|
||||
@@ -2099,8 +2111,11 @@ TextureMappingOffsetWeightField build_texture_mapping_offset_weight_field(const
|
||||
int(TextureMappingZone::DitheringClosest),
|
||||
int(TextureMappingZone::DitheringHalftoneV2));
|
||||
std::vector<uint32_t> binary_dither_masks;
|
||||
const bool has_calibrated_side_candidates =
|
||||
calibrated_side_candidates != nullptr && !calibrated_side_candidates->empty();
|
||||
const bool can_binary_dither =
|
||||
dithering_enabled &&
|
||||
!has_calibrated_side_candidates &&
|
||||
!raw_values_mode &&
|
||||
!is_halftone_dithering_method(clamped_binary_dither_method) &&
|
||||
component_count > 0 &&
|
||||
@@ -2245,7 +2260,7 @@ TextureMappingOffsetWeightField build_texture_mapping_offset_weight_field(const
|
||||
use_fixed_color_generic_solver ? fixed_colors : component_colors;
|
||||
ColorSolverCandidateSet candidates;
|
||||
const ColorSolverCandidateSet *candidate_ptr = nullptr;
|
||||
if (!raw_values_mode) {
|
||||
if (!raw_values_mode && !has_calibrated_side_candidates) {
|
||||
candidates = build_color_solver_candidates(solver_colors, color_solver_mix_model_from_index(generic_solver_mix_model));
|
||||
candidate_ptr = candidates.empty() ? nullptr : &candidates;
|
||||
}
|
||||
@@ -2301,7 +2316,8 @@ TextureMappingOffsetWeightField build_texture_mapping_offset_weight_field(const
|
||||
contrast_factor,
|
||||
tone_gamma,
|
||||
component_colors,
|
||||
candidate_ptr);
|
||||
candidate_ptr,
|
||||
calibrated_side_candidates);
|
||||
}
|
||||
for (size_t component_idx = 0; component_idx < component_count; ++component_idx) {
|
||||
const float v = component_idx < desired.size() ? clamp01f(desired[component_idx]) : 0.f;
|
||||
@@ -2669,8 +2685,10 @@ TransmissionDistanceCalibrationContext transmission_distance_calibration_context
|
||||
TransmissionDistanceCalibrationContext context;
|
||||
context.mode = std::clamp(zone.transmission_distance_calibration_mode,
|
||||
int(TextureMappingZone::TDCalibrationNone),
|
||||
int(TextureMappingZone::TDCalibrationNeighbor));
|
||||
if (context.mode == int(TextureMappingZone::TDCalibrationNone) || component_ids.empty())
|
||||
int(TextureMappingZone::TDCalibrationCalibratedNearestMeasuredSample));
|
||||
if (context.mode == int(TextureMappingZone::TDCalibrationNone) ||
|
||||
context.mode == int(TextureMappingZone::TDCalibrationCalibratedNearestMeasuredSample) ||
|
||||
component_ids.empty())
|
||||
return context;
|
||||
|
||||
std::vector<float> explicit_tds(component_ids.size(), 0.f);
|
||||
@@ -3609,13 +3627,36 @@ std::optional<TextureMappingOffsetContext> build_texture_mapping_offset_context_
|
||||
TextureMappingZone::MaxHalftoneDotSizeMm);
|
||||
const bool high_resolution_texture_sampling = zone.high_resolution_sampling || dithering_enabled;
|
||||
const bool compact_offset_mode = halftone_dithering_enabled ? false : zone.compact_offset_mode || dithering_enabled;
|
||||
const bool calibrated_side_mode =
|
||||
vertex_color_match_mode &&
|
||||
!raw_texture_mapping_mode &&
|
||||
zone.transmission_distance_calibration_mode == int(TextureMappingZone::TDCalibrationCalibratedNearestMeasuredSample);
|
||||
std::vector<float> component_strength_factors;
|
||||
component_strength_factors.reserve(component_ids.size());
|
||||
std::vector<float> component_minimum_offset_factors;
|
||||
component_minimum_offset_factors.reserve(component_ids.size());
|
||||
for (const unsigned int id : component_ids) {
|
||||
component_strength_factors.emplace_back(texture_mapping_offset_filament_strength_factor(zone, id));
|
||||
component_minimum_offset_factors.emplace_back(texture_mapping_offset_filament_minimum_offset_factor(zone, id));
|
||||
component_strength_factors.emplace_back(calibrated_side_mode ? 1.f : texture_mapping_offset_filament_strength_factor(zone, id));
|
||||
component_minimum_offset_factors.emplace_back(calibrated_side_mode ? 0.f : texture_mapping_offset_filament_minimum_offset_factor(zone, id));
|
||||
}
|
||||
std::vector<float> component_transmission_distances_mm;
|
||||
component_transmission_distances_mm.reserve(component_ids.size());
|
||||
for (const unsigned int id : component_ids) {
|
||||
const size_t idx = id > 0 ? size_t(id - 1) : size_t(-1);
|
||||
const float value = idx < zone.filament_transmission_distances_mm.size() ?
|
||||
zone.filament_transmission_distances_mm[idx] :
|
||||
0.f;
|
||||
component_transmission_distances_mm.emplace_back(std::isfinite(value) && value > 0.f ? std::clamp(value, 0.01f, 50.f) : 0.f);
|
||||
}
|
||||
std::optional<ColorSolverCandidateSet> calibrated_side_candidates;
|
||||
const ColorSolverCandidateSet *calibrated_side_candidates_ptr = nullptr;
|
||||
if (calibrated_side_mode) {
|
||||
calibrated_side_candidates =
|
||||
texture_mapping_side_surface_color_calibrated_candidates(zone,
|
||||
component_colors,
|
||||
component_transmission_distances_mm);
|
||||
if (calibrated_side_candidates && !calibrated_side_candidates->empty())
|
||||
calibrated_side_candidates_ptr = &*calibrated_side_candidates;
|
||||
}
|
||||
|
||||
TextureMappingOffsetWeightField weight_field;
|
||||
@@ -3632,7 +3673,8 @@ std::optional<TextureMappingOffsetContext> build_texture_mapping_offset_context_
|
||||
component_minimum_offset_factors, texture_contrast_pct, texture_tone_gamma,
|
||||
sample_z_mm, layer_sample_falloff_mm, high_resolution_texture_sampling,
|
||||
zone.high_speed_image_texture_sampling, texture_sample_pitch_mm_override,
|
||||
image_background_rgba_override, raw_top_surface_depth_override);
|
||||
image_background_rgba_override, calibrated_side_candidates_ptr,
|
||||
raw_top_surface_depth_override);
|
||||
if (weight_field.empty())
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -3734,11 +3776,11 @@ std::optional<TextureMappingOffsetContext> build_texture_mapping_offset_context_
|
||||
context.active_halftone_angle_deg = halftone_screen_angle_deg(filament_color_mode, active_component_idx);
|
||||
context.active_component_strength_factor = linear_gradient_mode ?
|
||||
1.f :
|
||||
texture_mapping_offset_filament_strength_factor(zone, active_component_id);
|
||||
(calibrated_side_mode ? 1.f : texture_mapping_offset_filament_strength_factor(zone, active_component_id));
|
||||
context.active_component_minimum_offset_factor = linear_gradient_mode ?
|
||||
0.f :
|
||||
texture_mapping_offset_filament_minimum_offset_factor(zone, active_component_id);
|
||||
context.active_component_td_width_factor = linear_gradient_mode ?
|
||||
(calibrated_side_mode ? 0.f : texture_mapping_offset_filament_minimum_offset_factor(zone, active_component_id));
|
||||
context.active_component_td_width_factor = linear_gradient_mode || calibrated_side_mode ?
|
||||
1.f :
|
||||
transmission_distance_width_factor(td_calibration_context, active_component_idx, previous_component_idx);
|
||||
context.base_outer_width_mm = base_outer_width_mm;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#include "libslic3r/BuildVolume.hpp"
|
||||
#include "libslic3r/Color.hpp"
|
||||
#include "libslic3r/ColorSolver.hpp"
|
||||
#include "ColorSolver.hpp"
|
||||
#include "libslic3r/ExtrusionEntity.hpp"
|
||||
#include "libslic3r/ExtrusionEntityCollection.hpp"
|
||||
#include "libslic3r/Geometry.hpp"
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "libslic3r/Format/bbs_3mf.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/TextureMapping.hpp"
|
||||
#include "libslic3r/ColorSolver.hpp"
|
||||
#include "ColorSolver.hpp"
|
||||
#include "libslic3r/Geometry.hpp"
|
||||
#include "libslic3r/AABBMesh.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/TextureMapping.hpp"
|
||||
#include "libslic3r/TextureMappingContoning.hpp"
|
||||
#include "libslic3r/ColorSolver.hpp"
|
||||
#include "ColorSolver.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
#include "libslic3r/Format/STL.hpp"
|
||||
#include "libslic3r/Format/DRC.hpp"
|
||||
#include "libslic3r/Format/STEP.hpp"
|
||||
#include "libslic3r/ColorSolver.hpp"
|
||||
#include "ColorSolver.hpp"
|
||||
#include "libslic3r/Format/AMF.hpp"
|
||||
//#include "libslic3r/Format/3mf.hpp"
|
||||
#include "libslic3r/Format/bbs_3mf.hpp"
|
||||
@@ -2550,6 +2550,8 @@ public:
|
||||
bool top_surface_contoning_variable_layer_height_compensation_enabled,
|
||||
const std::string &top_surface_color_calibration_name,
|
||||
const std::string &top_surface_color_calibration_json,
|
||||
const std::string &side_surface_color_calibration_name,
|
||||
const std::string &side_surface_color_calibration_json,
|
||||
std::function<bool(const std::vector<std::string>&)> apply_filament_colors,
|
||||
const TextureMappingZoneShellUsageSummary &top_surface_contoning_shell_usage,
|
||||
const TextureMappingManager &texture_mapping_zones,
|
||||
@@ -2569,6 +2571,8 @@ public:
|
||||
, m_apply_filament_colors(std::move(apply_filament_colors))
|
||||
, m_top_surface_color_calibration_name(top_surface_color_calibration_name)
|
||||
, m_top_surface_color_calibration_json(top_surface_color_calibration_json)
|
||||
, m_side_surface_color_calibration_name(side_surface_color_calibration_name)
|
||||
, m_side_surface_color_calibration_json(side_surface_color_calibration_json)
|
||||
{
|
||||
(void) reduce_outer_surface_texture;
|
||||
(void) top_surface_contoning_min_feature_mm;
|
||||
@@ -2671,20 +2675,24 @@ public:
|
||||
|
||||
auto *td_box = new wxStaticBoxSizer(wxVERTICAL, filament_page, _L("Transmission distance"));
|
||||
auto *td_mode_row = new wxBoxSizer(wxHORIZONTAL);
|
||||
td_mode_row->Add(new wxStaticText(filament_page, wxID_ANY, _L("TD calibration mode")),
|
||||
td_mode_row->Add(new wxStaticText(filament_page, wxID_ANY, _L("Side calibration mode")),
|
||||
0,
|
||||
wxALIGN_CENTER_VERTICAL | wxRIGHT,
|
||||
gap);
|
||||
wxArrayString td_mode_choices;
|
||||
td_mode_choices.Add(_L("None"));
|
||||
td_mode_choices.Add(_L("Absolute"));
|
||||
td_mode_choices.Add(_L("Neighbor"));
|
||||
td_mode_choices.Add(_L("Absolute TD"));
|
||||
td_mode_choices.Add(_L("Neighbour TD"));
|
||||
td_mode_choices.Add(_L("Calibrated: nearest measured sample"));
|
||||
m_transmission_distance_calibration_mode_choice =
|
||||
new wxChoice(filament_page, wxID_ANY, wxDefaultPosition, wxDefaultSize, td_mode_choices);
|
||||
m_transmission_distance_calibration_mode_choice->SetSelection(
|
||||
std::clamp(transmission_distance_calibration_mode,
|
||||
int(TextureMappingZone::TDCalibrationNone),
|
||||
int(TextureMappingZone::TDCalibrationNeighbor)));
|
||||
int(TextureMappingZone::TDCalibrationCalibratedNearestMeasuredSample)));
|
||||
m_transmission_distance_calibration_mode_choice->Bind(wxEVT_CHOICE, [this](wxCommandEvent &) {
|
||||
update_strength_offsets_visibility(true);
|
||||
});
|
||||
td_mode_row->Add(m_transmission_distance_calibration_mode_choice, 1, wxALIGN_CENTER_VERTICAL);
|
||||
td_box->Add(td_mode_row, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, gap);
|
||||
for (size_t i = 0; i < component_ids.size(); ++i) {
|
||||
@@ -2711,6 +2719,36 @@ public:
|
||||
}
|
||||
filament_root->Add(td_box, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, gap);
|
||||
|
||||
auto add_filament_calibration_row = [this, filament_page, filament_root, gap](const wxString &title,
|
||||
wxStaticText **label_out,
|
||||
std::function<void()> load_fn,
|
||||
std::function<void()> clear_fn) {
|
||||
auto *row = new wxBoxSizer(wxHORIZONTAL);
|
||||
row->Add(new wxStaticText(filament_page, wxID_ANY, title),
|
||||
0,
|
||||
wxALIGN_CENTER_VERTICAL | wxRIGHT,
|
||||
gap);
|
||||
auto *label = new wxStaticText(filament_page, wxID_ANY, wxEmptyString);
|
||||
row->Add(label, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
auto *load_button = new wxButton(filament_page, wxID_ANY, _L("Load..."));
|
||||
auto *clear_button = new wxButton(filament_page, wxID_ANY, _L("Clear"));
|
||||
row->Add(load_button, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, std::max(FromDIP(2), gap / 2));
|
||||
row->Add(clear_button, 0, wxALIGN_CENTER_VERTICAL);
|
||||
load_button->Bind(wxEVT_BUTTON, [load_fn](wxCommandEvent &) { load_fn(); });
|
||||
clear_button->Bind(wxEVT_BUTTON, [clear_fn](wxCommandEvent &) { clear_fn(); });
|
||||
if (label_out != nullptr)
|
||||
*label_out = label;
|
||||
filament_root->Add(row, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, gap);
|
||||
};
|
||||
add_filament_calibration_row(_L("Top Calibration"),
|
||||
&m_filament_top_surface_color_calibration_label,
|
||||
[this]() { load_top_surface_color_calibration(); },
|
||||
[this]() { clear_top_surface_color_calibration(); });
|
||||
add_filament_calibration_row(_L("Side Calibration"),
|
||||
&m_side_surface_color_calibration_label,
|
||||
[this]() { load_side_surface_color_calibration(); },
|
||||
[this]() { clear_side_surface_color_calibration(); });
|
||||
|
||||
m_strength_offsets_toggle_button = new wxButton(filament_page, wxID_ANY, wxEmptyString);
|
||||
m_strength_offsets_toggle_button->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) {
|
||||
m_strength_offsets_expanded = !m_strength_offsets_expanded;
|
||||
@@ -2763,9 +2801,9 @@ public:
|
||||
}
|
||||
strength_offsets_root->Add(minimum_offsets_box, 0, wxEXPAND | wxBOTTOM, gap);
|
||||
strength_offsets_root->Add(strengths_box, 0, wxEXPAND | wxBOTTOM, gap);
|
||||
auto *reset_btn = new wxButton(m_strength_offsets_panel, wxID_ANY, _L("Reset strengths and offsets"));
|
||||
reset_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { reset_strengths_and_offsets(); });
|
||||
strength_offsets_root->Add(reset_btn, 0, wxALIGN_RIGHT | wxBOTTOM, gap);
|
||||
m_strength_offsets_reset_button = new wxButton(m_strength_offsets_panel, wxID_ANY, _L("Reset strengths and offsets"));
|
||||
m_strength_offsets_reset_button->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { reset_strengths_and_offsets(); });
|
||||
strength_offsets_root->Add(m_strength_offsets_reset_button, 0, wxALIGN_RIGHT | wxBOTTOM, gap);
|
||||
filament_root->Add(m_strength_offsets_panel, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, gap);
|
||||
update_strength_offsets_visibility(false);
|
||||
|
||||
@@ -3324,6 +3362,7 @@ public:
|
||||
new wxChoice(m_top_surface_contoning_checkboxes_panel, wxID_ANY);
|
||||
rebuild_top_surface_contoning_color_prediction_choices(top_surface_contoning_color_prediction_mode);
|
||||
update_top_surface_color_calibration_label();
|
||||
update_side_surface_color_calibration_label();
|
||||
contoning_td_correction_row->Add(m_top_surface_contoning_td_correction_choice, 1, wxALIGN_CENTER_VERTICAL);
|
||||
contoning_checkboxes_root->Add(contoning_td_correction_row, 0, wxEXPAND | wxTOP | wxBOTTOM, gap / 2);
|
||||
m_top_surface_contoning_variable_layer_height_compensation_checkbox =
|
||||
@@ -3809,7 +3848,7 @@ public:
|
||||
return m_transmission_distance_calibration_mode_choice ?
|
||||
std::clamp(m_transmission_distance_calibration_mode_choice->GetSelection(),
|
||||
int(TextureMappingZone::TDCalibrationNone),
|
||||
int(TextureMappingZone::TDCalibrationNeighbor)) :
|
||||
int(TextureMappingZone::TDCalibrationCalibratedNearestMeasuredSample)) :
|
||||
TextureMappingZone::DefaultTransmissionDistanceCalibrationMode;
|
||||
}
|
||||
|
||||
@@ -4156,6 +4195,14 @@ public:
|
||||
{
|
||||
return m_top_surface_color_calibration_json;
|
||||
}
|
||||
std::string side_surface_color_calibration_name() const
|
||||
{
|
||||
return m_side_surface_color_calibration_name;
|
||||
}
|
||||
std::string side_surface_color_calibration_json() const
|
||||
{
|
||||
return m_side_surface_color_calibration_json;
|
||||
}
|
||||
bool top_surface_contoning_td_effective_alpha_correction_selected() const
|
||||
{
|
||||
const int effective_mode = TextureMappingZone::effective_top_surface_contoning_color_prediction_mode(
|
||||
@@ -4305,6 +4352,11 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
enum class CalibrationSurface {
|
||||
Top,
|
||||
Side
|
||||
};
|
||||
|
||||
static std::string prime_tower_color_mode_name(int selection)
|
||||
{
|
||||
switch (selection) {
|
||||
@@ -4482,7 +4534,9 @@ private:
|
||||
|
||||
void update_top_surface_color_calibration_label()
|
||||
{
|
||||
if (m_top_surface_color_calibration_label != nullptr) {
|
||||
auto update_label = [this](wxStaticText *label_widget) {
|
||||
if (label_widget == nullptr)
|
||||
return;
|
||||
wxString label = _L("No calibration loaded");
|
||||
wxString tooltip;
|
||||
if (!m_top_surface_color_calibration_json.empty()) {
|
||||
@@ -4497,9 +4551,11 @@ private:
|
||||
display = display.Left(19) + "..." + display.Right(20);
|
||||
label = display;
|
||||
}
|
||||
m_top_surface_color_calibration_label->SetLabel(label);
|
||||
m_top_surface_color_calibration_label->SetToolTip(tooltip);
|
||||
}
|
||||
label_widget->SetLabel(label);
|
||||
label_widget->SetToolTip(tooltip);
|
||||
};
|
||||
update_label(m_top_surface_color_calibration_label);
|
||||
update_label(m_filament_top_surface_color_calibration_label);
|
||||
|
||||
if (m_top_surface_color_calibration_warning_text != nullptr) {
|
||||
TextureMappingZone tmp;
|
||||
@@ -4520,6 +4576,59 @@ private:
|
||||
Layout();
|
||||
}
|
||||
|
||||
void update_side_surface_color_calibration_label()
|
||||
{
|
||||
if (m_side_surface_color_calibration_label != nullptr) {
|
||||
wxString label = _L("No calibration loaded");
|
||||
wxString tooltip;
|
||||
if (!m_side_surface_color_calibration_json.empty()) {
|
||||
std::string name = m_side_surface_color_calibration_name;
|
||||
if (name.empty())
|
||||
name = texture_mapping_side_surface_color_calibration_display_name(m_side_surface_color_calibration_json);
|
||||
if (name.empty())
|
||||
name = "Loaded calibration";
|
||||
tooltip = from_u8(name);
|
||||
wxString display = from_u8(name);
|
||||
if (display.length() > 42)
|
||||
display = display.Left(19) + "..." + display.Right(20);
|
||||
label = display;
|
||||
}
|
||||
m_side_surface_color_calibration_label->SetLabel(label);
|
||||
m_side_surface_color_calibration_label->SetToolTip(tooltip);
|
||||
}
|
||||
Layout();
|
||||
}
|
||||
|
||||
int preferred_top_surface_color_calibration_mode() const
|
||||
{
|
||||
const std::vector<int> modes =
|
||||
texture_mapping_top_surface_color_calibration_supported_modes(m_top_surface_color_calibration_json);
|
||||
const int nearest_mode = int(TextureMappingZone::ContoningColorPredictionCalibratedNearestMeasuredSample);
|
||||
if (std::find(modes.begin(), modes.end(), nearest_mode) != modes.end())
|
||||
return nearest_mode;
|
||||
return texture_mapping_top_surface_color_calibration_first_supported_mode(m_top_surface_color_calibration_json);
|
||||
}
|
||||
|
||||
bool apply_transmission_distances_from_calibration_filaments(
|
||||
const std::vector<TextureMappingColorCalibrationFilament> &filaments)
|
||||
{
|
||||
if (filaments.empty())
|
||||
return false;
|
||||
const std::vector<float> tds =
|
||||
texture_mapping_calibration_component_transmission_distances(filaments,
|
||||
top_surface_color_calibration_component_colors(),
|
||||
component_transmission_distances_mm(),
|
||||
m_filament_color_mode);
|
||||
bool applied = false;
|
||||
for (size_t idx = 0; idx < tds.size() && idx < m_transmission_distance_spins.size(); ++idx) {
|
||||
if (tds[idx] > 0.f && m_transmission_distance_spins[idx] != nullptr) {
|
||||
m_transmission_distance_spins[idx]->SetValue(double(tds[idx]));
|
||||
applied = true;
|
||||
}
|
||||
}
|
||||
return applied;
|
||||
}
|
||||
|
||||
bool filament_color_lists_differ(const std::vector<std::string> &lhs,
|
||||
const std::vector<std::string> &rhs) const
|
||||
{
|
||||
@@ -4677,10 +4786,11 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
void load_top_surface_color_calibration()
|
||||
void load_surface_color_calibration(CalibrationSurface target_surface)
|
||||
{
|
||||
const bool target_top = target_surface == CalibrationSurface::Top;
|
||||
wxFileDialog dlg(this,
|
||||
_L("Load top-surface color calibration"),
|
||||
target_top ? _L("Load top-surface color calibration") : _L("Load side-surface color calibration"),
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
_L("JSON files (*.json)|*.json"),
|
||||
@@ -4697,23 +4807,78 @@ private:
|
||||
std::ostringstream ss;
|
||||
ss << file.rdbuf();
|
||||
const std::string json_text = ss.str();
|
||||
std::string error;
|
||||
if (!texture_mapping_parse_top_surface_color_calibration(json_text, &error)) {
|
||||
std::string top_error;
|
||||
std::string side_error;
|
||||
std::optional<TextureMappingColorCalibration> top_calibration =
|
||||
texture_mapping_parse_top_surface_color_calibration(json_text, &top_error);
|
||||
std::optional<TextureMappingSideSurfaceColorCalibration> side_calibration =
|
||||
texture_mapping_parse_side_surface_color_calibration(json_text, &side_error);
|
||||
if ((target_top && !top_calibration) || (!target_top && !side_calibration)) {
|
||||
const std::string &error = target_top ? top_error : side_error;
|
||||
MessageDialog msg(this,
|
||||
error.empty() ? _L("The selected file is not a supported top-surface color calibration.") : from_u8(error),
|
||||
error.empty() ?
|
||||
(target_top ?
|
||||
_L("The selected file is not a supported top-surface color calibration.") :
|
||||
_L("The selected file is not a supported side-surface color calibration.")) :
|
||||
from_u8(error),
|
||||
_L("Invalid calibration"),
|
||||
wxOK | wxICON_WARNING);
|
||||
msg.ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
m_top_surface_color_calibration_json = json_text;
|
||||
m_top_surface_color_calibration_name =
|
||||
boost::filesystem::path(into_u8(dlg.GetPath())).filename().string();
|
||||
const int mode = texture_mapping_top_surface_color_calibration_first_supported_mode(m_top_surface_color_calibration_json);
|
||||
rebuild_top_surface_contoning_color_prediction_choices(mode);
|
||||
const std::string filename = boost::filesystem::path(into_u8(dlg.GetPath())).filename().string();
|
||||
bool top_changed = false;
|
||||
bool side_changed = false;
|
||||
if (target_top) {
|
||||
m_top_surface_color_calibration_json = json_text;
|
||||
m_top_surface_color_calibration_name = filename;
|
||||
rebuild_top_surface_contoning_color_prediction_choices(preferred_top_surface_color_calibration_mode());
|
||||
bool td_applied = apply_transmission_distances_from_calibration_filaments(top_calibration->filaments);
|
||||
top_changed = true;
|
||||
if (side_calibration && m_side_surface_color_calibration_json.empty()) {
|
||||
m_side_surface_color_calibration_json = json_text;
|
||||
m_side_surface_color_calibration_name = filename;
|
||||
if (m_transmission_distance_calibration_mode_choice != nullptr)
|
||||
m_transmission_distance_calibration_mode_choice->SetSelection(
|
||||
int(TextureMappingZone::TDCalibrationCalibratedNearestMeasuredSample));
|
||||
if (!td_applied)
|
||||
td_applied = apply_transmission_distances_from_calibration_filaments(side_calibration->filaments);
|
||||
side_changed = true;
|
||||
}
|
||||
} else {
|
||||
m_side_surface_color_calibration_json = json_text;
|
||||
m_side_surface_color_calibration_name = filename;
|
||||
if (m_transmission_distance_calibration_mode_choice != nullptr)
|
||||
m_transmission_distance_calibration_mode_choice->SetSelection(
|
||||
int(TextureMappingZone::TDCalibrationCalibratedNearestMeasuredSample));
|
||||
bool td_applied = apply_transmission_distances_from_calibration_filaments(side_calibration->filaments);
|
||||
side_changed = true;
|
||||
if (top_calibration && m_top_surface_color_calibration_json.empty()) {
|
||||
m_top_surface_color_calibration_json = json_text;
|
||||
m_top_surface_color_calibration_name = filename;
|
||||
rebuild_top_surface_contoning_color_prediction_choices(preferred_top_surface_color_calibration_mode());
|
||||
if (!td_applied)
|
||||
td_applied = apply_transmission_distances_from_calibration_filaments(top_calibration->filaments);
|
||||
top_changed = true;
|
||||
}
|
||||
}
|
||||
update_top_surface_color_calibration_label();
|
||||
update_top_surface_image_options_visibility(true);
|
||||
update_side_surface_color_calibration_label();
|
||||
if (top_changed)
|
||||
update_top_surface_image_options_visibility(true);
|
||||
if (side_changed)
|
||||
update_strength_offsets_visibility(true);
|
||||
}
|
||||
|
||||
void load_top_surface_color_calibration()
|
||||
{
|
||||
load_surface_color_calibration(CalibrationSurface::Top);
|
||||
}
|
||||
|
||||
void load_side_surface_color_calibration()
|
||||
{
|
||||
load_surface_color_calibration(CalibrationSurface::Side);
|
||||
}
|
||||
|
||||
void clear_top_surface_color_calibration()
|
||||
@@ -4725,6 +4890,19 @@ private:
|
||||
update_top_surface_image_options_visibility(true);
|
||||
}
|
||||
|
||||
void clear_side_surface_color_calibration()
|
||||
{
|
||||
m_side_surface_color_calibration_name.clear();
|
||||
m_side_surface_color_calibration_json.clear();
|
||||
if (m_transmission_distance_calibration_mode_choice != nullptr &&
|
||||
transmission_distance_calibration_mode() == int(TextureMappingZone::TDCalibrationCalibratedNearestMeasuredSample)) {
|
||||
m_transmission_distance_calibration_mode_choice->SetSelection(
|
||||
TextureMappingZone::DefaultTransmissionDistanceCalibrationMode);
|
||||
}
|
||||
update_side_surface_color_calibration_label();
|
||||
update_strength_offsets_visibility(true);
|
||||
}
|
||||
|
||||
void reset_strengths_and_offsets()
|
||||
{
|
||||
for (wxSlider *slider : m_minimum_offset_sliders)
|
||||
@@ -4773,6 +4951,22 @@ private:
|
||||
m_strength_offsets_toggle_button->SetLabel(m_strength_offsets_expanded ?
|
||||
_L("Hide Filament Strengths and Offsets") :
|
||||
_L("Show Filament Strengths and Offsets"));
|
||||
const bool manual_controls_enabled =
|
||||
transmission_distance_calibration_mode() != int(TextureMappingZone::TDCalibrationCalibratedNearestMeasuredSample);
|
||||
for (wxSlider *slider : m_minimum_offset_sliders)
|
||||
if (slider)
|
||||
slider->Enable(manual_controls_enabled);
|
||||
for (wxSpinCtrl *spin : m_minimum_offset_spins)
|
||||
if (spin)
|
||||
spin->Enable(manual_controls_enabled);
|
||||
for (wxSlider *slider : m_strength_sliders)
|
||||
if (slider)
|
||||
slider->Enable(manual_controls_enabled);
|
||||
for (wxSpinCtrl *spin : m_strength_spins)
|
||||
if (spin)
|
||||
spin->Enable(manual_controls_enabled);
|
||||
if (m_strength_offsets_reset_button != nullptr)
|
||||
m_strength_offsets_reset_button->Enable(manual_controls_enabled);
|
||||
if (m_strength_offsets_panel != nullptr)
|
||||
m_strength_offsets_panel->Show(m_strength_offsets_expanded);
|
||||
if (!fit_dialog)
|
||||
@@ -5531,6 +5725,8 @@ private:
|
||||
wxCheckBox *m_top_surface_contoning_surface_scatter_checkbox {nullptr};
|
||||
wxChoice *m_top_surface_contoning_td_correction_choice {nullptr};
|
||||
std::vector<int> m_top_surface_contoning_color_prediction_modes;
|
||||
wxStaticText *m_filament_top_surface_color_calibration_label {nullptr};
|
||||
wxStaticText *m_side_surface_color_calibration_label {nullptr};
|
||||
wxStaticText *m_top_surface_color_calibration_label {nullptr};
|
||||
wxStaticText *m_top_surface_color_calibration_warning_text {nullptr};
|
||||
wxButton *m_set_filament_colors_from_calibration_button {nullptr};
|
||||
@@ -5560,11 +5756,14 @@ private:
|
||||
std::function<bool(const std::vector<std::string>&)> m_apply_filament_colors;
|
||||
std::string m_top_surface_color_calibration_name;
|
||||
std::string m_top_surface_color_calibration_json;
|
||||
std::string m_side_surface_color_calibration_name;
|
||||
std::string m_side_surface_color_calibration_json;
|
||||
std::vector<wxSlider*> m_minimum_offset_sliders;
|
||||
std::vector<wxSpinCtrl*> m_minimum_offset_spins;
|
||||
std::vector<wxSlider*> m_strength_sliders;
|
||||
std::vector<wxSpinCtrl*> m_strength_spins;
|
||||
std::vector<wxSpinCtrlDouble*> m_transmission_distance_spins;
|
||||
wxButton *m_strength_offsets_reset_button {nullptr};
|
||||
bool m_strength_offsets_expanded {false};
|
||||
};
|
||||
|
||||
@@ -10650,6 +10849,8 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
updated.top_surface_contoning_variable_layer_height_compensation_enabled,
|
||||
updated.top_surface_color_calibration_name,
|
||||
updated.top_surface_color_calibration_json,
|
||||
updated.side_surface_color_calibration_name,
|
||||
updated.side_surface_color_calibration_json,
|
||||
apply_filament_colors_from_calibration,
|
||||
shell_usage,
|
||||
bundle->texture_mapping_zones,
|
||||
@@ -10762,6 +10963,10 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
dlg.top_surface_color_calibration_name();
|
||||
updated.top_surface_color_calibration_json =
|
||||
dlg.top_surface_color_calibration_json();
|
||||
updated.side_surface_color_calibration_name =
|
||||
dlg.side_surface_color_calibration_name();
|
||||
updated.side_surface_color_calibration_json =
|
||||
dlg.side_surface_color_calibration_json();
|
||||
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