476{
478 if (logical_filaments.empty() || nozzle_list.empty() || filament_change_seq.empty() || nozzle_change_seq.empty())
479 return result;
480
481
482
483
488
489
490 std::unordered_map<int, int> nozzle_to_extruder;
491 nozzle_to_extruder.reserve(nozzle_list.size());
492 for (const auto& nozzle : nozzle_list)
493 nozzle_to_extruder[nozzle.group_id] = nozzle.extruder_id;
494
495
496 std::unordered_map<int, int> filament_to_group;
497 filament_to_group.reserve(logical_filaments.size());
498 for (size_t i = 0; i < logical_filaments.size(); ++i)
499 filament_to_group[logical_filaments[i]] = group_of_filament[i];
500
501 const auto get_group = [&](int filament_id) -> int {
502 auto it = filament_to_group.find(filament_id);
503 return it != filament_to_group.end() ? it->second : -1;
504 };
505
506 const auto is_preload_enabled = [&](
int group_id) ->
bool {
508 return false;
509 return ams_preload_enabled[
group_id];
510 };
511
512
513 enum class Location { IN_AMS, IN_SELECTOR, IN_EXTRUDER };
514 std::unordered_map<int, Location> filament_location;
515 std::unordered_map<int, int> filament_extruder;
516 std::unordered_map<int, int> extruder_filament;
517
518 std::unordered_map<int, std::unordered_set<int>> ams_group_occupied;
519
520 filament_location.reserve(logical_filaments.size());
521 filament_extruder.reserve(logical_filaments.size());
522
523
524 for (
int f : logical_filaments)
525 filament_location[
f] = Location::IN_AMS;
526
527
529
530 const size_t seq_len = std::min(filament_change_seq.size(), nozzle_change_seq.size());
531 double actual_time = 0.0;
532 double sliced_time = 0.0;
533
534 for (size_t i = 0; i < seq_len; ++i) {
535 int B = filament_change_seq[i];
536 int nozzle_id = nozzle_change_seq[i];
537
538 auto nozzle_iter = nozzle_to_extruder.find(nozzle_id);
539 if (nozzle_iter == nozzle_to_extruder.end()) continue;
540
541 int E = nozzle_iter->second;
542
543
544
545
546 if (calc_sliced_time) {
547 int old_nozzle_in_E = sliced_recorder.get_nozzle_in_extruder(
E);
548 int old_filament_in_nozzle = sliced_recorder.get_filament_in_nozzle(nozzle_id);
549 int old_filament_in_ext = sliced_recorder.get_filament_in_nozzle(old_nozzle_in_E);
550
551 bool nozzle_change = (old_nozzle_in_E != nozzle_id);
552 bool filament_change = (old_filament_in_nozzle != B);
553
554 if (nozzle_change || filament_change) {
555 if (old_filament_in_ext != -1)
558 }
559 sliced_recorder.set_nozzle_status(nozzle_id, B,
E);
560 }
561
562
563 int A = -1;
564 {
565 auto it = extruder_filament.find(
E);
566 if (it != extruder_filament.end())
567 A = it->second;
568 }
569
570 int group_B = get_group(B);
571 int group_A = (A != -1) ? get_group(A) : -1;
572
573
574 auto group_it = ams_group_occupied.find(group_B);
575 if (group_it != ams_group_occupied.end()) {
576 for (
int X : group_it->second) {
577 if (
X == B)
continue;
578
579 Location loc_X = filament_location[
X];
580 if (loc_X == Location::IN_EXTRUDER) {
581 actual_time += unload_ext_to_selector + unload_ams_to_selector;
582 int E2 = filament_extruder[
X];
583 extruder_filament.erase(E2);
584 filament_extruder.erase(
X);
585 } else if (loc_X == Location::IN_SELECTOR) {
586 actual_time += unload_ams_to_selector;
587 }
588 filament_location[
X] = Location::IN_AMS;
589 }
590 group_it->second.clear();
591 }
592
593
594
595
596 bool step3_executed = false;
597 float step3_time = 0.0f;
598 if (A != -1 && A != B && filament_location[A] == Location::IN_EXTRUDER) {
599 if (is_preload_enabled(group_A) && group_A != group_B) {
600 step3_time = unload_ext_to_selector;
601 filament_location[A] = Location::IN_SELECTOR;
602 } else {
603 step3_time = unload_ext_to_selector + unload_ams_to_selector;
604 filament_location[A] = Location::IN_AMS;
605 ams_group_occupied[group_A].erase(A);
606 }
607 extruder_filament.erase(
E);
608 filament_extruder.erase(A);
609 step3_executed = true;
610 }
611
612 float step3_5_time = 0.0f;
613 if (step3_executed &&
614 filament_location[B] == Location::IN_AMS &&
615 group_A != group_B &&
616 is_preload_enabled(group_B)) {
617 step3_5_time = load_ams_to_selector;
618 filament_location[B] = Location::IN_SELECTOR;
619 ams_group_occupied[group_B].insert(B);
620 }
621
622 actual_time += std::max(step3_time, step3_5_time);
623
624
625
626
627 float step4_time = 0.0f;
628 Location loc_B = filament_location[B];
629 if (loc_B == Location::IN_AMS) {
630 step4_time = load_ams_to_selector + load_selector_to_ext;
631 } else if (loc_B == Location::IN_SELECTOR) {
632 step4_time = load_selector_to_ext;
633 }
634
635
636 extruder_filament[
E] = B;
637 filament_location[B] = Location::IN_EXTRUDER;
638 filament_extruder[B] =
E;
639 ams_group_occupied[group_B].insert(B);
640
641 float step6_time = 0.0f;
642 if (i + 1 < seq_len) {
643 int C = filament_change_seq[i + 1];
644 int group_C = get_group(C);
645 if (filament_location[C] == Location::IN_AMS &&
646 group_C != group_B &&
647 is_preload_enabled(group_C) &&
648 ams_group_occupied[group_C].
empty()) {
649 step6_time = load_ams_to_selector;
650 filament_location[C] = Location::IN_SELECTOR;
651 ams_group_occupied[group_C].insert(C);
652 }
653 }
654
655 actual_time += std::max(step4_time, step6_time);
656 }
657
660 return result;
661}
Definition MultiNozzleUtils.hpp:228
float standard_load_time
Definition MultiNozzleUtils.hpp:90
float selector_load_time
Definition MultiNozzleUtils.hpp:88
float selector_unload_time
Definition MultiNozzleUtils.hpp:89
float standard_unload_time
Definition MultiNozzleUtils.hpp:91
double actual_time
Definition MultiNozzleUtils.hpp:254
double sliced_time
Definition MultiNozzleUtils.hpp:255
Definition MultiNozzleUtils.hpp:253
static double f(double x, double z_sin, double z_cos, bool vertical, bool flip)
Definition FillGyroid.cpp:124
@ E
Definition libslic3r.h:144
@ X
Definition libslic3r.h:141
bool empty(const BoundingBoxBase< PointType, PointsType > &bb)
Definition BoundingBox.hpp:273