diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index be29229b67b..9349d4ebee4 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -269,6 +269,14 @@ void ToolOrdering::handle_dontcare_extruder(const std::vector& too assert(extruder_id > 0); --extruder_id; } + for (unsigned int &extruder_id : lt.texture_mapping_extruders) { + assert(extruder_id > 0); + --extruder_id; + } + for (unsigned int &extruder_id : lt.texture_mapping_component_extruders) { + assert(extruder_id > 0); + --extruder_id; + } } } @@ -339,6 +347,14 @@ void ToolOrdering::handle_dontcare_extruder(unsigned int last_extruder_id) assert(extruder_id > 0); -- extruder_id; } + for (unsigned int &extruder_id : lt.texture_mapping_extruders) { + assert(extruder_id > 0); + -- extruder_id; + } + for (unsigned int &extruder_id : lt.texture_mapping_component_extruders) { + assert(extruder_id > 0); + -- extruder_id; + } } } @@ -720,10 +736,35 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto // Store the current extruder override (set to zero if no overriden), so that layer_tools.wiping_extrusions().is_overridable_and_mark() will use it. layer_tools.extruder_override = extruder_override; - auto append_layer_filament = [&layer_tools](unsigned int filament_id) { - if (layer_tools.texture_mapping_manager != nullptr && layer_tools.texture_mapping_manager->is_texture_mapping_zone_id(filament_id)) + auto append_layer_filament = [&layer_tools, &object](unsigned int filament_id) { + const bool is_texture_mapping_zone = layer_tools.texture_mapping_manager != nullptr && + layer_tools.texture_mapping_manager->is_texture_mapping_zone_id(filament_id); + const unsigned int resolved_filament_id = layer_tools.resolve_filament_id(filament_id); + if (is_texture_mapping_zone) { layer_tools.has_texture_mapping_zone = true; - layer_tools.extruders.emplace_back(layer_tools.resolve_filament_id(filament_id)); + if (resolved_filament_id > 0) + layer_tools.texture_mapping_extruders.emplace_back(resolved_filament_id); + const TextureMappingZone *zone = layer_tools.texture_mapping_manager->zone_from_id(filament_id); + bool added_texture_component = false; + if (zone != nullptr && zone->enabled && !zone->deleted) { + std::vector filament_colours = object.print()->config().filament_colour.values; + filament_colours.resize(layer_tools.num_physical_filaments, "#FFFFFF"); + std::vector component_ids = + zone->is_image_texture() ? + TextureMappingManager::effective_texture_component_ids(*zone, + layer_tools.num_physical_filaments, + filament_colours) : + TextureMappingManager::selected_component_ids(*zone, layer_tools.num_physical_filaments); + for (const unsigned int component_id : component_ids) + if (component_id >= 1 && component_id <= layer_tools.num_physical_filaments) { + layer_tools.texture_mapping_component_extruders.emplace_back(component_id); + added_texture_component = true; + } + } + if (!added_texture_component && resolved_filament_id > 0) + layer_tools.texture_mapping_component_extruders.emplace_back(resolved_filament_id); + } + layer_tools.extruders.emplace_back(resolved_filament_id); }; // What extruders are required to print this object layer? @@ -841,6 +882,8 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto for (auto& layer : m_layer_tools) { // Sort and remove duplicates sort_remove_duplicates(layer.extruders); + sort_remove_duplicates(layer.texture_mapping_extruders); + sort_remove_duplicates(layer.texture_mapping_component_extruders); // make sure that there are some tools for each object layer (e.g. tall wiping object will result in empty extruders vector) if (layer.extruders.empty() && layer.has_object) diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp index 0747ec6ae4b..f41d2c2ec3b 100644 --- a/src/libslic3r/GCode/ToolOrdering.hpp +++ b/src/libslic3r/GCode/ToolOrdering.hpp @@ -156,6 +156,8 @@ public: bool has_support = false; // Zero based extruder IDs, ordered to minimize tool switches. std::vector extruders; + std::vector texture_mapping_extruders; + std::vector texture_mapping_component_extruders; // If per layer extruder switches are inserted by the G-code preview slider, this value contains the new (1 based) extruder, with which the whole object layer is being printed with. // If not overriden, it is set to 0. unsigned int extruder_override = 0; diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index c0bb0b1b45a..be58e0aa7f2 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -630,7 +630,7 @@ public: if (! m_preview_suppressed && e > 0.f && len > 0.f) { // Width of a squished extrusion, corrected for the roundings of the squished extrusions. // This is left zero if it is a travel move. - float width = e * m_filpar[0].filament_area / (len * m_layer_height); + float width = e * m_filpar[m_current_tool].filament_area / (len * m_layer_height); // Correct for the roundings of a squished extrusion. width += m_layer_height * float(1. - M_PI / 4.); if (m_extrusions.empty() || m_extrusions.back().pos != rotated_current_pos) @@ -688,7 +688,7 @@ public: #endif // ENABLE_GCODE_VIEWER_DATA_CHECKING // Width of a squished extrusion, corrected for the roundings of the squished extrusions. // This is left zero if it is a travel move. - float width = e * m_filpar[0].filament_area / (len * m_layer_height); + float width = e * m_filpar[m_current_tool].filament_area / (len * m_layer_height); // Correct for the roundings of a squished extrusion. width += m_layer_height * float(1. - M_PI / 4.); if (m_extrusions.empty() || m_extrusions.back().pos != rotated_current_pos) m_extrusions.emplace_back(WipeTower::Extrusion(rotated_current_pos, 0, m_current_tool)); @@ -1447,7 +1447,8 @@ static void prime_tower_textured_path(WipeTowerWriter &writer, float width_range = (base_width - min_width) * std::clamp(texture.global_strength, 0.f, 1.f); if (texture.sagging_ratio > EPSILON) width_range = std::min(width_range, layer_height * texture.sagging_ratio); - const float sample_step = std::max(0.35f, reference_width); + const float base_extrusion_flow = extrusion_flow * prime_tower_flow_scale_for_width(reference_width, base_width, layer_height); + const float sample_step = std::max(0.35f, base_width); float travelled = 0.f; bool have_shifted_pos = false; @@ -1476,7 +1477,7 @@ static void prime_tower_textured_path(WipeTowerWriter &writer, const float u = (mid_distance - texture_path.anchor_distance) / total_length; const float visibility = texture.sample_tool_visibility(current_tool, u, v, normalization_tools); const float target_width = base_width - (1.f - visibility) * width_range; - const float flow_scale = prime_tower_flow_scale_for_width(reference_width, target_width, layer_height); + const float flow_scale = prime_tower_flow_scale_for_width(base_width, target_width, layer_height); const float centerline_shift = 0.5f * (base_width - reference_width) + 0.5f * (base_width - target_width); const Vec2f p0 = a + delta * t0 - outward * centerline_shift; const Vec2f p1 = a + delta * t1 - outward * centerline_shift; @@ -1485,12 +1486,11 @@ static void prime_tower_textured_path(WipeTowerWriter &writer, shifted_pos = p0; have_shifted_pos = true; } - writer.extrude_explicit(p1, (p1 - p0).norm() * extrusion_flow * flow_scale, feedrate, true); + writer.extrude_explicit(p1, (p1 - p0).norm() * base_extrusion_flow * flow_scale, feedrate, true); shifted_pos = p1; } travelled += sample_len; } - writer.change_analyzer_line_width(reference_width); } static void prime_tower_textured_closed_path(WipeTowerWriter &writer, @@ -2748,12 +2748,17 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool std::vector texture_normalization_tools; if (m_prime_tower_texture.valid()) { const size_t texture_tool_count = m_prime_tower_texture.filament_colours.size(); - prime_tower_append_texture_tool(texture_normalization_tools, m_current_tool, texture_tool_count); - if (m_layer_info != m_plan.end()) { + if (m_layer_info != m_plan.end() && !m_layer_info->texture_mapping_layer_tools.empty()) { + for (const size_t tool : m_layer_info->texture_mapping_layer_tools) + prime_tower_append_texture_tool(texture_normalization_tools, tool, texture_tool_count); + } else if (m_layer_info != m_plan.end()) { + prime_tower_append_texture_tool(texture_normalization_tools, m_current_tool, texture_tool_count); for (const WipeTowerInfo::ToolChange &tool_change : m_layer_info->tool_changes) { prime_tower_append_texture_tool(texture_normalization_tools, tool_change.old_tool, texture_tool_count); prime_tower_append_texture_tool(texture_normalization_tools, tool_change.new_tool, texture_tool_count); } + } else { + prime_tower_append_texture_tool(texture_normalization_tools, m_current_tool, texture_tool_count); } } if (extrude_perimeter) { @@ -2835,13 +2840,23 @@ void WipeTower::plan_toolchange(float z_par, unsigned int new_tool, float wipe_volume, float purge_volume, - bool texture_mapping_single_component_layer) + bool texture_mapping_single_component_layer, + const std::vector &texture_mapping_layer_tools, + int texture_mapping_wall_tool) { assert(m_plan.empty() || m_plan.back().z <= z_par + WT_EPSILON); // refuses to add a layer below the last one if (m_plan.empty() || m_plan.back().z + WT_EPSILON < z_par) // if we moved to a new layer, we'll add it to m_plan first m_plan.push_back(WipeTowerInfo(z_par, layer_height_par)); m_plan.back().texture_mapping_single_component_layer |= texture_mapping_single_component_layer; + if (texture_mapping_wall_tool >= 0) + m_plan.back().texture_mapping_wall_tool = size_t(texture_mapping_wall_tool); + std::vector &layer_texture_tools = m_plan.back().texture_mapping_layer_tools; + for (const unsigned int tool : texture_mapping_layer_tools) { + const size_t tool_id = size_t(tool); + if (std::find(layer_texture_tools.begin(), layer_texture_tools.end(), tool_id) == layer_texture_tools.end()) + layer_texture_tools.emplace_back(tool_id); + } if (m_first_layer_idx == size_t(-1) && (! m_no_sparse_layers || old_tool != new_tool)) m_first_layer_idx = m_plan.size() - 1; @@ -4299,10 +4314,28 @@ void WipeTower::generate_new(std::vector int { - if (layer.tool_changes.size() == 0) + auto texture_wall_tool_for_this_layer = [this, &layer]() -> int { + if (!m_prime_tower_texture.valid() || layer.texture_mapping_wall_tool == size_t(-1)) + return -1; + const int texture_wall_tool = int(layer.texture_mapping_wall_tool); + if (layer.tool_changes.empty()) + return texture_wall_tool == int(m_current_tool) ? texture_wall_tool : -1; + if (int(layer.tool_changes.front().old_tool) == texture_wall_tool) + return texture_wall_tool; + for (const WipeTowerInfo::ToolChange &tool_change : layer.tool_changes) + if (int(tool_change.new_tool) == texture_wall_tool) + return texture_wall_tool; return -1; - if (m_prime_tower_texture.valid() && layer.texture_mapping_single_component_layer && layer.tool_changes.size() == 1) - return layer.tool_changes.front().new_tool; + }; + if (const int texture_wall_tool = texture_wall_tool_for_this_layer(); texture_wall_tool != -1) + return texture_wall_tool; + if (layer.tool_changes.size() == 0) { + return -1; + } + if (m_prime_tower_texture.valid()) { + if (layer.texture_mapping_single_component_layer && layer.tool_changes.size() == 1) + return layer.tool_changes.front().new_tool; + } int candidate_id = -1; for (size_t idx = 0; idx < layer.tool_changes.size(); ++idx) { @@ -4713,12 +4746,17 @@ Polygon WipeTower::generate_support_wall_new(WipeTowerWriter &writer, const box_ if (m_prime_tower_texture.valid() && result_wall.size() == 1 && !result_wall.front().points.empty()) { std::vector texture_normalization_tools; const size_t texture_tool_count = m_prime_tower_texture.filament_colours.size(); - prime_tower_append_texture_tool(texture_normalization_tools, m_current_tool, texture_tool_count); - if (m_layer_info != m_plan.end()) { + if (m_layer_info != m_plan.end() && !m_layer_info->texture_mapping_layer_tools.empty()) { + for (const size_t tool : m_layer_info->texture_mapping_layer_tools) + prime_tower_append_texture_tool(texture_normalization_tools, tool, texture_tool_count); + } else if (m_layer_info != m_plan.end()) { + prime_tower_append_texture_tool(texture_normalization_tools, m_current_tool, texture_tool_count); for (const WipeTowerInfo::ToolChange &tool_change : m_layer_info->tool_changes) { prime_tower_append_texture_tool(texture_normalization_tools, tool_change.old_tool, texture_tool_count); prime_tower_append_texture_tool(texture_normalization_tools, tool_change.new_tool, texture_tool_count); } + } else { + prime_tower_append_texture_tool(texture_normalization_tools, m_current_tool, texture_tool_count); } const bool closed_texture_path = !rib_wall && !skip_points; std::vector points; diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index 85c1b3529b6..218768ac8d0 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -76,8 +76,8 @@ struct PrimeTowerTextureRenderSettings float sample_tool_visibility(size_t tool, float u, float v) const { const float raw_visibility = sample_tool_visibility_raw(tool, u, v); - if (settings_zone_enabled || !compact_offset_mode) - return raw_visibility; + if (!compact_offset_mode) + return adjusted_tool_visibility(tool, raw_visibility); float max_visibility = std::clamp(raw_visibility, 0.f, 1.f); if (!tool_indices.empty()) { @@ -91,27 +91,126 @@ struct PrimeTowerTextureRenderSettings max_visibility = std::max(max_visibility, std::clamp(sample_tool_visibility_raw(candidate_tool, u, v), 0.f, 1.f)); } } - return max_visibility > 1e-6f ? - std::clamp(raw_visibility / max_visibility, 0.f, 1.f) : - std::clamp(raw_visibility, 0.f, 1.f); + return max_visibility > 1e-6f ? adjusted_tool_visibility(tool, raw_visibility / max_visibility) : + adjusted_tool_visibility(tool, raw_visibility); } float sample_tool_visibility(size_t tool, float u, float v, const std::vector &normalization_tools) const { const float raw_visibility = sample_tool_visibility_raw(tool, u, v); - if (settings_zone_enabled || !compact_offset_mode || normalization_tools.empty()) - return raw_visibility; + if (!compact_offset_mode || normalization_tools.empty()) + return adjusted_tool_visibility(tool, raw_visibility); float max_visibility = std::clamp(raw_visibility, 0.f, 1.f); for (const size_t normalization_tool : normalization_tools) max_visibility = std::max(max_visibility, std::clamp(sample_tool_visibility_raw(normalization_tool, u, v), 0.f, 1.f)); - return max_visibility > 1e-6f ? - std::clamp(raw_visibility / max_visibility, 0.f, 1.f) : - std::clamp(raw_visibility, 0.f, 1.f); + return max_visibility > 1e-6f ? adjusted_tool_visibility(tool, raw_visibility / max_visibility) : + adjusted_tool_visibility(tool, raw_visibility); + } + + std::vector component_tools_for_layer_sequence() const + { + std::vector tools; + if (!valid()) + return tools; + + if (settings_zone_enabled && !component_ids.empty()) { + tools.reserve(component_ids.size()); + for (const unsigned int physical_id : component_ids) { + if (physical_id >= 1 && physical_id <= filament_colours.size()) { + const size_t tool = size_t(physical_id - 1); + if (std::find(tools.begin(), tools.end(), tool) == tools.end()) + tools.emplace_back(tool); + } + } + if (!tools.empty()) + return tools; + } + + const std::vector> ideals = color_mode_ideals(color_mode); + if (ideals.empty()) + return tools; + + std::vector candidates; + if (!tool_indices.empty()) { + for (const size_t tool : tool_indices) + if (tool < filament_colours.size() && std::find(candidates.begin(), candidates.end(), tool) == candidates.end()) + candidates.emplace_back(tool); + } else { + candidates.reserve(filament_colours.size()); + for (size_t tool = 0; tool < filament_colours.size(); ++tool) + candidates.emplace_back(tool); + } + if (candidates.empty()) + return tools; + + std::vector used(filament_colours.size(), 0); + tools.reserve(ideals.size()); + for (const std::array &ideal : ideals) { + size_t best_tool = size_t(-1); + float best_distance = std::numeric_limits::max(); + for (const size_t candidate : candidates) { + if (candidate >= used.size() || used[candidate]) + continue; + const float distance = color_distance2(tool_color(candidate), ideal); + if (distance < best_distance) { + best_distance = distance; + best_tool = candidate; + } + } + if (best_tool != size_t(-1)) { + used[best_tool] = 1; + tools.emplace_back(best_tool); + } + } + return tools; + } + + size_t tool_for_layer_sequence(int layer_index) const + { + const std::vector tools = component_tools_for_layer_sequence(); + if (tools.empty()) + return size_t(-1); + const int tool_count = int(tools.size()); + const int index = ((layer_index % tool_count) + tool_count) % tool_count; + return tools[size_t(index)]; } private: + static std::vector> color_mode_ideals(int mode) + { + switch (mode) { + case CMY: + return {std::array{0.f, 1.f, 1.f}, std::array{1.f, 0.f, 1.f}, std::array{1.f, 1.f, 0.f}}; + case CMYK: + return {std::array{0.f, 1.f, 1.f}, + std::array{1.f, 0.f, 1.f}, + std::array{1.f, 1.f, 0.f}, + std::array{0.f, 0.f, 0.f}}; + case CMYW: + return {std::array{0.f, 1.f, 1.f}, + std::array{1.f, 0.f, 1.f}, + std::array{1.f, 1.f, 0.f}, + std::array{1.f, 1.f, 1.f}}; + case RGB: + return {std::array{1.f, 0.f, 0.f}, std::array{0.f, 1.f, 0.f}, std::array{0.f, 0.f, 1.f}}; + case RGBK: + return {std::array{1.f, 0.f, 0.f}, + std::array{0.f, 1.f, 0.f}, + std::array{0.f, 0.f, 1.f}, + std::array{0.f, 0.f, 0.f}}; + case RGBW: + return {std::array{1.f, 0.f, 0.f}, + std::array{0.f, 1.f, 0.f}, + std::array{0.f, 0.f, 1.f}, + std::array{1.f, 1.f, 1.f}}; + case BW: + return {std::array{0.f, 0.f, 0.f}, std::array{1.f, 1.f, 1.f}}; + default: return {}; + } + } + float sample_tool_visibility_raw(size_t tool, float u, float v) const { if (!valid()) @@ -321,6 +420,14 @@ private: return std::clamp(minimum + std::clamp(value, 0.f, 1.f) * strength * (1.f - minimum), 0.f, 1.f); } + float adjusted_tool_visibility(size_t tool, float value) const + { + const unsigned int physical_id = unsigned(tool + 1); + return settings_zone_enabled && std::find(component_ids.begin(), component_ids.end(), physical_id) != component_ids.end() ? + adjusted_visibility_factor(physical_id, value) : + std::clamp(value, 0.f, 1.f); + } + float sample_settings_zone_tool_visibility(size_t tool, float u, float v, bool back) const { const unsigned int physical_id = unsigned(tool + 1); @@ -350,15 +457,7 @@ private: return sample_image_tool_visibility(tool, u, v, back); apply_contrast(weights, std::clamp(contrast_pct, 25.f, 300.f) / 100.f, mapped_count); - if (compact_offset_mode) { - float max_weight = 0.f; - for (const float weight : weights) - max_weight = std::max(max_weight, std::clamp(weight, 0.f, 1.f)); - if (max_weight > 1e-6f) - for (float &weight : weights) - weight = std::clamp(weight / max_weight, 0.f, 1.f); - } - return adjusted_visibility_factor(physical_id, weights[component_idx]); + return std::clamp(weights[component_idx], 0.f, 1.f); } float fixed_mode_visibility(size_t tool, float r, float g, float b) const @@ -626,7 +725,9 @@ public: unsigned int new_tool, float wipe_volume = 0.f, float prime_volume = 0.f, - bool texture_mapping_single_component_layer = false); + bool texture_mapping_single_component_layer = false, + const std::vector &texture_mapping_layer_tools = {}, + int texture_mapping_wall_tool = -1); // Iterates through prepared m_plan, generates ToolChangeResults and appends them to "result" void generate(std::vector> &result); @@ -986,9 +1087,11 @@ private: float z; // z position of the layer float height; // layer height float depth; // depth of the layer based on all layers above - float extra_spacing; + float extra_spacing; bool extruder_fill{true}; bool texture_mapping_single_component_layer{false}; + std::vector texture_mapping_layer_tools; + size_t texture_mapping_wall_tool{size_t(-1)}; float toolchanges_depth() const { float sum = 0.f; for (const auto &a : tool_changes) sum += a.required_depth; return sum; } std::vector tool_changes; diff --git a/src/libslic3r/GCode/WipeTower2.cpp b/src/libslic3r/GCode/WipeTower2.cpp index 722d643db57..10a54b35596 100644 --- a/src/libslic3r/GCode/WipeTower2.cpp +++ b/src/libslic3r/GCode/WipeTower2.cpp @@ -683,7 +683,7 @@ public: if (! m_preview_suppressed && e > 0.f && len > 0.f) { // Width of a squished extrusion, corrected for the roundings of the squished extrusions. // This is left zero if it is a travel move. - float width = e * m_filpar[0].filament_area / (len * m_layer_height); + float width = e * m_filpar[m_current_tool].filament_area / (len * m_layer_height); // Correct for the roundings of a squished extrusion. width += m_layer_height * float(1. - M_PI / 4.); if (m_extrusions.empty() || m_extrusions.back().pos != rotated_current_pos) @@ -1019,7 +1019,7 @@ public: #endif // ENABLE_GCODE_VIEWER_DATA_CHECKING // Width of a squished extrusion, corrected for the roundings of the squished extrusions. // This is left zero if it is a travel move. - float width = e * m_filpar[0].filament_area / (len * m_layer_height); + float width = e * m_filpar[m_current_tool].filament_area / (len * m_layer_height); // Correct for the roundings of a squished extrusion. width += m_layer_height * float(1. - M_PI / 4.); if (m_extrusions.empty() || m_extrusions.back().pos != rotated_current_pos) @@ -1426,7 +1426,8 @@ static void prime_tower_textured_path(WipeTowerWriter2& writer, float width_range = (base_width - min_width) * std::clamp(texture.global_strength, 0.f, 1.f); if (texture.sagging_ratio > EPSILON) width_range = std::min(width_range, layer_height * texture.sagging_ratio); - const float sample_step = std::max(0.35f, reference_width); + const float base_extrusion_flow = extrusion_flow * prime_tower_flow_scale_for_width(reference_width, base_width, layer_height); + const float sample_step = std::max(0.35f, base_width); float travelled = 0.f; bool have_shifted_pos = false; @@ -1455,7 +1456,7 @@ static void prime_tower_textured_path(WipeTowerWriter2& writer, const float u = (mid_distance - texture_path.anchor_distance) / total_length; const float visibility = texture.sample_tool_visibility(current_tool, u, v, normalization_tools); const float target_width = base_width - (1.f - visibility) * width_range; - const float flow_scale = prime_tower_flow_scale_for_width(reference_width, target_width, layer_height); + const float flow_scale = prime_tower_flow_scale_for_width(base_width, target_width, layer_height); const float centerline_shift = 0.5f * (base_width - reference_width) + 0.5f * (base_width - target_width); const Vec2f p0 = a + delta * t0 - outward * centerline_shift; const Vec2f p1 = a + delta * t1 - outward * centerline_shift; @@ -1464,12 +1465,11 @@ static void prime_tower_textured_path(WipeTowerWriter2& writer, shifted_pos = p0; have_shifted_pos = true; } - writer.extrude_explicit(p1, (p1 - p0).norm() * extrusion_flow * flow_scale, feedrate, true); + writer.extrude_explicit(p1, (p1 - p0).norm() * base_extrusion_flow * flow_scale, feedrate, true); shifted_pos = p1; } travelled += sample_len; } - writer.change_analyzer_line_width(reference_width); } static void prime_tower_textured_closed_path(WipeTowerWriter2& writer, @@ -2521,13 +2521,26 @@ static float get_wipe_depth(float volume, float layer_height, float perimeter_wi } // Appends a toolchange into m_plan and calculates neccessary depth of the corresponding box -void WipeTower2::plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, - unsigned int new_tool, float wipe_volume) +void WipeTower2::plan_toolchange(float z_par, + float layer_height_par, + unsigned int old_tool, + unsigned int new_tool, + float wipe_volume, + const std::vector &texture_mapping_layer_tools, + int texture_mapping_wall_tool) { assert(m_plan.empty() || m_plan.back().z <= z_par + WT_EPSILON); // refuses to add a layer below the last one if (m_plan.empty() || m_plan.back().z + WT_EPSILON < z_par) // if we moved to a new layer, we'll add it to m_plan first m_plan.push_back(WipeTowerInfo(z_par, layer_height_par)); + if (texture_mapping_wall_tool >= 0) + m_plan.back().texture_mapping_wall_tool = size_t(texture_mapping_wall_tool); + std::vector &layer_texture_tools = m_plan.back().texture_mapping_layer_tools; + for (const unsigned int tool : texture_mapping_layer_tools) { + const size_t tool_id = size_t(tool); + if (std::find(layer_texture_tools.begin(), layer_texture_tools.end(), tool_id) == layer_texture_tools.end()) + layer_texture_tools.emplace_back(tool_id); + } if (m_first_layer_idx == size_t(-1) && (! m_no_sparse_layers || old_tool != new_tool || m_plan.size() == 1)) m_first_layer_idx = m_plan.size() - 1; @@ -2719,6 +2732,21 @@ void WipeTower2::generate(std::vector> m_y_shift = (m_wipe_tower_depth-m_layer_info->depth-m_perimeter_width)/2.f; int idx = first_toolchange_to_nonsoluble(layer.tool_changes); + auto texture_wall_finish_idx = [this, &layer]() -> int { + if (!m_prime_tower_texture.valid() || layer.texture_mapping_wall_tool == size_t(-1)) + return std::numeric_limits::min(); + const int texture_wall_tool = int(layer.texture_mapping_wall_tool); + if (layer.tool_changes.empty()) + return texture_wall_tool == int(m_current_tool) ? -1 : std::numeric_limits::min(); + if (int(layer.tool_changes.front().old_tool) == texture_wall_tool) + return -1; + for (int i = 0; i < int(layer.tool_changes.size()); ++i) + if (int(layer.tool_changes[i].new_tool) == texture_wall_tool) + return i; + return std::numeric_limits::min(); + }; + if (const int texture_idx = texture_wall_finish_idx(); texture_idx != std::numeric_limits::min()) + idx = texture_idx; WipeTower::ToolChangeResult finish_layer_tcr; if (idx == -1) { @@ -2843,12 +2871,17 @@ Polygon WipeTower2::generate_support_rib_wall(WipeTowerWriter2& if (m_prime_tower_texture.valid() && result_wall.size() == 1 && !result_wall.front().points.empty()) { std::vector texture_normalization_tools; const size_t texture_tool_count = m_prime_tower_texture.filament_colours.size(); - prime_tower_append_texture_tool(texture_normalization_tools, m_current_tool, texture_tool_count); - if (m_layer_info != m_plan.end()) { + if (m_layer_info != m_plan.end() && !m_layer_info->texture_mapping_layer_tools.empty()) { + for (const size_t tool : m_layer_info->texture_mapping_layer_tools) + prime_tower_append_texture_tool(texture_normalization_tools, tool, texture_tool_count); + } else if (m_layer_info != m_plan.end()) { + prime_tower_append_texture_tool(texture_normalization_tools, m_current_tool, texture_tool_count); for (const WipeTowerInfo::ToolChange &tool_change : m_layer_info->tool_changes) { prime_tower_append_texture_tool(texture_normalization_tools, tool_change.old_tool, texture_tool_count); prime_tower_append_texture_tool(texture_normalization_tools, tool_change.new_tool, texture_tool_count); } + } else { + prime_tower_append_texture_tool(texture_normalization_tools, m_current_tool, texture_tool_count); } const bool closed_texture_path = !rib_wall && !skip_points; std::vector points; @@ -2983,12 +3016,17 @@ Polygon WipeTower2::generate_support_cone_wall( if (m_prime_tower_texture.valid() && polylines.empty()) { std::vector texture_normalization_tools; const size_t texture_tool_count = m_prime_tower_texture.filament_colours.size(); - prime_tower_append_texture_tool(texture_normalization_tools, m_current_tool, texture_tool_count); - if (m_layer_info != m_plan.end()) { + if (m_layer_info != m_plan.end() && !m_layer_info->texture_mapping_layer_tools.empty()) { + for (const size_t tool : m_layer_info->texture_mapping_layer_tools) + prime_tower_append_texture_tool(texture_normalization_tools, tool, texture_tool_count); + } else if (m_layer_info != m_plan.end()) { + prime_tower_append_texture_tool(texture_normalization_tools, m_current_tool, texture_tool_count); for (const WipeTowerInfo::ToolChange &tool_change : m_layer_info->tool_changes) { prime_tower_append_texture_tool(texture_normalization_tools, tool_change.old_tool, texture_tool_count); prime_tower_append_texture_tool(texture_normalization_tools, tool_change.new_tool, texture_tool_count); } + } else { + prime_tower_append_texture_tool(texture_normalization_tools, m_current_tool, texture_tool_count); } std::vector ordered; ordered.reserve(pts.size()); diff --git a/src/libslic3r/GCode/WipeTower2.hpp b/src/libslic3r/GCode/WipeTower2.hpp index 1e4ef8646d1..83f88d30030 100644 --- a/src/libslic3r/GCode/WipeTower2.hpp +++ b/src/libslic3r/GCode/WipeTower2.hpp @@ -50,7 +50,13 @@ public: // Appends into internal structure m_plan containing info about the future wipe tower // to be used before building begins. The entries must be added ordered in z. - void plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, float wipe_volume = 0.f); + void plan_toolchange(float z_par, + float layer_height_par, + unsigned int old_tool, + unsigned int new_tool, + float wipe_volume = 0.f, + const std::vector &texture_mapping_layer_tools = {}, + int texture_mapping_wall_tool = -1); // Iterates through prepared m_plan, generates ToolChangeResults and appends them to "result" void generate(std::vector> &result); @@ -310,6 +316,8 @@ private: float z; // z position of the layer float height; // layer height float depth; // depth of the layer based on all layers above + std::vector texture_mapping_layer_tools; + size_t texture_mapping_wall_tool{size_t(-1)}; float toolchanges_depth() const { float sum = 0.f; for (const auto &a : tool_changes) sum += a.required_depth; return sum; } std::vector tool_changes; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index eee98a0c10b..8d083905599 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -3538,6 +3538,43 @@ void Print::_make_wipe_tower() return texture; }; const PrimeTowerTextureRenderSettings prime_tower_texture = build_prime_tower_texture(); + const std::vector prime_tower_texture_component_tools = prime_tower_texture.component_tools_for_layer_sequence(); + auto prime_tower_texture_layer_tools = [&prime_tower_texture, &prime_tower_texture_component_tools](const LayerTools &layer_tools) { + std::vector tools; + if (!prime_tower_texture.valid()) + return tools; + if (layer_tools.has_texture_mapping_zone && !layer_tools.texture_mapping_component_extruders.empty()) { + tools = layer_tools.texture_mapping_component_extruders; + return tools; + } + if (layer_tools.has_texture_mapping_zone && !layer_tools.texture_mapping_extruders.empty()) { + tools = layer_tools.texture_mapping_extruders; + return tools; + } + if (!prime_tower_texture_component_tools.empty()) { + tools.reserve(prime_tower_texture_component_tools.size()); + for (const size_t tool : prime_tower_texture_component_tools) + tools.emplace_back(unsigned(tool)); + return tools; + } + return tools; + }; + auto prime_tower_texture_wall_tool = [&prime_tower_texture](const LayerTools &layer_tools) -> int { + if (!prime_tower_texture.valid()) + return -1; + if (layer_tools.has_texture_mapping_zone && !layer_tools.texture_mapping_extruders.empty()) { + const size_t sequence_tool = prime_tower_texture.tool_for_layer_sequence(layer_tools.layer_index); + if (sequence_tool != size_t(-1) && std::find(layer_tools.texture_mapping_extruders.begin(), + layer_tools.texture_mapping_extruders.end(), + unsigned(sequence_tool)) != layer_tools.texture_mapping_extruders.end()) + return int(sequence_tool); + return int(layer_tools.texture_mapping_extruders.front()); + } + const size_t tool = prime_tower_texture.tool_for_layer_sequence(layer_tools.layer_index); + if (tool != size_t(-1)) + return int(tool); + return -1; + }; if (!is_wipe_tower_type2) { // in BBL machine, wipe tower is only use to prime extruder. So just use a global wipe volume. @@ -3584,13 +3621,17 @@ void Print::_make_wipe_tower() for (auto& layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) { // for all layers if (!layer_tools.has_wipe_tower) continue; bool first_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.front(); + std::vector texture_mapping_layer_tools = prime_tower_texture_layer_tools(layer_tools); + const int texture_mapping_wall_tool = prime_tower_texture_wall_tool(layer_tools); wipe_tower.plan_toolchange((float) layer_tools.print_z, (float) layer_tools.wipe_tower_layer_height, current_filament_id, current_filament_id, 0.f, 0.f, - layer_tools.has_texture_mapping_zone && layer_tools.extruders.size() == 1); + layer_tools.has_texture_mapping_zone && layer_tools.extruders.size() == 1, + texture_mapping_layer_tools, + texture_mapping_wall_tool); used_filament_ids.insert(layer_tools.extruders.begin(), layer_tools.extruders.end()); @@ -3718,8 +3759,10 @@ void Print::_make_wipe_tower() if (!layer_tools.has_wipe_tower) continue; bool first_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.front(); + std::vector texture_mapping_layer_tools = prime_tower_texture_layer_tools(layer_tools); + const int texture_mapping_wall_tool = prime_tower_texture_wall_tool(layer_tools); wipe_tower.plan_toolchange((float) layer_tools.print_z, (float) layer_tools.wipe_tower_layer_height, current_extruder_id, - current_extruder_id, false); + current_extruder_id, false, texture_mapping_layer_tools, texture_mapping_wall_tool); for (const auto extruder_id : layer_tools.extruders) { if ((first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back()) || extruder_id != current_extruder_id) {