BambuSrc/libslic3r/GCode/Smoothing.cpp

224 lines
9.6 KiB
C++

#include "Smoothing.hpp"
namespace Slic3r {
void SmoothCalculator::build_node(std::vector<OutwallCollection> & wall_collection,
const std::vector<int> & object_label,
const std::vector<PerExtruderAdjustments> &per_extruder_adjustments)
{
if (per_extruder_adjustments.empty())
return;
// BBS: update outwall feedrate
// update feedrate of outwall after initial cooling process
// initial and arrange node collection seq
for (size_t object_idx = 0; object_idx < object_label.size(); ++object_idx) {
OutwallCollection object_level;
object_level.object_id = object_label[object_idx];
wall_collection.push_back(object_level);
}
for (size_t extruder_idx = 0; extruder_idx < per_extruder_adjustments.size(); ++extruder_idx) {
const PerExtruderAdjustments &extruder_adjustments = per_extruder_adjustments[extruder_idx];
for (size_t line_idx = 0; line_idx < extruder_adjustments.lines.size(); ++line_idx) {
const CoolingLine &line = extruder_adjustments.lines[line_idx];
if (line.outwall_smooth_mark) {
// search node id
if (wall_collection[line.object_id].cooling_nodes.count(line.cooling_node_id) == 0) {
CoolingNode node;
wall_collection[line.object_id].cooling_nodes.emplace(line.cooling_node_id, node);
}
CoolingNode &node = wall_collection[line.object_id].cooling_nodes[line.cooling_node_id];
if (line.type & CoolingLine::TYPE_EXTERNAL_PERIMETER) {
node.outwall_line.emplace_back(line_idx, extruder_idx);
if (node.max_feedrate < line.feedrate) {
node.max_feedrate = line.feedrate;
node.filter_feedrate = node.max_feedrate;
}
}
}
}
}
}
static void exclude_participate_in_speed_slowdown(std::vector<std::pair<int, int>> & lines,
std::vector<PerExtruderAdjustments> &per_extruder_adjustments,
CoolingNode & node)
{
// BBS: add protect, feedrate will be 0 if the outwall is overhang. just apply not adjust flage
bool apply_speed = node.max_feedrate > 0 && node.filter_feedrate > 0;
if (apply_speed) node.rate = node.filter_feedrate / node.max_feedrate;
for (std::pair<int, int> line_pos : lines) {
CoolingLine &line = per_extruder_adjustments[line_pos.second].lines[line_pos.first];
if (apply_speed && line.feedrate > node.filter_feedrate) {
line.feedrate = node.filter_feedrate;
line.slowdown = true;
}
// not adjust outwal line speed
line.type = line.type & (~CoolingLine::TYPE_ADJUSTABLE);
// update time cost
if (line.feedrate == 0 || line.length == 0)
line.time = 0;
else
line.time = line.length / line.feedrate;
}
}
float SmoothCalculator::recaculate_layer_time(int layer_id, std::vector<PerExtruderAdjustments> &extruder_adjustments)
{
// rewrite feedrate
for (size_t obj_id = 0; obj_id < layers_wall_collection[layer_id].size(); ++obj_id) {
for (size_t node_id = 0; node_id < layers_wall_collection[layer_id][obj_id].cooling_nodes.size(); ++node_id) {
CoolingNode &node = layers_wall_collection[layer_id][obj_id].cooling_nodes[node_id];
// set outwall speed
exclude_participate_in_speed_slowdown(node.outwall_line, extruder_adjustments, node);
}
}
float layer_time = 0;
for (PerExtruderAdjustments extruder : extruder_adjustments) {
layer_time += extruder.collection_line_times_of_extruder();
}
return layer_time;
};
void SmoothCalculator::init_object_node_range()
{
for (size_t object_id = 0; object_id < objects_node_range.size(); ++object_id) {
for (size_t layer_id = 1; layer_id < layers_wall_collection.size(); ++layer_id) {
const OutwallCollection &each_object = layers_wall_collection[layer_id][object_id];
auto it = each_object.cooling_nodes.begin();
while (it != each_object.cooling_nodes.end()) {
if (objects_node_range[object_id].count(it->first) == 0) {
objects_node_range[object_id].emplace(it->first, std::pair<int, int>(layer_id, layer_id));
} else {
objects_node_range[object_id][it->first].second = layer_id;
}
it++;
}
}
}
}
void SmoothCalculator::smooth_layer_speed()
{
init_object_node_range();
for (size_t obj_id = 0; obj_id < objects_node_range.size(); ++obj_id) {
auto it = objects_node_range[obj_id].begin();
while (it != objects_node_range[obj_id].end()) {
int step_count = 0;
while (step_count < max_steps_count && speed_filter_continue(obj_id, it->first)) {
step_count++;
layer_speed_filter(obj_id, it->first);
}
it++;
}
}
}
void SmoothCalculator::layer_speed_filter(const int object_id, const int node_id)
{
int start_pos = guassian_filter.size() / 2;
// first layer don't need to be smoothed
int layer_start = objects_node_range[object_id][node_id].first;
int layer_end = objects_node_range[object_id][node_id].second;
// BBS: some layers may empty as the support has indenpendent layer
for (int layer_id = layer_start; layer_id <= layer_end; ++layer_id) {
if (layers_wall_collection[layer_id].empty()) continue;
if (layers_wall_collection[layer_id][object_id].cooling_nodes.count(node_id) == 0) break;
CoolingNode &node = layers_wall_collection[layer_id][object_id].cooling_nodes[node_id];
if (node.outwall_line.empty()) continue;
double conv_sum = 0;
for (int filter_pos_idx = 0; filter_pos_idx < guassian_filter.size(); ++filter_pos_idx) {
int remap_data_pos = layer_id - start_pos + filter_pos_idx;
if (remap_data_pos < layer_start)
remap_data_pos = layer_start;
else if (remap_data_pos > layer_end)
remap_data_pos = layer_end;
// some node may not start at layer 1
double remap_data = node.filter_feedrate;
if (!layers_wall_collection[remap_data_pos][object_id].cooling_nodes[node_id].outwall_line.empty())
remap_data = layers_wall_collection[remap_data_pos][object_id].cooling_nodes[node_id].filter_feedrate;
conv_sum += guassian_filter[filter_pos_idx] * remap_data;
}
double filter_res = conv_sum / filter_sum;
if (filter_res < node.filter_feedrate) node.filter_feedrate = filter_res;
}
}
bool SmoothCalculator::speed_filter_continue(const int object_id, const int node_id)
{
int layer_id = objects_node_range[object_id][node_id].first;
int layer_end = objects_node_range[object_id][node_id].second;
// BBS: some layers may empty as the support has indenpendent layer
for (; layer_id < layer_end; ++layer_id) {
if (std::abs(layers_wall_collection[layer_id + 1][object_id].cooling_nodes[node_id].filter_feedrate -
layers_wall_collection[layer_id][object_id].cooling_nodes[node_id].filter_feedrate) > guassian_stop_threshold)
return true;
}
return false;
}
void SmoothCalculator::filter_layer_time()
{
int start_pos = guassian_filter.size() / 2;
// first layer don't need to be smoothed
for (int layer_id = 1; layer_id < layers_cooling_time.size(); ++layer_id) {
if (layers_cooling_time[layer_id] > layer_time_smoothing_threshold) continue;
double conv_sum = 0;
for (int filter_pos_idx = 0; filter_pos_idx < guassian_filter.size(); ++filter_pos_idx) {
int remap_data_pos = layer_id - start_pos + filter_pos_idx;
if (remap_data_pos < 1)
remap_data_pos = 1;
else if (remap_data_pos > layers_cooling_time.size() - 1)
remap_data_pos = layers_cooling_time.size() - 1;
// if the layer time big enough, surface defact will disappear
double data_temp = layers_cooling_time[remap_data_pos] > layer_time_smoothing_threshold ? layer_time_smoothing_threshold : layers_cooling_time[remap_data_pos];
conv_sum += guassian_filter[filter_pos_idx] * data_temp;
}
double filter_res = conv_sum / filter_sum;
filter_res = filter_res > layer_time_smoothing_threshold ? layer_time_smoothing_threshold : filter_res;
if (filter_res > layers_cooling_time[layer_id]) layers_cooling_time[layer_id] = filter_res;
}
}
bool SmoothCalculator::layer_time_filter_continue()
{
for (int layer_id = 1; layer_id < layers_cooling_time.size() - 1; ++layer_id) {
double layer_time = layers_cooling_time[layer_id] > layer_time_smoothing_threshold ? layer_time_smoothing_threshold : layers_cooling_time[layer_id];
double layer_time_cmp = layers_cooling_time[layer_id + 1] > layer_time_smoothing_threshold ? layer_time_smoothing_threshold : layers_cooling_time[layer_id + 1];
if (std::abs(layer_time - layer_time_cmp) > guassian_layer_time_stop_threshold) return true;
}
return false;
}
void SmoothCalculator::smooth_layer_time()
{
int step_count = 0;
while (step_count < max_steps_count && layer_time_filter_continue()) {
step_count++;
filter_layer_time();
}
}
} // namespace Slic3r