Warn if loaded raw offset atlas uses different min/max line widths than the slicer is using
This commit is contained in:
@@ -102,6 +102,41 @@ static std::string standard_hex_for_color_code(const std::string &color)
|
||||
return "#FFFFFF";
|
||||
}
|
||||
|
||||
static ImageMapRawExpectedLineWidth expected_line_width_from_json(const nlohmann::json &root)
|
||||
{
|
||||
ImageMapRawExpectedLineWidth expected;
|
||||
const auto it = root.find("expected_line_width_mm");
|
||||
if (it == root.end() || !it->is_object())
|
||||
return expected;
|
||||
const nlohmann::json &entry = *it;
|
||||
const auto min_it = entry.find("min");
|
||||
const auto max_it = entry.find("max");
|
||||
if (min_it == entry.end() || max_it == entry.end() || !min_it->is_number() || !max_it->is_number())
|
||||
return expected;
|
||||
expected.min_mm = min_it->get<double>();
|
||||
expected.max_mm = max_it->get<double>();
|
||||
if (!std::isfinite(expected.min_mm) || !std::isfinite(expected.max_mm) || expected.min_mm <= 0.0 || expected.max_mm <= 0.0 ||
|
||||
expected.max_mm < expected.min_mm) {
|
||||
expected = {};
|
||||
return expected;
|
||||
}
|
||||
const auto warn_it = entry.find("warn_if_differs");
|
||||
expected.warn_if_differs = warn_it != entry.end() && warn_it->is_boolean() ? warn_it->get<bool>() : false;
|
||||
expected.valid = true;
|
||||
return expected;
|
||||
}
|
||||
|
||||
static ImageMapRawExpectedLineWidth expected_line_width_from_metadata_json(const std::string &metadata_json)
|
||||
{
|
||||
try {
|
||||
const nlohmann::json root = nlohmann::json::parse(metadata_json);
|
||||
if (root.is_object())
|
||||
return expected_line_width_from_json(root);
|
||||
} catch (...) {
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static nlohmann::json atlas_metadata_json(const ImageMapRawFilamentOffsetAtlas &atlas, uint32_t header_rows)
|
||||
{
|
||||
const uint32_t region_count = (atlas.channels + 2u) / 3u;
|
||||
@@ -121,6 +156,15 @@ static nlohmann::json atlas_metadata_json(const ImageMapRawFilamentOffsetAtlas &
|
||||
entry["hex"] = filament.hex;
|
||||
root["filaments"].push_back(std::move(entry));
|
||||
}
|
||||
const ImageMapRawExpectedLineWidth expected =
|
||||
atlas.expected_line_width_mm.valid ? atlas.expected_line_width_mm : expected_line_width_from_metadata_json(atlas.metadata_json);
|
||||
if (expected.valid) {
|
||||
root["expected_line_width_mm"] = {
|
||||
{ "min", expected.min_mm },
|
||||
{ "max", expected.max_mm },
|
||||
{ "warn_if_differs", expected.warn_if_differs }
|
||||
};
|
||||
}
|
||||
root["regions"] = nlohmann::json::array();
|
||||
for (uint32_t region_idx = 0; region_idx < region_count; ++region_idx) {
|
||||
nlohmann::json channels = nlohmann::json::object();
|
||||
@@ -237,6 +281,11 @@ std::vector<ImageMapRawFilament> image_map_raw_filaments_from_metadata_json(cons
|
||||
return image_map_raw_filaments_for_channels(filaments, channels);
|
||||
}
|
||||
|
||||
ImageMapRawExpectedLineWidth image_map_raw_expected_line_width_from_metadata_json(const std::string &metadata_json)
|
||||
{
|
||||
return expected_line_width_from_metadata_json(metadata_json);
|
||||
}
|
||||
|
||||
std::vector<std::string> image_map_raw_filament_channel_keys(const std::vector<ImageMapRawFilament> &filaments)
|
||||
{
|
||||
std::vector<std::string> keys;
|
||||
@@ -320,6 +369,7 @@ bool decode_image_map_raw_filament_offset_atlas(const std::vector<uint8_t> &rgba
|
||||
decoded.offsets.assign(size_t(decoded.width) * size_t(decoded.height) * size_t(decoded.channels), 0);
|
||||
decoded.mask.assign(size_t(decoded.width) * size_t(decoded.height), 255);
|
||||
decoded.metadata_json = metadata;
|
||||
decoded.expected_line_width_mm = expected_line_width_from_json(root);
|
||||
|
||||
const nlohmann::json filaments = root.value("filaments", nlohmann::json::array());
|
||||
if (filaments.is_array()) {
|
||||
|
||||
@@ -15,6 +15,14 @@ struct ImageMapRawFilament
|
||||
std::string hex;
|
||||
};
|
||||
|
||||
struct ImageMapRawExpectedLineWidth
|
||||
{
|
||||
double min_mm { 0.0 };
|
||||
double max_mm { 0.0 };
|
||||
bool warn_if_differs { false };
|
||||
bool valid { false };
|
||||
};
|
||||
|
||||
struct ImageMapRawFilamentOffsetAtlas
|
||||
{
|
||||
uint32_t width { 0 };
|
||||
@@ -24,6 +32,7 @@ struct ImageMapRawFilamentOffsetAtlas
|
||||
std::vector<uint8_t> offsets;
|
||||
std::vector<uint8_t> mask;
|
||||
std::string metadata_json;
|
||||
ImageMapRawExpectedLineWidth expected_line_width_mm;
|
||||
|
||||
bool valid() const;
|
||||
};
|
||||
@@ -50,6 +59,8 @@ std::vector<ImageMapRawFilament> image_map_raw_filaments_for_channels(const std:
|
||||
std::vector<ImageMapRawFilament> image_map_raw_filaments_from_metadata_json(const std::string &metadata_json,
|
||||
uint32_t channels);
|
||||
|
||||
ImageMapRawExpectedLineWidth image_map_raw_expected_line_width_from_metadata_json(const std::string &metadata_json);
|
||||
|
||||
std::vector<std::string> image_map_raw_filament_channel_keys(const std::vector<ImageMapRawFilament> &filaments);
|
||||
|
||||
std::vector<uint8_t> image_map_raw_filament_offset_preview_rgba(const ImageMapRawFilamentOffsetAtlas &atlas);
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
|
||||
#include <tbb/parallel_for.h>
|
||||
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "ElephantFootCompensation.hpp"
|
||||
#include "ImageMapRawFilamentOffsetAtlas.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "Layer.hpp"
|
||||
#include "MultiMaterialSegmentation.hpp"
|
||||
@@ -169,6 +173,99 @@ static std::vector<std::string> collect_texture_mapping_outer_wall_gradient_line
|
||||
return warnings;
|
||||
}
|
||||
|
||||
static bool model_volume_has_raw_offset_texture_data(const ModelVolume *volume)
|
||||
{
|
||||
return volume != nullptr &&
|
||||
volume->imported_texture_width > 0 &&
|
||||
volume->imported_texture_height > 0 &&
|
||||
volume->imported_texture_raw_channels > 0 &&
|
||||
volume->imported_texture_raw_filament_offsets.size() >=
|
||||
size_t(volume->imported_texture_width) *
|
||||
size_t(volume->imported_texture_height) *
|
||||
size_t(volume->imported_texture_raw_channels);
|
||||
}
|
||||
|
||||
static std::string format_texture_mapping_line_width_mm(double value)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << std::fixed << std::setprecision(3) << value;
|
||||
std::string formatted = stream.str();
|
||||
while (formatted.size() > 1 && formatted.back() == '0')
|
||||
formatted.pop_back();
|
||||
if (!formatted.empty() && formatted.back() == '.')
|
||||
formatted.pop_back();
|
||||
return formatted + " mm";
|
||||
}
|
||||
|
||||
static bool texture_mapping_line_width_differs(double lhs, double rhs)
|
||||
{
|
||||
return std::abs(lhs - rhs) > 0.001;
|
||||
}
|
||||
|
||||
static std::vector<std::string> collect_texture_mapping_raw_atlas_line_width_warnings(const PrintObject &print_object)
|
||||
{
|
||||
const Print *print = print_object.print();
|
||||
if (print == nullptr)
|
||||
return {};
|
||||
|
||||
const ModelObject *model_object = print_object.model_object();
|
||||
if (model_object == nullptr)
|
||||
return {};
|
||||
|
||||
const double active_max_line_width_mm =
|
||||
std::max(0.05, print->config().texture_mapping_outer_wall_gradient_max_line_width.value);
|
||||
const double active_min_line_width_mm =
|
||||
std::clamp(print->config().texture_mapping_outer_wall_gradient_min_line_width.value, 0.05, active_max_line_width_mm);
|
||||
|
||||
std::vector<std::string> warnings;
|
||||
std::set<std::string> seen;
|
||||
for (const ModelVolume *volume : model_object->volumes) {
|
||||
if (!model_volume_has_raw_offset_texture_data(volume))
|
||||
continue;
|
||||
|
||||
const ImageMapRawExpectedLineWidth expected =
|
||||
image_map_raw_expected_line_width_from_metadata_json(volume->imported_texture_raw_metadata_json);
|
||||
if (!expected.valid || !expected.warn_if_differs)
|
||||
continue;
|
||||
if (!texture_mapping_line_width_differs(active_min_line_width_mm, expected.min_mm) &&
|
||||
!texture_mapping_line_width_differs(active_max_line_width_mm, expected.max_mm))
|
||||
continue;
|
||||
|
||||
const std::vector<int> used_extruders = volume->get_extruders();
|
||||
for (const int filament_id : used_extruders) {
|
||||
if (filament_id <= 0)
|
||||
continue;
|
||||
|
||||
const unsigned int filament_id_u = unsigned(filament_id);
|
||||
const TextureMappingZone *zone = print->texture_mapping_manager().zone_from_id(filament_id_u);
|
||||
if (zone == nullptr ||
|
||||
!zone->enabled ||
|
||||
zone->deleted ||
|
||||
!zone->is_image_texture() ||
|
||||
zone->texture_mapping_mode != int(TextureMappingZone::TextureMappingRawValues))
|
||||
continue;
|
||||
|
||||
std::ostringstream key_stream;
|
||||
key_stream << filament_id_u << "|" << std::fixed << std::setprecision(3) << expected.min_mm << "|" << expected.max_mm;
|
||||
const std::string key = key_stream.str();
|
||||
if (!seen.insert(key).second)
|
||||
continue;
|
||||
|
||||
warnings.emplace_back(
|
||||
L("Texture mapping zone ") + std::to_string(filament_id_u) +
|
||||
L(" uses a raw filament offset atlas authored for line widths ") +
|
||||
format_texture_mapping_line_width_mm(expected.min_mm) + " - " +
|
||||
format_texture_mapping_line_width_mm(expected.max_mm) +
|
||||
L(", but current texture mapping settings use ") +
|
||||
format_texture_mapping_line_width_mm(active_min_line_width_mm) + " - " +
|
||||
format_texture_mapping_line_width_mm(active_max_line_width_mm) +
|
||||
L(". Update the texture mapping minimum/maximum outer wall line width or regenerate the raw offset atlas."));
|
||||
}
|
||||
}
|
||||
|
||||
return warnings;
|
||||
}
|
||||
|
||||
static std::vector<std::string> collect_texture_mapping_vertex_color_match_warnings(const PrintObject &print_object)
|
||||
{
|
||||
const Print *print = print_object.print();
|
||||
@@ -1467,6 +1564,8 @@ void PrintObject::slice_volumes()
|
||||
this->apply_conical_overhang();
|
||||
for (const std::string &warning_msg : collect_texture_mapping_outer_wall_gradient_line_width_warnings(*this))
|
||||
this->active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL, warning_msg);
|
||||
for (const std::string &warning_msg : collect_texture_mapping_raw_atlas_line_width_warnings(*this))
|
||||
this->active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL, warning_msg);
|
||||
for (const std::string &warning_msg : collect_texture_mapping_vertex_color_match_warnings(*this))
|
||||
this->active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL, warning_msg);
|
||||
for (const std::string &warning_msg : collect_texture_mapping_filament_color_match_warnings(*this))
|
||||
|
||||
Reference in New Issue
Block a user