2247{
2248 const auto &is_mixed = config.filament_is_mixed.values;
2249 const auto &comp_strs = config.filament_mixed_components.values;
2250 const auto &ratio_strs = config.filament_mixed_sublayer_ratios.values;
2251
2252
2253
2256 std::set<unsigned int> used;
2258 for (unsigned int ext : lt.extruders)
2259 if (ext < is_mixed.size() && is_mixed[ext])
2260 used.insert(ext);
2262 }
2263
2265 return;
2266
2267 const bool sublayer_enabled = config.enable_mixed_color_sublayer.value;
2268
2269 struct SlotInfo {
2270 std::vector<unsigned int> components;
2271 std::vector<double> ratios;
2272 std::vector<long long> accum;
2273 };
2274 std::vector<SlotInfo> slots(is_mixed.size());
2275 for (size_t i = 0; i < is_mixed.size(); ++i) {
2276 if (!is_mixed[i])
2277 continue;
2279 if (slots[i].components.size() < 2) {
2280 slots[i].components.clear();
2281 continue;
2282 }
2283 for (unsigned int cid : slots[i].components) {
2284 unsigned int idx0 = cid - 1;
2285 if (idx0 >= is_mixed.size() || (idx0 < is_mixed.size() && is_mixed[idx0])) {
2286 slots[i].components.clear();
2287 break;
2288 }
2289 }
2290 if (slots[i].components.empty())
2291 continue;
2293 i < ratio_strs.size() ? ratio_strs[i] : "", slots[i].components.size());
2294 if (!sublayer_enabled) {
2295 for (double &r : slots[i].ratios)
2297 double sum = 0;
2298 for (double r : slots[i].ratios) sum += r;
2299 if (sum > 0)
2300 for (double &r : slots[i].ratios) r /= sum;
2301 }
2302 slots[i].accum.assign(slots[i].components.size(), 0LL);
2303 }
2304
2305
2306 const auto &gradient_flags = config.filament_mixed_gradient.values;
2307 const auto &gradient_range_strs = config.filament_mixed_gradient_range.values;
2308 const auto &gradient_curve_strs = config.filament_mixed_gradient_curve.values;
2309 struct GradientInfo {
2310 double start = 0.10;
2311 double end_val = 0.90;
2312 GradientCurve curve;
2313 };
2314 std::vector<bool> is_gradient(is_mixed.size(), false);
2315 std::vector<GradientInfo> gradient_info(is_mixed.size());
2316 for (size_t i = 0; i < is_mixed.size(); ++i) {
2317 if (!is_mixed[i] || slots[i].components.size() != 2)
2318 continue;
2319 if (i >= gradient_flags.size() || !gradient_flags[i])
2320 continue;
2321 is_gradient[i] = true;
2322 if (i < gradient_range_strs.size() && !gradient_range_strs[i].empty()) {
2323 CNumericLocalesSetter c_locale_setter;
2324 float v0 = 0, v1 = 0;
2325 if (std::sscanf(gradient_range_strs[i].c_str(), "%f,%f", &v0, &v1) == 2 &&
2326 v0 > 0 && v0 < 1.0 && v1 > 0 && v1 < 1.0) {
2327 gradient_info[i].start = v0;
2328 gradient_info[i].end_val = v1;
2329 }
2330 }
2331 if (i < gradient_curve_strs.size() && !gradient_curve_strs[i].empty())
2333 }
2334
2335
2336
2337 struct GradientRunInfo {
2338 std::vector<size_t> run_lengths;
2339 int current_run = -1;
2340 size_t current_idx = 0;
2341 bool prev_appeared = false;
2342 bool last_absent_was_relevant = false;
2343 };
2344 std::map<unsigned int, GradientRunInfo> gradient_runs;
2345 for (size_t i = 0; i < is_mixed.size(); ++i)
2346 if (is_gradient[i]) gradient_runs[static_cast<unsigned int>(i)] = {};
2347
2348
2349
2350
2351
2352 std::map<unsigned int, std::set<size_t>> slot_relevant_layers;
2354 for (
auto &[obj,
_] : obj_map) {
2357 slot_relevant_layers[slot_idx].insert(it->second.begin(), it->second.end());
2358 }
2359 }
2360
2361 if (!gradient_runs.empty()) {
2363 if (li == 0) continue;
2365 for (auto &[slot, run] : gradient_runs) {
2366 bool here = std::find(lt.extruders.begin(), lt.extruders.end(), slot) != lt.extruders.end();
2367 if (here) {
2368 bool real_gap = false;
2369 if (!
run.prev_appeared && !
run.run_lengths.empty()) {
2370 real_gap =
run.last_absent_was_relevant;
2371 }
2372 if (
run.run_lengths.empty() || real_gap)
2373 run.run_lengths.push_back(0);
2374 run.run_lengths.back()++;
2375 run.last_absent_was_relevant =
false;
2376 }
else if (!
run.run_lengths.empty()) {
2377 auto rel_it = slot_relevant_layers.find(slot);
2378 if (rel_it != slot_relevant_layers.end() && rel_it->second.count(li))
2379 run.last_absent_was_relevant =
true;
2380 }
2381 run.prev_appeared = here;
2382 }
2383 }
2384 for (auto &[slot, run] : gradient_runs) {
2385 run.current_run = -1;
2386 run.current_idx = 0;
2387 run.prev_appeared =
false;
2388 run.last_absent_was_relevant =
false;
2389 }
2390 }
2391
2392
2393 struct PerObjRunState {
2394 std::vector<size_t> run_start_offsets;
2395 std::vector<size_t> run_lengths;
2396 int current_run = -1;
2397 size_t current_idx = 0;
2398 };
2399
2400
2401
2402
2403
2404 auto has_real_gap = [](size_t prev_idx, size_t cur_idx,
2405 const std::set<size_t>& obj_set,
2406 const std::set<size_t>& slot_set) -> bool {
2407 for (auto it = obj_set.lower_bound(prev_idx + 1);
2408 it != obj_set.end() && *it < cur_idx; ++it) {
2409 if (!slot_set.count(*it))
2410 return true;
2411 }
2412 return false;
2413 };
2414
2415
2416
2417 auto segment_runs = [&](const std::vector<size_t>& layer_indices,
2418 const std::set<size_t>& obj_set,
2419 const std::set<size_t>& slot_set) -> PerObjRunState {
2420 PerObjRunState st;
2421 for (size_t i = 0; i < layer_indices.size(); ++i) {
2422 bool new_run = (i == 0) ||
2423 has_real_gap(layer_indices[i - 1], layer_indices[i], obj_set, slot_set);
2424 if (new_run) {
2425 st.run_start_offsets.push_back(i);
2426 st.run_lengths.push_back(0);
2427 }
2428 st.run_lengths.back()++;
2429 }
2430 return st;
2431 };
2432
2433 std::map<unsigned int, std::map<const PrintObject*, PerObjRunState>> per_obj_runs;
2435 if (slot >= is_gradient.size() || !is_gradient[slot])
2436 continue;
2437 for (auto &[obj, layer_indices] : obj_map) {
2439
2440 if (!layer_indices.empty() && layer_indices.front() == 0)
2441 layer_indices.erase(layer_indices.begin());
2442
2444 std::set<size_t> all_obj_set(all_obj_layers.begin(), all_obj_layers.end());
2445 std::set<size_t> grad_set(layer_indices.begin(), layer_indices.end());
2446
2447 per_obj_runs[slot][obj] = segment_runs(layer_indices, all_obj_set, grad_set);
2448 }
2449 }
2450
2451
2452
2453
2454
2455
2456 using VolumeKey = LayerTools::MixedSubLayerGroup::VolumeKey;
2457 std::map<unsigned int, std::map<VolumeKey, PerObjRunState>> per_vol_runs;
2459 if (slot >= is_gradient.size() || !is_gradient[slot])
2460 continue;
2461 for (auto &[vkey, layer_indices] : vol_map) {
2463 if (!layer_indices.empty() && layer_indices.front() == 0)
2464 layer_indices.erase(layer_indices.begin());
2465
2467 std::set<size_t> all_obj_set(all_obj_layers.begin(), all_obj_layers.end());
2468 std::set<size_t> vol_grad_set(layer_indices.begin(), layer_indices.end());
2469
2470 per_vol_runs[slot][vkey] = segment_runs(layer_indices, all_obj_set, vol_grad_set);
2471 }
2472 }
2473
2475
2476
2477
2478 std::map<unsigned int, coordf_t> prev_print_z_for_slot;
2479
2480
2481
2482
2483 std::map<unsigned int, coordf_t> prev_relevant_z_for_slot;
2484
2485
2486
2487
2488
2489 auto calc_slot_lh = [&](
unsigned int ext,
coordf_t print_z) ->
double {
2490 auto slot_pz_it = prev_print_z_for_slot.find(ext);
2491 auto rel_pz_it = prev_relevant_z_for_slot.find(ext);
2493 if (slot_pz_it != prev_print_z_for_slot.end()) {
2494 base_z = slot_pz_it->second;
2495 if (rel_pz_it != prev_relevant_z_for_slot.end())
2496 base_z = std::max(base_z, rel_pz_it->second);
2497 }
2498 double lh = print_z - base_z;
2499 return (lh > 0.) ? lh : 0.2;
2500 };
2501
2503 size_t layer_idx =
static_cast<size_t>(< -
m_layer_tools.data());
2504
2505
2506 if (layer_idx > 0) {
2507 for (auto &[slot, run] : gradient_runs) {
2508 bool here = std::find(lt.extruders.begin(), lt.extruders.end(), slot) != lt.extruders.end();
2509 if (here) {
2510 if (!
run.prev_appeared) {
2511 if (
run.last_absent_was_relevant ||
run.current_run < 0) {
2513 run.current_idx = 0;
2514 }
2515 }
2516 run.last_absent_was_relevant =
false;
2517 } else {
2518 auto rel_it = slot_relevant_layers.find(slot);
2519 if (rel_it != slot_relevant_layers.end() && rel_it->second.count(layer_idx))
2520 run.last_absent_was_relevant =
true;
2521 }
2522 run.prev_appeared = here;
2523 }
2524 }
2525
2526 std::vector<unsigned int> new_extruders;
2527 for (unsigned int ext : lt.extruders) {
2528 if (ext >= slots.size() || slots[ext].components.empty()) {
2529 new_extruders.push_back(ext);
2530 continue;
2531 }
2532 auto &s = slots[ext];
2533
2534
2535 if (sublayer_enabled && layer_idx > 0) {
2536 double lh = calc_slot_lh(ext, lt.print_z);
2537 size_t n = s.components.size();
2538
2539 std::vector<double> sub_heights;
2540 bool gradient_last_no_split = false;
2541 unsigned int gradient_last_dominant_0b = 0;
2542 if (is_gradient[ext] && n == 2) {
2543 auto gr_it = gradient_runs.find(ext);
2544 if (gr_it != gradient_runs.end() && gr_it->second.current_run >= 0 &&
2545 static_cast<size_t>(gr_it->second.current_run) < gr_it->second.run_lengths.size()) {
2546 auto &
run = gr_it->second;
2547 size_t N =
run.run_lengths[
run.current_run];
2548 size_t idx =
run.current_idx++;
2549 double t = (
N > 0) ? (2.0 * idx + 1.0) / (2.0 *
N) : 0.5;
2550
2551 double r1 = gradient_info[ext].curve.empty()
2552 ? (gradient_info[ext].start + (gradient_info[ext].end_val - gradient_info[ext].start) * t)
2554 double r2 = 1.0 - r1;
2555 sub_heights.push_back(r1 * lh);
2556 sub_heights.push_back(r2 * lh);
2557
2558
2559
2560
2561
2562
2563 if (idx == N - 1) {
2564
2565 size_t dominant = (r1 >= r2) ? 0 : 1;
2566 unsigned int dom_0b = s.components[dominant] - 1;
2567 unsigned int oth_0b = s.components[1 - dominant] - 1;
2568 if (dom_0b < oth_0b) {
2569 gradient_last_no_split = true;
2570 gradient_last_dominant_0b = dom_0b;
2571 }
2572 }
2573 } else {
2574 for (double r : s.ratios)
2575 sub_heights.push_back(r * lh);
2576 }
2577 } else {
2578 for (double r : s.ratios)
2579 sub_heights.push_back(r * lh);
2580 }
2581
2582
2583
2584
2585
2586
2587
2588 bool per_vol_active_for_slot = per_vol_runs.find(ext) != per_vol_runs.end()
2589 && !per_vol_runs[ext].empty();
2590
2591 if (gradient_last_no_split && !per_vol_active_for_slot) {
2592 lt.mixed_filament_resolution[ext] = gradient_last_dominant_0b;
2593 new_extruders.push_back(gradient_last_dominant_0b);
2594 prev_print_z_for_slot[ext] = lt.print_z;
2595 continue;
2596 }
2597
2598 LayerTools::MixedSubLayerGroup grp;
2599 grp.mixed_slot_0based = ext;
2600 grp.layer_height = lh;
2601 grp.is_gradient = is_gradient[ext];
2602 for (size_t k = 0; k < s.components.size(); ++k) {
2603 unsigned int comp_0based = s.components[k] - 1;
2604 grp.components_0based.push_back(comp_0based);
2605 }
2606 grp.sub_heights = sub_heights;
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616 if (grp.is_gradient) {
2617 auto vol_runs_slot_it = per_vol_runs.find(ext);
2618 if (vol_runs_slot_it != per_vol_runs.end()) {
2620 for (auto &[vkey, st] : vol_runs_slot_it->second) {
2621 auto &layer_indices = vol_slot_it->second[vkey];
2622 if (!std::binary_search(layer_indices.begin(), layer_indices.end(), layer_idx))
2623 continue;
2624 if (st.current_run < 0 ||
2625 st.current_idx >= st.run_lengths[st.current_run]) {
2626 st.current_run++;
2627 st.current_idx = 0;
2628 }
2629 size_t run_N = st.run_lengths[st.current_run];
2630 size_t run_idx = st.current_idx++;
2631 grp.per_volume_gradient[vkey] = {
2632 run_N,
2633 run_idx,
2634 gradient_info[ext].start,
2635 gradient_info[ext].end_val,
2636 gradient_info[ext].curve,
2637 };
2638 }
2639 }
2640
2641 auto runs_slot_it = per_obj_runs.find(ext);
2642 if (runs_slot_it != per_obj_runs.end()) {
2644 for (auto &[obj, st] : runs_slot_it->second) {
2645 auto &layer_indices = slot_it->second[obj];
2646 if (!std::binary_search(layer_indices.begin(), layer_indices.end(), layer_idx))
2647 continue;
2648 if (st.current_run < 0 ||
2649 st.current_idx >= st.run_lengths[st.current_run]) {
2650 st.current_run++;
2651 st.current_idx = 0;
2652 }
2653 size_t run_N = st.run_lengths[st.current_run];
2654 size_t run_idx = st.current_idx++;
2655 grp.per_object_gradient[obj] = {
2656 run_N,
2657 run_idx,
2658 gradient_info[ext].start,
2659 gradient_info[ext].end_val,
2660 gradient_info[ext].curve,
2661 };
2662 }
2663 }
2664 }
2665
2666 if (grp.components_0based.size() > 1) {
2667 unsigned int first_comp_0based = s.components[0] - 1;
2668 std::vector<size_t> idx(grp.components_0based.size());
2669 std::iota(idx.begin(), idx.end(), 0);
2670 std::sort(idx.begin(), idx.end(), [&](size_t a, size_t b) {
2671 return grp.components_0based[a] < grp.components_0based[b];
2672 });
2673 std::vector<unsigned int> sorted_comps;
2674 std::vector<double> sorted_heights;
2675 for (size_t i : idx) {
2676 sorted_comps.push_back(grp.components_0based[i]);
2677 sorted_heights.push_back(grp.sub_heights[i]);
2678 }
2679 grp.components_0based = std::move(sorted_comps);
2680 grp.sub_heights = std::move(sorted_heights);
2681 if (grp.is_gradient) {
2682 for (size_t i = 0; i < grp.components_0based.size(); ++i) {
2683 if (grp.components_0based[i] == first_comp_0based) {
2684 grp.gradient_first_sorted_idx = static_cast<int>(i);
2685 break;
2686 }
2687 }
2688 }
2689 }
2690
2691 for (unsigned int comp : grp.components_0based)
2692 new_extruders.push_back(comp);
2693 lt.mixed_sub_layer_groups.push_back(std::move(grp));
2694 prev_print_z_for_slot[ext] = lt.print_z;
2695 } else {
2696
2697
2698
2699 double lh = calc_slot_lh(ext, lt.print_z);
2700 long long lh_i = std::llround(lh * 1e6);
2701
2702
2703
2704
2705
2706
2707
2708 if (layer_idx == 0 && is_gradient[ext] && s.components.size() == 2) {
2709 double r0 = gradient_info[ext].start;
2710 s.accum[0] += std::llround(r0 * lh_i);
2711 s.accum[1] += std::llround((1.0 - r0) * lh_i);
2712 } else {
2713 for (size_t k = 0; k < s.ratios.size(); ++k)
2714 s.accum[k] += std::llround(s.ratios[k] * lh_i);
2715 }
2716 size_t sel = 0;
2717 for (size_t k = 1; k < s.accum.size(); ++k)
2718 if (s.accum[k] > s.accum[sel])
2719 sel = k;
2720 s.accum[sel] -= lh_i;
2721 unsigned int resolved = s.components[sel] - 1;
2722 lt.mixed_filament_resolution[ext] = resolved;
2723 new_extruders.push_back(resolved);
2724 prev_print_z_for_slot[ext] = lt.print_z;
2725 }
2726 }
2727 lt.extruders = new_extruders;
2729
2730
2731
2732 for (auto &[slot, rel_set] : slot_relevant_layers) {
2733 if (rel_set.count(layer_idx))
2734 prev_relevant_z_for_slot[slot] = lt.print_z;
2735 }
2736
2737 prev_print_z = lt.print_z;
2738 }
2739}
#define _(s)
Definition 3mf.cpp:306
AppActionRunResult run(const std::string &key, const std::string ¶m={})
Definition NativeCommands.cpp:668
@ N
Definition CalibrationWizardSavePage.cpp:124
GradientCurve parse_gradient_curve(const std::string &s)
Definition FilamentMixer.cpp:269
static double snap_to_simple_fraction(double r, int max_denom=10)
Definition ToolOrdering.cpp:2228
double sample_gradient_curve(const GradientCurve &c, double t)
Definition FilamentMixer.cpp:357
std::vector< double > parse_mixed_ratios(const std::string &str, size_t n_components)
Definition FilamentMixer.cpp:404