2218{
2219 auto get_valid_extruder_id = [&](int last_nozzle_id) {
2221 return nozzle_opt ? nozzle_opt->extruder_id : 0;
2222 };
2223
2225 if (idx < 0 || idx >= (int) pre_cooling_temps.size() || idx >= (int) nozzle_temps.size())
2226 return false;
2227 return pre_cooling_temps[idx] > 0 && pre_cooling_temps[idx] < nozzle_temps[idx];
2228 };
2229
2230 auto get_partial_free_cooling_thres = [&](int idx) -> float {
2232 return 30.f;
2235 };
2236
2237 auto gcode_move_comp = [](const GCodeProcessorResult::MoveVertex& a, unsigned int gcode_id) {
2238 return a.gcode_id < gcode_id;
2239 };
2240
2242 auto it = std::upper_bound(
2244 [](unsigned int id, const std::pair<unsigned int, unsigned int>& block) { return id < block.first; });
2246 auto candidate = std::prev(it);
2247 if (gcode_id >= candidate->first && gcode_id <= candidate->second)
2248 return candidate->second;
2249 }
2250 return 0;
2251 };
2252
2254 auto it = std::upper_bound(
2256 [](unsigned int id, const std::pair<unsigned int, unsigned int>& block) { return id < block.first; });
2258 auto candidate = std::prev(it);
2259 if (gcode_id >= candidate->first && gcode_id <= candidate->second)
2260 return candidate->first;
2261 }
2262 return 0;
2263 };
2264
2265 auto adjust_iter = [&](std::vector<GCodeProcessorResult::MoveVertex>::const_iterator iter,
2266 const std::vector<GCodeProcessorResult::MoveVertex>::const_iterator&
begin,
2267 const std::vector<GCodeProcessorResult::MoveVertex>::const_iterator&
end,
2268 bool forward) -> std::vector<GCodeProcessorResult::MoveVertex>::const_iterator {
2269 if (forward) {
2270 while (iter != end) {
2271 unsigned current_id = iter->gcode_id;
2272 unsigned skip_block_end = find_skip_block_end(current_id);
2273 if (skip_block_end == 0)
2274 break;
2275 iter = std::lower_bound(iter, end, skip_block_end + 1, gcode_move_comp);
2276 }
2277 } else {
2278 while (iter != begin) {
2279 unsigned current_id = iter->gcode_id;
2280 unsigned skip_block_start = find_skip_block_start(current_id);
2281 if (skip_block_start == 0)
2282 break;
2283 auto new_iter = std::lower_bound(begin, iter, skip_block_start, gcode_move_comp);
2284 if (new_iter == begin)
2285 break;
2286 iter = std::prev(new_iter);
2287 }
2288 }
2289 return iter;
2290 };
2291
2292 if (!pre_cooling && !pre_heating && block.free_upper_gcode_id <= block.free_lower_gcode_id)
2293 return;
2294
2295 auto move_iter_lower = std::lower_bound(
moves.begin(),
moves.end(), block.free_lower_gcode_id, gcode_move_comp);
2296 auto move_iter_upper = std::lower_bound(
moves.begin(),
moves.end(), block.free_upper_gcode_id, gcode_move_comp);
2297
2298 if (move_iter_lower ==
moves.end() || move_iter_upper ==
moves.begin())
2299 return;
2300 --move_iter_upper;
2301 float complete_free_time_gap = 0;
2302 if (move_iter_lower ==
moves.begin())
2304 else
2306
2307 auto partial_free_move_lower = std::lower_bound(
moves.begin(),
moves.end(), block.partial_free_lower_id, gcode_move_comp);
2308 auto partial_free_move_upper = std::lower_bound(
moves.begin(),
moves.end(), block.partial_free_upper_id, gcode_move_comp);
2309 if (partial_free_move_lower ==
moves.end() || partial_free_move_upper ==
moves.begin())
2310 return;
2311 --partial_free_move_upper;
2312 float partial_free_time_gap = 0;
2313 if (partial_free_move_lower ==
moves.begin())
2315 else
2317
2318 if (move_iter_lower >= move_iter_upper)
2319 return;
2320
2321 bool apply_cooling_when_partial_free = is_pre_cooling_valid(block.last_filament_id) && pre_cooling;
2322
2323 if (apply_cooling_when_partial_free && partial_free_time_gap + complete_free_time_gap <
inject_time_threshold)
2324 return;
2325
2327 return;
2328
2329 int extruder_id = get_valid_extruder_id(block.last_nozzle_id);
2332
2333 auto add_M104_lines = [&](
int gcode_id,
int target_extruder,
int target_temp,
int target_filament,
bool skippable,
int next_filament_idx,
int next_nozzle_id,
TimeProcessor::InsertLineType type,
const std::string& comment = std::string()) {
2334 auto format_line_M104 = [&](int target_extruder, int target_temp, int target_filament, bool skippable, int next_filament_idx, int next_nozzle_id, const std::string& comment = std::string()) -> std::vector<std::string> {
2335 std::vector<std::string> buffer;
2336 if (skippable) {
2337 const bool support_dynamic_nozzle_map = this->
nozzle_group_result.is_support_dynamic_nozzle_map();
2338 std::string m632_line = "M632 S" + std::to_string(next_filament_idx);
2339 if (support_dynamic_nozzle_map)
2340 m632_line += " H" + std::to_string(next_nozzle_id);
2342 m632_line += " N R";
2343 m632_line += " W\n";
2344 buffer.emplace_back(std::move(m632_line));
2345 }
2346 buffer.emplace_back("M400\n");
2347 std::string M104_line = "M104";
2349 M104_line += (" I" + std::to_string(target_filament == -1 ? next_filament_idx : target_filament));
2350 } else if (target_extruder != -1) {
2352 }
2353
2354 M104_line += " S" + std::to_string(target_temp);
2355 M104_line += " N0";
2356
2357 if (!comment.empty())
2358 M104_line += " ;" + comment;
2359 M104_line += '\n';
2360
2361 buffer.emplace_back(M104_line);
2362
2363 if (skippable)
2364 buffer.emplace_back("M633\n");
2365
2366 return buffer;
2367 };
2368
2369 std::vector<std::string> line_buf = format_line_M104(target_extruder, target_temp, target_filament, skippable, next_filament_idx, next_nozzle_id, comment);
2370 for (auto& line : line_buf)
2371 inserted_operation_lines[gcode_id].emplace_back(line, type);
2372 };
2373
2374 constexpr float room_temperature = 25.f;
2375
2376 if (apply_cooling_when_partial_free) {
2377 float max_cooling_temp = std::min(curr_temp, std::min(get_partial_free_cooling_thres(block.last_filament_id), partial_free_time_gap * ext_cooling_rate));
2378 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": partial cooling for %1% %2%") % max_cooling_temp % curr_temp;
2379 curr_temp = std::max(room_temperature, curr_temp - max_cooling_temp);
2380 add_M104_lines(block.partial_free_lower_id, extruder_id, curr_temp, block.last_filament_id,
false, block.next_filament_id, block.next_nozzle_id,
TimeProcessor::InsertLineType::PreCooling,
"Multi extruder pre cooling in post extrusion");
2381 }
2382
2383 if (pre_cooling && !pre_heating) {
2384
2385 if (target_temp >= curr_temp)
2386 return;
2387 int clamped_target = std::max((int) room_temperature, (int) target_temp);
2388 add_M104_lines(block.free_lower_gcode_id, extruder_id, clamped_target, block.last_filament_id,
false, block.next_filament_id, block.next_nozzle_id,
TimeProcessor::InsertLineType::PreCooling,
"Multi extruder pre cooling");
2389 return;
2390 }
2391 if (!pre_cooling && pre_heating) {
2392
2393 if (target_temp <= curr_temp)
2394 return;
2395 float heating_start_time = move_iter_upper->time[
valid_machine_id] - (target_temp - curr_temp) / ext_heating_rate;
2396 auto heating_move_iter = std::upper_bound(move_iter_lower, move_iter_upper + 1, heating_start_time, [
valid_machine_id = this->
valid_machine_id](
float time,
const GCodeProcessorResult::MoveVertex& a) {
return time < a.time[
valid_machine_id]; });
2397 if (heating_move_iter == move_iter_lower) {
2398 add_M104_lines(block.free_lower_gcode_id, extruder_id, target_temp, block.next_filament_id,
true, block.next_filament_id, block.next_nozzle_id,
TimeProcessor::InsertLineType::PreHeating,
"Multi extruder pre heating");
2399 } else {
2400 --heating_move_iter;
2401 heating_move_iter = adjust_iter(heating_move_iter, move_iter_lower, move_iter_upper, false);
2402 add_M104_lines(heating_move_iter->gcode_id, extruder_id, target_temp, block.next_filament_id,
true, block.next_filament_id, block.next_nozzle_id,
TimeProcessor::InsertLineType::PreHeating,
"Multi extruder pre heating");
2403 }
2404 return;
2405 }
2406
2407 float mid_temp = std::max(room_temperature, (curr_temp * ext_heating_rate + target_temp * ext_cooling_rate - complete_free_time_gap * ext_cooling_rate * ext_heating_rate) / (ext_cooling_rate + ext_heating_rate));
2408 float heating_temp = target_temp - mid_temp;
2409 float heating_start_time = move_iter_upper->time[
valid_machine_id] - heating_temp / ext_heating_rate;
2410 auto heating_move_iter = std::upper_bound(move_iter_lower, move_iter_upper + 1, heating_start_time, [
valid_machine_id = this->
valid_machine_id](
float time,
const GCodeProcessorResult::MoveVertex& a) {
return time < a.time[
valid_machine_id]; });
2411 if (heating_move_iter == move_iter_lower)
2412 return;
2413 --heating_move_iter;
2414 heating_move_iter = adjust_iter(heating_move_iter, move_iter_lower, move_iter_upper, false);
2415
2416
2418 int real_delta_temp = std::min((int) (real_cooling_time * ext_cooling_rate), (int) curr_temp);
2419 if (real_delta_temp == 0)
2420 return;
2421 int cooling_temp = std::max((int) room_temperature, (int) curr_temp - real_delta_temp);
2422 add_M104_lines(block.free_lower_gcode_id, extruder_id, cooling_temp, block.last_filament_id,
false, block.next_filament_id, block.next_nozzle_id,
TimeProcessor::InsertLineType::PreCooling,
"Multi extruder pre cooling");
2423 add_M104_lines(heating_move_iter->gcode_id, extruder_id, target_temp, block.next_filament_id,
true, block.next_filament_id, block.next_nozzle_id,
TimeProcessor::InsertLineType::PreHeating,
"Multi extruder pre heating");
2424}
T * begin(Slic3r::Mat< N, M, T > &mat)
Definition Point.hpp:838
T * end(Slic3r::Mat< N, M, T > &mat)
Definition Point.hpp:841
static T value_at_or_front(const std::vector< T > &v, int i, T fallback)
Definition GCodeProcessor.cpp:2207
InsertLineType
Definition GCodeProcessor.hpp:914
@ PreCooling
Definition GCodeProcessor.hpp:919
@ PreHeating
Definition GCodeProcessor.hpp:920