Update G-code modulation to use shared TextureMappingOffset code
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
#include "ShortestPath.hpp"
|
||||
#include "Print.hpp"
|
||||
#include "TextureMapping.hpp"
|
||||
#include "TextureMappingOffset.hpp"
|
||||
#include "ColorSolver.hpp"
|
||||
#include "ImageMapRawFilamentOffsetAtlas.hpp"
|
||||
#include "TriangleSelector.hpp"
|
||||
@@ -5649,30 +5650,6 @@ static std::unique_ptr<EdgeGrid::Grid> calculate_layer_edge_grid(const Layer& la
|
||||
return out;
|
||||
}
|
||||
|
||||
static std::vector<unsigned int> decode_offset_component_ids_for_gcode(const TextureMappingZone &zone, size_t num_physical)
|
||||
{
|
||||
std::vector<unsigned int> out;
|
||||
for (const char c : zone.component_ids) {
|
||||
if (c < '1' || c > '9')
|
||||
continue;
|
||||
const unsigned int id = unsigned(c - '0');
|
||||
if (id == 0 || id > num_physical)
|
||||
continue;
|
||||
if (std::find(out.begin(), out.end(), id) == out.end())
|
||||
out.emplace_back(id);
|
||||
}
|
||||
|
||||
if (out.empty()) {
|
||||
if (zone.component_a >= 1 && zone.component_a <= num_physical)
|
||||
out.emplace_back(zone.component_a);
|
||||
if (zone.component_b >= 1 && zone.component_b <= num_physical &&
|
||||
std::find(out.begin(), out.end(), zone.component_b) == out.end()) {
|
||||
out.emplace_back(zone.component_b);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static float normalize_angle_deg_for_gcode(float angle)
|
||||
{
|
||||
float normalized = std::fmod(angle, 360.f);
|
||||
@@ -5998,62 +5975,11 @@ static float repeated_rotation_progress_for_gcode(float progress01, float repeat
|
||||
return clamp01f_for_gcode(local);
|
||||
}
|
||||
|
||||
static float offset_fade_factor_for_gcode(int fade_mode, float progress01)
|
||||
{
|
||||
const float p = clamp01f_for_gcode(progress01);
|
||||
switch (fade_mode) {
|
||||
case int(TextureMappingZone::OffsetFadeInUp):
|
||||
return p;
|
||||
case int(TextureMappingZone::OffsetFadeOutUp):
|
||||
return 1.f - p;
|
||||
case int(TextureMappingZone::OffsetFadeInOut):
|
||||
return 1.f - std::abs(2.f * p - 1.f);
|
||||
case int(TextureMappingZone::OffsetFadeOutIn):
|
||||
return std::abs(2.f * p - 1.f);
|
||||
case int(TextureMappingZone::OffsetFadeOutInReversed):
|
||||
return 2.f * p - 1.f;
|
||||
default:
|
||||
return 1.f;
|
||||
}
|
||||
}
|
||||
|
||||
static bool has_explicit_offset_gradient_profile_for_gcode(const TextureMappingZone &zone)
|
||||
{
|
||||
return zone.has_custom_offset_settings();
|
||||
}
|
||||
|
||||
static float overhang_filament_strength_factor_for_gcode(const TextureMappingZone &zone, unsigned int physical_filament_id)
|
||||
{
|
||||
if (physical_filament_id == 0)
|
||||
return 1.f;
|
||||
|
||||
const size_t idx = size_t(physical_filament_id - 1);
|
||||
if (idx >= zone.filament_strengths_pct.size())
|
||||
return 1.f;
|
||||
|
||||
const float strength_pct = zone.filament_strengths_pct[idx];
|
||||
if (!std::isfinite(strength_pct))
|
||||
return 1.f;
|
||||
|
||||
return std::clamp(strength_pct / 100.f, 0.f, 1.f);
|
||||
}
|
||||
|
||||
static float overhang_filament_minimum_offset_factor_for_gcode(const TextureMappingZone &zone, unsigned int physical_filament_id)
|
||||
{
|
||||
if (physical_filament_id == 0)
|
||||
return 0.f;
|
||||
|
||||
const size_t idx = size_t(physical_filament_id - 1);
|
||||
if (idx >= zone.filament_minimum_offsets_pct.size())
|
||||
return 0.f;
|
||||
|
||||
const float minimum_offset_pct = zone.filament_minimum_offsets_pct[idx];
|
||||
if (!std::isfinite(minimum_offset_pct))
|
||||
return 0.f;
|
||||
|
||||
return std::clamp(minimum_offset_pct / 100.f, 0.f, 1.f);
|
||||
}
|
||||
|
||||
struct TransmissionDistanceCalibrationContextForGCode {
|
||||
bool enabled { false };
|
||||
int mode { int(TextureMappingZone::TDCalibrationNone) };
|
||||
@@ -9148,7 +9074,7 @@ std::optional<PreferredSeamPoint> GCode::texture_mapping_seam_hiding_hint(const
|
||||
if (layer_object == nullptr || object_layer_count <= 0 || (upper_layer == nullptr && lower_layer == nullptr))
|
||||
return std::nullopt;
|
||||
|
||||
std::vector<unsigned int> component_ids = decode_offset_component_ids_for_gcode(*zone, num_physical);
|
||||
std::vector<unsigned int> component_ids = decode_texture_mapping_offset_component_ids(*zone, num_physical);
|
||||
if (vertex_color_match_mode) {
|
||||
const std::vector<unsigned int> effective_component_ids =
|
||||
TextureMappingManager::effective_texture_component_ids(*zone, num_physical, m_config.filament_colour.values);
|
||||
@@ -9310,7 +9236,7 @@ std::optional<PreferredSeamPoint> GCode::texture_mapping_seam_hiding_hint(const
|
||||
}
|
||||
|
||||
const float signed_fade_factor =
|
||||
offset_fade_factor_for_gcode(zone->offset_fade_mode, z_progress);
|
||||
texture_mapping_offset_fade_factor(zone->offset_fade_mode, z_progress);
|
||||
const float fade_factor = std::abs(signed_fade_factor);
|
||||
if (fade_factor <= EPSILON)
|
||||
return std::nullopt;
|
||||
@@ -9322,8 +9248,8 @@ std::optional<PreferredSeamPoint> GCode::texture_mapping_seam_hiding_hint(const
|
||||
active_component_id,
|
||||
active_component_idx,
|
||||
weight_field,
|
||||
overhang_filament_strength_factor_for_gcode(*zone, active_component_id),
|
||||
overhang_filament_minimum_offset_factor_for_gcode(*zone, active_component_id),
|
||||
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),
|
||||
signed_fade_factor,
|
||||
fade_factor
|
||||
@@ -10450,29 +10376,18 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
bool enabled { false };
|
||||
bool vertex_color_match_mode { false };
|
||||
bool high_resolution_texture_sampling { false };
|
||||
bool nonlinear_offset_adjustment { false };
|
||||
bool compact_offset_mode { false };
|
||||
bool object_center_mode { false };
|
||||
Point object_center;
|
||||
unsigned int active_component_id { 0 };
|
||||
size_t active_component_idx { size_t(-1) };
|
||||
const VertexColorOverhangWeightField *vertex_color_weight_field { nullptr };
|
||||
std::vector<unsigned int> component_ids;
|
||||
std::vector<float> component_distances_mm;
|
||||
std::vector<float> rotated_angles;
|
||||
float inset_strength_reference_mm { 0.f };
|
||||
float fade_factor { 0.f };
|
||||
float signed_fade_factor { 1.f };
|
||||
float max_width_delta_mm { 0.f };
|
||||
float active_component_strength_factor { 1.f };
|
||||
float active_component_minimum_offset_factor { 0.f };
|
||||
float active_component_td_width_factor { 1.f };
|
||||
float base_outer_width_mm { 0.4f };
|
||||
float flow_reference_width_mm { 0.4f };
|
||||
float base_centerline_shift_mm { 0.f };
|
||||
float centerline_shift_balance_mm { 0.f };
|
||||
float centerline_shift_balance_weight_scale { 0.f };
|
||||
float layer_height_mm { 0.2f };
|
||||
TextureMappingOffsetContext offset_context;
|
||||
};
|
||||
|
||||
if (is_bridge(path.role()))
|
||||
@@ -10517,7 +10432,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
(vertex_color_match_mode ||
|
||||
is_2d_offset_gradient_row_for_gcode(*zone) ||
|
||||
has_explicit_offset_gradient_profile_for_gcode(*zone))) {
|
||||
std::vector<unsigned int> component_ids = decode_offset_component_ids_for_gcode(*zone, num_physical);
|
||||
std::vector<unsigned int> component_ids = decode_texture_mapping_offset_component_ids(*zone, num_physical);
|
||||
if (vertex_color_match_mode) {
|
||||
if (!m_warned_texture_mapping_filament_count_mismatch &&
|
||||
TextureMappingManager::component_count_mismatch(*zone, num_physical)) {
|
||||
@@ -10577,51 +10492,15 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
std::accumulate(reference_nozzles.begin(), reference_nozzles.end(), 0.f) / float(reference_nozzles.size());
|
||||
const float max_allowed_distance_mm = TextureMappingManager::max_component_surface_offset_mm(reference_nozzle);
|
||||
|
||||
std::vector<float> distances_mm = TextureMappingManager::effective_offset_distances(*zone, component_ids.size(), reference_nozzle);
|
||||
std::vector<float> angles_deg = TextureMappingManager::effective_offset_angles(*zone, component_ids.size());
|
||||
if (distances_mm.size() != component_ids.size())
|
||||
distances_mm.assign(component_ids.size(), 0.f);
|
||||
if (angles_deg.size() != component_ids.size())
|
||||
angles_deg = TextureMappingManager::default_offset_angles(component_ids.size());
|
||||
for (float &a : angles_deg)
|
||||
a = normalize_angle_deg_for_gcode(a);
|
||||
|
||||
bool has_nonzero_distance = false;
|
||||
if (vertex_color_match_mode) {
|
||||
distances_mm.assign(component_ids.size(), max_allowed_distance_mm);
|
||||
has_nonzero_distance = max_allowed_distance_mm > EPSILON;
|
||||
} else {
|
||||
for (float &d : distances_mm) {
|
||||
d = std::clamp(d, 0.f, max_allowed_distance_mm);
|
||||
has_nonzero_distance = has_nonzero_distance || (d > EPSILON);
|
||||
}
|
||||
}
|
||||
|
||||
if (has_nonzero_distance) {
|
||||
if (max_allowed_distance_mm > EPSILON) {
|
||||
const PrintObject *layer_object = m_layer ? m_layer->object() : nullptr;
|
||||
const int object_layer_count = layer_object ? int(layer_object->layer_count()) : 0;
|
||||
const int current_layer_index = m_layer ? int(m_layer->id()) : 0;
|
||||
const float z_progress = object_layer_count > 1 ?
|
||||
std::clamp(float(current_layer_index) / float(object_layer_count - 1), 0.f, 1.f) : 0.f;
|
||||
|
||||
float rotation_deg = 0.f;
|
||||
if (zone->offset_rotation_enabled) {
|
||||
const float repeated = repeated_rotation_progress_for_gcode(z_progress, std::max(1.f, zone->offset_repeats), zone->offset_reverse_repeats);
|
||||
const float direction = zone->offset_clockwise ? -1.f : 1.f;
|
||||
rotation_deg = direction * 360.f * zone->offset_rotations * repeated;
|
||||
}
|
||||
|
||||
const float signed_fade_factor = offset_fade_factor_for_gcode(zone->offset_fade_mode, z_progress);
|
||||
const float signed_fade_factor = texture_mapping_offset_fade_factor(zone->offset_fade_mode, z_progress);
|
||||
const float fade_factor = std::abs(signed_fade_factor);
|
||||
|
||||
std::vector<float> rotated_angles = angles_deg;
|
||||
for (float &a : rotated_angles)
|
||||
a = normalize_angle_deg_for_gcode(a + rotation_deg);
|
||||
|
||||
const size_t active_component_idx = size_t(active_component_it - component_ids.begin());
|
||||
const float active_component_strength_factor = overhang_filament_strength_factor_for_gcode(*zone, active_component_id);
|
||||
const float active_component_minimum_offset_factor = overhang_filament_minimum_offset_factor_for_gcode(*zone, active_component_id);
|
||||
const float max_component_distance_mm = *std::max_element(distances_mm.begin(), distances_mm.end());
|
||||
const float path_outer_width_mm = std::max(
|
||||
0.01f,
|
||||
path.width > EPSILON ? path.width : float(m_config.outer_wall_line_width.get_abs_value(reference_nozzle)));
|
||||
@@ -10652,136 +10531,23 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
const bool object_center_mode =
|
||||
!vertex_color_match_mode &&
|
||||
zone->offset_angle_mode != int(TextureMappingZone::OffsetAngleSurfaceNormal);
|
||||
const bool use_layer_aware_weighting = m_layer != nullptr;
|
||||
const bool high_resolution_texture_sampling = zone->high_resolution_sampling;
|
||||
const bool high_speed_image_texture_sampling = zone->high_speed_image_texture_sampling;
|
||||
const bool nonlinear_offset_adjustment = zone->nonlinear_offset_adjustment;
|
||||
const bool compact_offset_mode = zone->compact_offset_mode;
|
||||
const float layer_sample_z_mm = use_layer_aware_weighting ? float(m_layer->print_z) : 0.f;
|
||||
const float layer_sample_falloff_mm = high_resolution_texture_sampling ?
|
||||
std::max(0.03f, layer_height_mm * 0.5f) :
|
||||
std::max(0.12f, layer_height_mm * 1.5f);
|
||||
const int texture_filament_color_mode = std::clamp(
|
||||
zone->filament_color_mode,
|
||||
int(TextureMappingZone::FilamentColorAny),
|
||||
int(TextureMappingZone::FilamentColorRGBKW));
|
||||
const bool texture_force_sequential_filaments = zone->force_sequential_filaments;
|
||||
const int generic_solver_lookup_mode = std::clamp(zone->generic_solver_lookup_mode,
|
||||
int(TextureMappingZone::GenericSolverClosestMix),
|
||||
int(TextureMappingZone::GenericSolverBlendClosestTwo));
|
||||
const int generic_solver_mode = std::clamp(zone->generic_solver_mode,
|
||||
int(TextureMappingZone::GenericSolverLegacy),
|
||||
int(TextureMappingZone::GenericSolverV2));
|
||||
const int generic_solver_mix_model = TextureMappingZone::DefaultGenericSolverMixModel;
|
||||
const bool use_legacy_fixed_color_mode = zone->use_legacy_fixed_color_mode;
|
||||
const float texture_contrast_pct = std::clamp(zone->contrast_pct, 25.f, 300.f);
|
||||
const float texture_tone_gamma =
|
||||
(!std::isfinite(zone->tone_gamma) || zone->tone_gamma <= 0.f) ?
|
||||
1.f :
|
||||
std::clamp(zone->tone_gamma, 0.5f, 3.f);
|
||||
const bool reduce_outer_surface_texture =
|
||||
vertex_color_match_mode && zone->reduce_outer_surface_texture && !compact_offset_mode;
|
||||
|
||||
const bool raw_texture_mapping_mode =
|
||||
zone->texture_mapping_mode == int(TextureMappingZone::TextureMappingRawValues);
|
||||
std::vector<std::array<float, 3>> component_colors;
|
||||
component_colors.reserve(component_ids.size());
|
||||
bool missing_component_color = false;
|
||||
for (const unsigned int id : component_ids) {
|
||||
if (id < 1 || id > m_config.filament_colour.values.size()) {
|
||||
if (raw_texture_mapping_mode)
|
||||
component_colors.push_back({ 0.f, 0.f, 0.f });
|
||||
else
|
||||
missing_component_color = true;
|
||||
continue;
|
||||
}
|
||||
ColorRGB decoded;
|
||||
if (!decode_color(m_config.filament_colour.get_at(size_t(id - 1)), decoded)) {
|
||||
if (raw_texture_mapping_mode)
|
||||
component_colors.push_back({ 0.f, 0.f, 0.f });
|
||||
else
|
||||
missing_component_color = true;
|
||||
continue;
|
||||
}
|
||||
component_colors.push_back({ decoded.r(), decoded.g(), decoded.b() });
|
||||
std::optional<TextureMappingOffsetContext> offset_context;
|
||||
if (layer_object != nullptr && m_layer != nullptr) {
|
||||
offset_context = build_texture_mapping_offset_context_for_layer(*layer_object,
|
||||
*m_layer,
|
||||
*zone,
|
||||
texture_zone_id,
|
||||
active_component_id,
|
||||
base_outer_width_mm,
|
||||
layer_height_mm);
|
||||
}
|
||||
const TransmissionDistanceCalibrationContextForGCode td_calibration_context =
|
||||
transmission_distance_calibration_context_for_gcode(*zone,
|
||||
component_ids,
|
||||
component_colors,
|
||||
texture_filament_color_mode);
|
||||
size_t previous_component_idx = size_t(-1);
|
||||
if (current_layer_index > 0) {
|
||||
const unsigned int previous_component_id =
|
||||
texture_mgr.resolve_zone_component(texture_zone_id, num_physical, current_layer_index - 1);
|
||||
const auto previous_component_it =
|
||||
std::find(component_ids.begin(), component_ids.end(), previous_component_id);
|
||||
if (previous_component_it != component_ids.end())
|
||||
previous_component_idx = size_t(previous_component_it - component_ids.begin());
|
||||
}
|
||||
const float active_component_td_width_factor =
|
||||
transmission_distance_width_factor_for_gcode(td_calibration_context,
|
||||
active_component_idx,
|
||||
previous_component_idx);
|
||||
|
||||
const VertexColorOverhangWeightField *vertex_color_weight_field = nullptr;
|
||||
auto *generic_mix_candidate_cache = &m_generic_solver_mix_candidate_cache;
|
||||
if (vertex_color_match_mode && layer_object != nullptr) {
|
||||
if (!missing_component_color && component_colors.size() == component_ids.size() && !component_colors.empty()) {
|
||||
std::ostringstream component_key_stream;
|
||||
for (size_t idx = 0; idx < component_ids.size(); ++idx) {
|
||||
if (idx > 0)
|
||||
component_key_stream << '/';
|
||||
component_key_stream << component_ids[idx];
|
||||
}
|
||||
component_key_stream << (raw_texture_mapping_mode ? "|raw" : "|blend");
|
||||
component_key_stream << "|fc" << texture_filament_color_mode;
|
||||
component_key_stream << "|fs" << (texture_force_sequential_filaments ? 1 : 0);
|
||||
component_key_stream << "|gl" << generic_solver_lookup_mode;
|
||||
component_key_stream << "|gm" << generic_solver_mode;
|
||||
component_key_stream << "|gx" << generic_solver_mix_model;
|
||||
component_key_stream << "|lf" << (use_legacy_fixed_color_mode ? 1 : 0);
|
||||
component_key_stream << "|ct" << int(std::lround(texture_contrast_pct));
|
||||
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 (m_layer != nullptr)
|
||||
component_key_stream << "|L" << m_layer->id();
|
||||
const auto cache_key = std::make_tuple(layer_object, texture_zone_id, component_key_stream.str());
|
||||
auto cache_it = m_vertex_color_overhang_weight_field_cache.find(cache_key);
|
||||
if (cache_it == m_vertex_color_overhang_weight_field_cache.end()) {
|
||||
cache_it = m_vertex_color_overhang_weight_field_cache
|
||||
.emplace(cache_key,
|
||||
build_vertex_color_weight_field_for_gcode(*layer_object,
|
||||
component_colors,
|
||||
raw_texture_mapping_mode,
|
||||
texture_filament_color_mode,
|
||||
texture_force_sequential_filaments,
|
||||
generic_solver_lookup_mode,
|
||||
generic_solver_mode,
|
||||
generic_solver_mix_model,
|
||||
use_legacy_fixed_color_mode,
|
||||
generic_mix_candidate_cache,
|
||||
&m_uv_texture_triangle_cache,
|
||||
texture_contrast_pct,
|
||||
texture_tone_gamma,
|
||||
use_layer_aware_weighting,
|
||||
layer_sample_z_mm,
|
||||
layer_sample_falloff_mm,
|
||||
high_resolution_texture_sampling,
|
||||
high_speed_image_texture_sampling))
|
||||
.first;
|
||||
}
|
||||
if (!cache_it->second.empty())
|
||||
vertex_color_weight_field = &cache_it->second;
|
||||
}
|
||||
}
|
||||
|
||||
const bool has_vertex_color_weight_field =
|
||||
vertex_color_weight_field != nullptr && !vertex_color_weight_field->empty();
|
||||
|
||||
if (fade_factor > EPSILON && max_component_distance_mm > EPSILON && effective_max_width_delta_mm > EPSILON &&
|
||||
(!vertex_color_match_mode || has_vertex_color_weight_field)) {
|
||||
if (fade_factor > EPSILON && effective_max_width_delta_mm > EPSILON &&
|
||||
offset_context) {
|
||||
Point object_center = layer_object ? layer_object->bounding_box().center() :
|
||||
Point(coord_t((int64_t(path.first_point().x()) + int64_t(path.last_point().x())) / 2),
|
||||
coord_t((int64_t(path.first_point().y()) + int64_t(path.last_point().y())) / 2));
|
||||
@@ -10789,27 +10555,16 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
outer_wall_gradient_dynamic_ctx.enabled = true;
|
||||
outer_wall_gradient_dynamic_ctx.vertex_color_match_mode = vertex_color_match_mode;
|
||||
outer_wall_gradient_dynamic_ctx.high_resolution_texture_sampling = high_resolution_texture_sampling;
|
||||
outer_wall_gradient_dynamic_ctx.nonlinear_offset_adjustment = nonlinear_offset_adjustment;
|
||||
outer_wall_gradient_dynamic_ctx.compact_offset_mode = compact_offset_mode;
|
||||
outer_wall_gradient_dynamic_ctx.object_center_mode = object_center_mode;
|
||||
outer_wall_gradient_dynamic_ctx.object_center = object_center;
|
||||
outer_wall_gradient_dynamic_ctx.active_component_id = active_component_id;
|
||||
outer_wall_gradient_dynamic_ctx.active_component_idx = active_component_idx;
|
||||
outer_wall_gradient_dynamic_ctx.vertex_color_weight_field = vertex_color_weight_field;
|
||||
outer_wall_gradient_dynamic_ctx.component_ids = component_ids;
|
||||
outer_wall_gradient_dynamic_ctx.component_distances_mm = distances_mm;
|
||||
outer_wall_gradient_dynamic_ctx.rotated_angles = rotated_angles;
|
||||
outer_wall_gradient_dynamic_ctx.inset_strength_reference_mm = max_allowed_distance_mm;
|
||||
outer_wall_gradient_dynamic_ctx.fade_factor = fade_factor;
|
||||
outer_wall_gradient_dynamic_ctx.signed_fade_factor = signed_fade_factor;
|
||||
outer_wall_gradient_dynamic_ctx.max_width_delta_mm = effective_max_width_delta_mm;
|
||||
outer_wall_gradient_dynamic_ctx.active_component_strength_factor = active_component_strength_factor;
|
||||
outer_wall_gradient_dynamic_ctx.active_component_minimum_offset_factor = active_component_minimum_offset_factor;
|
||||
outer_wall_gradient_dynamic_ctx.active_component_td_width_factor = active_component_td_width_factor;
|
||||
outer_wall_gradient_dynamic_ctx.base_outer_width_mm = base_outer_width_mm;
|
||||
outer_wall_gradient_dynamic_ctx.flow_reference_width_mm = flow_reference_width_mm;
|
||||
outer_wall_gradient_dynamic_ctx.base_centerline_shift_mm = base_centerline_shift_mm;
|
||||
outer_wall_gradient_dynamic_ctx.layer_height_mm = layer_height_mm;
|
||||
outer_wall_gradient_dynamic_ctx.offset_context = std::move(*offset_context);
|
||||
|
||||
outer_wall_gradient_segment_mods.reserve(path.polyline.points.size() - 1);
|
||||
|
||||
@@ -10863,65 +10618,13 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
double outward_y = 0.0;
|
||||
resolve_segment_shift_outward_normal_for_gcode(m_layer, mid_point, dx, dy, len, radial_x, radial_y, outward_x, outward_y);
|
||||
|
||||
double theta_direction_x = outward_x;
|
||||
double theta_direction_y = outward_y;
|
||||
if (object_center_mode) {
|
||||
const double radial_len = std::hypot(radial_x, radial_y);
|
||||
if (radial_len > EPSILON) {
|
||||
theta_direction_x = radial_x / radial_len;
|
||||
theta_direction_y = radial_y / radial_len;
|
||||
}
|
||||
}
|
||||
|
||||
const float theta_deg = normalize_angle_deg_for_gcode(float(Geometry::rad2deg(std::atan2(theta_direction_y, theta_direction_x))));
|
||||
float inset_strength = 0.f;
|
||||
if (vertex_color_match_mode) {
|
||||
if (vertex_color_weight_field != nullptr &&
|
||||
active_component_idx < component_ids.size() &&
|
||||
!vertex_color_weight_field->empty()) {
|
||||
const float mid_x_mm = 0.5f * (unscale<float>(line.a.x()) + unscale<float>(line.b.x()));
|
||||
const float mid_y_mm = 0.5f * (unscale<float>(line.a.y()) + unscale<float>(line.b.y()));
|
||||
const float desired_strength = sample_vertex_color_weight_field_for_gcode(
|
||||
*vertex_color_weight_field,
|
||||
mid_x_mm,
|
||||
mid_y_mm,
|
||||
active_component_idx,
|
||||
high_resolution_texture_sampling,
|
||||
compact_offset_mode);
|
||||
inset_strength = std::clamp(1.f - desired_strength, 0.f, 1.f);
|
||||
}
|
||||
} else {
|
||||
float raw_inset_mm = 0.f;
|
||||
for (size_t i = 0; i < component_ids.size(); ++i) {
|
||||
if (i == active_component_idx)
|
||||
continue;
|
||||
const float influence = component_angular_influence_for_gcode(component_ids[i],
|
||||
theta_deg,
|
||||
component_ids,
|
||||
rotated_angles);
|
||||
raw_inset_mm += distances_mm[i] * influence;
|
||||
}
|
||||
inset_strength = std::clamp(raw_inset_mm / std::max(max_allowed_distance_mm, float(EPSILON)), 0.f, 1.f);
|
||||
}
|
||||
inset_strength = std::clamp(inset_strength * fade_factor, 0.f, 1.f);
|
||||
const float stair_step_mm = nonlinear_offset_adjustment ?
|
||||
local_surface_stair_step_distance_for_gcode(m_layer,
|
||||
mid_point,
|
||||
outward_x,
|
||||
outward_y,
|
||||
base_outer_width_mm,
|
||||
max_allowed_distance_mm) :
|
||||
std::numeric_limits<float>::quiet_NaN();
|
||||
const float variable_width_delta_mm = variable_width_delta_for_visibility_range_for_gcode(
|
||||
inset_strength,
|
||||
max_width_delta_limit_mm,
|
||||
active_component_minimum_offset_factor,
|
||||
active_component_strength_factor,
|
||||
active_component_td_width_factor,
|
||||
nonlinear_offset_adjustment,
|
||||
layer_height_mm,
|
||||
stair_step_mm);
|
||||
const float width_delta_mm = std::clamp(variable_width_delta_mm, 0.f, max_width_delta_limit_mm);
|
||||
const float width_delta_mm = std::clamp(
|
||||
texture_mapping_offset_surface_inset_mm(outer_wall_gradient_dynamic_ctx.offset_context,
|
||||
mid_point,
|
||||
-outward_x,
|
||||
-outward_y),
|
||||
0.f,
|
||||
max_width_delta_limit_mm);
|
||||
if (!std::isfinite(width_delta_mm) || !std::isfinite(base_outer_width_mm) || !std::isfinite(layer_height_mm)) {
|
||||
outer_wall_gradient_segment_mods.emplace_back(mod);
|
||||
continue;
|
||||
@@ -11599,76 +11302,18 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
outward_x,
|
||||
outward_y);
|
||||
|
||||
double theta_direction_x = outward_x;
|
||||
double theta_direction_y = outward_y;
|
||||
if (outer_wall_gradient_dynamic_ctx.object_center_mode) {
|
||||
const double radial_len = std::hypot(radial_x, radial_y);
|
||||
if (radial_len > EPSILON) {
|
||||
theta_direction_x = radial_x / radial_len;
|
||||
theta_direction_y = radial_y / radial_len;
|
||||
}
|
||||
}
|
||||
|
||||
const float theta_deg = normalize_angle_deg_for_gcode(float(Geometry::rad2deg(std::atan2(theta_direction_y, theta_direction_x))));
|
||||
float inset_strength = 0.f;
|
||||
if (outer_wall_gradient_dynamic_ctx.vertex_color_match_mode) {
|
||||
if (outer_wall_gradient_dynamic_ctx.vertex_color_weight_field != nullptr &&
|
||||
!outer_wall_gradient_dynamic_ctx.vertex_color_weight_field->empty() &&
|
||||
outer_wall_gradient_dynamic_ctx.active_component_idx <
|
||||
outer_wall_gradient_dynamic_ctx.vertex_color_weight_field->component_count) {
|
||||
const float mid_x_mm = 0.5f * (unscale<float>(line.a.x()) + unscale<float>(line.b.x()));
|
||||
const float mid_y_mm = 0.5f * (unscale<float>(line.a.y()) + unscale<float>(line.b.y()));
|
||||
const float desired_strength = sample_vertex_color_weight_field_for_gcode(
|
||||
*outer_wall_gradient_dynamic_ctx.vertex_color_weight_field,
|
||||
mid_x_mm,
|
||||
mid_y_mm,
|
||||
outer_wall_gradient_dynamic_ctx.active_component_idx,
|
||||
outer_wall_gradient_dynamic_ctx.high_resolution_texture_sampling,
|
||||
outer_wall_gradient_dynamic_ctx.compact_offset_mode);
|
||||
inset_strength = std::clamp(1.f - desired_strength, 0.f, 1.f);
|
||||
}
|
||||
} else {
|
||||
float raw_inset_mm = 0.f;
|
||||
const size_t component_count = std::min(outer_wall_gradient_dynamic_ctx.component_ids.size(),
|
||||
outer_wall_gradient_dynamic_ctx.component_distances_mm.size());
|
||||
for (size_t i = 0; i < component_count; ++i) {
|
||||
if (i == outer_wall_gradient_dynamic_ctx.active_component_idx)
|
||||
continue;
|
||||
const float influence = component_angular_influence_for_gcode(outer_wall_gradient_dynamic_ctx.component_ids[i],
|
||||
theta_deg,
|
||||
outer_wall_gradient_dynamic_ctx.component_ids,
|
||||
outer_wall_gradient_dynamic_ctx.rotated_angles);
|
||||
raw_inset_mm += outer_wall_gradient_dynamic_ctx.component_distances_mm[i] * influence;
|
||||
}
|
||||
inset_strength = std::clamp(
|
||||
raw_inset_mm / std::max(outer_wall_gradient_dynamic_ctx.inset_strength_reference_mm, float(EPSILON)),
|
||||
0.f,
|
||||
1.f);
|
||||
}
|
||||
inset_strength = std::clamp(inset_strength * outer_wall_gradient_dynamic_ctx.fade_factor, 0.f, 1.f);
|
||||
float max_width_delta_limit_mm = std::min(
|
||||
outer_wall_gradient_dynamic_ctx.max_width_delta_mm,
|
||||
2.f * outer_wall_gradient_dynamic_ctx.inset_strength_reference_mm);
|
||||
if (!std::isfinite(max_width_delta_limit_mm) || max_width_delta_limit_mm <= EPSILON)
|
||||
return OuterWallGradientSegmentMod{};
|
||||
const float stair_step_mm = outer_wall_gradient_dynamic_ctx.nonlinear_offset_adjustment ?
|
||||
local_surface_stair_step_distance_for_gcode(surface_layer,
|
||||
mid_point,
|
||||
outward_x,
|
||||
outward_y,
|
||||
outer_wall_gradient_dynamic_ctx.base_outer_width_mm,
|
||||
outer_wall_gradient_dynamic_ctx.inset_strength_reference_mm) :
|
||||
std::numeric_limits<float>::quiet_NaN();
|
||||
const float variable_width_delta_mm = variable_width_delta_for_visibility_range_for_gcode(
|
||||
inset_strength,
|
||||
max_width_delta_limit_mm,
|
||||
outer_wall_gradient_dynamic_ctx.active_component_minimum_offset_factor,
|
||||
outer_wall_gradient_dynamic_ctx.active_component_strength_factor,
|
||||
outer_wall_gradient_dynamic_ctx.active_component_td_width_factor,
|
||||
outer_wall_gradient_dynamic_ctx.nonlinear_offset_adjustment,
|
||||
outer_wall_gradient_dynamic_ctx.layer_height_mm,
|
||||
stair_step_mm);
|
||||
const float width_delta_mm = std::clamp(variable_width_delta_mm, 0.f, max_width_delta_limit_mm);
|
||||
const float width_delta_mm = std::clamp(
|
||||
texture_mapping_offset_surface_inset_mm(outer_wall_gradient_dynamic_ctx.offset_context,
|
||||
mid_point,
|
||||
-outward_x,
|
||||
-outward_y),
|
||||
0.f,
|
||||
max_width_delta_limit_mm);
|
||||
if (!std::isfinite(width_delta_mm) ||
|
||||
!std::isfinite(outer_wall_gradient_dynamic_ctx.base_outer_width_mm) ||
|
||||
!std::isfinite(outer_wall_gradient_dynamic_ctx.layer_height_mm))
|
||||
|
||||
@@ -461,8 +461,6 @@ std::vector<std::array<float, 3>> fixed_color_generic_solver_component_colors(in
|
||||
return { { { 1.f, 0.f, 0.f } }, { { 0.f, 1.f, 0.f } }, { { 0.f, 0.f, 1.f } }, { { 0.f, 0.f, 0.f } } };
|
||||
case int(TextureMappingZone::FilamentColorRGBW):
|
||||
return { { { 1.f, 0.f, 0.f } }, { { 0.f, 1.f, 0.f } }, { { 0.f, 0.f, 1.f } }, { { 1.f, 1.f, 1.f } } };
|
||||
case int(TextureMappingZone::FilamentColorBW):
|
||||
return { { { 0.f, 0.f, 0.f } }, { { 1.f, 1.f, 1.f } } };
|
||||
case int(TextureMappingZone::FilamentColorCMYKW):
|
||||
return { { { 0.f, 1.f, 1.f } }, { { 1.f, 0.f, 1.f } }, { { 1.f, 1.f, 0.f } }, { { 0.f, 0.f, 0.f } }, { { 1.f, 1.f, 1.f } } };
|
||||
case int(TextureMappingZone::FilamentColorRGBKW):
|
||||
@@ -476,7 +474,7 @@ std::vector<size_t> best_matching_component_indices_for_semantic_colors(
|
||||
const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<std::array<float, 3>> &semantic_colors)
|
||||
{
|
||||
if (component_colors.size() != semantic_colors.size() || component_colors.empty() || component_colors.size() > 8)
|
||||
if (component_colors.size() != semantic_colors.size() || component_colors.empty())
|
||||
return {};
|
||||
|
||||
std::vector<size_t> permutation(component_colors.size(), 0);
|
||||
@@ -947,7 +945,8 @@ TextureMappingOffsetWeightField build_texture_mapping_offset_weight_field(
|
||||
float texture_tone_gamma,
|
||||
float layer_z_mm,
|
||||
float layer_z_falloff_mm,
|
||||
bool high_resolution_texture_sampling)
|
||||
bool high_resolution_texture_sampling,
|
||||
bool high_speed_image_texture_sampling)
|
||||
{
|
||||
TextureMappingOffsetWeightField weight_field;
|
||||
if (component_colors.empty())
|
||||
@@ -1004,11 +1003,6 @@ TextureMappingOffsetWeightField build_texture_mapping_offset_weight_field(
|
||||
[&rgba](const Vec3f &) { return TextureSampleData{ rgba, {}, false }; }, accumulate_sample))
|
||||
return;
|
||||
|
||||
const float min_z = std::min({ float(p0.z()), float(p1.z()), float(p2.z()) });
|
||||
const float max_z = std::max({ float(p0.z()), float(p1.z()), float(p2.z()) });
|
||||
if (layer_z_mm < min_z - 4.f * safe_layer_z_falloff_mm || layer_z_mm > max_z + 4.f * safe_layer_z_falloff_mm)
|
||||
return;
|
||||
|
||||
const float max_world_edge_mm = std::max({ float((p1 - p0).norm()), float((p2 - p1).norm()), float((p0 - p2).norm()) });
|
||||
if (!std::isfinite(max_world_edge_mm))
|
||||
return;
|
||||
@@ -1168,10 +1162,13 @@ TextureMappingOffsetWeightField build_texture_mapping_offset_weight_field(
|
||||
}, accumulate_sample))
|
||||
continue;
|
||||
|
||||
const float min_z = std::min({ float(p0.z()), float(p1.z()), float(p2.z()) });
|
||||
const float max_z = std::max({ float(p0.z()), float(p1.z()), float(p2.z()) });
|
||||
if (layer_z_mm < min_z - 4.f * safe_layer_z_falloff_mm || layer_z_mm > max_z + 4.f * safe_layer_z_falloff_mm)
|
||||
continue;
|
||||
if (high_speed_image_texture_sampling) {
|
||||
const float min_z = std::min({ float(p0.z()), float(p1.z()), float(p2.z()) });
|
||||
const float max_z = std::max({ float(p0.z()), float(p1.z()), float(p2.z()) });
|
||||
const float z_margin = std::max(1e-4f, safe_layer_z_falloff_mm * 8.f + float(EPSILON));
|
||||
if (layer_z_mm < min_z - z_margin || layer_z_mm > max_z + z_margin)
|
||||
continue;
|
||||
}
|
||||
|
||||
const float max_world_edge_mm = std::max({ float((p1 - p0).norm()), float((p2 - p1).norm()), float((p0 - p2).norm()) });
|
||||
const double tri_area_mm2 = 0.5 * ((p1 - p0).cross(p2 - p0)).norm();
|
||||
@@ -1219,8 +1216,6 @@ TextureMappingOffsetWeightField build_texture_mapping_offset_weight_field(
|
||||
if (!world_pos.allFinite())
|
||||
continue;
|
||||
const float dz = std::abs(float(world_pos.z()) - layer_z_mm);
|
||||
if (dz > 4.f * safe_layer_z_falloff_mm)
|
||||
continue;
|
||||
const float z_norm = dz / safe_layer_z_falloff_mm;
|
||||
const float sample_weight = std::exp(-0.5f * z_norm * z_norm);
|
||||
if (!std::isfinite(sample_weight) || sample_weight <= EPSILON)
|
||||
@@ -1416,6 +1411,64 @@ std::vector<float> sample_weight_field_components(const TextureMappingOffsetWeig
|
||||
values[component_idx] = clamp01f(weighted_sum[component_idx] / total_weight);
|
||||
return values;
|
||||
}
|
||||
|
||||
float nearest_d2 = std::numeric_limits<float>::max();
|
||||
size_t nearest_sample_idx = size_t(-1);
|
||||
const int nearest_ring_limit = std::min(std::max(max_ring + 2, 4), std::max(weight_field.bucket_width, weight_field.bucket_height));
|
||||
for (int ring = 0; ring <= nearest_ring_limit; ++ring) {
|
||||
const int min_x = std::max(0, cx - ring);
|
||||
const int max_x = std::min(weight_field.bucket_width - 1, cx + ring);
|
||||
const int min_y = std::max(0, cy - ring);
|
||||
const int max_y = std::min(weight_field.bucket_height - 1, cy + ring);
|
||||
|
||||
auto visit_bucket = [&weight_field, x_mm, y_mm, &nearest_d2, &nearest_sample_idx](int bx, int by) {
|
||||
if (bx < 0 || by < 0 || bx >= weight_field.bucket_width || by >= weight_field.bucket_height)
|
||||
return;
|
||||
const size_t bucket_idx = size_t(by) * size_t(weight_field.bucket_width) + size_t(bx);
|
||||
if (bucket_idx >= weight_field.buckets.size())
|
||||
return;
|
||||
for (const uint32_t sample_idx_u32 : weight_field.buckets[bucket_idx]) {
|
||||
const size_t sample_idx = size_t(sample_idx_u32);
|
||||
if (sample_idx >= weight_field.sample_x_mm.size() || sample_idx >= weight_field.sample_y_mm.size())
|
||||
continue;
|
||||
const float dx = x_mm - weight_field.sample_x_mm[sample_idx];
|
||||
const float dy = y_mm - weight_field.sample_y_mm[sample_idx];
|
||||
const float d2 = dx * dx + dy * dy;
|
||||
if (d2 >= nearest_d2)
|
||||
continue;
|
||||
const size_t value_idx = sample_idx * weight_field.component_count;
|
||||
if (value_idx + weight_field.component_count > weight_field.sample_component_weights.size())
|
||||
continue;
|
||||
nearest_d2 = d2;
|
||||
nearest_sample_idx = sample_idx;
|
||||
}
|
||||
};
|
||||
|
||||
if (ring == 0) {
|
||||
visit_bucket(cx, cy);
|
||||
} else {
|
||||
for (int x = min_x; x <= max_x; ++x) {
|
||||
visit_bucket(x, min_y);
|
||||
if (max_y != min_y)
|
||||
visit_bucket(x, max_y);
|
||||
}
|
||||
for (int y = min_y + 1; y <= max_y - 1; ++y) {
|
||||
visit_bucket(min_x, y);
|
||||
if (max_x != min_x)
|
||||
visit_bucket(max_x, y);
|
||||
}
|
||||
}
|
||||
if (nearest_d2 < std::numeric_limits<float>::max() && ring >= 2)
|
||||
break;
|
||||
}
|
||||
|
||||
if (nearest_sample_idx != size_t(-1)) {
|
||||
std::vector<float> values(weight_field.component_count, 0.f);
|
||||
const size_t value_idx = nearest_sample_idx * weight_field.component_count;
|
||||
for (size_t component_idx = 0; component_idx < weight_field.component_count; ++component_idx)
|
||||
values[component_idx] = clamp01f(weight_field.sample_component_weights[value_idx + component_idx]);
|
||||
return values;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
@@ -1877,7 +1930,10 @@ std::optional<TextureMappingOffsetContext> build_texture_mapping_offset_context_
|
||||
const PrintObject &print_object,
|
||||
const Layer &layer,
|
||||
const TextureMappingZone &zone,
|
||||
unsigned int texture_zone_id)
|
||||
unsigned int texture_zone_id,
|
||||
unsigned int active_component_id_override,
|
||||
std::optional<float> base_outer_width_mm_override,
|
||||
std::optional<float> layer_height_mm_override)
|
||||
{
|
||||
const Print *print = print_object.print();
|
||||
if (print == nullptr)
|
||||
@@ -1905,7 +1961,8 @@ std::optional<TextureMappingOffsetContext> build_texture_mapping_offset_context_
|
||||
const float z_progress = object_layer_count > 1 ?
|
||||
std::clamp(float(layer_index) / float(object_layer_count - 1), 0.f, 1.f) :
|
||||
0.f;
|
||||
const unsigned int active_component_id =
|
||||
const unsigned int active_component_id = active_component_id_override != 0 ?
|
||||
active_component_id_override :
|
||||
texture_mgr.resolve_zone_component(texture_zone_id, num_physical, layer_index);
|
||||
const auto active_component_it = std::find(component_ids.begin(), component_ids.end(), active_component_id);
|
||||
if (active_component_it == component_ids.end())
|
||||
@@ -2005,13 +2062,16 @@ std::optional<TextureMappingOffsetContext> build_texture_mapping_offset_context_
|
||||
if (global_strength_factor <= EPSILON)
|
||||
return std::nullopt;
|
||||
|
||||
const float base_outer_width_mm =
|
||||
const float base_outer_width_mm = base_outer_width_mm_override ?
|
||||
std::max(0.05f, *base_outer_width_mm_override) :
|
||||
std::max(0.05f, float(print_config.texture_mapping_outer_wall_gradient_max_line_width.value));
|
||||
const float config_min_gradient_width_mm = std::clamp(
|
||||
float(print_config.texture_mapping_outer_wall_gradient_min_line_width.value),
|
||||
0.05f,
|
||||
base_outer_width_mm);
|
||||
const float layer_height_mm = std::max(0.01f, float(layer.height));
|
||||
const float layer_height_mm = layer_height_mm_override ?
|
||||
std::max(0.01f, *layer_height_mm_override) :
|
||||
std::max(0.01f, float(layer.height));
|
||||
const float min_width_for_positive_spacing_mm = layer_height_mm * float(1. - 0.25 * PI) + 1e-4f;
|
||||
const float safe_min_gradient_width_mm = std::clamp(
|
||||
std::max(config_min_gradient_width_mm, min_width_for_positive_spacing_mm),
|
||||
@@ -2041,7 +2101,8 @@ std::optional<TextureMappingOffsetContext> build_texture_mapping_offset_context_
|
||||
texture_tone_gamma,
|
||||
float(layer.print_z),
|
||||
layer_sample_falloff_mm,
|
||||
zone.high_resolution_sampling);
|
||||
zone.high_resolution_sampling,
|
||||
zone.high_speed_image_texture_sampling);
|
||||
if (weight_field.empty())
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,10 @@ std::optional<TextureMappingOffsetContext> build_texture_mapping_offset_context_
|
||||
const PrintObject &print_object,
|
||||
const Layer &layer,
|
||||
const TextureMappingZone &zone,
|
||||
unsigned int texture_zone_id);
|
||||
unsigned int texture_zone_id,
|
||||
unsigned int active_component_id_override = 0,
|
||||
std::optional<float> base_outer_width_mm_override = std::nullopt,
|
||||
std::optional<float> layer_height_mm_override = std::nullopt);
|
||||
|
||||
float texture_mapping_offset_surface_inset_mm(const TextureMappingOffsetContext &context,
|
||||
const Point &point,
|
||||
|
||||
Reference in New Issue
Block a user