1150{
1151
1153
1155
1156#ifdef __WXGTK__
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185 {
1186 const char* gdk_backend = ::getenv("GDK_BACKEND");
1187
1188
1189 const bool x11_opt_in = gdk_backend && boost::starts_with(gdk_backend, "x11");
1190
1191
1192
1193
1195 ::setenv("WEBKIT_DMABUF_RENDERER_FORCE_SHM", "1", false);
1196 ::setenv("WEBKIT_FORCE_DMABUF_RENDERER", "1", false);
1197 }
1198
1200 ::setenv("WEBKIT_DMABUF_RENDERER_FORCE_SHM", "1", false);
1201
1202 if (x11_opt_in) {
1203
1204 BOOST_LOG_TRIVIAL(info) << "GDK_BACKEND=x11 detected; applying v2.3.2 X11/XWayland workarounds.";
1205
1206
1207
1208
1209 ::setenv("DRI_PRIME", "1", false);
1210
1211
1212
1213
1214 if (::access("/proc/driver/nvidia/version", F_OK) == 0) {
1215 ::setenv("__NV_PRIME_RENDER_OFFLOAD", "1", false);
1216 ::setenv("__GLX_VENDOR_LIBRARY_NAME", "nvidia", false);
1217 }
1218
1219
1220
1221
1222 #if __has_include(<X11/Xlib.h>)
1223 XInitThreads();
1224 #endif
1225 } else {
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235 #if !defined(wxHAS_EGL) || !wxHAS_EGL
1236 {
1237 const char* wayland_env = ::getenv("WAYLAND_DISPLAY");
1238 if (wayland_env && *wayland_env) {
1239 BOOST_LOG_TRIVIAL(warning) << "Wayland detected but wxWidgets has no EGL support (wxHAS_EGL is OFF). Forcing X11 backend.";
1240 ::setenv("GDK_BACKEND", "x11", true);
1241
1242
1243
1244
1245
1246
1248 ::setenv("WEBKIT_DISABLE_COMPOSITING_MODE", "1", false);
1249 }
1250 }
1251 #endif
1252
1253
1254
1255
1256 #if __has_include(<X11/Xlib.h>)
1257 {
1258 const char* display_env = ::getenv("DISPLAY");
1259 if (display_env && *display_env) {
1260 XInitThreads();
1261 }
1262 }
1263 #endif
1264 }
1265 }
1266#endif
1267
1268
1269 try {
1270 boost::nowide::nowide_filesystem();
1271 } catch (const std::runtime_error& ex) {
1273 std::string text = std::string("boost::nowide::nowide_filesystem Failed!\n") + (
1275 #if defined(_WIN32) && defined(SLIC3R_GUI)
1277
1278 MessageBoxA(NULL, text.c_str(), caption.c_str(), MB_OK | MB_ICONERROR);
1279 #endif
1280 boost::nowide::cerr << text.c_str() << std::endl;
1282 }
1283
1284 if (!this->
setup(argc, argv))
1285 {
1286 boost::nowide::cerr << "setup params error" << std::endl;
1288 }
1289 BOOST_LOG_TRIVIAL(info) << "finished setup params, argc="<< argc << std::endl;
1291
1292 try {
1293 boost::filesystem::create_directories(temp_path);
1294 } catch (const std::exception &ex) {
1295 BOOST_LOG_TRIVIAL(warning) << "failed to create per-user temp dir " << temp_path << ": " << ex.what();
1296 }
1298
1299
1300
1301
1303 m_extra_config.set_key_value(
"has_filament_switcher",
new ConfigOptionBool(
false));
1305 m_extra_config.set_key_value(
"enable_filament_dynamic_map",
new ConfigOptionBool(
false));
1306
1309
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321 bool translate_old = false, regenerate_thumbnails = false, keep_old_params = false, remove_wrapping_detect = false, filament_color_changed = false, downward_check = false;
1322 int current_printable_width, current_printable_depth, current_printable_height, shrink_to_new_bed = 0;
1323 int old_printable_height = 0, old_printable_width = 0, old_printable_depth = 0;
1324 Pointfs old_printable_area, old_exclude_area;
1325 float old_max_radius = 0.f, old_height_to_rod = 0.f, old_height_to_lid = 0.f;
1326 std::vector<double> old_max_layer_height, old_min_layer_height;
1327 std::string outfile_dir =
m_config.opt_string(
"outputdir",
true);
1328 const std::vector<std::string> &load_configs =
m_config.option<ConfigOptionStrings>(
"load_settings",
true)->values;
1329 const std::vector<std::string> &uptodate_configs =
m_config.option<ConfigOptionStrings>(
"uptodate_settings",
true)->values;
1330 const std::vector<std::string> &uptodate_filaments =
m_config.option<ConfigOptionStrings>(
"uptodate_filaments",
true)->values;
1331 std::vector<std::string> downward_settings =
m_config.option<ConfigOptionStrings>(
"downward_settings",
true)->values;
1332 std::vector<std::string> downward_compatible_machines;
1333
1334
1336 const std::vector<std::string> &load_filaments =
m_config.option<ConfigOptionStrings>(
"load_filaments",
true)->values;
1337
1339 std::map<int, bool> skip_maps;
1340 bool need_skip = (skip_objects.size() > 0)?true:false;
1341 long long global_begin_time = 0, global_current_time;
1343
1345
1346
1347
1349 boost::nowide::cerr << "--strict cannot be combined with --no-check" << std::endl;
1352 }
1353 std::map<std::string, std::string> record_key_values;
1354
1355 ConfigOptionBool* downward_check_option =
m_config.option<ConfigOptionBool>(
"downward_check");
1356 if (downward_check_option)
1357 downward_check = downward_check_option->
value;
1358
1359
1360
1361
1363 static const std::set<std::string> inspect_compatible = { "inspect_mesh", "uptodate", "load_defaultfila", "min_save",
1364 "mtcpp", "mstpp", "no_check", "normative_check", "pipe" };
1365 for (
const std::string &action :
m_actions) {
1366 if (inspect_compatible.count(action) == 0) {
1367 std::string flag = action;
1368 std::replace(flag.begin(), flag.end(), '_', '-');
1369 boost::nowide::cerr << "--inspect-mesh cannot be combined with --" << flag << std::endl;
1372 }
1373 }
1374
1376 boost::nowide::cerr << "--inspect-mesh needs an input file or --load-assemble-list" << std::endl;
1379 }
1380 }
1381
1382
1383
1384
1386 static const std::set<std::string> inspect_compatible = { "inspect_paint", "uptodate", "load_defaultfila", "min_save",
1387 "mtcpp", "mstpp", "no_check", "normative_check", "pipe" };
1388 for (
const std::string &action :
m_actions) {
1389 if (inspect_compatible.count(action) == 0) {
1390 std::string flag = action;
1391 std::replace(flag.begin(), flag.end(), '_', '-');
1392 boost::nowide::cerr << "--inspect-paint cannot be combined with --" << flag << std::endl;
1395 }
1396 }
1397
1399 boost::nowide::cerr << "--inspect-paint needs an input file or --load-assemble-list" << std::endl;
1402 }
1403 }
1404
1405
1406
1407
1409 static const std::set<std::string> stdout_compatible = { "export_settings", "uptodate", "load_defaultfila", "min_save",
1410 "mtcpp", "mstpp", "no_check", "normative_check", "pipe" };
1412 for (const std::string &opt_key : *opt_keys) {
1413 if (stdout_compatible.count(opt_key) == 0) {
1414 std::string flag = opt_key;
1415 std::replace(flag.begin(), flag.end(), '_', '-');
1416 boost::nowide::cerr << "--export-settings - cannot be combined with --" << flag << std::endl;
1419 }
1420 }
1421 }
1422 }
1423
1424 bool start_gui =
m_actions.empty() && !downward_check;
1425 if (start_gui) {
1426 BOOST_LOG_TRIVIAL(info) << "no action, start gui directly" << std::endl;
1427#ifdef SLIC3R_GUI
1428 #if !defined(_WIN32) && !defined(__APPLE__)
1429
1430 const char *display = boost::nowide::getenv("DISPLAY");
1431 const char *wayland_display = boost::nowide::getenv("WAYLAND_DISPLAY");
1432 if (! ((display && *display) || (wayland_display && *wayland_display))) {
1433 boost::nowide::cerr << "Neither DISPLAY nor WAYLAND_DISPLAY set, GUI mode not available." << std::endl << std::endl;
1435
1436 return 1;
1437 }
1438 #endif
1439 Slic3r::GUI::GUI_InitParams params;
1444
1445 std::vector<std::string> gcode_files;
1446 std::vector<std::string> non_gcode_files;
1449 gcode_files.emplace_back(filename);
1450 else {
1451 non_gcode_files.emplace_back(filename);
1452 }
1453 }
1454 if (non_gcode_files.empty() && !gcode_files.empty()) {
1457 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ <<
", gcode only, gcode_files size = "<<params.
input_files.size();
1458 }
1459 else {
1461 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ <<
", normal mode, input_files size = "<<params.
input_files.size();
1462 }
1463
1464
1465
1466 BOOST_LOG_TRIVIAL(info) << "begin to launch OrcaSlicer GUI soon";
1468#else
1469
1471
1472 return (argc == 0) ? 0 : 1;
1473#endif
1474 }
1475
1476
1477 const ConfigOptionInt* opt_loglevel =
m_config.opt<ConfigOptionInt>(
"debug");
1478 if (opt_loglevel) {
1480 }
1481 else {
1483 }
1485 if (opt_logfile) {
1487 }
1488
1490 BOOST_LOG_TRIVIAL(warning) << boost::format("cli mode, Current OrcaSlicer Version %1%")%SoftFever_VERSION;
1491
1492
1494 std::vector<plate_obj_size_info_t> plate_obj_size_infos;
1495
1496 int plate_to_slice = 0, filament_count = 0, duplicate_count = 0, real_duplicate_count = 0, current_extruder_count = 1, new_extruder_count = 1, current_printer_variant_count = 1, current_print_variant_count = 1, new_printer_variant_count = 1;
1497 bool first_file = true, is_bbl_3mf = false, need_arrange = true, has_thumbnails = false, up_config_to_date = false, normative_check = true, duplicate_single_object = false, use_first_fila_as_default = false, minimum_save = false, enable_timelapse = false;
1498 bool allow_rotations = false, skip_modified_gcodes = false, avoid_extrusion_cali_region = false, skip_useless_pick = false, allow_newer_file = false, current_is_multi_extruder = false, new_is_multi_extruder = false, allow_mix_temp = false, enable_wrapping_detect = false;
1499 Semver file_version;
1500 std::map<size_t, bool> orients_requirement;
1501 std::vector<Preset*> project_presets;
1502 std::vector<NozzleVolumeType> current_nozzle_volume_type, new_nozzle_volume_type;
1503 std::string new_printer_name, current_printer_name, new_process_name, current_process_name, current_printer_system_name, current_process_system_name, new_process_system_name, new_printer_system_name, printer_model_id, current_printer_model, printer_model, new_default_process_name;
1504 std::vector<std::string> upward_compatible_printers, new_print_compatible_printers, current_print_compatible_printers, current_different_settings;
1505 std::vector<std::string> current_filaments_name, current_filaments_system_name, current_inherits_group, current_extruder_variants, new_extruder_variants, current_print_extruder_variants, new_printer_extruder_variants;
1506 DynamicPrintConfig load_process_config, load_machine_config;
1507
1508
1509
1510 DynamicPrintConfig current_process_full_config, current_printer_full_config;
1511 bool new_process_config_is_system = true, new_printer_config_is_system = true;
1512 std::string pipe_name, makerlab_name, makerlab_version, different_process_setting;
1513 const std::vector<std::string> &metadata_name =
m_config.option<ConfigOptionStrings>(
"metadata_name",
true)->values;
1514 const std::vector<std::string> &metadata_value =
m_config.option<ConfigOptionStrings>(
"metadata_value",
true)->values;
1515
1516 if (metadata_name.size() != metadata_value.size())
1517 {
1518 BOOST_LOG_TRIVIAL(error) << boost::format("metadata_name should be the same size with metadata_value");
1521 }
1522
1523
1524 BOOST_LOG_TRIVIAL(info) <<
"Will start to read model file now, file count :" <<
m_input_files.size() <<
"\n";
1525 ConfigOptionInt* slice_option =
m_config.option<ConfigOptionInt>(
"slice");
1526 if (slice_option)
1527 plate_to_slice = slice_option->
value;
1528
1529 ConfigOptionBool* normative_check_option =
m_config.option<ConfigOptionBool>(
"normative_check");
1530 if (normative_check_option)
1531 normative_check = normative_check_option->
value;
1532
1533 ConfigOptionBool* uptodate_option =
m_config.option<ConfigOptionBool>(
"uptodate");
1534 if (uptodate_option)
1535 up_config_to_date = uptodate_option->
value;
1536
1537 ConfigOptionBool* load_defaultfila_option =
m_config.option<ConfigOptionBool>(
"load_defaultfila");
1538 if (load_defaultfila_option)
1539 use_first_fila_as_default = load_defaultfila_option->
value;
1540
1541 ConfigOptionBool* min_save_option =
m_config.option<ConfigOptionBool>(
"min_save");
1542 if (min_save_option)
1543 minimum_save = min_save_option->
value;
1544
1545 ConfigOptionBool* enable_timelapse_option =
m_config.option<ConfigOptionBool>(
"enable_timelapse");
1546 if (enable_timelapse_option)
1547 enable_timelapse = enable_timelapse_option->
value;
1548
1549 ConfigOptionBool* allow_rotations_option =
m_config.option<ConfigOptionBool>(
"allow_rotations");
1550 if (allow_rotations_option)
1551 allow_rotations = allow_rotations_option->
value;
1552
1553 std::optional<bool> align_to_y_axis;
1555 align_to_y_axis =
m_config.opt_bool(
"align_to_y_axis");
1556
1557 ConfigOptionBool* skip_modified_gcodes_option =
m_config.option<ConfigOptionBool>(
"skip_modified_gcodes");
1558 if (skip_modified_gcodes_option)
1559 skip_modified_gcodes = skip_modified_gcodes_option->
value;
1560
1561 ConfigOptionBool* skip_useless_picks_option =
m_config.option<ConfigOptionBool>(
"skip_useless_pick");
1562 if (skip_useless_picks_option)
1563 skip_useless_pick = skip_useless_picks_option->
value;
1564
1565 ConfigOptionBool* allow_newer_file_option =
m_config.option<ConfigOptionBool>(
"allow_newer_file");
1566 if (allow_newer_file_option)
1567 allow_newer_file = allow_newer_file_option->
value;
1568
1569 ConfigOptionBool* allow_mix_temp_option =
m_config.option<ConfigOptionBool>(
"allow_mix_temp");
1570 if (allow_mix_temp_option)
1571 allow_mix_temp = allow_mix_temp_option->
value;
1572
1573 const ConfigOptionBool* export_statistics_option =
m_config.option<ConfigOptionBool>(
"export_statistics");
1574 const bool export_statistics = export_statistics_option !=
nullptr && export_statistics_option->
value;
1575
1576 ConfigOptionBool* avoid_extrusion_cali_region_option =
m_config.option<ConfigOptionBool>(
"avoid_extrusion_cali_region");
1577 if (avoid_extrusion_cali_region_option)
1578 avoid_extrusion_cali_region = avoid_extrusion_cali_region_option->
value;
1579
1581 if (pipe_option) {
1582 pipe_name = pipe_option->
value;
1583 if (!pipe_name.empty()) {
1584 BOOST_LOG_TRIVIAL(info) << boost::format("Will use pipe %1%")%pipe_name;
1585#if defined(__linux__) || defined(__LINUX__)
1586 g_cli_callback_mgr.start(pipe_name);
1587 PrintBase::SlicingStatus slicing_status{1, "Start to load files"};
1588 cli_status_callback(slicing_status);
1589#endif
1590 }
1591 }
1592
1594 if (makerlab_name_option)
1595 makerlab_name = makerlab_name_option->
value;
1596
1598 if (makerlab_version_option)
1599 makerlab_version = makerlab_version_option->
value;
1600
1601
1602 if (need_skip) {
1603 BOOST_LOG_TRIVIAL(info) << boost::format("need to skip objects, size %1%:")%skip_objects.size();
1604 for (int index = 0; index < skip_objects.size(); index++)
1605 {
1606 skip_maps[skip_objects[index]] = false;
1607 BOOST_LOG_TRIVIAL(info) << boost::format("object %1%, id %2%")%index %skip_objects[index];
1608 }
1609 }
1610
1611 std::string custom_gcode_file;
1613 if (custom_gcode_option)
1614 custom_gcode_file = custom_gcode_option->
value;
1615
1616 std::string load_assemble_list;
1617 std::vector<assemble_plate_info_t> assemble_plate_info_list;
1619 if (load_assemble_list_option)
1620 load_assemble_list = load_assemble_list_option->
value;
1621
1622 bool allow_multicolor_oneplate =
m_config.option<ConfigOptionBool>(
"allow_multicolor_oneplate",
true)->value;
1625
1626 std::set<int> used_filament_set;
1627 BOOST_LOG_TRIVIAL(info) << boost::format("allow_multicolor_oneplate %1%, allow_rotations %2% skip_modified_gcodes %3% avoid_extrusion_cali_region %4% loaded_filament_ids size %5%, clone_objects size %6%, skip_useless_pick %7%, allow_newer_file %8%, allow_mix_temp %9%")
1628 %allow_multicolor_oneplate %allow_rotations %skip_modified_gcodes %avoid_extrusion_cali_region %loaded_filament_ids.
size() %clone_objects.size() %skip_useless_pick %allow_newer_file %allow_mix_temp;
1629 if (clone_objects.size() > 0)
1630 {
1632 {
1633 BOOST_LOG_TRIVIAL(error) << boost::format(
"clone_objects size %1% should be the same with input files size %2%")%clone_objects.size() %
m_input_files.size();
1636 }
1637 else if (load_filaments.size() == 0)
1638 {
1639 BOOST_LOG_TRIVIAL(error) << boost::format("clone_objects should be used with load_filaments together");
1642 }
1643 }
1644 if (loaded_filament_ids.size() > 0)
1645 {
1647 {
1648 BOOST_LOG_TRIVIAL(error) << boost::format(
"loaded_filament_ids size %1% should be the same with input files size %2%")%loaded_filament_ids.size() %
m_input_files.size();
1651 }
1652 else if (load_filaments.size() == 0)
1653 {
1654 BOOST_LOG_TRIVIAL(error) << boost::format("loaded_filament_ids should be used with load_filaments together");
1657 }
1658 }
1659
1660
1661
1662
1663
1664
1665
1666 BOOST_LOG_TRIVIAL(info) << boost::format("plate_to_slice=%1%, normative_check=%2%, use_first_fila_as_default=%3%")%plate_to_slice %normative_check %use_first_fila_as_default;
1667 unsigned int input_index = 0;
1668 std::vector<RGBA> input_obj_colours;
1670 {
1671 BOOST_LOG_TRIVIAL(error) << boost::format("load_assemble_list should not be used with input model files to load and should not be sued with transforms");
1674 }
1675 if (load_assemble_list.empty()) {
1677 if (!boost::filesystem::exists(file)) {
1678 boost::nowide::cerr << "No such file: " << file << std::endl;
1681 }
1682 Model model;
1683
1684
1685 BOOST_LOG_TRIVIAL(info) << "read model file:" << file << "\n";
1686 try {
1687
1688 DynamicPrintConfig config;
1689 ConfigSubstitutionContext config_substitutions(config_substitution_rule);
1690
1691
1692 is_bbl_3mf = false;
1694 if (boost::algorithm::iends_with(file, ".3mf") && first_file) {
1695 if ((clone_objects.size() > 0) || (loaded_filament_ids.size() > 0))
1696 {
1697 BOOST_LOG_TRIVIAL(error) << boost::format("can not load 3mf when set loaded_filament_ids or clone_objects");
1700 }
1702
1703 }
1704 else {
1706 }
1707
1708
1709
1710 model =
Model::read_from_file(file, &config, &config_substitutions, strategy, &plate_data_src, &project_presets, &is_bbl_3mf, &file_version,
nullptr,
nullptr,
nullptr, plate_to_slice);
1711 if (is_bbl_3mf)
1712 {
1713 if (!first_file)
1714 {
1715 BOOST_LOG_TRIVIAL(info) << "The BBL 3mf file should be placed at the first position, filename=" << file << "\n";
1718 }
1719 BOOST_LOG_TRIVIAL(info) << boost::format(
"the first file is a 3mf, version %1%, got plate count %2%") %file_version.
to_string() %plate_data_src.size();
1720 need_arrange = false;
1721
1722
1723
1724
1725
1726
1728 if (!allow_newer_file && ((cli_ver.
maj() < file_version.
maj()) || ((cli_ver.
maj() == file_version.
maj()) && (cli_ver.
min() < file_version.
min())))){
1729 BOOST_LOG_TRIVIAL(error) << boost::format(
"Version Check: File Version %1% not supported by current cli version %2%")%file_version.
to_string() %SoftFever_VERSION;
1732 }
1733 Semver old_version(1, 5, 9), old_version2(1, 5, 9), old_version3(2, 0, 0), old_version4(2, 2, 0);
1734 if ((file_version < old_version) && !config.
empty()) {
1735 translate_old = true;
1736 BOOST_LOG_TRIVIAL(info) << boost::format(
"old 3mf version %1%, need to translate")%file_version.
to_string();
1737 }
1738 if ((file_version < old_version2) && !config.
empty()) {
1739 regenerate_thumbnails = true;
1740 BOOST_LOG_TRIVIAL(info) << boost::format(
"old 3mf version %1%, need to regenerate_thumbnails for all")%file_version.
to_string();
1741 }
1742
1743 if (file_version < old_version4) {
1744 remove_wrapping_detect = true;
1745 BOOST_LOG_TRIVIAL(info) << boost::format(
"old 3mf version %1%, need to set enable_wrapping_detection to false")%file_version.
to_string();
1746 }
1747
1748
1749
1750
1751
1752 if (normative_check) {
1753 ConfigOptionStrings* postprocess_scripts = config.
option<ConfigOptionStrings>(
"post_process");
1754 if (postprocess_scripts) {
1755 std::vector<std::string> postprocess_values = postprocess_scripts->
values;
1756 if (postprocess_values.size() > 0) {
1757 BOOST_LOG_TRIVIAL(error) << boost::format("normative_check: postprocess not supported, array size %1%")%postprocess_values.size();
1760 }
1761 }
1762 }
1763
1764
1765
1766
1767
1768
1769
1770
1771
1775 if (
const auto *o = config.
option<ConfigOptionStrings>(
"filament_settings_id")) current_filaments_name = o->values;
1776 if (
const auto *o = config.
option<
ConfigOptionFloats>(
"nozzle_diameter")) current_extruder_count = o->values.size();
1777 current_printer_variant_count = config.
option<ConfigOptionStrings>(
"printer_extruder_variant",
true)->values.size();
1778 current_print_variant_count = config.
option<ConfigOptionStrings>(
"print_extruder_variant",
true)->values.size();
1779 current_is_multi_extruder = current_extruder_count > 1;
1780
1783 if (opt_nozzle_volume_type) {
1784 int nozzle_volume_type_size = opt_nozzle_volume_type->values.size();
1785 current_nozzle_volume_type.resize(nozzle_volume_type_size,
nvtStandard);
1786 for (int i = 0; i < nozzle_volume_type_size; i++)
1787 {
1788 current_nozzle_volume_type[i] = (
NozzleVolumeType)(opt_nozzle_volume_type->values[i]);
1789 }
1790 }
1791
1792 current_extruder_variants.resize(current_extruder_count, "");
1793 for (int e_index = 0; e_index < current_extruder_count; e_index++)
1794 {
1798 }
1799
1800
1801 BOOST_LOG_TRIVIAL(info) << boost::format("current_printer_name %1%, current_process_name %2%")%current_printer_name %current_process_name;
1802 ConfigOptionStrings* option_strings = config.
option<ConfigOptionStrings>(
"inherits_group");
1803
1804
1805 if (option_strings && option_strings->
values.size() != current_filaments_name.size() + 2) {
1806 boost::nowide::cerr <<
"Warning: inherits_group has " << option_strings->
values.size() <<
" entries, expected "
1807 << current_filaments_name.size() + 2 << " for " << current_filaments_name.size() << " filaments" << std::endl;
1808 if (option_strings->
values.size() < 2)
1809 option_strings = nullptr;
1810 }
1811 if (option_strings) {
1812 current_inherits_group = option_strings->
values;
1813 size_t size = current_inherits_group.size();
1814 if (current_inherits_group[size-1].
empty()) {
1815 current_printer_system_name = current_printer_name;
1816 BOOST_LOG_TRIVIAL(info) << boost::format("inherits of printer is null, should be system preset");
1817 }
1818 else {
1819 current_printer_system_name = current_inherits_group[size-1];
1820 BOOST_LOG_TRIVIAL(info) << boost::format("inherits of printer valid, current_printer_system_name is %1%") %current_printer_system_name;
1821 }
1822
1823 if (current_inherits_group[0].
empty()) {
1824 current_process_system_name = current_process_name;
1825 BOOST_LOG_TRIVIAL(info) << boost::format("inherits of process is null, should be system preset");
1826 }
1827 else {
1828 current_process_system_name = current_inherits_group[0];
1829 BOOST_LOG_TRIVIAL(info) << boost::format("inherits of process valid, current_process_system_name is %1%") %current_process_system_name;
1830 }
1831
1832
1833 current_filaments_system_name = current_filaments_name;
1834 for (size_t index = 1; index < size - 1 && index <= current_filaments_name.size(); index++) {
1835 if (!current_inherits_group[index].
empty())
1836 current_filaments_system_name[index-1] = current_inherits_group[index];
1837 }
1838 }
1839 else {
1840 current_printer_system_name = current_printer_name;
1841 current_process_system_name = current_process_name;
1842 current_filaments_system_name = current_filaments_name;
1843 BOOST_LOG_TRIVIAL(info) << boost::format("no inherits_group: use system name the same as current name");
1844 }
1845 filament_count = current_filaments_name.size();
1846 upward_compatible_printers = config.
option<ConfigOptionStrings>(
"upward_compatible_machine",
true)->values;
1847 current_print_compatible_printers = config.
option<ConfigOptionStrings>(
"print_compatible_printers",
true)->values;
1848 current_different_settings = config.
option<ConfigOptionStrings>(
"different_settings_to_system",
true)->values;
1849
1850
1851 old_printable_area = config.
option<ConfigOptionPoints>(
"printable_area",
true)->values;
1853 if (old_printable_area.
size() >= 4) {
1854 BoundingBoxf old_printable_bbox(old_printable_area);
1855 old_printable_width = static_cast<int>(old_printable_bbox.size().x());
1856 old_printable_depth = static_cast<int>(old_printable_bbox.size().y());
1857 }
1858
1859
1861 old_printable_height = (int)(config.
opt_float(
"printable_height"));
1862
1864 old_height_to_rod = config.
opt_float(
"extruder_clearance_height_to_rod");
1866 old_height_to_lid = config.
opt_float(
"extruder_clearance_height_to_lid");
1868 old_max_radius = config.
opt_float(
"extruder_clearance_radius");
1873 BOOST_LOG_TRIVIAL(info) << boost::format("old printable size from 3mf: {%1%, %2%, %3%}")%old_printable_width %old_printable_depth %old_printable_height;
1874 BOOST_LOG_TRIVIAL(info) << boost::format("old extruder_clearance_height_to_rod %1%, extruder_clearance_height_to_lid %2%, extruder_clearance_radius %3%}")%old_height_to_rod %old_height_to_lid %old_max_radius;
1875 }
1876 else
1877 {
1878 need_arrange = true;
1879 int object_extruder_id = 0, clone_count = 1;
1880 if (loaded_filament_ids.size() > input_index) {
1881 if (loaded_filament_ids[input_index] > 0) {
1882 if (loaded_filament_ids[input_index] > load_filaments.size()) {
1883 BOOST_LOG_TRIVIAL(error) << boost::format("invalid filament_id %1% at index %2%, max %3%")%loaded_filament_ids[input_index] % (input_index + 1) %load_filaments.size();
1886 }
1887 object_extruder_id = loaded_filament_ids[input_index];
1888 used_filament_set.emplace(object_extruder_id);
1889 }
1890 }
1891
1892 if (clone_objects.size() > input_index) {
1893 if (clone_objects[input_index] > 0) {
1895 BOOST_LOG_TRIVIAL(error) << boost::format(
"invalid clone count %1% at index %2%, max %3%")%clone_objects[input_index] % (input_index + 1) %
MAX_CLONEABLE_SIZE;
1898 }
1899 clone_count = clone_objects[input_index];
1900 }
1901 }
1902
1903
1904 if (clone_count > 1)
1905 {
1906 unsigned int object_count = model.
objects.size();
1907
1908 for (unsigned int obj_index = 0; obj_index < object_count; obj_index++)
1909 {
1910 ModelObject*
object = model.
objects[obj_index];
1911
1912 for (unsigned int clone_index = 1; clone_index < clone_count; clone_index++)
1913 {
1914 ModelObject* newObj = model.
add_object(*
object);
1915 newObj->
name =
object->name +
"_"+ std::to_string(clone_index+1);
1916 }
1917 object->name = object->name +"_"+ std::to_string(1);
1918 }
1919 }
1920
1921 for (ModelObject* o : model.
objects)
1922 {
1923 if (object_extruder_id != 0) {
1925 }
1926
1927
1928
1929 BOOST_LOG_TRIVIAL(info) <<
"object "<<o->
name <<
", id :" << o->
id().
id <<
", from stl or other 3mf\n";
1931 }
1932 }
1933 first_file = false;
1934
1938 }
1940 boost::nowide::cerr <<
"invalid printer_technology " <<
printer_technology<<
", from source file "<< file <<std::endl;
1943 }
1944 if (!config_substitutions.substitutions.empty()) {
1945 BOOST_LOG_TRIVIAL(info) << "Found legacy configuration values, substituted when loading " << file << ":\n";
1946 for (const ConfigSubstitution &subst : config_substitutions.substitutions)
1948 }
1949
1950
1953 input_index++;
1954 }
1955 catch (std::exception& e) {
1956 boost::nowide::cerr << file << ": " << e.what() << std::endl;
1959 }
1961 boost::nowide::cerr << "Error: file is empty: " << file << std::endl;
1962 continue;
1963 }
1964 m_models.push_back(std::move(model));
1965 }
1966 }
1967 else {
1968
1969 Model model;
1970
1977 if (ret) {
1980 }
1981
1982 try {
1984 if (ret) {
1987 }
1988 }
1989 catch (std::exception& e) {
1990 boost::nowide::cerr << "construct_assemble_list: " << e.what() << std::endl;
1993 }
1995 m_models.push_back(std::move(model));
1996 }
1997
1998 if (!is_bbl_3mf && plate_to_slice > 0)
1999 {
2000 BOOST_LOG_TRIVIAL(warning) << boost::format("%1%: not support to slice plate %2%, reset to 0")%__LINE__ %plate_to_slice;
2001 plate_to_slice = 0;
2002 }
2003
2004
2005 std::map<int, CustomGCode::Info> custom_gcodes_map;
2006 if (!custom_gcode_file.empty()) {
2007
2008 std::string file = custom_gcode_file;
2009 if(!boost::filesystem::exists(file)) {
2010 boost::nowide::cerr << __FUNCTION__ << ": can not find custom_gcode file: " << file << std::endl;
2013 }
2014 try {
2015 nlohmann::json jj;
2016 boost::nowide::ifstream ifs(file);
2017 ifs >> jj;
2018 ifs.close();
2019
2020 int plate_id = 0;
2021 if (plate_to_slice == 0)
2022 plate_id = 0;
2023 else
2024 plate_id = plate_to_slice-1;
2025
2026 CustomGCode::Info info;
2028
2029 custom_gcodes_map.emplace(plate_id, info);
2030 BOOST_LOG_TRIVIAL(info) << boost::format("load custom_gcode from file %1% success, store custom gcodes to plate %2%")%file %(plate_id+1);
2031 }
2032 catch (std::exception &ex) {
2033 boost::nowide::cerr << __FUNCTION__<< ":Loading custom-gcode file \"" << file << "\" failed: " << ex.what() << std::endl;
2036 }
2037 }
2038
2039 std::unique_ptr<PresetBundle> cli_preset_bundle;
2040 auto ensure_cli_preset_bundle = [&cli_preset_bundle](std::string &error) -> PresetBundle * {
2041 if (cli_preset_bundle)
2042 return cli_preset_bundle.get();
2043 try {
2044 AppConfig app_config;
2045 const std::string app_config_error = app_config.
load_if_exists();
2046 if (!app_config_error.empty()) {
2047 BOOST_LOG_TRIVIAL(warning) << "Ignoring invalid app config during CLI preset resolution: " << app_config_error;
2049 }
2050
2051 auto bundle = std::make_unique<PresetBundle>();
2052 std::string load_error;
2053 bundle->load_presets(app_config, config_substitution_rule,
2054 PresetBundle::PresetPreferences(), &load_error, true);
2055 if (!load_error.empty()) {
2056 error = "Failed to load presets for inheritance resolution: " + load_error;
2057 return nullptr;
2058 }
2059 cli_preset_bundle = std::move(bundle);
2060 return cli_preset_bundle.get();
2061 } catch (const std::exception &ex) {
2062 error = ex.what();
2063 return nullptr;
2064 }
2065 };
2066
2067
2068 std::unique_ptr<PresetBundle> system_preset_resolver;
2069 auto ensure_system_preset_resolver = [&system_preset_resolver]() -> PresetBundle & {
2070 if (!system_preset_resolver)
2071 system_preset_resolver = std::make_unique<PresetBundle>();
2072 return *system_preset_resolver;
2073 };
2074 auto resolve_preset = [&ensure_cli_preset_bundle, &ensure_system_preset_resolver](const std::string &file, DynamicPrintConfig &config,
2075 std::string &config_type, const std::string &config_from,
2076 bool probe_type, std::string &error) {
2078 if (!probe_type && (inherits == nullptr || inherits->value.empty()))
2079 return true;
2080
2081 PresetBundle *bundle = nullptr;
2082 bool allow_source_manifest = false;
2083 if (config_from == "system") {
2084 bundle = &ensure_system_preset_resolver();
2085 allow_source_manifest = true;
2086 } else {
2087 bundle = ensure_cli_preset_bundle(error);
2088 if (bundle == nullptr)
2089 return false;
2090 }
2091
2092 if (probe_type) {
2095 error, allow_source_manifest))
2096 return false;
2098 return true;
2099 }
2100
2102 if (config_type == "process")
2104 else if (config_type == "filament")
2106 else if (config_type == "machine")
2108 else {
2109 error = "Unsupported preset type: " + config_type;
2110 return false;
2111 }
2113 error, allow_source_manifest);
2114 };
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125 auto cli_different_settings = [&ensure_cli_preset_bundle](const DynamicPrintConfig &resolved,
2126 const std::string &parent_name,
2128 if (parent_name.empty())
2129 return std::string();
2130 std::string error;
2131 PresetBundle *bundle = ensure_cli_preset_bundle(error);
2132 if (bundle == nullptr) {
2133 BOOST_LOG_TRIVIAL(warning) << "CLI: no preset bundle for different_settings_to_system: " << error;
2134 return std::string();
2135 }
2136 const PresetCollection *collection = nullptr;
2137 switch (type) {
2141 default: return std::string();
2142 }
2144 if (parent == nullptr) {
2145 BOOST_LOG_TRIVIAL(warning) << boost::format("CLI: parent preset '%1%' not found; leaving different_settings_to_system empty")%parent_name;
2146 return std::string();
2147 }
2148 std::vector<std::string> keys = resolved.
diff(parent->
config);
2149
2150
2151 keys.erase(std::remove_if(keys.begin(), keys.end(), [](const std::string &k) {
2152 return k == "inherits" || k == "compatible_printers" || k == "compatible_prints"
2153 || k == "compatible_printers_condition" || k == "compatible_prints_condition"
2154 || k == "print_settings_id" || k == "filament_settings_id" || k == "printer_settings_id";
2155 }),
2156 keys.end());
2157 BOOST_LOG_TRIVIAL(info) << boost::format("CLI: %1% overrides vs parent '%2%'")%keys.size()%parent_name;
2159 };
2160
2161 auto load_config_file = [&resolve_preset](const std::string& file, DynamicPrintConfig& config, std::string& config_type,
2162 std::string& config_name, std::string& filament_id, std::string& config_from) {
2163 if (! boost::filesystem::exists(file)) {
2164 boost::nowide::cerr << __FUNCTION__<< ": can not find setting file: " << file << std::endl;
2166 }
2168 try {
2169 BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< ":load setting file "<< file << ", with rule "<< config_substitution_rule << std::endl;
2170 std::map<std::string, std::string> key_values;
2171 std::string reason;
2172
2173 config_substitutions = config.load_from_json(file, config_substitution_rule, key_values, reason);
2174 if (!reason.empty()) {
2175 BOOST_LOG_TRIVIAL(error) <<__FUNCTION__<< ":Can not load config from file "<<file<<"\n";
2177 }
2178
2181 if (from_iter != key_values.end()) {
2182 config_from = from_iter->second;
2183 }
2184 if ((config_from != "system")&&(config_from != "User")&&(config_from != "user")) {
2185 boost::nowide::cerr <<__FUNCTION__ << boost::format(":file %1%'s from %2% unsupported") % file % config_from;
2187 }
2188
2190 const bool probe_type = type_iter == key_values.end();
2191 if (!probe_type)
2192 config_type = type_iter->second;
2193
2194 if (!resolve_preset(file, config, config_type, config_from, probe_type, reason)) {
2195 boost::nowide::cerr << __FUNCTION__ << boost::format(": can not resolve preset %1%: %2%") % file % reason << std::endl;
2197 }
2198
2199 if (config_type == "machine") {
2200
2201
2202 }
2203 else if (config_type == "process") {
2204
2205
2206 }
2207 else if (config_type == "filament") {
2209 if (filament_id_iter != key_values.end())
2210 filament_id = filament_id_iter->second;
2211 }
2212 else {
2213 boost::nowide::cerr <<__FUNCTION__ << boost::format(": unknown config type %1% of file %2% in load-settings") % config_type % file;
2215 }
2216 config.normalize_fdm();
2217
2218 if (! config_substitutions.empty()) {
2219 BOOST_LOG_TRIVIAL(info) << "Found legacy configuration values, substituted when loading " << file << ":\n";
2220 for (const ConfigSubstitution &subst : config_substitutions)
2221 BOOST_LOG_TRIVIAL(info) << "\tkey = \"" << subst.opt_def->opt_key << "\"\t old_value = \"" << subst.old_value << "\tnew_value = \"" << subst.new_value->serialize() << "\"\n";
2222 }
2223 else {
2224 BOOST_LOG_TRIVIAL(info) << "no substitutions performed from file " << file << "\n";
2225 }
2226
2227
2228
2229 } catch (std::exception &ex) {
2230 boost::nowide::cerr << __FUNCTION__<< ":Loading setting file \"" << file << "\" failed: " << ex.what() << std::endl;
2232 }
2233 return 0;
2234 };
2235 BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< ":before load settings, file count="<< load_configs.size() << std::endl;
2236
2237
2238 for (auto const &file : load_configs) {
2239 DynamicPrintConfig config;
2240 std::string config_type, config_name, filament_id, config_from;
2241 int ret = load_config_file(file, config, config_type, config_name, filament_id, config_from);
2242 if (ret) {
2245 }
2246
2247 if (config_type == "machine") {
2248 if (!new_printer_name.empty()) {
2249 boost::nowide::cerr << "duplicate machine config file: " << file << std::endl;
2252 }
2253 new_printer_name = config_name;
2254 if (config_from == "system") {
2255 new_printer_system_name = new_printer_name;
2256 new_printer_config_is_system = true;
2257 }
2258 else {
2260 new_printer_config_is_system = false;
2261 }
2262 config.
set(
"printer_settings_id", new_printer_name,
true);
2263
2264
2266 if (!printer_model.empty()) {
2267 std::string printer_model_path =
resources_dir() +
"/profiles/BBL/machine_full/"+printer_model+
".json";
2268 if (boost::filesystem::exists(printer_model_path))
2269 {
2270 std::map<std::string, std::string> key_values;
2271
2273 if (key_values.find("model_id") != key_values.end()) {
2274 printer_model_id = key_values["model_id"];
2275 BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(":%1%, load printer_model_id %2% from current printer model %3%")%__LINE__ %printer_model_id %printer_model;
2276 }
2277 }
2278 }
2279
2282
2283
2284 load_machine_config = std::move(config);
2285 BOOST_LOG_TRIVIAL(info) << boost::format("loaded machine config %1%, type %2%, name %3%, inherits %4%, printer_model_id %5%")%file %config_name %config_from % new_printer_system_name %printer_model_id;
2286 }
2287 else if (config_type == "process") {
2288 if (!new_process_name.empty()) {
2289 boost::nowide::cerr << "duplicate process config file: " << file << std::endl;
2292 }
2293 new_process_name = config_name;
2294 if (config_from == "system") {
2295 new_process_system_name = new_process_name;
2296 new_process_config_is_system = true;
2297 }
2298 else {
2300 new_process_config_is_system = false;
2301 }
2302 config.
set(
"print_settings_id", new_process_name,
true);
2303
2304 new_print_compatible_printers = config.
option<ConfigOptionStrings>(
"compatible_printers",
true)->values;
2305
2306 if (!is_bbl_3mf && config.
option<ConfigOptionStrings>(
"different_settings_to_system")) {
2307 std::vector<std::string> diff_settings = config.
option<ConfigOptionStrings>(
"different_settings_to_system")->values;
2308 different_process_setting = diff_settings[0];
2309 }
2310 load_process_config = std::move(config);
2311 BOOST_LOG_TRIVIAL(info) << boost::format("loaded process config %1%, type %2%, name %3%, inherits %4%")%file %config_name %config_from % new_process_system_name;
2312 }
2313
2317 }
2318
2320 boost::nowide::cerr <<
"invalid printer_technology " <<
printer_technology<<
", from config "<< file <<std::endl;
2323 }
2324 }
2325
2326
2327 int load_filament_count = load_filaments.size();
2328 std::vector<int> load_filaments_index;
2329 std::set<std::string> load_filaments_set;
2330 bool disable_wipe_tower_after_mapping = false;
2331 std::vector<DynamicPrintConfig> load_filaments_config;
2332 std::vector<std::string> load_filaments_id;
2333 std::vector<std::string> load_filaments_name, load_filaments_inherit;
2334 int current_index = 0;
2335 std::string default_load_fila_name, default_load_fila_id, default_filament_file, default_filament_inherit;
2336 DynamicPrintConfig default_load_fila_config;
2337 if (use_first_fila_as_default) {
2338
2339 for (int index = 0; index < load_filament_count; index++) {
2340 const std::string& file = load_filaments[index];
2341 if (default_filament_file.empty() && !file.empty()) {
2342 DynamicPrintConfig config;
2343 std::string config_type, config_name, filament_id, config_from;
2344 int ret = load_config_file(file, config, config_type, config_name, filament_id, config_from);
2345 if (ret) {
2348 }
2349
2350 if (config_type != "filament") {
2351 BOOST_LOG_TRIVIAL(error) <<__FUNCTION__ << boost::format(": unknown config type %1% of file %2% in load-filaments") % config_type % file;
2354 }
2355
2356 if ((config_from == "User")||(config_from == "user")) {
2358 }
2359
2360 default_filament_file = file;
2361 default_load_fila_name = config_name;
2362 default_load_fila_id = filament_id;
2363 default_load_fila_config = std::move(config);
2364
2365 BOOST_LOG_TRIVIAL(info) << boost::format("loaded default filament config %1%, type %2%, name %3%, inherits %4%")%file %config_from %config_name % default_filament_inherit;
2366 break;
2367 }
2368 }
2369 if ((load_filament_count > 0) && default_filament_file.empty())
2370 {
2371 BOOST_LOG_TRIVIAL(error) <<__FUNCTION__ << boost::format(": load_filament_count is %1%, but can not load a default filament") % load_filament_count;
2374 }
2375 }
2376 for (int index = 0; index < load_filament_count; index++) {
2377 const std::string& file = load_filaments[index];
2378 current_index++;
2379 if (!file.empty()) {
2380 DynamicPrintConfig config;
2381 std::string config_type, config_name, filament_id, config_from;
2382 int ret = load_config_file(file, config, config_type, config_name, filament_id, config_from);
2383 if (ret) {
2386 }
2387
2388 if (config_type != "filament") {
2389 BOOST_LOG_TRIVIAL(error) <<__FUNCTION__ << boost::format(": unknown config type %1% of file %2% in load-filaments") % config_type % file;
2392 }
2393
2397 }
2399 BOOST_LOG_TRIVIAL(error) <<
"invalid printer_technology " <<
printer_technology<<
", from filament file "<< file;
2402 }
2403 std::string inherits;
2404 if ((config_from == "User")||(config_from == "user")) {
2406 }
2407 load_filaments_inherit.push_back(inherits);
2408 load_filaments_id.push_back(filament_id);
2409 load_filaments_name.push_back(config_name);
2410 load_filaments_config.push_back(std::move(config));
2411 load_filaments_index.push_back(current_index);
2412
2413 load_filaments_set.emplace(config_name);
2414
2415 BOOST_LOG_TRIVIAL(info) << boost::format("loaded filament %1% from file %2%, type %3%, name %4%, inherits %5%")%(index+1) %file %config_from %config_name % inherits;
2416 }
2417 else {
2418 if (use_first_fila_as_default) {
2419 BOOST_LOG_TRIVIAL(info)<<__FUNCTION__ << boost::format(": load filament %1% from default, config name %2%, filament_id %3%, current_index %4%") % (index+1) % default_load_fila_name %default_load_fila_id %current_index;
2420 load_filaments_id.push_back(default_load_fila_id);
2421 load_filaments_name.push_back(default_load_fila_name);
2422 load_filaments_config.push_back(default_load_fila_config);
2423 load_filaments_index.push_back(current_index);
2424 load_filaments_inherit.push_back(default_filament_inherit);
2425
2426 load_filaments_set.emplace(default_load_fila_name);
2427 }
2428 continue;
2429 }
2430 }
2431
2432
2433 if (input_obj_colours.size() > 0) {
2434 BOOST_LOG_TRIVIAL(info) << boost::format("%1%:%2%, got input obj colors %3%")%__FUNCTION__ %__LINE__ %input_obj_colours.size();
2435 int input_color_count = input_obj_colours.size();
2436 if (load_filament_count == 0) {
2437 BOOST_LOG_TRIVIAL(error) << boost::format("filament config not loaded when loading colored obj");
2440 }
2441
2442
2443 ConfigOptionStrings *selected_filament_colors_option =
m_extra_config.option<ConfigOptionStrings>(
"filament_colour");
2444 if (selected_filament_colors_option) {
2445 BOOST_LOG_TRIVIAL(error) << boost::format("filament_colour should not be set when loading colored obj");
2448 }
2449 if (load_filament_count < input_color_count) {
2450 int delta = input_color_count - load_filament_count;
2451 for (int index = 0; index < delta; index++) {
2452 load_filaments_id.push_back(load_filaments_id[0]);
2453 load_filaments_name.push_back(load_filaments_name[0]);
2454 load_filaments_config.push_back(load_filaments_config[0]);
2455 load_filaments_index.push_back(index+1+load_filament_count);
2456 load_filaments_inherit.push_back(load_filaments_inherit[0]);
2457 }
2458 load_filament_count = input_color_count;
2459 }
2460
2461 selected_filament_colors_option =
m_extra_config.option<ConfigOptionStrings>(
"filament_colour",
true);
2462 std::vector<std::string>& filament_colors = selected_filament_colors_option->
values;
2463 filament_colors.resize(input_color_count);
2464 for (int index = 0; index < input_color_count; index++)
2465 {
2466 std::string color_string;
2467 int color[4];
2468 color[0] = std::clamp((int) (input_obj_colours[index][0] * 255.f), 0, 255);
2469 color[1] = std::clamp((int) (input_obj_colours[index][1] * 255.f), 0, 255);
2470 color[2] = std::clamp((int) (input_obj_colours[index][2] * 255.f), 0, 255);
2471 color[3] = std::clamp((int) (input_obj_colours[index][3] * 255.f), 0, 255);
2472
2473 std::stringstream stream;
2474 stream << std::hex << std::uppercase << std::setfill('0') << std::setw(2) << color[0];
2475 stream << std::hex << std::uppercase << std::setfill('0') << std::setw(2) << color[1];
2476 stream << std::hex << std::uppercase << std::setfill('0') << std::setw(2) << color[2];
2477 stream << std::hex << std::uppercase << std::setfill('0') << std::setw(2) << color[3];
2478 std::string result(stream.str());
2479
2480 filament_colors[index] = "#" + result;
2481
2482 BOOST_LOG_TRIVIAL(info) << boost::format("%1%:%2%, index %3%, argb {%4%,%5%,%6%,%7%} to string %8%")%__FUNCTION__ %__LINE__ %(index+1) %color[0] %color[1] %color[2] %color[3] %filament_colors[index];
2483 }
2484 }
2485
2486 if (filament_count == 0)
2487 filament_count = load_filament_count;
2488
2489 if (is_bbl_3mf && (load_filament_count > 0) && (load_filaments_set.size() == 1))
2490 {
2491 disable_wipe_tower_after_mapping = true;
2492 BOOST_LOG_TRIVIAL(info) << boost::format("map all the filaments to the same one, load_filament_count %1%")%load_filament_count;
2493 }
2494
2495
2496 bool fetch_compatible_values = false, fetch_upward_values = false;
2497 if (is_bbl_3mf && up_config_to_date) {
2498 if (uptodate_configs.size() > 0)
2499 {
2500 for (auto const &file : uptodate_configs) {
2501 DynamicPrintConfig config;
2502 std::string config_type, config_name, filament_id, config_from;
2503 int ret = load_config_file(file, config, config_type, config_name, filament_id, config_from);
2504 if (ret) {
2507 }
2508
2509 if (config_type == "machine") {
2510 if ( config_name != current_printer_system_name ) {
2511 BOOST_LOG_TRIVIAL(error) << boost::format("wrong machine config file %1% loaded, current machine config name %2% ")%config_name %current_printer_system_name;
2514 }
2515 upward_compatible_printers = config.
option<ConfigOptionStrings>(
"upward_compatible_machine",
true)->values;
2516 BOOST_LOG_TRIVIAL(info) << boost::format("load a machine config %1% from file %2%, upward_compatible_printers size is %3% ")%config_name %file %upward_compatible_printers.size();
2517 if (new_printer_name.empty() && !current_printer_system_name.empty())
2518 {
2519 config.
set(
"printer_settings_id", config_name,
true);
2520
2521
2523 if (!printer_model.empty()) {
2524 std::string printer_model_path =
resources_dir() +
"/profiles/BBL/machine_full/"+printer_model+
".json";
2525 if (boost::filesystem::exists(printer_model_path))
2526 {
2527 std::map<std::string, std::string> key_values;
2528
2530 if (key_values.find("model_id") != key_values.end()) {
2531 printer_model_id = key_values["model_id"];
2532 BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(":%1%, load printer_model_id %2% from current printer model %3%")%__LINE__ %printer_model_id %printer_model;
2533 }
2534 }
2535 }
2536
2537 int orig_printable_width = 0, orig_printable_depth = 0, orig_printable_height = 0;
2539 orig_printable_area = config.
option<ConfigOptionPoints>(
"printable_area",
true)->values;
2540 if (orig_printable_area.size() >= 4) {
2541 BoundingBoxf orig_printable_bbox(orig_printable_area);
2542 orig_printable_width = static_cast<int>(orig_printable_bbox.size().x());
2543 orig_printable_depth = static_cast<int>(orig_printable_bbox.size().y());
2544 }
2546 orig_printable_height = (int)(config.
opt_float(
"printable_height"));
2547 BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(":%1%, check printable size: old_printable_width=%2%, orig_printable_width=%3%, old_printable_depth=%4%, orig_printable_depth=%5%, old_printable_height=%6%, orig_printable_height=%7%")
2548 %__LINE__ %old_printable_width %orig_printable_width %old_printable_depth %orig_printable_depth %old_printable_height %orig_printable_height;
2549 if ((orig_printable_width > 0) && (orig_printable_depth > 0) && (orig_printable_height > 0))
2550 {
2551 if ((old_printable_width > orig_printable_width) || (old_printable_depth > orig_printable_depth) || (old_printable_height > orig_printable_height))
2552 {
2553 std::string error_str = (boost::format("Printer Settings: the printable size {%1%, %2%, %3%} exceeds the default size.")%old_printable_width %old_printable_depth %old_printable_height).str();
2554 BOOST_LOG_TRIVIAL(error) << error_str;
2557 }
2558 }
2559
2560 load_machine_config = std::move(config);
2561 }
2562 }
2563 else if (config_type == "process") {
2564 if ( config_name != current_process_system_name ) {
2565 BOOST_LOG_TRIVIAL(error) << boost::format("wrong process config file %1% loaded, current process config name %2% ")%config_name %current_process_system_name;
2568 }
2569 current_print_compatible_printers = config.
option<ConfigOptionStrings>(
"compatible_printers",
true)->values;
2570 BOOST_LOG_TRIVIAL(info) << boost::format(
"load a process config %1% from file %2%, current_print_compatible_printers size is %3% ")%config_name %file %current_print_compatible_printers.
size();
2571 if (new_process_name.empty() && !current_process_system_name.empty())
2572 {
2573 config.
set(
"print_settings_id", config_name,
true);
2574 load_process_config = std::move(config);
2575 }
2576 }
2577 else {
2578 BOOST_LOG_TRIVIAL(error) << boost::format("found invalid config type %1% from config %2% ")%config_type %file;
2581 }
2582 }
2583 }
2584 else {
2585 if (new_printer_name.empty() && !current_printer_system_name.empty()) {
2586
2587 std::string system_printer_path =
resources_dir() +
"/profiles/BBL/machine_full/"+current_printer_system_name+
".json";
2588 if (! boost::filesystem::exists(system_printer_path)) {
2589 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__<< boost::format(":%1%, can not find system preset file: %2% ")%__LINE__ %system_printer_path;
2590
2591 }
2592 else {
2593 DynamicPrintConfig config;
2594 std::string config_type, config_name, filament_id, config_from;
2595 int ret = load_config_file(system_printer_path, config, config_type, config_name, filament_id, config_from);
2596 if (ret) {
2599 }
2600
2601 upward_compatible_printers = config.
option<ConfigOptionStrings>(
"upward_compatible_machine",
true)->values;
2602 config.
set(
"printer_settings_id", config_name,
true);
2603
2604
2606 if (!printer_model.empty()) {
2607 std::string printer_model_path =
resources_dir() +
"/profiles/BBL/machine_full/"+printer_model+
".json";
2608 if (boost::filesystem::exists(printer_model_path))
2609 {
2610 std::map<std::string, std::string> key_values;
2611
2613 if (key_values.find("model_id") != key_values.end()) {
2614 printer_model_id = key_values["model_id"];
2615 BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(":%1%, load printer_model_id %2% from current printer model %3%")%__LINE__ %printer_model_id %printer_model;
2616 }
2617 }
2618 }
2619
2620 load_machine_config = std::move(config);
2621 }
2622 }
2623 else
2624 fetch_upward_values = true;
2625
2626 if (new_process_name.empty() && !current_process_system_name.empty()) {
2627
2628 std::string system_process_path =
resources_dir() +
"/profiles/BBL/process_full/"+current_process_system_name+
".json";
2629 if (! boost::filesystem::exists(system_process_path)) {
2630 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__<< boost::format(":%1%, can not find system preset file: %2% ")%__LINE__ %system_process_path;
2631
2632 }
2633 else {
2634 DynamicPrintConfig config;
2635 std::string config_type, config_name, filament_id, config_from;
2636 int ret = load_config_file(system_process_path, config, config_type, config_name, filament_id, config_from);
2637 if (ret) {
2640 }
2641 current_print_compatible_printers = config.
option<ConfigOptionStrings>(
"compatible_printers",
true)->values;
2642 config.
set(
"print_settings_id", config_name,
true);
2643 load_process_config = std::move(config);
2644 }
2645 }
2646 else
2647 fetch_compatible_values = true;
2648 }
2649
2650
2651 if (load_filament_count == 0)
2652 {
2653 if (uptodate_filaments.size() > 0)
2654 {
2655 if (uptodate_filaments.size() != (size_t)filament_count)
2656 {
2657 BOOST_LOG_TRIVIAL(error) << boost::format("uptodate_filaments size %1% not equal to filament_count %2% ")%uptodate_filaments.size() %filament_count;
2660 }
2661 for (int index = 0; index < filament_count; index ++)
2662 {
2663 std::string file = uptodate_filaments[index];
2664 DynamicPrintConfig config;
2665 std::string config_type, config_name, filament_id, config_from;
2666 int ret = load_config_file(file, config, config_type, config_name, filament_id, config_from);
2667 if (ret) {
2668 BOOST_LOG_TRIVIAL(error) << boost::format("load uptodate_filaments %1% fail, index %2%!")%file %index;
2671 }
2672
2673 if (config_type != "filament") {
2674 BOOST_LOG_TRIVIAL(error) <<__FUNCTION__ << boost::format(": unknown config type %1% of file %2% in load-filaments") % config_type % file;
2677 }
2678
2679 if (config_name != current_filaments_system_name[index]) {
2680 BOOST_LOG_TRIVIAL(error) << boost::format("wrong filament config file %1% loaded, current filament config name %2%, index %3%")%config_name %current_filaments_system_name[index] %index;
2683 }
2684
2685 load_filaments_id.push_back(filament_id);
2686 load_filaments_name.push_back(config_name);
2687 load_filaments_config.push_back(std::move(config));
2688 load_filaments_index.push_back(index+1);
2689 load_filaments_inherit.push_back(config_name);
2690 BOOST_LOG_TRIVIAL(info) << boost::format("load a filament config %1% from file %2%, using uptodate_filaments index %3%")%config_name %file %index;
2691 }
2692 }
2693 else
2694 {
2695 current_index = 0;
2696 for (int index = 0; index < current_filaments_system_name.size(); index++)
2697 {
2698 std::string system_filament_path =
resources_dir() +
"/profiles/BBL/filament_full/"+current_filaments_system_name[index]+
".json";
2699 current_index++;
2700 if (! boost::filesystem::exists(system_filament_path)) {
2701 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__<< boost::format(":%1%, can not find system preset file: %2% ")%__LINE__ %system_filament_path;
2702 continue;
2703 }
2704 DynamicPrintConfig config;
2705 std::string config_type, config_name, filament_id, config_from;
2706 int ret = load_config_file(system_filament_path, config, config_type, config_name, filament_id, config_from);
2707 if (ret) {
2710 }
2711
2712 if (config_type != "filament") {
2713 BOOST_LOG_TRIVIAL(error) <<__FUNCTION__ << boost::format(": unknown config type %1% of file %2% in load-filaments") % config_type % system_filament_path;
2716 }
2717
2718 load_filaments_id.push_back(filament_id);
2719 load_filaments_name.push_back(config_name);
2720 load_filaments_config.push_back(std::move(config));
2721 load_filaments_index.push_back(current_index);
2722 load_filaments_inherit.push_back(config_name);
2723 BOOST_LOG_TRIVIAL(info) << boost::format("LINE %4%: load a filament config %1% from file %2%, index %3%")%config_name %system_filament_path %index %__LINE__;
2724 }
2725 }
2726 }
2727 }
2728 else if (is_bbl_3mf){
2729 fetch_upward_values = true;
2730 fetch_compatible_values = true;
2731 }
2732
2733
2734
2735
2736 const bool refresh_unlisted = up_config_to_date || std::any_of(current_different_settings.begin(), current_different_settings.end(),
2737 [](const std::string &keys) { return !keys.empty(); });
2738
2739
2740
2741
2742
2743
2744 std::vector<bool> load_filaments_refresh(load_filaments_config.size(), false);
2745 std::set<std::string> project_keys;
2746 if (!refresh_unlisted) {
2748 project_keys.insert(key);
2749 project_keys.erase("filament_extruder_variant");
2750 }
2751 if (is_bbl_3mf && new_printer_name.empty()) {
2752 const ConfigOptionStrings *project_filament_ids =
m_print_config.option<ConfigOptionStrings>(
"filament_ids");
2753 for (size_t index = 0; index < current_filaments_system_name.size(); index++) {
2754 const int slot = static_cast<int>(index) + 1;
2755 if (std::find(load_filaments_index.begin(), load_filaments_index.end(), slot) != load_filaments_index.end())
2756 continue;
2757 std::string system_name = current_filaments_system_name[index];
2758 if (system_name.empty())
2759 continue;
2761 DynamicPrintConfig config;
2762 std::string error;
2763 if (!ensure_system_preset_resolver().resolve_system_preset(config,
Preset::TYPE_FILAMENT, system_name, config_substitution_rule, error)) {
2764 BOOST_LOG_TRIVIAL(warning) << boost::format("CLI: system filament preset '%1%' not resolved (%2%); filament %3% keeps its values") % system_name % error % slot;
2765 continue;
2766 }
2767 const size_t at = std::upper_bound(load_filaments_index.begin(), load_filaments_index.end(), slot) - load_filaments_index.begin();
2768 load_filaments_id.insert(load_filaments_id.begin() + at,
2769 project_filament_ids !=
nullptr && index < project_filament_ids->size() ? project_filament_ids->
values[index] : std::string());
2770 load_filaments_name.insert(load_filaments_name.begin() + at, system_name);
2771 load_filaments_config.insert(load_filaments_config.begin() + at, std::move(config));
2772 load_filaments_index.insert(load_filaments_index.begin() + at, slot);
2773 load_filaments_inherit.insert(load_filaments_inherit.begin() + at, system_name);
2774 load_filaments_refresh.insert(load_filaments_refresh.begin() + at, true);
2775 }
2776 }
2777
2778
2779 if (fetch_upward_values) {
2780 if (!current_printer_system_name.empty()) {
2781
2782 std::string system_printer_path =
resources_dir() +
"/profiles/BBL/machine_full/"+current_printer_system_name+
".json";
2783 if (! boost::filesystem::exists(system_printer_path)) {
2784 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__<< boost::format(":%1%, can not find system preset file: %2% ")%__LINE__ %system_printer_path;
2785
2786 }
2787 else {
2788 DynamicPrintConfig config;
2789 std::string config_type, config_name, filament_id, config_from;
2790 int ret = load_config_file(system_printer_path, config, config_type, config_name, filament_id, config_from);
2791 if (ret) {
2794 }
2795 upward_compatible_printers = config.
option<ConfigOptionStrings>(
"upward_compatible_machine",
true)->values;
2796
2797 current_printer_full_config = std::move(config);
2798 }
2799 }
2800 }
2801
2802
2803 if (fetch_compatible_values) {
2804 if (!current_process_system_name.empty()) {
2805
2806 std::string system_process_path =
resources_dir() +
"/profiles/BBL/process_full/"+current_process_system_name+
".json";
2807 if (! boost::filesystem::exists(system_process_path)) {
2808 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__<< boost::format(":%1%, can not find system preset file: %2% ")%__LINE__ %system_process_path;
2809
2810 }
2811 else {
2812 DynamicPrintConfig config;
2813 std::string config_type, config_name, filament_id, config_from;
2814 int ret = load_config_file(system_process_path, config, config_type, config_name, filament_id, config_from);
2815 if (ret) {
2818 }
2819 current_print_compatible_printers = config.
option<ConfigOptionStrings>(
"compatible_printers",
true)->values;
2820
2821 current_process_full_config = std::move(config);
2822 }
2823 }
2824 }
2825
2826
2827 bool process_compatible = false, machine_upwards = false, machine_switch = false;
2828 BOOST_LOG_TRIVIAL(info) << boost::format("current printer %1%, new printer %2%, current process %3%, new process %4%")%current_printer_name %new_printer_name %current_process_name %new_process_name;
2829 BOOST_LOG_TRIVIAL(info) << boost::format("current printer inherits %1%, new printer inherits %2%, current process inherits %3%, new process inherits %4%")
2830 %current_printer_system_name %new_printer_system_name %current_process_system_name %new_process_system_name;
2831 for (
int index = 0; index < current_print_compatible_printers.
size(); index++) {
2832 BOOST_LOG_TRIVIAL(info) << boost::format("index %1%, current print compatible printer %2%")%index %current_print_compatible_printers[index];
2833 }
2834 for (int index = 0; index < new_print_compatible_printers.size(); index++) {
2835 BOOST_LOG_TRIVIAL(info) << boost::format("index %1%, new print compatible printer %2%")%index %new_print_compatible_printers[index];
2836 }
2837 for (int index = 0; index < upward_compatible_printers.size(); index++) {
2838 BOOST_LOG_TRIVIAL(info) << boost::format("index %1%, upward_compatible_printers %2%")%index %upward_compatible_printers[index];
2839 }
2840
2841
2842
2843
2844
2845
2846
2847
2848 auto check_compat = [](const DynamicPrintConfig &process_cfg,
2849 const DynamicPrintConfig &printer_cfg,
2850 const std::string &printer_name) -> bool {
2852 };
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867 auto cli_process_compat_config = [](const DynamicPrintConfig &project_cfg) -> DynamicPrintConfig {
2868 DynamicPrintConfig cfg = project_cfg;
2869 const auto *raw_list = project_cfg.option<ConfigOptionStrings>("compatible_printers");
2870 const auto *list = project_cfg.option<ConfigOptionStrings>("print_compatible_printers");
2871 if ((raw_list ==
nullptr || raw_list->values.empty()) && list !=
nullptr && !list->
values.empty())
2873 const auto *raw_cond = project_cfg.option<
ConfigOptionString>(
"compatible_printers_condition");
2874 const auto *group = project_cfg.option<ConfigOptionStrings>("compatible_machine_expression_group");
2875 if ((raw_cond ==
nullptr || raw_cond->value.empty()) && group !=
nullptr && !group->values.
empty() &&
2876 !group->values.front().
empty())
2878 return cfg;
2879 };
2880 if (!new_printer_name.empty()) {
2881 if (!new_process_name.empty()) {
2882
2883 process_compatible = check_compat(load_process_config, load_machine_config, new_printer_system_name);
2884 BOOST_LOG_TRIVIAL(info) << boost::format("new printer %1%, inherited from %2%, new process %3%, inherited from %4% ,compatible %5%")
2885 %new_printer_name %new_printer_system_name %new_process_name %new_process_system_name %process_compatible;
2886 }
2887 else {
2888
2889
2890
2891
2892
2893 {
2894
2895
2896 const DynamicPrintConfig process_cfg = current_process_full_config.
empty()
2898 : current_process_full_config;
2899 process_compatible = check_compat(process_cfg, load_machine_config, new_printer_system_name);
2900 }
2901 BOOST_LOG_TRIVIAL(info) << boost::format("new printer %1%, inherited from %2%, old process %3%, inherited from %4% ,compatible %5%")
2902 %new_printer_name %new_printer_system_name %current_process_name %current_process_system_name %process_compatible;
2903 }
2904 }
2905 else if (!new_process_name.empty()) {
2906
2907
2908
2909 {
2910 const DynamicPrintConfig &printer_cfg = current_printer_full_config.
empty() ?
m_print_config : current_printer_full_config;
2911 process_compatible = check_compat(load_process_config, printer_cfg, current_printer_system_name);
2912 }
2913 BOOST_LOG_TRIVIAL(info) << boost::format("old printer %1%, inherited from %2%, new process %3%, inherited from %4% ,compatible %5%")
2914 %current_printer_name %current_printer_system_name %new_process_name %new_process_system_name %process_compatible;
2915 }
2916 else {
2917
2918 if (!current_process_full_config.
empty() && !current_printer_full_config.
empty())
2919 process_compatible = check_compat(current_process_full_config, current_printer_full_config, current_printer_system_name);
2920 else
2921 process_compatible = std::find(current_print_compatible_printers.begin(), current_print_compatible_printers.end(), current_printer_system_name) != current_print_compatible_printers.end();
2922 if (!process_compatible && current_print_compatible_printers.
empty())
2923 {
2924 BOOST_LOG_TRIVIAL(info) << boost::format("old 3mf, no compatible printers, set to compatible");
2925 process_compatible = true;
2926 }
2927 BOOST_LOG_TRIVIAL(info) << boost::format("old printer %1%, inherited from %2%, old process %3%, inherited from %4% ,compatible %5%")
2928 %current_printer_name %current_printer_system_name %current_process_name %current_process_system_name %process_compatible;
2929 }
2930 if (!process_compatible && !new_printer_name.empty() && !current_printer_name.empty() && (new_printer_name != current_printer_name)) {
2931
2932 if (new_process_name.empty())
2933 process_compatible = true;
2934 machine_switch = true;
2935 BOOST_LOG_TRIVIAL(info) << boost::format("switch to new printers, set to compatible");
2936 if (upward_compatible_printers.size() > 0) {
2937 for (int index = 0; index < upward_compatible_printers.size(); index++) {
2938 if (upward_compatible_printers[index] == new_printer_system_name) {
2939 process_compatible = true;
2940 machine_upwards = true;
2941 BOOST_LOG_TRIVIAL(info) << boost::format("new printer is upward_compatible");
2942 break;
2943 }
2944 }
2945 if (!process_compatible) {
2946 BOOST_LOG_TRIVIAL(error) <<__FUNCTION__ << boost::format(" %1% : current 3mf file not support the new printer %2%, new_printer_system_name %3%")%__LINE__%new_printer_name %new_printer_system_name;
2949 }
2950 }
2951
2952
2953
2954
2955
2956 }
2957
2958 if (!process_compatible) {
2959 BOOST_LOG_TRIVIAL(error) <<__FUNCTION__ << boost::format(" %1%: process not compatible with printer.")%__LINE__;
2962 }
2964
2965
2966 Preset *new_preset = NULL;
2967 if (is_bbl_3mf && machine_switch) {
2968
2969 Preset *current_preset = NULL;
2970 size_t project_presets_count = project_presets.size();
2971 for (int index = 0; index < project_presets_count; index++)
2972 {
2973 if (project_presets[index]->name == current_process_name) {
2974 current_preset = project_presets[index];
2975 break;
2976 }
2977 }
2979 if (current_preset) {
2980 *new_preset = *current_preset;
2981 std::vector<std::string>& compatible_printers = new_preset->
config.
option<ConfigOptionStrings>(
"compatible_printers",
true)->values;
2982 bool need_insert = true;
2983 for (int index = 0; index < compatible_printers.size(); index++) {
2984 if (compatible_printers[index] == new_printer_system_name) {
2985 need_insert = false;
2986 break;
2987 }
2988 }
2989 if (need_insert)
2990 compatible_printers.push_back(new_printer_system_name);
2991 }
2992 else {
2993
2996 std::vector<std::string>& compatible_printers = new_preset->
config.
option<ConfigOptionStrings>(
"compatible_printers",
true)->values;
2997 compatible_printers = current_print_compatible_printers;
2998 compatible_printers.push_back(new_printer_system_name);
2999 if (current_process_system_name != current_process_name) {
3001 inherits = current_process_system_name;
3002 }
3005
3006 }
3007 new_preset->
name +=
"(auto)";
3008 new_preset->
config.
set(
"print_settings_id", new_preset->
name,
true);
3010 project_presets.push_back(new_preset);
3011 }
3012
3013
3014 auto compute_variant_index = [](DynamicPrintConfig& full_config, const DynamicPrintConfig& new_config, std::string id_name, std::string variant_name, std::vector<int>& new_index, bool& count_changed) {
3015 auto curr_variant_opt =
dynamic_cast<const ConfigOptionStrings*
>(full_config.
option(variant_name));
3016 auto new_variant_opt = dynamic_cast<const ConfigOptionStrings*>(new_config.option(variant_name));
3018 auto new_id_opt =
dynamic_cast<const ConfigOptionInts*
>(new_config.option(id_name));
3019 if (!new_variant_opt || !new_id_opt) {
3020 BOOST_LOG_TRIVIAL(error) << boost::format("%1%:%2%, can not get %3% or %4% from new config")%__FUNCTION__ %__LINE__ % variant_name %id_name;
3021 count_changed = false;
3022 return;
3023 }
3024 int new_variant_count = new_variant_opt->
size(), curr_variant_count = 0;
3025 new_index.clear();
3026 new_index.resize(new_variant_count, -1);
3027 if (curr_variant_opt && curr_id_opt) {
3028 if (curr_variant_opt->size() != curr_id_opt->size()) {
3029 BOOST_LOG_TRIVIAL(error) << boost::format("%1%:%2%, %3%'s size %4% not equal to %5%'s size %6%")%__FUNCTION__ %__LINE__ % variant_name %curr_variant_opt->size() %id_name %curr_id_opt->size();
3030 count_changed = false;
3031 return;
3032 }
3033 curr_variant_count = curr_variant_opt->size();
3034 count_changed = (curr_variant_count != new_variant_count);
3035 }
3036 else
3037 count_changed = (new_variant_count != 1);
3038
3039
3040 for (int i = 0; i < new_variant_count; i++)
3041 {
3042 if (curr_variant_count > 0) {
3043 for (int j = 0; j < curr_variant_count; j++)
3044 {
3045 if ((curr_variant_opt->values[j] == new_variant_opt->values[i]) && (curr_id_opt->values[j] == new_id_opt->values[i])) {
3046 new_index[i] = j;
3047 break;
3048 }
3049 }
3050 }
3051 else if ((new_variant_opt->values[i] == "Direct Drive Standard") && (new_id_opt->values[i] == 1))
3052 new_index[i] = 0;
3053 }
3054 };
3055
3056
3057 auto update_full_config = [](DynamicPrintConfig& full_config, const DynamicPrintConfig& config, std::set<std::string>& diff_key_sets, bool variant_count_changed, std::set<std::string>& key_set_1, std::set<std::string>& key_set_2, std::vector<int> variant_index, bool update_all = false, bool skip_gcodes = false) {
3059 BOOST_LOG_TRIVIAL(info) << boost::format("update_full_config: config keys count %1%")%config_keys.size();
3061 if (!update_all && !diff_key_sets.empty()) {
3062 std::set<std::string>::iterator iter = diff_key_sets.find(opt_key);
3063 if ( iter != diff_key_sets.end()) {
3065 {
3066 diff_key_sets.erase(iter);
3067 BOOST_LOG_TRIVIAL(info) << boost::format("%1%, gcodes %2% modified, reset to default.")%__LINE__ %opt_key;
3068 }
3069 else {
3070
3071 BOOST_LOG_TRIVIAL(info) << boost::format("%1%, keep key %2%")%__LINE__ %opt_key;
3072 if (variant_count_changed) {
3073
3074 int stride = 0;
3075 if (key_set_1.count(opt_key) > 0)
3076 {
3077 stride = 1;
3078 }
3079 else if (key_set_2.count(opt_key) > 0)
3080 {
3081 stride = 2;
3082 }
3083
3084 if (stride > 0) {
3085 const ConfigOption *source_opt = config.option(opt_key);
3086 ConfigOption *dest_opt = full_config.
option(opt_key,
true);
3087 const ConfigOptionVectorBase* opt_vec_src = static_cast<const ConfigOptionVectorBase*>(source_opt);
3088 ConfigOptionVectorBase* opt_vec_dest = static_cast<ConfigOptionVectorBase*>(dest_opt);
3089
3091 }
3092 else
3093 continue;
3094 }
3095 else
3096 continue;
3097 }
3098 }
3099 }
3100 const ConfigOption *source_opt = config.option(opt_key);
3101 if (source_opt == nullptr) {
3102
3103 boost::nowide::cerr << __FUNCTION__<<": can not found option " <<opt_key<<"from config." <<std::endl;
3105 }
3106 if (opt_key == "compatible_prints" || opt_key == "compatible_printers" || opt_key == "model_id" || opt_key == "inherits" ||opt_key == "dev_model_name"
3107 || opt_key == "name" || opt_key == "from" || opt_key == "type" || opt_key == "version" || opt_key == "setting_id" || opt_key == "instantiation" )
3108 continue;
3109 else {
3110 ConfigOption *dest_opt = full_config.
option(opt_key,
true);
3111 if (dest_opt == nullptr) {
3112 boost::nowide::cerr << __FUNCTION__<<":can not create option " <<opt_key<<" to full_config "<<std::endl;
3114 }
3115 dest_opt->
set(source_opt);
3116
3117 }
3118 }
3119 return 0;
3120 };
3121
3122
3123
3124
3125 auto load_project_preset = [
this, &ensure_system_preset_resolver, ¤t_different_settings, refresh_unlisted, filament_count](
const std::string &system_name,
Preset::Type type) {
3126 if (system_name.empty())
3127 return;
3128
3129 static const std::set<std::string> bookkeeping_keys = {"inherits", "compatible_printers", "compatible_prints", "compatible_printers_condition",
3130 "compatible_prints_condition", "print_settings_id", "printer_settings_id"};
3132 PresetBundle &resolver = ensure_system_preset_resolver();
3133 DynamicPrintConfig system_config;
3138 [&](const std::string &) -> DynamicPrintConfig * {
3139 std::string error;
3140 if (resolver.resolve_system_preset(system_config, type, system_name, config_substitution_rule, error))
3141 return &system_config;
3142 BOOST_LOG_TRIVIAL(warning) << boost::format("CLI: system preset '%1%' not resolved (%2%); the project keeps its values") % system_name % error;
3143 return nullptr;
3144 }, &keys);
3145 for (const std::string &key : keys) {
3146 const ConfigOption *opt = config.
option(key);
3148 if (bookkeeping_keys.count(key) != 0 || opt == nullptr || (old != nullptr && (!refresh_unlisted || *old == *opt)))
3149 continue;
3150 BOOST_LOG_TRIVIAL(info) << boost::format(
"CLI: %1% from '%2%': %3% -> %4%") % key % system_name % (old ? old->
serialize() : std::string(
"(missing)")) % opt->
serialize();
3152 }
3153 };
3154
3155 if (new_printer_name.empty() && load_machine_config.
empty())
3157 if (new_process_name.empty() && load_process_config.
empty())
3159
3160 std::vector<std::string>& different_settings =
m_print_config.option<ConfigOptionStrings>(
"different_settings_to_system",
true)->values;
3161 std::vector<std::string>& inherits_group =
m_print_config.option<ConfigOptionStrings>(
"inherits_group",
true)->values;
3162 inherits_group.resize(filament_count + 2, std::string());
3163 different_settings.resize(filament_count + 2, std::string());
3164 if (!is_bbl_3mf && !different_process_setting.empty()) {
3165 different_settings[0] = different_process_setting;
3166 }
3167
3168 std::vector<int> new_variant_index;
3169 bool variant_count_changed = false;
3170
3171 if (!new_printer_name.empty() || up_config_to_date) {
3172 std::vector<std::string> different_keys;
3173
3174 if (new_printer_name.empty()) {
3175 std::string diff_settings;
3176 if (!different_settings.empty()) {
3177 diff_settings = different_settings[filament_count+1];
3179 }
3180 }
3181 else {
3182
3183 different_settings[filament_count+1] = new_printer_config_is_system
3184 ? std::string()
3185 : cli_different_settings(load_machine_config, new_printer_system_name,
Preset::TYPE_PRINTER);
3186 if (new_printer_config_is_system)
3187 inherits_group[filament_count+1] = "";
3188 else
3189 inherits_group[filament_count+1] = new_printer_system_name;
3190 }
3191
3192 std::set<std::string> different_keys_set(different_keys.begin(), different_keys.end());
3193 BOOST_LOG_TRIVIAL(info) << boost::format("update printer config to newest, different size %1%, different_settings: %2%")%different_keys_set.size() %different_settings[filament_count+1];
3194
3195 int ret;
3196
3198 if (new_printer_name.empty()) {
3199 int diff_keys_size = different_keys_set.size();
3200 compute_variant_index(
m_print_config, load_machine_config,
"printer_extruder_id",
"printer_extruder_variant", new_variant_index, variant_count_changed);
3202 if (diff_keys_size != different_keys_set.size()) {
3203
3204 BOOST_LOG_TRIVIAL(info) << boost::format("new different key size %1%")%different_keys_set.size();
3205 different_keys.clear();
3206
3207 for (std::set<std::string>::iterator iter=different_keys_set.begin(); iter !=different_keys_set.end(); ++iter)
3208 different_keys.emplace_back(*iter);
3210 }
3211 BOOST_LOG_TRIVIAL(info) << boost::format("no new printer, only update the different key, new different_settings: %1%")%different_settings[filament_count+1];
3212 }
3213 else {
3215 BOOST_LOG_TRIVIAL(info) << boost::format("load a new printer, update all the keys, different_settings: %1%")%different_settings[filament_count+1];
3216 if (new_printer_name != current_printer_name)
3217 {
3218
3219 BOOST_LOG_TRIVIAL(info) << boost::format("check printer cli safe params, current_printer_name %1%, new_printer_name %2%, printer_model %3%")%current_printer_name %new_printer_name %printer_model;
3220 std::map<std::string, std::string> printer_params;
3221 std::string cli_config_file =
resources_dir() +
"/profiles/BBL/cli_config.json";
3222 boost::filesystem::path directory_path(cli_config_file);
3223
3224 BOOST_LOG_TRIVIAL(info) << boost::format("line %1% , will parse file %2%")%__LINE__ % cli_config_file;
3225 if (!fs::exists(directory_path)) {
3226 BOOST_LOG_TRIVIAL(warning) << boost::format("file %1% not exist.")%cli_config_file;
3227 }
3228 else {
3229 try {
3231 boost::nowide::ifstream ifs(cli_config_file);
3232 ifs >> root_json;
3233 ifs.close();
3234
3235 if (root_json.contains("printer")) {
3236 json printer_json = root_json[
"printer"];
3237 if (!printer_model.empty() && printer_json.contains(printer_model)) {
3238 json printer_model_json = printer_json[printer_model];
3239
3240 if (printer_model_json.contains("machine_limits")) {
3241 json machine_limits_json = printer_model_json[
"machine_limits"];
3242 printer_params = machine_limits_json.get<std::map<std::string, std::string>>();
3243
3244 for (auto param_iter = printer_params.begin(); param_iter != printer_params.end(); param_iter++)
3245 {
3246 std::string key = param_iter->first;
3247
3248 key.replace(0, 8, "machine_max");
3249
3251 if (option) {
3252
3253 unsigned int array_count = option->
size();
3256 unsigned int new_array_count = new_option.
size();
3257 for (unsigned int index = 0; index < array_count; index++)
3258 {
3259 if ((index < new_array_count) && new_option.
values[index] != 0.f && (new_option.
values[index] < option->
values[index]))
3260 {
3261 BOOST_LOG_TRIVIAL(info) << boost::format(
"set key %1% index %2%, from %3% to %4%") % key %index %option->
values[index] % new_option.
values[index];
3263 }
3264 }
3265 }
3266 else
3267 BOOST_LOG_TRIVIAL(warning) << boost::format("can not find key %1% in config") %key;
3268 }
3269 }
3270 else {
3271 BOOST_LOG_TRIVIAL(info) << boost::format("can not find machine_limits for printer %1% in cli_config.json")%printer_model;
3272 }
3273 }
3274 else {
3275 BOOST_LOG_TRIVIAL(info) << boost::format("can not find key %1% in the file")%printer_model;
3276 }
3277 }
3278 else {
3279 BOOST_LOG_TRIVIAL(warning) << boost::format("can not find key printer in the file");
3280 }
3281 }
3282 catch (std::exception &err) {
3283 BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": parse file "<<cli_config_file<<" got a generic exception, reason = " << err.what();
3284 }
3285 }
3286 }
3287 }
3288
3289 if (ret) {
3292 }
3293 }
3296 new_is_multi_extruder = new_extruder_count > 1;
3297 new_printer_extruder_variants =
m_print_config.option<ConfigOptionStrings>(
"printer_extruder_variant",
true)->values;
3298 new_printer_variant_count = new_printer_extruder_variants.size();
3299 }
3300
3301
3302 std::vector<std::string>& print_compatible_printers =
m_print_config.option<ConfigOptionStrings>(
"print_compatible_printers",
true)->values;
3303 if (!new_process_name.empty() || up_config_to_date) {
3304 std::vector<std::string> different_keys;
3305
3306 if (new_process_name.empty()) {
3307 std::string diff_settings;
3308 if (!different_settings.empty()) {
3309 diff_settings = different_settings[0];
3311 int remove_index = -1;
3312 for (int index = 0; index < different_keys.size(); index++) {
3313 if (different_keys[index] == "compatible_printers") {
3314 remove_index = index;
3315 break;
3316 }
3317 }
3318 if (remove_index != -1) {
3319 different_keys[remove_index] = different_keys[different_keys.size() - 1];
3320 different_keys.erase(different_keys.begin() + different_keys.size() - 1);
3322 }
3323 }
3324 print_compatible_printers = std::move(current_print_compatible_printers);
3325 }
3326 else {
3327
3328
3329 if (!different_process_setting.empty())
3330 different_settings[0] = different_process_setting;
3331 else
3332 different_settings[0] = new_process_config_is_system
3333 ? std::string()
3334 : cli_different_settings(load_process_config, new_process_system_name,
Preset::TYPE_PRINT);
3335 if (new_process_config_is_system)
3336 inherits_group[0] = "";
3337 else
3338 inherits_group[0] = new_process_system_name;
3339 print_compatible_printers = std::move(new_print_compatible_printers);
3340 }
3341
3342 std::set<std::string> different_keys_set(different_keys.begin(), different_keys.end());
3343 BOOST_LOG_TRIVIAL(info) << boost::format("update process config to newest, different size %1%, different_settings: %2%")%different_keys_set.size() %different_settings[0];
3344
3345 int ret;
3346
3348 if (new_process_name.empty()) {
3349 int diff_keys_size = different_keys_set.size();
3350 compute_variant_index(
m_print_config, load_process_config,
"print_extruder_id",
"print_extruder_variant", new_variant_index, variant_count_changed);
3352 if (diff_keys_size != different_keys_set.size()) {
3353
3354 BOOST_LOG_TRIVIAL(info) << boost::format("new different key size %1%")%different_keys_set.size();
3355 different_keys.clear();
3356
3357 for (std::set<std::string>::iterator iter=different_keys_set.begin(); iter !=different_keys_set.end(); ++iter)
3358 different_keys.emplace_back(*iter);
3360 }
3361 BOOST_LOG_TRIVIAL(info) << boost::format("no new process, only update the different key, new different_settings: %1%")%different_settings[0];
3362 }
3363 else {
3365 BOOST_LOG_TRIVIAL(info) << boost::format("load a new process, update all the keys, different_settings: %1%")%different_settings[0];
3366 }
3367 current_print_variant_count =
m_print_config.option<ConfigOptionStrings>(
"print_extruder_variant",
true)->values.size();
3368
3369 if (ret) {
3372 }
3373 }
3374
3375
3378 if (opt_nozzle_volume_type) {
3379 int nozzle_volume_type_size = opt_nozzle_volume_type->values.size();
3380 new_nozzle_volume_type.resize(nozzle_volume_type_size,
nvtStandard);
3381 for (int i = 0; i < nozzle_volume_type_size; i++)
3382 {
3383 new_nozzle_volume_type[i] = (
NozzleVolumeType) (opt_nozzle_volume_type->values[i]);
3384 }
3385 }
3386 }
3387 else {
3388 new_nozzle_volume_type.resize(new_extruder_count,
nvtStandard);
3389 }
3390 new_extruder_variants.resize(new_extruder_count, "");
3392 for (int e_index = 0; e_index < new_extruder_count; e_index++) {
3395 }
3396
3397 if (current_nozzle_volume_type.empty())
3398 {
3399 current_nozzle_volume_type.resize(current_extruder_count,
nvtStandard);
3400 }
3401 current_print_extruder_variants =
m_print_config.option<ConfigOptionStrings>(
"print_extruder_variant",
true)->values;
3402
3403 if (machine_switch) {
3404 print_compatible_printers.push_back(new_printer_system_name);
3405
3406 std::string old_setting = different_settings[0];
3407 if (old_setting.empty())
3408 different_settings[0] = "compatible_printers";
3409 else {
3410 std::vector<std::string> different_keys;
3412 bool need_insert = true;
3413 for (int index = 0; index < different_keys.size(); index++) {
3414 if (different_keys[index] == "compatible_printers") {
3415 need_insert = false;
3416 break;
3417 }
3418 }
3419 if (need_insert)
3420 different_settings[0] = old_setting + ";compatible_printers";
3421 }
3422
3423
3424 if (new_process_name.empty() && ((current_extruder_count != new_extruder_count) || (current_print_variant_count != new_printer_variant_count))) {
3425 if (new_default_process_name.empty()) {
3426 BOOST_LOG_TRIVIAL(error) << boost::format("machine_switch: default process configis null, should not happen, new_printer_name %1%")%new_printer_name;
3429 }
3430 else {
3431 std::string default_path =
resources_dir() +
"/profiles/BBL/process_full/";
3432 std::string file_path = default_path + new_default_process_name + ".json";
3433 DynamicPrintConfig config;
3434 std::string config_type, config_name, filament_id, config_from, downward_printer;
3435 int ret = load_config_file(file_path, config, config_type, config_name, filament_id, config_from);
3436 if (ret) {
3439 }
3440 if ((config_type != "process") || (config_from != "system")) {
3441 BOOST_LOG_TRIVIAL(error) << boost::format("found invalid config type %1% or from %2% in file %3% when downward_check")%config_type %config_from %file_path;
3444 }
3445 BOOST_LOG_TRIVIAL(info) << boost::format("%1%, machine_switch: loaded default process config %2%, from %3%")%__LINE__ %config_name %file_path ;
3446 BOOST_LOG_TRIVIAL(info) << boost::format("%1%, current_is_multi_extruder: %2%, new_is_multi_extruder: %3%, current_print_variant_count: %4%, new_printer_variant_count: %5%")
3447 %__LINE__ %current_is_multi_extruder %new_is_multi_extruder %current_print_variant_count %new_printer_variant_count;
3448
3449 if (!current_is_multi_extruder && new_is_multi_extruder && (current_print_variant_count == 1)) {
3450
3452 }
3453 else {
3454
3456 }
3457
3458 if (ret) {
3459 BOOST_LOG_TRIVIAL(error) << boost::format("current_is_multi_extruder %1% new_is_multi_extruder %2%, update_values failed") % current_is_multi_extruder % new_is_multi_extruder;
3462 }
3463 }
3464 }
3465 }
3466
3467
3468 if ((load_filament_count > 0) || (up_config_to_date) || !load_filaments_config.empty())
3469 {
3470
3471 std::vector<int> old_start_indice(filament_count, 0);
3472 std::vector<int> old_variant_counts(filament_count, 1), new_variant_counts;
3473
3475 bool need_regenerate_self_index = !filament_self_index_opt;
3476 if (filament_self_index_opt) {
3477
3478
3479
3480
3481
3482 int max_self_index = 0, min_self_index = 1;
3483 for (
int v : filament_self_index_opt->
values) {
3484 max_self_index = std::max(max_self_index, v);
3485 min_self_index = std::min(min_self_index, v);
3486 }
3487
3488
3489
3490
3491 if (max_self_index > filament_count || min_self_index < 1 || max_self_index < filament_count
3492 || (
int) filament_self_index_opt->
values.size() < filament_count) {
3493 BOOST_LOG_TRIVIAL(warning) << boost::format("filament_self_index range [%1%, %2%] (size %4%) is invalid for filament_count %3%, regenerating")
3494 % min_self_index % max_self_index % filament_count % filament_self_index_opt->
values.size();
3495 need_regenerate_self_index = true;
3496 }
3497 }
3498 if (need_regenerate_self_index) {
3500 std::vector<int>& filament_self_indice = filament_self_index_opt->
values;
3501 filament_self_indice.resize(filament_count);
3502 for (int index = 0; index < filament_count; index++)
3503 filament_self_indice[index] = index + 1;
3504 }
3505
3506 std::vector<int> old_self_indice= filament_self_index_opt->
values;
3507 int old_self_indice_size = old_self_indice.size();
3508 int k = -1, current_filament = 0;
3509 for (size_t i = 0; i < old_self_indice_size; i++) {
3510 if (old_self_indice[i] > current_filament) {
3511 current_filament = old_self_indice[i];
3512 old_start_indice[++k] = i;
3513 old_variant_counts[k] = 1;
3514 }
3515 else {
3516 old_variant_counts[k] = old_variant_counts[k] + 1;
3517 }
3518 }
3519 new_variant_counts = old_variant_counts;
3520
3521
3522
3523
3524 for (const DynamicPrintConfig &config : load_filaments_config)
3526 if (opt_key !=
"filament_extruder_variant" && config.
has(opt_key))
3529 for (int index = 0; index < load_filaments_config.size(); index++) {
3530 DynamicPrintConfig& config = load_filaments_config[index];
3531 int filament_index = load_filaments_index[index];
3532
3533 const bool loaded = load_filament_count > 0 && !load_filaments_refresh[index];
3534
3535 const bool keep_project = load_filaments_refresh[index] && !refresh_unlisted;
3536 std::vector<std::string> different_keys;
3537
3538
3539
3540
3541
3542
3543
3544 std::string filament_different_settings;
3545 if (loaded)
3546 filament_different_settings = cli_different_settings(config, load_filaments_inherit[index],
Preset::TYPE_FILAMENT);
3547
3549
3550 if (loaded) {
3551 ConfigOptionStrings *opt_filament_settings =
static_cast<ConfigOptionStrings *
> (
m_print_config.option(
"filament_settings_id",
true));
3552 std::string& filament_name = load_filaments_name[index];
3554 if (opt_filament_settings->
size() < filament_count)
3555 opt_filament_settings->
resize(filament_count, filament_name_setting);
3556 opt_filament_settings->
set_at(filament_name_setting, filament_index-1, 0);
3557 config.
erase(
"filament_settings_id");
3558
3559
3560 different_settings[filament_index] = filament_different_settings;
3561 inherits_group[filament_index] = load_filaments_inherit[index];
3562 }
3563 else if (keep_project)
3564 different_keys.assign(project_keys.begin(), project_keys.end());
3565 else {
3566 std::string diff_settings;
3567
3568 if (!different_settings.empty()) {
3569 diff_settings = different_settings[filament_index];
3571 }
3572 }
3573
3574
3575 std::string& filament_id = load_filaments_id[index];
3576 ConfigOptionStrings *opt_filament_ids =
static_cast<ConfigOptionStrings *
> (
m_print_config.option(
"filament_ids",
true));
3578 if (opt_filament_ids->
size() < filament_count)
3579 opt_filament_ids->
resize(filament_count, filament_id_setting);
3580 opt_filament_ids->
set_at(filament_id_setting, filament_index-1, 0);
3581
3582
3583 ConfigOptionStrings *curr_variant_opt =
m_print_config.option<ConfigOptionStrings>(
"filament_extruder_variant");
3584 if (!curr_variant_opt) {
3585 curr_variant_opt =
m_print_config.option<ConfigOptionStrings>(
"filament_extruder_variant",
true);
3586 std::vector<std::string>& filament_variants = curr_variant_opt->
values;
3588 }
3589
3590
3591 if ((
int) curr_variant_opt->
values.size() < filament_count)
3593 const ConfigOptionStrings *new_variant_opt =
dynamic_cast<const ConfigOptionStrings*
>(config.
option(
"filament_extruder_variant",
true));
3594
3595 std::vector<int> new_variant_indice;
3596 int new_variant_count = new_variant_opt->
size(), old_variant_count = old_variant_counts[filament_index - 1];
3597 new_variant_indice.resize(new_variant_count, -1);
3598
3599 for (int i = 0; i < new_variant_count; i++)
3600 {
3601 for (
int j = old_start_indice[filament_index - 1]; j < old_start_indice[filament_index - 1] + old_variant_count && j < (int) curr_variant_opt->
values.size(); j++)
3602 {
3603 if (curr_variant_opt->
values[j] == new_variant_opt->
values[i]) {
3604 new_variant_indice[i] = j;
3605 break;
3606 }
3607 }
3608 }
3609
3610
3611
3612 std::set<std::string> different_keys_set(different_keys.begin(), different_keys.end());
3613 int diff_keys_size = different_keys_set.size();
3614 BOOST_LOG_TRIVIAL(info) << boost::format("update filament %1%'s config to newest, different size %2%, name %3%, different_settings %4%")
3615 %filament_index%different_keys_set.size()%load_filaments_name[index] % different_settings[filament_index];
3617
3618
3619
3620 const ConfigOption *source_opt = config.
option(opt_key);
3621 if (source_opt == nullptr) {
3622
3623 BOOST_LOG_TRIVIAL(error) << boost::format("can not find %1% from filament %2%: %3%")%opt_key%filament_index%load_filaments_name[index];
3626 }
3627
3628 if (!loaded && !different_keys_set.empty())
3629 {
3630 std::set<std::string>::iterator iter = different_keys_set.find(opt_key);
3631 if ( iter != different_keys_set.end()) {
3633 {
3634 different_keys_set.erase(iter);
3635 BOOST_LOG_TRIVIAL(info) << boost::format("%1%, filament %2%'s gcodes %3% modified, reset to default.")%__LINE__ %filament_index %opt_key;
3636 }
3637 else {
3638
3639 BOOST_LOG_TRIVIAL(info) << boost::format("%1%, keep key %2%")%__LINE__ %opt_key;
3641 {
3643 if (opt == nullptr) {
3644
3645
3646 BOOST_LOG_TRIVIAL(error) << boost::format("can not find option %1% from config, but can find it in different settings")%opt_key;
3649 }
3650 ConfigOptionVectorBase* opt_vec_dst = static_cast<ConfigOptionVectorBase*>(opt);
3651 const ConfigOptionVectorBase* opt_vec_src = static_cast<const ConfigOptionVectorBase*>(source_opt);
3652
3653 try {
3654
3655
3656 if (opt_vec_src->
size() > 0 && opt_vec_dst->
size() <
size_t(old_start_indice[filament_index - 1] + old_variant_count))
3657 opt_vec_dst->
resize(
size_t(old_start_indice[filament_index - 1] + old_variant_count), opt_vec_src);
3658
3659 opt_vec_dst->
set_with_restore_2(opt_vec_src, new_variant_indice, old_start_indice[filament_index - 1], old_variant_count, keep_project);
3660 } catch (const std::exception &ex) {
3661 BOOST_LOG_TRIVIAL(error) << boost::format("filament %1%: option %2% could not be applied: %3%") % filament_index % opt_key % ex.what();
3662 boost::nowide::cerr << "filament " << filament_index << ": option " << opt_key << " could not be applied: " << ex.what() << std::endl;
3665 }
3666 }
3667
3668 continue;
3669 }
3670 }
3671 }
3672
3674 if (opt_key == "compatible_printers_condition") {
3675 ConfigOption *opt =
m_print_config.option(
"compatible_machine_expression_group",
true);
3676 ConfigOptionStrings* opt_vec_dst = static_cast<ConfigOptionStrings*>(opt);
3677 if (opt_vec_dst->
size() == 0)
3679 opt_vec_dst->
set_at(source_opt, filament_index, 0);
3680 }
3681 else if (opt_key == "compatible_prints_condition") {
3682 ConfigOption *opt =
m_print_config.option(
"compatible_process_expression_group",
true);
3683 ConfigOptionStrings* opt_vec_dst = static_cast<ConfigOptionStrings*>(opt);
3684 if (opt_vec_dst->
size() == 0)
3686 opt_vec_dst->
set_at(source_opt, filament_index-1, 0);
3687 }
3688 else {
3689
3690 BOOST_LOG_TRIVIAL(info) << boost::format("skip scalar option %1% from filament %2%: %3%")%opt_key%filament_index%load_filaments_name[index];;
3691 continue;
3692 }
3693 }
3694 else
3695 {
3696 if (opt_key == "compatible_prints" || opt_key == "compatible_printers" || opt_key == "model_id" || opt_key == "dev_model_name" || opt_key == "filament_settings_id")
3697 continue;
3698
3700 continue;
3702 if (opt == nullptr) {
3703
3704
3705 BOOST_LOG_TRIVIAL(error) << boost::format("can not create option %1% to config, from filament %2%: %3%")%opt_key%filament_index%load_filaments_name[index];
3708 }
3709 ConfigOptionVectorBase* opt_vec_dst = static_cast<ConfigOptionVectorBase*>(opt);
3710 const ConfigOptionVectorBase* opt_vec_src = static_cast<const ConfigOptionVectorBase*>(source_opt);
3712 std::vector<int> temp_variant_indice;
3713 temp_variant_indice.resize(new_variant_count, -1);
3714 try {
3715 if (opt_vec_src->
size() > 0 && opt_vec_dst->
size() <
size_t(old_start_indice[filament_index - 1] + old_variant_count))
3716 opt_vec_dst->
resize(
size_t(old_start_indice[filament_index - 1] + old_variant_count), opt_vec_src);
3717 opt_vec_dst->
set_with_restore_2(opt_vec_src, temp_variant_indice, old_start_indice[filament_index - 1], old_variant_count,
true);
3718 } catch (const std::exception &ex) {
3719 BOOST_LOG_TRIVIAL(error) << boost::format("filament %1%: option %2% could not be applied: %3%") % filament_index % opt_key % ex.what();
3720 boost::nowide::cerr << "filament " << filament_index << ": option " << opt_key << " could not be applied: " << ex.what() << std::endl;
3723 }
3724
3725 if (opt_key == "filament_extruder_variant")
3726 new_variant_counts[filament_index - 1] = opt_vec_src->
size();
3727 }
3728 else {
3729 opt_vec_dst->
set_at(opt_vec_src, filament_index - 1, 0);
3730 }
3731 }
3732 }
3733
3734
3735
3736 const int old_start = old_start_indice[filament_index - 1];
3737 std::vector<int> kept_variant_indice = new_variant_indice;
3738 for (int &i : kept_variant_indice)
3739 if (i < 0)
3740 i = old_start;
3742 if (config.
has(opt_key))
3743 continue;
3744 auto *opt_vec_dst =
dynamic_cast<ConfigOptionVectorBase *
>(
m_print_config.option(opt_key));
3745 if (opt_vec_dst ==
nullptr || opt_vec_dst->
size() <
size_t(old_start + old_variant_count))
3746 continue;
3747
3748 std::unique_ptr<ConfigOption> old_values(opt_vec_dst->
clone());
3749 opt_vec_dst->
set_with_restore_2(
static_cast<ConfigOptionVectorBase *
>(old_values.get()), kept_variant_indice, old_start,
3750 old_variant_count, true);
3751 }
3752
3753
3754 if (old_variant_count != new_variant_count)
3755 {
3756 for (int i = index + 1; i < filament_count; i++ )
3757 {
3758 old_start_indice[i] += new_variant_count - old_variant_count;
3759 }
3760 }
3761
3762 if (!keep_project && diff_keys_size != different_keys_set.size()) {
3763
3764 different_keys.clear();
3765
3766 for (std::set<std::string>::iterator iter=different_keys_set.begin(); iter !=different_keys_set.end(); ++iter)
3767 different_keys.emplace_back(*iter);
3769 BOOST_LOG_TRIVIAL(info) << boost::format("filament %1% new different key size %2%, different_settings %3%")%filament_index %different_keys_set.size() %different_settings[filament_index];
3770 }
3771 }
3772
3773
3774 std::vector<const DynamicPrintConfig *> filament_configs(filament_count, nullptr);
3775 for (size_t index = 0; index < load_filaments_config.size(); index++)
3776 if (load_filaments_index[index] >= 1 && load_filaments_index[index] <= filament_count)
3777 filament_configs[load_filaments_index[index] - 1] = &load_filaments_config[index];
3778
3779
3780
3781 if (refresh_unlisted || std::find(load_filaments_refresh.begin(), load_filaments_refresh.end(), false) != load_filaments_refresh.end()) {
3782 if (std::find(filament_configs.begin(), filament_configs.end(), nullptr) == filament_configs.end())
3784 } else {
3785 const DynamicPrintConfig no_preset;
3786 std::replace(filament_configs.begin(), filament_configs.end(), static_cast<const DynamicPrintConfig *>(nullptr), &no_preset);
3787 DynamicPrintConfig dev_config;
3789 for (
const std::string &key : dev_config.
keys())
3790 if (project_keys.count(key) == 0)
3792 }
3793
3794 if (
m_print_config.option<ConfigOptionStrings>(
"filament_extruder_variant")) {
3796 int index_size =
m_print_config.option<ConfigOptionStrings>(
"filament_extruder_variant")->size();
3797 filament_self_indice.resize(index_size, 1);
3798 int k = 0;
3799 for (size_t i = 0; i < filament_count; i++) {
3800 for (size_t j = 0; j < new_variant_counts[i]; j++) {
3801 filament_self_indice[k++] = i + 1;
3802 }
3803 }
3804 }
3805 }
3806
3807
3808 ConfigOptionStrings *selected_filament_colors_option =
m_extra_config.option<ConfigOptionStrings>(
"filament_colour");
3809 ConfigOptionStrings *project_filament_colors_option =
m_print_config.option<ConfigOptionStrings>(
"filament_colour");
3810 if ((!project_filament_colors_option || (project_filament_colors_option->values.size() == 0)) && selected_filament_colors_option)
3811 {
3812 BOOST_LOG_TRIVIAL(info) << boost::format("initial project_filament_colors is null, create it due to filament_colour set in cli");
3813 project_filament_colors_option =
m_print_config.option<ConfigOptionStrings>(
"filament_colour",
true);
3814 std::vector<std::string>& project_filament_colors = project_filament_colors_option->values;
3815 project_filament_colors.resize(filament_count, "#FFFFFF");
3816 }
3817
3818 if (project_filament_colors_option &&
3819 (selected_filament_colors_option || !
m_print_config.option<
ConfigOptionFloats>(
"flush_volumes_matrix") || (current_extruder_count != new_extruder_count) || (new_nozzle_volume_type != current_nozzle_volume_type)))
3820 {
3821 std::vector<std::string> selected_filament_colors;
3822 if (selected_filament_colors_option) {
3823 selected_filament_colors = selected_filament_colors_option->
values;
3824
3826
3827 if (disable_wipe_tower_after_mapping) {
3828 std::set<std::string> filament_color_set;
3829 for (unsigned int color_index = 0; color_index <selected_filament_colors.size(); color_index++)
3830 {
3831 if (!selected_filament_colors[color_index].
empty()) {
3832 filament_color_set.emplace(selected_filament_colors[color_index]);
3833 BOOST_LOG_TRIVIAL(info) << boost::format("add color, index %1%, value %2% to set")%color_index %selected_filament_colors[color_index];
3834 }
3835 else
3836 BOOST_LOG_TRIVIAL(info) << boost::format("skip empty color %1%")%color_index;
3837 }
3838
3839 if (filament_color_set.size() > 1) {
3840 disable_wipe_tower_after_mapping = false;
3841 BOOST_LOG_TRIVIAL(info) << boost::format("different filament colours, switch disable_wipe_tower_after_mapping back to false");
3842 }
3843 else {
3844 BOOST_LOG_TRIVIAL(warning) << boost::format("only %1% filament colour, finally set disable_wipe_tower_after_mapping to true")%filament_color_set.size();
3845 }
3846
3847 }
3848 }
3849
3850 std::vector<std::string> &project_filament_colors = project_filament_colors_option->values;
3851 size_t project_filament_count = project_filament_colors.size();
3852 BOOST_LOG_TRIVIAL(info) << boost::format("select filament color from cli, size %1%")%selected_filament_colors.size();
3853 BOOST_LOG_TRIVIAL(info) << boost::format("project filament colors size %1%")%project_filament_colors.size();
3854 if (project_filament_count > 0)
3855 {
3856 for ( size_t index = 0; index < project_filament_count; index++ )
3857 {
3858 BOOST_LOG_TRIVIAL(info) << boost::format("project filament %1% original color %2%")%index %project_filament_colors[index];
3859 if (selected_filament_colors.size() > index)
3860 {
3861 if (!selected_filament_colors[index].
empty())
3862 {
3863 BOOST_LOG_TRIVIAL(info) << boost::format("changed to new color %1%")%selected_filament_colors[index];
3864 unsigned char ori_rgb_color[4] = {}, new_rgb_color[4] = {};
3867 if ((ori_rgb_color[0] != new_rgb_color[0]) || (ori_rgb_color[1] != new_rgb_color[1]) || (ori_rgb_color[2] != new_rgb_color[2]) || (ori_rgb_color[3] != new_rgb_color[3]))
3868 {
3869 BOOST_LOG_TRIVIAL(info) << boost::format("found color changes, need to regenerate thumbnail");
3870 filament_color_changed = true;
3871 }
3872 project_filament_colors[index] = selected_filament_colors[index];
3873 }
3874 }
3875 }
3876
3877
3879
3881
3882 if (filament_is_support->
size() != project_filament_count)
3883 {
3884 BOOST_LOG_TRIVIAL(error) << boost::format(
"filament_is_support's count %1% not equal to filament_colour's size %2%")%filament_is_support->
size() %project_filament_count;
3887 }
3888
3889 {
3890 std::ostringstream volumes_str;
3891 std::copy(min_flush_volumes.begin(), min_flush_volumes.end(), std::ostream_iterator<int>(volumes_str, ","));
3892 BOOST_LOG_TRIVIAL(info) << boost::format("extra_flush_volume: %1%") % volumes_str.str();
3893 BOOST_LOG_TRIVIAL(info) << boost::format(
"filament_is_support: %1%") % filament_is_support->
serialize();
3895 }
3896
3898 flush_vol_matrix.resize(project_filament_count * project_filament_count * new_extruder_count, 0.f);
3899
3900
3902 flush_multipliers.resize(new_extruder_count, 1.f);
3903
3904 std::vector<int> nozzle_flush_dataset(new_extruder_count, 0);
3905 {
3908 nozzle_flush_dataset_full.resize(new_printer_variant_count, 0);
3909 else
3910 nozzle_flush_dataset_full.resize(1, 0);
3911
3912 std::vector<int> extruders;
3915 else
3917
3918 std::vector<int> volume_types;
3921 else
3923
3926
3927 for (int eidx = 0; eidx < new_extruder_count; ++eidx) {
3928 int index = 0;
3931 nozzle_flush_dataset[eidx] = nozzle_flush_dataset_full[index];
3932 }
3933 }
3934
3935
3936
3938 if (!is_mixed_opt)
3940 auto is_mixed_slot = [is_mixed_opt](int idx) {
3941 return is_mixed_opt && idx < static_cast<int>(is_mixed_opt->
values.size()) && is_mixed_opt->
values[idx];
3942 };
3943
3944 for (size_t nozzle_id = 0; nozzle_id < new_extruder_count; ++nozzle_id) {
3946 for (int from_idx = 0; from_idx < project_filament_count; from_idx++) {
3947 const std::string &from_color = project_filament_colors[from_idx];
3948 unsigned char from_rgb[4] = {};
3950 bool is_from_support = filament_is_support->
get_at(from_idx);
3951 for (int to_idx = 0; to_idx < project_filament_count; to_idx++) {
3952 bool is_to_support = filament_is_support->
get_at(to_idx);
3953 if (from_idx == to_idx || is_mixed_slot(from_idx) || is_mixed_slot(to_idx)) {
3954 flush_vol_mtx[project_filament_count * from_idx + to_idx] = 0.f;
3955 } else {
3956 int flushing_volume = 0;
3957 if (is_to_support) {
3959 } else {
3960 const std::string &to_color = project_filament_colors[to_idx];
3961 unsigned char to_rgb[4] = {};
3963
3964 Slic3r::FlushVolCalculator calculator(min_flush_volumes[from_idx],
Slic3r::g_max_flush_volume,nozzle_flush_dataset[nozzle_id]);
3965 flushing_volume = calculator.calc_flush_vol(from_rgb[3], from_rgb[0], from_rgb[1], from_rgb[2],
to_rgb[3],
to_rgb[0],
to_rgb[1],
to_rgb[2]);
3967 }
3968
3969 flush_vol_mtx[project_filament_count * from_idx + to_idx] = flushing_volume;
3970 }
3971 }
3973 }
3974 }
3976 }
3977 else
3978 {
3979 BOOST_LOG_TRIVIAL(warning) << boost::format("filament colors count is 0 in projects");
3980 }
3981 }
3982 else
3983 {
3984 BOOST_LOG_TRIVIAL(warning) << boost::format("no filament colors found in projects");
3985 }
3986
3987
3990
3991
3992 BOOST_LOG_TRIVIAL(info) <<
"total " <<
m_models.size() <<
" models, "<<orients_requirement.size()<<
" objects"<<std::endl;
3994 {
3995 BOOST_LOG_TRIVIAL(info) << "merge all the models into one\n";
3996 Model m;
3999 for (ModelObject* o : model.
objects)
4000 {
4002
4003
4004
4005 }
4008 m_models.emplace_back(std::move(m));
4009 }
4010
4011
4012
4013 if ((machine_switch) && ((current_extruder_count != new_extruder_count) || (current_print_variant_count != new_printer_variant_count)))
4014 {
4015
4016 size_t num_objects =
m_models[0].objects.size();
4017 for (int i = 0; i < num_objects; ++i) {
4018 ModelObject*
object =
m_models[0].objects[i];
4019 DynamicPrintConfig object_config = object->config.get();
4020 if (!object_config.
empty()) {
4021
4022
4023
4024
4026 object->config.assign_config(std::move(object_config));
4027 }
4028 for (ModelVolume* v : object->
volumes) {
4030 DynamicPrintConfig volume_config = v->
config.
get();
4031 if (!volume_config.
empty()) {
4032
4033
4034
4035
4038 }
4039 }
4040 }
4041
4043 ModelConfig& layer_model_config = layer_config_it.second;
4044 DynamicPrintConfig layer_config = layer_model_config.
get();
4045 if (!layer_config.
empty()) {
4046
4047
4048
4049
4052 }
4053 }
4054 }
4055 }
4056
4057
4058 if ((custom_gcodes_map.size() > 0)&&(
m_models.size() > 0))
4059 {
4060 m_models[0].plates_custom_gcodes = custom_gcodes_map;
4061
4062
4063
4064
4065
4066
4067
4068 }
4069
4070 if (skip_modified_gcodes)
4071 {
4072 std::map<int, CustomGCode::Info>::iterator gcodes_iter;
4073 for (gcodes_iter =
m_models[0].plates_custom_gcodes.begin(); gcodes_iter !=
m_models[0].plates_custom_gcodes.end(); gcodes_iter++)
4074 {
4075 CustomGCode::Info &gcode_info = gcodes_iter->second;
4076 std::vector<CustomGCode::Item>::iterator item_iter = gcode_info.
gcodes.begin();
4077
4078 while ( item_iter != gcode_info.
gcodes.end() )
4079 {
4081 BOOST_LOG_TRIVIAL(warning) << boost::format("skip_modified_gcodes: remove custom gcodes %1% in plate %2%") %item_iter->extra %gcodes_iter->first;
4082 item_iter = gcode_info.
gcodes.erase(item_iter);
4083 }
4084 else
4085 item_iter++;
4086 }
4087 }
4088 }
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111 std::map<std::string, std::unique_ptr<ConfigOption>> cli_override_before;
4112 for (
const std::string &key :
m_config.keys()) {
4114 continue;
4116 cli_override_before[key].reset(loaded !=
nullptr ? loaded->
clone() :
nullptr);
4117 }
4118
4119
4120
4122
4123 if (!cli_override_before.empty()) {
4124 std::vector<std::string> &columns =
m_print_config.option<ConfigOptionStrings>(
"different_settings_to_system",
true)->values;
4125 auto owned_by = [](const std::vector<std::string> &options, const std::string &key) {
4126 return std::find(options.begin(), options.end(), key) != options.end();
4127 };
4128 auto add_to_column = [&columns](size_t index, const std::string &key) {
4129 std::vector<std::string> keys;
4131 if (std::find(keys.begin(), keys.end(), key) == keys.end()) {
4132 keys.push_back(key);
4134 }
4135 };
4136 auto same_value = [](const ConfigOption *a, const ConfigOption *b) {
4137 if (a == nullptr || b == nullptr)
4138 return false;
4139 const auto *va = dynamic_cast<const ConfigOptionVectorBase *>(a);
4140 const auto *vb = dynamic_cast<const ConfigOptionVectorBase *>(b);
4141 if (va == nullptr || vb == nullptr)
4142 return va == vb && a->
serialize() == b->serialize();
4143 const std::vector<std::string> ea = va->vserialize(), eb = vb->vserialize();
4144 if (ea.empty() || eb.empty())
4145 return ea.empty() && eb.empty();
4146 for (size_t i = 0; i < std::max(ea.size(), eb.size()); ++i)
4147 if (ea[i < ea.size() ? i : 0] != eb[i < eb.size() ? i : 0])
4148 return false;
4149 return true;
4150 };
4151
4152
4153
4154
4155 if (columns.size() >= 2) {
4156 for (const auto &[key, before] : cli_override_before) {
4158 continue;
4159 bool recorded = false;
4161 add_to_column(0, key);
4162 recorded = true;
4163 }
4165 for (size_t i = 1; i + 1 < columns.size(); ++i)
4166 add_to_column(i, key);
4167 recorded = true;
4168 }
4170 add_to_column(columns.size() - 1, key);
4171 recorded = true;
4172 }
4173 if (recorded)
4174 BOOST_LOG_TRIVIAL(info) << boost::format("CLI: override %1% recorded in different_settings_to_system") % key;
4175 }
4176 }
4177 }
4178
4180
4181
4182
4183
4185 const auto &is_mixed = is_mixed_opt->
values;
4186 for (size_t slot = static_cast<size_t>(std::max(filament_count, 0)); slot < is_mixed.size(); ++slot) {
4187 if (!is_mixed[slot])
4188 continue;
4189 BOOST_LOG_TRIVIAL(error) << boost::format("mixed filament slot %1% has no filament of its own, only %2% filaments are loaded; "
4190 "load one filament per slot, including each mixed one")
4191 % (slot + 1) % filament_count;
4194 }
4195 }
4196 if (filament_count > 0)
4198
4200
4202
4203 FullPrintConfig fff_print_config;
4204
4205
4206
4210
4211
4213 } else {
4214 boost::nowide::cerr << "invalid printer_technology " << std::endl;
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228 }
4229
4230 std::map<std::string, std::string> validity =
m_print_config.validate(
true);
4231 if (!validity.empty()) {
4232 boost::nowide::cerr << "Param values in 3mf/config error: "<< std::endl;
4233 for (std::map<std::string, std::string>::iterator it=validity.begin(); it!=validity.end(); ++it)
4234 boost::nowide::cerr << it->first <<": "<< it->second << std::endl;
4237 }
4238
4239 ConfigOptionBool* enable_wrapping_detection_option =
m_print_config.option<ConfigOptionBool>(
"enable_wrapping_detection",
true);
4240 BOOST_LOG_TRIVIAL(info) << boost::format(
"%1%, remove_wrapping_detect %2%, old value %3%")%__LINE__ %remove_wrapping_detect %enable_wrapping_detection_option->
value;
4241 if (is_bbl_3mf && remove_wrapping_detect) {
4242 enable_wrapping_detection_option->
value =
false;
4243 }
4244 enable_wrapping_detect = enable_wrapping_detection_option->
value;
4245 Pointfs current_wrapping_exclude_area =
m_print_config.opt<ConfigOptionPoints>(
"wrapping_exclude_area",
true)->values;
4246 if (disable_wipe_tower_after_mapping && enable_wrapping_detect && !current_wrapping_exclude_area.empty())
4247 {
4248 disable_wipe_tower_after_mapping = false;
4249 BOOST_LOG_TRIVIAL(info) << boost::format("%1%, set disable_wipe_tower_after_mapping back to false due to wrapping detect")%__LINE__;
4250 }
4251
4252
4253 const ConfigOptionBool* belt_printer_opt =
m_print_config.option<ConfigOptionBool>(
"belt_printer");
4254 const bool is_belt_printer = belt_printer_opt && belt_printer_opt->
value;
4255
4256 auto timelapse_type_opt =
m_print_config.option(
"timelapse_type");
4257 bool is_smooth_timelapse = false;
4259 is_smooth_timelapse = true;
4260
4261
4262 if (disable_wipe_tower_after_mapping) {
4265 disable_wipe_tower_after_mapping = false;
4266 BOOST_LOG_TRIVIAL(info) << boost::format("%1%, set disable_wipe_tower_after_mapping back to false due to a mixed filament")%__LINE__;
4267 }
4268 }
4269 if (disable_wipe_tower_after_mapping) {
4270 if (is_smooth_timelapse)
4271 {
4272 disable_wipe_tower_after_mapping = false;
4273 BOOST_LOG_TRIVIAL(warning) << boost::format("%1%: disable_wipe_tower_after_mapping: set back to false due to smooth timelapse!")%__LINE__;
4274 }
4275 else {
4276 ConfigOptionBool* enable_wipe_op =
m_print_config.option<ConfigOptionBool>(
"enable_prime_tower",
true);
4277 enable_wipe_op->
value =
false;
4278 BOOST_LOG_TRIVIAL(warning) << boost::format("%1%: disable_wipe_tower_after_mapping: disable prime tower for only one filament!")%__LINE__;
4279
4280 std::string diff_settings = different_settings[0];
4281
4282 if (diff_settings.empty())
4283 different_settings[0] = "enable_prime_tower";
4284 else {
4285 std::vector<std::string> different_keys;
4287 bool need_insert = true;
4288 for (int index = 0; index < different_keys.size(); index++) {
4289 if (different_keys[index] == "enable_prime_tower") {
4290 need_insert = false;
4291 break;
4292 }
4293 }
4294 if (need_insert)
4295 different_settings[0] = diff_settings + ";enable_prime_tower";
4296 }
4297 }
4298 }
4299
4300
4302
4305 std::vector<Pointfs> current_extruder_areas;
4306
4307 double print_height =
m_print_config.opt_float(
"printable_height");
4308 std::vector<double> current_extruder_print_heights;
4309 double height_to_lid =
m_print_config.opt_float(
"extruder_clearance_height_to_lid");
4310 double height_to_rod =
m_print_config.opt_float(
"extruder_clearance_height_to_rod");
4311 double clearance_radius =
m_print_config.opt_float(
"extruder_clearance_radius");
4314 int shared_printable_width = 0, shared_printable_depth = 0, shared_printable_height = 0, shared_center_x = 0, shared_center_y = 0;
4315
4316 std::string bed_texture;
4317
4318 if (
m_print_config.opt<ConfigOptionPointsGroups>(
"extruder_printable_area")) {
4319 current_extruder_areas =
m_print_config.opt<ConfigOptionPointsGroups>(
"extruder_printable_area")->values;
4320 }
4323 }
4324 {
4325 BoundingBoxf current_printable_bbox(current_printable_area);
4326 current_printable_width = static_cast<int>(current_printable_bbox.size().x());
4327 current_printable_depth = static_cast<int>(current_printable_bbox.size().y());
4328 }
4329 current_printable_height = print_height;
4330 if (old_printable_width == 0)
4331 old_printable_width = current_printable_width;
4332 if (old_printable_depth == 0)
4333 old_printable_depth = current_printable_depth;
4334 if (old_printable_height == 0)
4335 old_printable_height = current_printable_height;
4336 if ((current_extruder_areas.size() > 0) && (current_extruder_areas.size() == current_extruder_print_heights.size())) {
4337 BoundingBox current_bbox({0, 0}, {current_printable_width, current_printable_depth});
4338 int temp_height = current_printable_height;
4339
4340 for (unsigned int temp_index = 0; temp_index < current_extruder_areas.size(); temp_index++)
4341 {
4342 BoundingBox temp_bbox;
4343 Pointfs& temp_extruder_shape = current_extruder_areas[temp_index];
4344 for (unsigned int temp_index2 = 0; temp_index2 < temp_extruder_shape.size(); temp_index2++)
4345 temp_bbox.
merge({temp_extruder_shape[temp_index2].x(), temp_extruder_shape[temp_index2].y()});
4346
4347 if (current_bbox.min.x() < temp_bbox.
min.x())
4348 current_bbox.min.x() = temp_bbox.
min.x();
4349 if (current_bbox.min.y() < temp_bbox.
min.y())
4350 current_bbox.min.y() = temp_bbox.
min.y();
4351 if (current_bbox.max.x() > temp_bbox.
max.x())
4352 current_bbox.max.x() = temp_bbox.
max.x();
4353 if (current_bbox.max.y() > temp_bbox.
max.y())
4354 current_bbox.max.y() = temp_bbox.
max.y();
4355 if ((int)(current_extruder_print_heights[temp_index]) < temp_height)
4356 temp_height = current_extruder_print_heights[temp_index];
4357 }
4358 shared_printable_width = current_bbox.size().x();
4359 shared_printable_depth = current_bbox.size().y();
4360 shared_printable_height = temp_height;
4361 shared_center_x = current_bbox.center().x();
4362 shared_center_y = current_bbox.center().y();
4363
4364 BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: shared_printable_size {%2%, %3%, %4%}, shared_center {%5%, %6%}")
4365 %__LINE__ %shared_printable_width %shared_printable_depth %shared_printable_height %shared_center_x %shared_center_y;
4366 }
4367 if (is_bbl_3mf && (old_printable_width > 0) && (old_printable_depth > 0) && (old_printable_height > 0))
4368 {
4369
4370
4371 if ((old_printable_width > current_printable_width) || (old_printable_depth > current_printable_depth) || (old_printable_height > current_printable_height))
4372 {
4373 BOOST_LOG_TRIVIAL(error) << boost::format("old printable size {%1%, %2%, %3%} is larger than new printable size {%4%, %5%, %6%}, the object size should be limited")
4374 %old_printable_width %old_printable_depth %old_printable_height %current_printable_width %current_printable_depth %current_printable_height;
4375
4376
4377 shrink_to_new_bed = 2;
4378 }
4379 else if ((old_printable_width < current_printable_width) || (old_printable_depth < current_printable_depth))
4380 {
4381 BOOST_LOG_TRIVIAL(info) << boost::format("old printable size {%1%, %2%, %3%} is smaller than new printable size {%4%, %5%, %6%}, need to center the model")
4382 %old_printable_width %old_printable_depth %old_printable_height %current_printable_width %current_printable_depth %current_printable_height;
4383 shrink_to_new_bed = 1;
4384 }
4385 else {
4386 if ((current_exclude_area.size() > 0)&&(current_exclude_area != old_exclude_area)) {
4387 BOOST_LOG_TRIVIAL(info) << boost::format("old printable size {%1%, %2%, %3%}, new printable size {%4%, %5%, %6%}, exclude_area different, need to shrink")
4388 %old_printable_width %old_printable_depth %old_printable_height %current_printable_width %current_printable_depth %current_printable_height;
4389 shrink_to_new_bed = 2;
4390 }
4391 else {
4392 BOOST_LOG_TRIVIAL(info) << boost::format("old printable size {%1%, %2%, %3%}, new printable size {%4%, %5%, %6%}, extract the same, no need shrink")
4393 %old_printable_width %old_printable_depth %old_printable_height %current_printable_width %current_printable_depth %current_printable_height;
4394 }
4395 }
4396 }
4397
4399 {
4400 BOOST_LOG_TRIVIAL(info) << boost::format("translate_old %1%, shrink_to_new_bed %2%, old bed size {%3%, %4%, %5%}")%translate_old%shrink_to_new_bed %old_printable_width %old_printable_depth %old_printable_height;
4401 if (translate_old) {
4404 }
4405 else {
4406 partplate_list.reset_size(old_printable_width, old_printable_depth, old_printable_height, false);
4407 }
4408 partplate_list.set_shapes(
make_counter_clockwise(current_printable_area), current_exclude_area, current_wrapping_exclude_area, current_extruder_areas, current_extruder_print_heights, bed_texture,
4409 height_to_lid, height_to_rod);
4410
4411 }
4412
4413
4414 if (is_bbl_3mf && keep_old_params) {
4415 std::vector<std::string> different_keys;
4417 std::set<std::string> different_key_set(different_keys.begin(), different_keys.end());
4418 BOOST_LOG_TRIVIAL(info) << boost::format("%1%, process old params for support and wipe tower")%__LINE__;
4419
4420
4421 ConfigOptionEnum<WipeTowerWallType> *prime_tower_rib_wall_option =
m_print_config.option<ConfigOptionEnum<WipeTowerWallType>>(
"wipe_tower_wall_type",
true);
4423
4424 ConfigOptionPercent *prime_tower_infill_gap_option =
m_print_config.option<ConfigOptionPercent>(
"prime_tower_infill_gap",
true);
4425 prime_tower_infill_gap_option->
value = 100;
4426
4428 std::vector<int>& filament_adhesiveness_category_values = filament_adhesiveness_category_option->
values;
4429 filament_adhesiveness_category_values.resize(filament_count);
4430 for (int index = 0; index < filament_count; index++)
4431 filament_adhesiveness_category_values[index] = 100;
4432
4433
4434 ConfigOptionBool *enable_support_option =
m_print_config.option<ConfigOptionBool>(
"enable_support",
true);
4435 ConfigOptionEnum<SupportType>* support_type_option =
m_print_config.option<ConfigOptionEnum<SupportType>>(
"support_type",
true);
4436 ConfigOptionEnum<SupportMaterialStyle>* support_style_option =
m_print_config.option<ConfigOptionEnum<SupportMaterialStyle>>(
"support_style",
true);
4438 if (support_type_option->value ==
stTreeAuto)
4439 {
4440 if (different_key_set.find("support_type") == different_key_set.end())
4442 }
4443
4444
4445 size_t num_objects =
m_models[0].objects.size();
4446 for (int i = 0; i < num_objects; ++i) {
4447 ModelObject*
object =
m_models[0].objects[i];
4448 DynamicPrintConfig object_config = object->config.get();
4449 ConfigOptionBool *obj_enable_support_option = object_config.
option<ConfigOptionBool>(
"enable_support");
4450 if (enable_support_option->
value || (obj_enable_support_option && obj_enable_support_option->
value)) {
4451 ConfigOptionEnum<SupportType>* obj_support_type_option = object_config.
option<ConfigOptionEnum<SupportType>>(
"support_type");
4452 ConfigOptionEnum<SupportMaterialStyle>* obj_support_style_option = object_config.
option<ConfigOptionEnum<SupportMaterialStyle>>(
"support_style");
4454
4455 SupportType obj_support_type = obj_support_type_option? obj_support_type_option->
value: support_type_option->value;
4458 {
4459 float support_top_z_distance = obj_support_top_z_distance_option? obj_support_top_z_distance_option->
value: support_top_z_distance_option->
value;
4461 obj_support_style_option = object_config.
option<ConfigOptionEnum<SupportMaterialStyle>>(
"support_style",
true);
4463 }
4464 }
4465 }
4466 }
4467
4468
4471 travel_acceleration_option->
values = default_acceleration_option->values;
4472
4475 initial_layer_travel_acceleration_option->
values = initial_layer_acceleration_option->values;
4476 }
4477
4478 auto get_print_sequence = [](Slic3r::GUI::PartPlate* plate, DynamicPrintConfig& print_config, bool &is_seq_print) {
4481 auto seq_print = print_config.option<ConfigOptionEnum<PrintSequence>>("print_sequence");
4483 BOOST_LOG_TRIVIAL(info) << boost::format("plate print by object, set from global");
4484 is_seq_print = true;
4485 }
4486 }
4488 BOOST_LOG_TRIVIAL(info) << boost::format("plate print by object, set from plate self");
4489 is_seq_print = true;
4490 }
4491 };
4492
4493 auto check_plate_wipe_tower = [get_print_sequence, is_smooth_timelapse, is_belt_printer](Slic3r::GUI::PartPlate* plate,
int plate_index, DynamicPrintConfig& print_config,
plate_obj_size_info_t &plate_obj_size_info) {
4494 plate_obj_size_info.obj_bbox= plate->get_objects_bounding_box();
4495 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%, object bbox: min {%2%, %3%, %4%} - max {%5%, %6%, %7%}")
4496 %(plate_index+1) %plate_obj_size_info.obj_bbox.min.x() % plate_obj_size_info.obj_bbox.min.y() % plate_obj_size_info.obj_bbox.min.z() %plate_obj_size_info.obj_bbox.max.x() % plate_obj_size_info.obj_bbox.max.y() % plate_obj_size_info.obj_bbox.max.z();
4497 if (is_belt_printer || !print_config.has("wipe_tower_x")) {
4498 plate_obj_size_info.has_wipe_tower = false;
4499 BOOST_LOG_TRIVIAL(info) << boost::format("can not found wipe_tower_x in config, set to no wipe tower");
4500 return;
4501 }
4502
4503 int valid_count = plate->printable_instance_size();
4504 if (valid_count <= 0){
4505 plate_obj_size_info.has_wipe_tower = false;
4506 BOOST_LOG_TRIVIAL(info) << boost::format("no printable object found, set to no wipe tower");
4507 return;
4508 }
4509
4510 bool is_sequence = false;
4511 get_print_sequence(plate, print_config, is_sequence);
4512 if (is_sequence && valid_count > 1) {
4513 plate_obj_size_info.has_wipe_tower = false;
4514 BOOST_LOG_TRIVIAL(info) << boost::format("sequence print, valid_count=%1%, set to no wipe tower")%valid_count;
4515 return;
4516 }
4517
4518 std::vector<int> extruders = plate->get_extruders_under_cli(true, print_config);
4519 unsigned int filaments_cnt = extruders.size();
4520 if ((filaments_cnt <= 1) && !is_smooth_timelapse){
4521 plate_obj_size_info.has_wipe_tower = false;
4522 BOOST_LOG_TRIVIAL(info) << boost::format("filaments_cnt=%1%, set to no wipe tower")%filaments_cnt;
4523 return;
4524 }
4525
4528
4529
4530 if (
static_cast<size_t>(plate_index) >= wipe_x_option->
values.size() ||
static_cast<size_t>(plate_index) >= wipe_y_option->
values.size()) {
4531 BOOST_LOG_TRIVIAL(warning) << boost::format("plate %1%: wipe_tower_x/y only has %2%/%3% entries, reusing entry 0's position")
4532 %(plate_index+1) %wipe_x_option->
values.size() %wipe_y_option->
values.size();
4533 }
4534 plate_obj_size_info.wipe_x = wipe_x_option->
get_at(plate_index);
4535 plate_obj_size_info.wipe_y = wipe_y_option->
get_at(plate_index);
4536
4537
4538
4539 const WipeTowerFootprint footprint = plate->estimate_wipe_tower_footprint(print_config, filaments_cnt);
4540 float brim_width = float(footprint.
brim_width);
4541
4542 plate_obj_size_info.wipe_width = footprint.
width;
4543 plate_obj_size_info.wipe_depth = footprint.
depth;
4544
4545 Vec3d origin = plate->get_origin();
4546 Vec3d start(origin(0) + plate_obj_size_info.wipe_x - brim_width, origin(1) + plate_obj_size_info.wipe_y, 0.f);
4547 plate_obj_size_info.obj_bbox.merge(start);
4548 Vec3d end(origin(0) + plate_obj_size_info.wipe_x + plate_obj_size_info.wipe_width + brim_width, origin(1) + plate_obj_size_info.wipe_y + plate_obj_size_info.wipe_depth, 0.f);
4549 plate_obj_size_info.obj_bbox.merge(end);
4550 plate_obj_size_info.has_wipe_tower = true;
4551 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%, has wipe tower, wipe bbox: min {%2%, %3%, %4%} - max {%5%, %6%, %7%}")
4552 %(plate_index+1) %start.x() % start.y() % start.z() %
end.x() %
end.y() %
end.z();
4553 };
4554
4555 auto translate_models = [translate_old, shrink_to_new_bed, old_printable_width, old_printable_depth, old_printable_height, current_printable_width, current_printable_depth, current_printable_height, shared_center_x, shared_center_y, current_exclude_area, &plate_obj_size_infos] (Slic3r::GUI::PartPlateList& plate_list, DynamicPrintConfig& print_config) {
4556
4557 if (translate_old) {
4558
4559 int plate_count = plate_list.get_plate_count();
4560 for (int index = 1; index < plate_count; index ++) {
4561 Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)plate_list.get_plate(index);
4562
4564 Vec3d new_origin = plate_list.compute_origin_using_new_size(index, old_printable_width, old_printable_depth);
4565
4567 }
4568 BOOST_LOG_TRIVIAL(info) << boost::format("translate old 3mf, switch back to current bed size,{%1%, %2%, %3%}")%old_printable_width %old_printable_depth %old_printable_height;
4569 plate_list.reset_size(old_printable_width, old_printable_depth, old_printable_height, true, true);
4570 }
4571
4572 if (shrink_to_new_bed > 0)
4573 {
4574 int plate_count = plate_list.get_plate_count();
4577 if (print_config.has("wipe_tower_x")) {
4578 wipe_x_option =
dynamic_cast<ConfigOptionFloats *
>(print_config.option(
"wipe_tower_x"));
4579 wipe_y_option =
dynamic_cast<ConfigOptionFloats *
>(print_config.option(
"wipe_tower_y"));
4580 }
4581 double exclude_width = 0.f, exclude_depth = 0.f;
4582
4583 if (current_exclude_area.size() >= 4) {
4584 exclude_width = current_exclude_area[2].x() - current_exclude_area[0].x();
4585 exclude_depth = current_exclude_area[2].y() - current_exclude_area[0].y();
4586 }
4587 for (int index = 0; index < plate_count; index ++) {
4588 Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)plate_list.get_plate(index);
4590 Vec3d new_origin = plate_list.compute_origin_using_new_size(index, current_printable_width, current_printable_depth);
4592
4593
4594 if (shrink_to_new_bed == 1) {
4595 Vec3d cur_center_offset { ((double)old_printable_width)/2, ((
double)old_printable_depth)/2, 0}, new_center_offset { ((double)current_printable_width)/2, ((
double)current_printable_depth)/2, 0};
4596 Vec3d cur_center = cur_origin + cur_center_offset;
4597 Vec3d new_center = new_origin + new_center_offset;
4598
4599 offset = new_center - cur_center;
4600
4601 if (index == 0)
4603
4604 BOOST_LOG_TRIVIAL(info) << boost::format("shrink_to_new_bed 1, plate %1%, cur_origin: {%2%, %3%}, new_origin: {%4%, %5%}, cur_center {%6%, %7%} new_center {%8%, %9%}")
4605 %(index+1) %cur_origin(0) %cur_origin(1) %new_origin(0) %new_origin(1) %cur_center(0) %cur_center(1) %new_center(0) %new_center(1);
4606 }
4607 else {
4608
4609 Vec3d new_center_offset { ((double)current_printable_width + exclude_width)/2, ((
double)current_printable_depth + exclude_depth)/2, 0};
4610 BoundingBoxf3& bbox = plate_obj_size_infos[index].obj_bbox;
4612 if (shared_center_x != 0)
4613 new_center_offset(0) = (double)shared_center_x;
4614 else if (exclude_width > 0) {
4615 if (size.x() > (current_printable_width - exclude_width))
4616 new_center_offset(0) = ((double)current_printable_width)/2;
4617 }
4618 if (shared_center_y != 0)
4619 new_center_offset(1) = (double)shared_center_y;
4620 else if (exclude_depth > 0) {
4621 if (size.y() > (current_printable_depth - exclude_depth))
4622 new_center_offset(1) = ((double)current_printable_depth)/2;
4623 }
4624 Vec3d new_center = new_origin + new_center_offset;
4625
4627
4628 wipe_offset =
offset + cur_origin - new_origin;
4629 BOOST_LOG_TRIVIAL(info) << boost::format("shrink_to_new_bed 2, plate %1%, new_origin: {%2%, %3%}, new_center: {%4%, %5%}, obj bbox(including wipe tower) min {%6%, %7%} max {%8%, %9%}")
4630 %(index+1) %new_origin(0) %new_origin(1) %new_center(0) %new_center(1) %bbox.
min(0) %bbox.
min(1) %bbox.
max(0) %bbox.
max(1);
4631 }
4633 BOOST_LOG_TRIVIAL(info) << boost::format(
"shrink_to_new_bed %1%, plate %2% translate offset: {%3%, %4%} wipe_offset {%5%, %6%}") %shrink_to_new_bed %(index+1) %
offset[0] %
offset[1] %wipe_offset[0] %wipe_offset[1];
4635
4636 if (wipe_x_option) {
4637 BOOST_LOG_TRIVIAL(info) << boost::format(
"shrink_to_new_bed %4%, plate %1%: wipe tower src: {%2%, %3%}")%(index+1) %wipe_x_option->
get_at(index) %wipe_y_option->
get_at(index)%shrink_to_new_bed;
4640
4641 wipe_x_option->
set_at(&wipe_tower_x, index, 0);
4643 BOOST_LOG_TRIVIAL(info) << boost::format(
"shrink_to_new_bed %4%, plate %1% wipe tower changes to: {%2%, %3%}")%(index+1) %wipe_x_option->
get_at(index) %wipe_y_option->
get_at(index) %shrink_to_new_bed;
4644 }
4645
4646
4647 }
4648 BOOST_LOG_TRIVIAL(info) << boost::format("shrink_to_new_bed, shrink all the models to current bed size,{%1%, %2%, %3%}")%current_printable_width %current_printable_depth %current_printable_height;
4649 plate_list.reset_size(current_printable_width, current_printable_depth, current_printable_height, true, true);
4650 }
4651 };
4652 if (plate_data_src.size() > 0)
4653 {
4654 partplate_list.load_from_3mf_structure(plate_data_src);
4655
4656 int plate_count = partplate_list.get_plate_count();
4658 for (int index = 0; index < plate_count; index ++) {
4659 Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)partplate_list.get_plate(index);
4660
4661 check_plate_wipe_tower(cur_plate, index,
m_print_config, plate_obj_size_infos[index]);
4662 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%, has_wipe_tower %2%, wipe_x %3%, wipe_y %4%, width %5%, depth %6%")
4663 %(index+1) %plate_obj_size_infos[index].has_wipe_tower %plate_obj_size_infos[index].wipe_x %plate_obj_size_infos[index].wipe_y %plate_obj_size_infos[index].wipe_width %plate_obj_size_infos[index].wipe_depth;
4664 }
4665
4667 }
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677 std::vector<printer_plate_info_t> downward_check_printers;
4678 std::vector<bool> downward_check_status;
4679 if (downward_check) {
4680 bool use_default = false;
4681 std::string default_path;
4682 if (downward_settings.size() == 0) {
4683
4684 std::string cli_config_file =
resources_dir() +
"/profiles/BBL/cli_config.json";
4686 use_default = true;
4687 default_path =
resources_dir() +
"/profiles/BBL/machine_full/";
4688 }
4689 for (auto const &file : downward_settings) {
4690 DynamicPrintConfig config;
4691 std::string config_type, config_name, filament_id, config_from, downward_printer;
4692 std::string file_path = use_default?(default_path+file+".json"):file;
4693 int ret = load_config_file(file_path, config, config_type, config_name, filament_id, config_from);
4694 if (ret) {
4697 }
4698 if ((config_type != "machine") || (config_from != "system")) {
4699 BOOST_LOG_TRIVIAL(info) << boost::format("found invalid config type %1% or from %2% in file %3% when downward_check")%config_type %config_from %file_path;
4702
4703 }
4704 BOOST_LOG_TRIVIAL(info) << boost::format("downward_check: loaded machine config %1%, from %2%")%config_name %file_path ;
4705
4707 Pointfs temp_printable_area, temp_exclude_area, temp_wrapping_area;
4708 std::vector<Pointfs> temp_extruder_areas;
4709 std::vector<double> temp_extruder_print_heights;
4710
4712
4713 temp_printable_area = config.
option<ConfigOptionPoints>(
"printable_area",
true)->values;
4715 temp_wrapping_area = config.
option<ConfigOptionPoints>(
"wrapping_exclude_area",
true)->values;
4716 temp_extruder_areas = config.
option<ConfigOptionPointsGroups>(
"extruder_printable_area",
true)->values;
4718
4719 if (temp_printable_area.size() >= 4) {
4720 BoundingBoxf temp_printable_bbox(temp_printable_area);
4721 printer_plate.
printable_width =
static_cast<int>(temp_printable_bbox.size().x());
4722 printer_plate.
printable_depth =
static_cast<int>(temp_printable_bbox.size().y());
4725 }
4726 if (temp_exclude_area.size() >= 4) {
4727 printer_plate.
exclude_width = (int)(temp_exclude_area[2].x() - temp_exclude_area[0].x());
4728 printer_plate.
exclude_depth = (int)(temp_exclude_area[2].y() - temp_exclude_area[0].y());
4729 printer_plate.
exclude_x = (int)temp_exclude_area[0].x();
4730 printer_plate.
exclude_y = (int)temp_exclude_area[0].y();
4731 }
4732 if (temp_wrapping_area.size() >= 4) {
4733 printer_plate.
wrapping_width = (int)(temp_wrapping_area[2].x() - temp_wrapping_area[0].x());
4734 printer_plate.
wrapping_depth = (int)(temp_wrapping_area[2].y() - temp_wrapping_area[0].y());
4735 printer_plate.
wrapping_x = (int)temp_wrapping_area[0].x();
4736 printer_plate.
wrapping_y = (int)temp_wrapping_area[0].y();
4737 }
4738 if ((temp_extruder_areas.size() > 0) && (temp_extruder_print_heights.size() == temp_extruder_areas.size())) {
4741
4742 for (unsigned int temp_index = 0; temp_index < temp_extruder_areas.size(); temp_index++)
4743 {
4744 BoundingBox temp_bbox;
4745 Pointfs& temp_extruder_shape = temp_extruder_areas[temp_index];
4746 for (unsigned int temp_index2 = 0; temp_index2 < temp_extruder_shape.size(); temp_index2++)
4747 temp_bbox.
merge({temp_extruder_shape[temp_index2].x(), temp_extruder_shape[temp_index2].y()});
4748
4749 if (current_bbox.min.x() < temp_bbox.
min.x())
4750 current_bbox.min.x() = temp_bbox.
min.x();
4751 if (current_bbox.min.y() < temp_bbox.
min.y())
4752 current_bbox.min.y() = temp_bbox.
min.y();
4753 if (current_bbox.max.x() > temp_bbox.
max.x())
4754 current_bbox.max.x() = temp_bbox.
max.x();
4755 if (current_bbox.max.y() > temp_bbox.
max.y())
4756 current_bbox.max.y() = temp_bbox.
max.y();
4757 if (temp_extruder_height > temp_extruder_print_heights[temp_index])
4758 temp_extruder_height = temp_extruder_print_heights[temp_index];
4759 }
4763
4764 BOOST_LOG_TRIVIAL(info) << boost::format("downward_check: for multi-extruder printer, change printable size to bbox {%1%, %2%, 0} - {%3%, %4%, %5%}")
4765 %current_bbox.min.x() %current_bbox.min.y() %current_bbox.max.x() %current_bbox.max.y() %temp_extruder_height;
4766 }
4767 BOOST_LOG_TRIVIAL(info) << boost::format("downward_check: printable size{%1%,%2%, %3%}, exclude area{%4%, %5%: %6% x %7%}, wrapping area{%8%, %9%: %10% x %11%}, enable_wrapping_detect %12%")
4771
4772 downward_check_printers.push_back(std::move(printer_plate));
4773 }
4774 }
4775
4776 int downward_check_size = downward_check_printers.size();
4777 if (downward_check_size > 0)
4778 {
4779 downward_check_status.resize(downward_check_size, false);
4780 int plate_count = partplate_list.get_plate_count();
4781 int failed_count = 0;
4782 for (int index = 0; index < plate_count; index ++)
4783 {
4784 if (failed_count == downward_check_size) {
4785 BOOST_LOG_TRIVIAL(info) << boost::format("downward_check: all failed, size %1%")%downward_check_size;
4786 break;
4787 }
4788 Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)partplate_list.get_plate(index);
4789 Vec3d size = plate_obj_size_infos[index].obj_bbox.size();
4790
4791 for (int index2 = 0; index2 < downward_check_size; index2 ++)
4792 {
4793 if (failed_count == downward_check_size) {
4794 break;
4795 }
4796 if (downward_check_status[index2])
4797 continue;
4800 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%, downward_check index %2%, name %3%, bbox {%4%, %5%, %6%} exceeds printer size {%7%, %8%, %9%}")
4803 downward_check_status[index2] = true;
4804 failed_count ++;
4805 continue;
4806 }
4810 if ((size.x() > real_width) && (size.y() > real_depth)) {
4811 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%, downward_check index %2%, name %3%, bbox {%4%, %5%} exceeds real size without exclude_area {%6%, %7%}")
4813 %size.x() % size.y() %real_width %real_depth;
4814 downward_check_status[index2] = true;
4815 failed_count ++;
4816 continue;
4817 }
4818 }
4820
4822 if ( size.y() > real_depth) {
4823 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%, downward_check index %2%, name %3%, bbox {%4%, %5%} exceeds real size without wrapping_area {%6%, %7%}")
4826 downward_check_status[index2] = true;
4827 failed_count ++;
4828 continue;
4829 }
4830 }
4831 }
4832 }
4833 if (failed_count < downward_check_size)
4834 {
4835
4836 BOOST_LOG_TRIVIAL(info) << boost::format("downward_check: downward_check_size %1%, failed_count %2%")%downward_check_size %failed_count;
4837 for (int index2 = 0; index2 < downward_check_size; index2 ++)
4838 {
4839 if (downward_check_status[index2])
4840 continue;
4842 BOOST_LOG_TRIVIAL(info) << boost::format(
"downward_check: found compatible printer %1%")%plate_info.
printer_name;
4843 downward_compatible_machines.push_back(plate_info.
printer_name);
4844 }
4846 }
4847 }
4848
4849
4850 bool user_center_specified = false;
4852 ArrangeParams arrange_cfg;
4853
4854 BOOST_LOG_TRIVIAL(info) <<
"will start transforms, commands count " <<
m_transforms.size() <<
"\n";
4855#if defined(__linux__) || defined(__LINUX__)
4856 if (g_cli_callback_mgr.is_started()) {
4857 PrintBase::SlicingStatus slicing_status{2, "Loading files finished"};
4858 cli_status_callback(slicing_status);
4859 }
4860#endif
4861
4863 BOOST_LOG_TRIVIAL(info) << "process transform " << opt_key << "\n";
4864 if (opt_key == "assemble") {
4865 if (clone_objects.size() > 0) {
4866 BOOST_LOG_TRIVIAL(error) << "Invalid params: can not set assemble and clone_objects together." << std::endl;
4869 }
4871 boost::nowide::cerr << "Invalid params: --assemble needs at least one input model." << std::endl;
4874 }
4875 Model m;
4877 new_object->
name =
_u8L(
"Assembly");
4879 int idx = 0;
4881 for (ModelObject* o : model.
objects) {
4882 for (
auto volume : o->
volumes) {
4883 ModelVolume* new_volume = new_object->
add_volume(*volume);
4884
4886 }
4887 }
4889 m_models.emplace_back(std::move(m));
4890 }
4891 else if (opt_key == "repetitions") {
4892 int repetitions_count =
m_config.option<ConfigOptionInt>(
"repetitions")->value;
4893 if (repetitions_count <= 1)
4894 {
4895 BOOST_LOG_TRIVIAL(info) << "invalid repetitions value " << repetitions_count << ", just skip\n";
4896 }
4897 else {
4898 if (plate_to_slice == 0) {
4899 BOOST_LOG_TRIVIAL(error) << "Invalid params: can not set repetitions when slice all." << std::endl;
4902 }
4903 else if (plate_to_slice > partplate_list.get_plate_count()) {
4904 BOOST_LOG_TRIVIAL(error) << boost::format("Invalid params:invalid plate %1% to slice, total %2%")%plate_to_slice %partplate_list.get_plate_count();
4907 }
4908
4909 BOOST_LOG_TRIVIAL(info) << "repetitions value " << repetitions_count << std::endl;
4910
4911 duplicate_count = repetitions_count - 1;
4912 }
4913 }
4914 else if (opt_key == "convert_unit") {
4917 BOOST_LOG_TRIVIAL(info) << "convert from meter to millimeter\n";
4919 }
4921 BOOST_LOG_TRIVIAL(info) << "convert from inch to millimeter\n";
4923 }
4924 }
4925 }
4926 else if (opt_key == "orient") {
4927
4928 int orient_option =
m_config.option<ConfigOptionInt>(
"orient")->value;
4929
4930 if (orient_option == 0)
4931 {
4932
4934 for (ModelObject* o : model.
objects)
4935 {
4936 orients_requirement.insert(std::pair<size_t, bool>(o->
id().
id,
false));
4937 BOOST_LOG_TRIVIAL(info) <<
"object "<<o->
name <<
", id :" << o->
id().
id <<
", no need to orient when setting orient to 0\n";
4938 }
4939 }
4940 else if (orient_option == 1)
4941 {
4942
4943
4945 for (ModelObject* o : model.
objects)
4946 {
4947 orients_requirement.insert(std::pair<size_t, bool>(o->
id().
id,
true));
4948 BOOST_LOG_TRIVIAL(info) <<
"object "<<o->
name <<
", id :" << o->
id().
id <<
", need to orient when setting orient to 1\n";
4949 }
4950 }
4951 else
4952 {
4953
4954 }
4955 BOOST_LOG_TRIVIAL(info) << boost::format("orient_option %1%")%orient_option;
4956 }
4957 else if (opt_key == "copy") {
4959 const bool all_objects_have_instances = std::none_of(
4961 [](ModelObject* o){ return o->instances.empty(); }
4962 );
4963
4964 int dups =
m_config.opt_int(
"copy");
4966
4967 try {
4968 if (dups > 1) {
4969
4970 duplicate(model,
size_t(dups), beds, arrange_cfg);
4971 } else {
4973 }
4974 } catch (std::exception &ex) {
4975 boost::nowide::cerr << "error: " << ex.what() << std::endl;
4978 }
4979 }
4980 } else if (opt_key == "center") {
4981 user_center_specified = true;
4984
4986
4987
4988
4989 BoundingBoxf3 bbox;
4990 for (ModelObject *model_object : model.
objects)
4991
4993 for (ModelObject *model_object : model.
objects)
4994 for (ModelInstance *model_instance : model_object->
instances)
4996 }
4997 } else if (opt_key == "align_xy") {
4998 const Vec2d &p =
m_config.option<ConfigOptionPoint>(
"align_xy")->value;
5001
5003 }
5004 } else if (opt_key == "arrange") {
5005
5006 int arrange_option =
m_config.option<ConfigOptionInt>(
"arrange")->value;
5007
5008 if (arrange_option == 0)
5009 {
5010 need_arrange = false;
5011 }
5012 else if (arrange_option == 1)
5013 {
5014 need_arrange = true;
5015 }
5016 else
5017 {
5018
5019 }
5020 } else if (opt_key == "ensure_on_bed") {
5021
5022 } else if (opt_key == "rotate") {
5025
5027 } else if (opt_key == "rotate_x") {
5030
5032 } else if (opt_key == "rotate_y") {
5035
5037 } else if (opt_key == "ground_largest_face" || opt_key == "ground_face_normal" || opt_key == "ground_face_point") {
5038
5039
5040
5041 std::function<int(
const std::vector<LayOnFacePlane>&,
const Transform3d&)> pick;
5042 if (opt_key == "ground_largest_face") {
5045 } else {
5046
5047 const std::string& value =
m_config.opt_string(opt_key);
5049 int consumed = 0;
5050 if (sscanf(value.c_str(), "%lf,%lf,%lf%n", &v.x(), &v.y(), &v.z(), &consumed) != 3 || consumed != int(value.size()) ||
5051 !v.allFinite() || (opt_key ==
"ground_face_normal" && v.norm() <
EPSILON)) {
5052 BOOST_LOG_TRIVIAL(error) << boost::format("Invalid params: %1% expects three comma-separated numbers, got \"%2%\"") % opt_key % value;
5055 }
5056 if (opt_key == "ground_face_normal")
5058 else
5059 pick = [v](
const std::vector<LayOnFacePlane>& planes,
const Transform3d& inst_matrix) {
5061 };
5062 }
5063 if (pick) {
5064 size_t laid = 0, missed = 0;
5067 for (ModelObject* o : model.
objects)
5068 for (
size_t i = 0; i < o->
instances.size(); ++i) {
5071 if (planes.empty()) {
5072
5073 BOOST_LOG_TRIVIAL(warning) << boost::format(
"%1%: object %2% has no face large enough to lay on, left as it is") % opt_key % o->
name;
5074 continue;
5075 }
5076 const int idx = pick(planes, inst_matrix);
5077 if (idx < 0) {
5078
5079 BOOST_LOG_TRIVIAL(warning) << boost::format(
"%1%: no face of object %2% contains the point, left as it is") % opt_key % o->
name;
5080 ++missed;
5081 continue;
5082 }
5083 BOOST_LOG_TRIVIAL(info) << boost::format("%1%: object %2% instance %3% laid on the %4% mm2 face with normal %5%")
5084 % opt_key % o->
name % i % planes[idx].area % planes[idx].normal.transpose();
5086 ++laid;
5087 }
5088 }
5089 if (laid == 0 && missed > 0) {
5090 BOOST_LOG_TRIVIAL(error) << boost::format("Invalid params: %1%: no face of any object contains the point") % opt_key;
5093 }
5094 }
5095 } else if (opt_key == "scale") {
5096 float ratio =
m_config.opt_float(opt_key);
5097 if (ratio <= 0.f) {
5098 BOOST_LOG_TRIVIAL(error) << boost::format("Invalid params:invalid scale ratio %1%")%ratio;
5101 }
5104
5106 } else if (opt_key == "scale_to_fit") {
5107 const Vec3d &opt =
m_config.opt<ConfigOptionPoint3>(opt_key)->value;
5108 if (opt.x() <= 0 || opt.y() <= 0 || opt.z() <= 0) {
5109 boost::nowide::cerr << "--scale-to-fit requires a positive volume" << std::endl;
5112 }
5115
5117 } else if (opt_key == "cut" || opt_key == "cut_x" || opt_key == "cut_y") {
5118 boost::nowide::cerr << "Cut operation is not supported yet" << std::endl;
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164 }
5165#if 0
5166 else if (opt_key == "cut_grid") {
5167 std::vector<Model> new_models;
5169 TriangleMesh mesh = model.
mesh();
5170 mesh.repair();
5171
5172 std::vector<TriangleMesh> meshes = mesh.cut_by_grid(
m_config.option<ConfigOptionPoint>(
"cut_grid")->value);
5173 size_t i = 0;
5174 for (TriangleMesh* m : meshes) {
5175 Model out;
5179 delete m;
5180 }
5181 }
5182
5183
5185
5188 }
5189#endif
5190 else if (opt_key == "split") {
5192 size_t num_objects = model.
objects.size();
5193 for (size_t i = 0; i < num_objects; ++ i) {
5195 model.
objects.front()->split(&new_objects,
false);
5197 }
5198 }
5199 } else if (opt_key == "repair") {
5202 for (ModelObject *
object : model.
objects) {
5203 for (ModelVolume *volume : object->
volumes) {
5204 MeshRepairStats stats;
5205 std::string error;
5206 if (!volume->
repair(
true, &stats, &error))
5207 BOOST_LOG_TRIVIAL(warning) <<
"repair of " <<
object->name <<
" / " << volume->
name <<
" failed: " << error;
5209 BOOST_LOG_TRIVIAL(info) <<
"repaired " <<
object->name <<
" / " << volume->
name;
5210 }
5211 object->invalidate_bounding_box();
5212 }
5213 } else {
5214 boost::nowide::cerr << "error: option not implemented yet: " << opt_key << std::endl;
5217 }
5218 }
5219
5220 BOOST_LOG_TRIVIAL(info) << "finished model pre-process commands\n";
5221 bool oriented_or_arranged = false;
5222 bool arranged_without_rotations = false;
5223
5225 {
5226 for (ModelObject* o : model.
objects)
5227 {
5228 if (orients_requirement[o->
id().
id])
5229 {
5230 BOOST_LOG_TRIVIAL(info) <<
"Before process command, Orient object, name=" << o->
name <<
",id="<<o->
id().
id<<std::endl;
5232 oriented_or_arranged = true;
5233 }
5234 else
5235 {
5236 BOOST_LOG_TRIVIAL(debug) <<
"Before process command, no need to orient, object id :" << o->
id().
id<<std::endl;
5237 }
5238 }
5239 }
5240
5241 orients_requirement.clear();
5242
5243 bool is_seq_print_for_curr_plate = false;
5244 if ((plate_to_slice < 0) || (plate_to_slice > partplate_list.get_plate_count()))
5245 {
5246 BOOST_LOG_TRIVIAL(error) << boost::format("invalid plate id %1%, total %2%")%plate_to_slice %partplate_list.get_plate_count();
5249 }
5250 else if (plate_to_slice > 0){
5251 Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)partplate_list.get_plate(plate_to_slice-1);
5253
5255 auto seq_print =
m_print_config.option<ConfigOptionEnum<PrintSequence>>(
"print_sequence");
5257 BOOST_LOG_TRIVIAL(info) << boost::format("Check whether need to arrange by print_sequence: plate %1% print by object, set from global")%plate_to_slice;
5258 is_seq_print_for_curr_plate = true;
5259 }
5260 }
5262 BOOST_LOG_TRIVIAL(info) << boost::format("Check whether need to arrange by print_sequence: plate %1% print by object, set from plate self")%plate_to_slice;
5263 is_seq_print_for_curr_plate = true;
5264 }
5265
5266 if (duplicate_count > 0) {
5267 const ConfigOptionBool* spiral_vase =
m_print_config.option<ConfigOptionBool>(
"spiral_mode");
5268 if ((spiral_vase !=
nullptr) && spiral_vase->
value)
5269 {
5270
5271 if (!is_seq_print_for_curr_plate) {
5272 BOOST_LOG_TRIVIAL(warning) << boost::format("Spiral mode can not be duplicated under by-object print, skip duplicate");
5273 duplicate_count = 0;
5274 }
5275 }
5276 }
5277
5278 if (duplicate_count > 0)
5279 need_arrange = true;
5280 }
5281
5282 if ((!need_arrange) && is_bbl_3mf && !shrink_to_new_bed && (plate_to_slice > 0))
5283 {
5284 if (((old_height_to_rod != 0.f) && (old_height_to_rod != height_to_rod))
5285 || ((old_height_to_lid != 0.f) && (old_height_to_lid != height_to_lid))
5286 || ((old_max_radius != 0.f) && (old_max_radius != clearance_radius)))
5287 {
5288 if (is_seq_print_for_curr_plate) {
5289 need_arrange = true;
5290 BOOST_LOG_TRIVIAL(info) << boost::format("old_height_to_rod %1%, old_height_to_lid %2%, old_max_radius %3%, current height_to_rod %4%, height_to_lid %5%, clearance_radius %6%, need arrange!")
5291 %old_height_to_rod %old_height_to_lid %old_max_radius %height_to_rod %height_to_lid %clearance_radius;
5292 }
5293 }
5294 }
5295
5296 oriented_or_arranged |= need_arrange;
5297
5298 BOOST_LOG_TRIVIAL(info) << boost::format("before arrange, need_arrange=%1%, duplicate_count %2%, filament_color_changed %3%")%need_arrange %duplicate_count %filament_color_changed;
5299 if (need_arrange || filament_color_changed)
5300 {
5301 for (int index = 0; index < partplate_list.get_plate_count(); index ++)
5302 {
5303 if ((plate_to_slice != 0) && (plate_to_slice != (index + 1))) {
5304 continue;
5305 }
5306
5307 if (plate_data_src.size() > index) {
5308 if (!plate_data_src[index]->thumbnail_file.empty()) {
5309 BOOST_LOG_TRIVIAL(info) << boost::format("Plate %1%: clear loaded thumbnail %2%.")%(index+1)%plate_data_src[index]->thumbnail_file;
5310 plate_data_src[index]->thumbnail_file.clear();
5311 }
5312 if (!plate_data_src[index]->no_light_thumbnail_file.empty()) {
5313 BOOST_LOG_TRIVIAL(info) << boost::format("Plate %1%: clear loaded no_light_thumbnail %2%.")%(index+1)%plate_data_src[index]->no_light_thumbnail_file;
5314 plate_data_src[index]->no_light_thumbnail_file.clear();
5315 }
5316 if (!plate_data_src[index]->top_file.empty()) {
5317 BOOST_LOG_TRIVIAL(info) << boost::format("Plate %1%: clear loaded top_thumbnail %2%.")%(index+1)%plate_data_src[index]->top_file;
5318 plate_data_src[index]->top_file.clear();
5319 }
5320 if (!plate_data_src[index]->pick_file.empty()) {
5321 BOOST_LOG_TRIVIAL(info) << boost::format("Plate %1%: clear loaded pick_thumbnail %2%.")%(index+1)%plate_data_src[index]->pick_file;
5322 plate_data_src[index]->pick_file.clear();
5323 }
5324 }
5325 }
5326 }
5327
5328 if (!assemble_plate_info_list.empty())
5329 {
5330
5331 int plate_count = assemble_plate_info_list.size();
5332 if (plate_count != partplate_list.get_plate_count())
5333 {
5334 BOOST_LOG_TRIVIAL(error) << boost::format("mismatch plate count, to_assemble %1%, generated %2%") % plate_count % partplate_list.get_plate_count();
5337 }
5338
5339 for (size_t i = 0; i < plate_count; i++)
5340 {
5341 Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate*)partplate_list.get_plate(i);
5342
5343 if (!assemble_plate_info_list[i].need_arrange)
5344 cur_plate->
lock(
true);
5345 }
5346
5347 for (size_t i = 0; i < plate_count; i++)
5348 {
5350 Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate*)partplate_list.get_plate(i);
5351 BOOST_LOG_TRIVIAL(info) << boost::format(
"plate %1%, need arrange %2%, filaments_count %3%") % (i+1) % assemble_plate.
need_arrange % assemble_plate.
filaments_count;
5352 if (assemble_plate.need_arrange)
5353 {
5354
5357 arrange_cfg = ArrangeParams();
5359
5360
5361 partplate_list.lock_plate(i, false);
5362 partplate_list.select_plate(i);
5363 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% set to selected") % i;
5364 size_t plate_obj_count = assemble_plate.loaded_obj_list.size();
5365 for (size_t oidx = 0; oidx < plate_obj_count; ++oidx)
5366 {
5367 ModelObject* mo = assemble_plate.loaded_obj_list[oidx];
5368
5369 for (
size_t inst_idx = 0; inst_idx < mo->
instances.size(); ++inst_idx)
5370 {
5371 ModelInstance* minst = mo->
instances[inst_idx];
5373 ap.
itemid = selected.size();
5374 selected.emplace_back(std::move(ap));
5375 BOOST_LOG_TRIVIAL(debug) << boost::format(
"plate %1%: add object %2% object index %3%, into selected") % (i+1) % ap.
name %(oidx+1);
5376 }
5377 }
5378
5379 if (!is_belt_printer && ((!arrange_cfg.
is_seq_print && (assemble_plate.filaments_count > 1)) || (enable_wrapping_detect && !current_wrapping_exclude_area.empty())))
5380 {
5381
5382 int plate_count = partplate_list.get_plate_count();
5383
5384 auto printer_structure_opt =
m_print_config.option<ConfigOptionEnum<PrinterStructure>>(
"printer_structure");
5385
5386
5388 if (tower_brim_width < 0.f) tower_brim_width = 8.f;
5390
5391
5397 }
5398 if (x < tower_margin) {
5399 x = tower_margin;
5400 }
5401 if (y < tower_margin) {
5402 y = tower_margin;
5403 }
5404
5405
5411 ConfigOptionEnum<WipeTowerWallType> *prime_tower_rib_wall_option =
m_print_config.option<ConfigOptionEnum<WipeTowerWallType>>(
"wipe_tower_wall_type",
true);
5412
5413 BOOST_LOG_TRIVIAL(info) << boost::format("prime_tower_width %1% wipe_tower_rotation_angle %2% prime_volume %3%, rib_wall %4%") % width_option->value % rotation_angle_option->value % volume_option->value %prime_tower_rib_wall_option->value;
5414
5417
5418 wipe_x_option->
set_at(&wt_x_opt, i, 0);
5419 wipe_y_option->set_at(&wt_y_opt, i, 0);
5420
5421 Vec3d wipe_tower_size, wipe_tower_pos;
5423
5424
5425 wt_x_opt.value = wipe_tower_pos(0);
5426 wt_y_opt.value = wipe_tower_pos(1);
5427 BOOST_LOG_TRIVIAL(info) << boost::format("%1%, after estimate_wipe_tower_polygon pos {%2%, %3%}, size {%4%, %5%}")%__LINE__ % wipe_tower_pos(0) % wipe_tower_pos(1) % wipe_tower_size(0) %wipe_tower_size(1);
5428
5429 wipe_x_option->
set_at(&wt_x_opt, i, 0);
5430 wipe_y_option->set_at(&wt_y_opt, i, 0);
5431
5433 unselected.emplace_back(wipe_tower_ap);
5434 }
5435
5436
5437 partplate_list.preprocess_exclude_areas(unselected,
m_print_config, enable_wrapping_detect, i + 1);
5438 if (avoid_extrusion_cali_region)
5439 partplate_list.preprocess_nonprefered_areas(unselected, i + 1);
5440
5441
5455 }
5456 if (align_to_y_axis.has_value()) {
5458 }
else if (
auto printer_structure_opt =
m_print_config.option<ConfigOptionEnum<PrinterStructure>>(
"printer_structure")) {
5460 }
5461
5466
5468
5469 partplate_list.preprocess_exclude_areas(
5471
5472 {
5473 BOOST_LOG_TRIVIAL(debug) << "arrange bedpts:" << beds[0].transpose() << ", " << beds[1].transpose() << ", " << beds[2].transpose() << ", " << beds[3].transpose();
5474 BOOST_LOG_TRIVIAL(info) <<
"Arrange full params: " << arrange_cfg.
to_json();
5475 BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items selected before arranging: %1%") % selected.size();
5476 for (auto item : selected)
5477 BOOST_LOG_TRIVIAL(
trace) << item.name <<
", extruder: " << item.extrude_ids.back() <<
", bed: " << item.bed_idx
5478 << ", trans: " << item.translation.transpose();
5479 BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items unselected before arranging: %1%") % unselected.size();
5480 for (auto item : unselected)
5481 BOOST_LOG_TRIVIAL(
trace) << item.name <<
", bed: " << item.bed_idx <<
", trans: " << item.translation.transpose();
5482 }
5483 arrange_cfg.
progressind = [](
unsigned st, std::string str =
"") {
5484
5485 };
5486
5487
5488 BOOST_LOG_TRIVIAL(info) << boost::format("start plate %1%'s arranging...") % (i + 1);
5490
5492 BOOST_LOG_TRIVIAL(info) << boost::format("finished plate %1%'s arranging") % (i + 1);
5493
5494
5495 partplate_list.clear(false, false, true, i);
5496
5497 for (ArrangePolygon& ap : selected) {
5498 partplate_list.postprocess_bed_index_for_current_plate(ap);
5500 {
5501 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(
":arrange failed: ap.name %1% ap.bed_idx %2%, plate index %3%") % ap.
name % ap.
bed_idx % i;
5504 }
5505 }
5506
5507
5508 for (ArrangePolygon& ap : selected) {
5509
5510 partplate_list.postprocess_arrange_polygon(ap, true);
5511
5513 }
5514
5515 cur_plate->
lock(
true);
5516 }
5517 else {
5518 size_t plate_obj_count = assemble_plate.loaded_obj_list.size();
5520
5521 for (size_t oidx = 0; oidx < plate_obj_count; ++oidx)
5522 {
5523 ModelObject* mo = assemble_plate.loaded_obj_list[oidx];
5524
5526
5527 BOOST_LOG_TRIVIAL(debug) << boost::format(
"plate %1%: no arrange, directly translate object %2% by {%3%, %4%}") % (i+1) % mo->
name %plate_origin(0) %plate_origin(1);
5528 }
5529
5530 bool is_seq_print = false;
5532
5533 if (!is_belt_printer && !is_seq_print && (assemble_plate.filaments_count > 1) && !has_wipe_tower_position)
5534 {
5535
5536 auto printer_structure_opt =
m_print_config.option<ConfigOptionEnum<PrinterStructure>>(
"printer_structure");
5537
5543 }
5546 }
5549 }
5550
5551
5556
5557 wipe_x_option->
set_at(&wt_x_opt, i, 0);
5558 wipe_y_option->set_at(&wt_y_opt, i, 0);
5559 }
5560 }
5561 }
5562
5563 for (size_t i = 0; i < plate_count; i++)
5564 {
5565
5566 Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate*)partplate_list.get_plate(i);
5567 cur_plate->
lock(
false);
5568 }
5569
5570 partplate_list.reload_all_objects(false, -1);
5571 }
5572 else if (need_arrange)
5573 {
5575
5576
5578 {
5580 Model original_model;
5581 std::set<std::pair<int, int>> backup_set;
5582 bool finished_arrange = false, first_run = true;
5583 Slic3r::GUI::PartPlate* cur_plate = nullptr;
5584 int low_duplicate_count = 0, up_duplicate_count = duplicate_count, arrange_count = 0;
5585 float orig_wipe_x = 0.f, orig_wipe_y = 0.f;
5586
5587 if (duplicate_count > 0) {
5588 original_model = model;
5589 }
5590
5591 while(!finished_arrange)
5592 {
5593 arrange_cfg = ArrangeParams();
5594 arrange_count++;
5595
5596 if (duplicate_count > 0)
5597 {
5598
5599 if (!first_run) {
5600 BOOST_LOG_TRIVIAL(info) << boost::format("restore model object and plate, new duplicate_count %1%, arrange_count=%2%")%duplicate_count%arrange_count;
5604 model = original_model;
5605 partplate_list.load_from_3mf_structure(plate_data_src);
5606
5607 selected.clear();
5608 unselected.clear();
5609 unprintable.clear();
5610 locked_aps.clear();
5611 }
5612 else {
5613 first_run = false;
5614 if (plate_to_slice > 0) {
5617
5618 if (wipe_x_option && (wipe_x_option->
size() > (plate_to_slice-1))) {
5619 orig_wipe_x = wipe_x_option->
get_at(plate_to_slice-1);
5620 BOOST_LOG_TRIVIAL(info) << boost::format("%1%, plate_to_slice %2%, orig_wipe_x=%3%")%__LINE__%plate_to_slice%orig_wipe_x;
5621 }
5622 if (wipe_y_option && (wipe_y_option->size() > (plate_to_slice-1))) {
5623 orig_wipe_y = wipe_y_option->get_at(plate_to_slice-1);
5624 BOOST_LOG_TRIVIAL(info) << boost::format("%1%, plate_to_slice %2%, orig_wipe_y=%3%")%__LINE__%plate_to_slice%orig_wipe_y;
5625 }
5626 }
5627 }
5628
5629 cur_plate = (Slic3r::GUI::PartPlate *)partplate_list.get_plate(plate_to_slice-1);
5631 }
5632 else if (plate_to_slice > 0)
5633 {
5634 cur_plate = (Slic3r::GUI::PartPlate *)partplate_list.get_plate(plate_to_slice-1);
5635 }
5636
5637 if (cur_plate) {
5639 }
5640
5641
5642 if ((duplicate_count == 0) && (plate_to_slice == 0))
5643 {
5644
5645 for (
size_t oidx = 0; oidx < model.
objects.size(); ++oidx)
5646 {
5647 ModelObject* mo = model.
objects[oidx];
5648 for (
size_t inst_idx = 0; inst_idx < mo->
instances.size(); ++inst_idx)
5649 {
5650 ModelInstance* minst = mo->
instances[inst_idx];
5652
5653
5654
5655 bool locked = partplate_list.preprocess_arrange_polygon(oidx, inst_idx, ap, true);
5656 if (!locked)
5657 {
5658 ap.
itemid = selected.size();
5660 selected.emplace_back(ap);
5661 else
5662 unprintable.emplace_back(ap);
5663 }
5664 else
5665 {
5666
5667 ap.
itemid = locked_aps.size();
5668 locked_aps.emplace_back(ap);
5669 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": skip locked instance, obj_id %1%, instance_id %2%") % oidx % inst_idx;
5670 }
5671 }
5672 }
5673
5677 }
5678
5679
5680 partplate_list.preprocess_exclude_areas(unselected,
m_print_config, enable_wrapping_detect);
5681
5682
5683
5684 const int plate_count = partplate_list.get_plate_count();
5685 const bool from_project = used_filament_set.empty();
5686 std::vector<int> plate_filament_counts(plate_count, static_cast<int>(used_filament_set.size()));
5687 if (from_project)
5688 for (int plate_index = 0; plate_index < plate_count; ++plate_index)
5689 plate_filament_counts[plate_index] =
static_cast<int>(partplate_list.get_plate(plate_index)->get_extruders_under_cli(
true,
m_print_config).size());
5690
5691
5692 const bool project_tower_allowed =
m_print_config.option<ConfigOptionBool>(
"enable_prime_tower",
true)->value &&
5694 const auto plate_needs_wipe_tower = [from_project, project_tower_allowed, is_smooth_timelapse](int filament_count) {
5695 if (!from_project)
5696 return filament_count > 0;
5697 return project_tower_allowed && (filament_count > 1 || (filament_count > 0 && is_smooth_timelapse));
5698 };
5699 const int max_filament_count = plate_count > 0 ? *std::max_element(plate_filament_counts.begin(), plate_filament_counts.end()) : 0;
5700
5701 if (!is_belt_printer && plate_needs_wipe_tower(max_filament_count))
5702 {
5703
5704 auto printer_structure_opt =
m_print_config.option<ConfigOptionEnum<PrinterStructure>>(
"printer_structure");
5705
5706
5708 if (tower_brim_width < 0.f) tower_brim_width = 8.f;
5710
5716 }
5717
5718 if (x < tower_margin) {
5719 x = tower_margin;
5720 }
5721 if (y < tower_margin) {
5722 y = tower_margin;
5723 }
5726
5727
5733
5734 BOOST_LOG_TRIVIAL(info) << boost::format("prime_tower_width %1% wipe_tower_rotation_angle %2% prime_volume %3%")%width_option->value %rotation_angle_option->value %volume_option->value ;
5735
5736
5738 int plate_index_valid = std::min(bedid, plate_count - 1);
5739
5740 const int extruder_size = bedid < plate_count ? plate_filament_counts[bedid] : max_filament_count;
5741 if (!plate_needs_wipe_tower(extruder_size))
5742 continue;
5743 if (bedid < plate_count && !from_project) {
5744 wipe_x_option->
set_at(&wt_x_opt, plate_index_valid, 0);
5745 wipe_y_option->set_at(&wt_y_opt, plate_index_valid, 0);
5746 }
5747
5748 Vec3d wipe_tower_size, wipe_tower_pos;
5749 ArrangePolygon wipe_tower_ap = partplate_list.get_plate(plate_index_valid)->estimate_wipe_tower_polygon(
m_print_config, plate_index_valid, wipe_tower_pos, wipe_tower_size, extruder_size,
true);
5750
5751
5752 if (bedid < plate_count) {
5753 wt_x_opt.value = wipe_tower_pos(0);
5754 wt_y_opt.value = wipe_tower_pos(1);
5755
5756 wipe_x_option->
set_at(&wt_x_opt, plate_index_valid, 0);
5757 wipe_y_option->set_at(&wt_y_opt, plate_index_valid, 0);
5758
5759 BOOST_LOG_TRIVIAL(info) << boost::format("%1%, after estimate_wipe_tower_polygon, pos {%2%, %3%}, size {%4%, %5%}, plate %6%")%__LINE__ % wipe_tower_pos(0) % wipe_tower_pos(1) % wipe_tower_size(0) %wipe_tower_size(1) %bedid;
5760 }
5761
5762 wipe_tower_ap.
bed_idx = bedid;
5763 unselected.emplace_back(wipe_tower_ap);
5764 }
5765 }
5766 }
5767 else {
5768
5769 partplate_list.lock_plate(plate_to_slice - 1, false);
5770 partplate_list.select_plate(plate_to_slice-1);
5771 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% set to selected")%plate_to_slice;
5772
5773 for (
size_t oidx = 0; oidx < model.
objects.size(); ++oidx)
5774 {
5775 ModelObject* mo = model.
objects[oidx];
5776
5777 for (
size_t inst_idx = 0; inst_idx < mo->
instances.size(); ++inst_idx)
5778 {
5779 ModelInstance* minst = mo->
instances[inst_idx];
5782
5784 (in_plate ? selected : unselected) :
5785 unprintable;
5786 bool locked = partplate_list.preprocess_arrange_polygon_other_locked(oidx, inst_idx, ap, in_plate);
5787 BOOST_LOG_TRIVIAL(info) << boost::format(
"name %4% in_plate %1% printable %2%, locked %3%")%in_plate %mo->
instances[inst_idx]->printable %locked % ap.
name ;
5788 if (!locked)
5789 {
5791 cont.emplace_back(std::move(ap));
5792 }
5793 else
5794 {
5795
5796 ap.
itemid = locked_aps.size();
5797 locked_aps.emplace_back(std::move(ap));
5798 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(
"arrange: skip locked instance, obj_id %1%, name %2%") % oidx % mo->
name;
5799 }
5800 }
5801 }
5802 if ((duplicate_count > 0)&&(selected.size() == (duplicate_count + 1)))
5803 {
5804 duplicate_single_object = true;
5805 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": found single object mode");
5806 }
5807
5808 if (!is_belt_printer &&
m_print_config.has(
"wipe_tower_x") && (is_smooth_timelapse || !arrange_cfg.
is_seq_print || (selected.size() <= 1))) {
5809 float x;
5810 float y;
5811 if (duplicate_count > 0) {
5812 auto printer_structure_opt =
m_print_config.option<ConfigOptionEnum<PrinterStructure>>(
"printer_structure");
5818 }
5819 }
5820 else {
5821
5824 }
5828 unsigned int filaments_cnt = (plate_data_src.size() >= static_cast<size_t>(plate_to_slice)) ? plate_data_src[plate_to_slice-1]->slice_filaments_info.size() : 0;
5829 if ((filaments_cnt == 0) || need_skip)
5830 {
5831
5833 filaments_cnt = extruders.size();
5834 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("arrange: slice filaments info invalid or need_skip, get from partplate: filament_count %1%")%filaments_cnt;
5835 }
5836
5837 if ((filaments_cnt <= 1) && !is_smooth_timelapse && (!enable_wrapping_detect || current_wrapping_exclude_area.empty()))
5838 {
5839 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("arrange: not a multi-color object anymore, drop the wipe tower before arrange.");
5840 }
5841 else
5842 {
5844 ConfigOption* layer_height_opt =
m_print_config.option(
"layer_height");
5845 if (layer_height_opt)
5847
5848
5849
5853 int plate_width, plate_depth;
5854 double plate_height;
5855 partplate_list.get_plate_size(plate_width, plate_depth, plate_height);
5856 float depth = wipe_tower_size(1);
5857
5858 float margin = 15.f, wp_brim_width = float(footprint.
brim_width);
5859 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("arrange wipe_tower: wp_brim_width %1%")%wp_brim_width;
5860 w = wipe_tower_size(0);
5861
5862 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("arrange wipe_tower: x=%1%, y=%2%, width=%3%, depth=%4%, angle=%5%, prime_volume=%6%, filaments_cnt=%7%, layer_height=%8%, plate_width=%9%, plate_depth=%10%")
5863 %x %y %w %depth %a %v %filaments_cnt %
layer_height %plate_width %plate_depth;
5864 if ((y + depth + margin + wp_brim_width) > (float)plate_depth) {
5865 y = (float)plate_depth - depth - margin - wp_brim_width;
5866 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("arrange wipe_tower: exceeds the border, change y to %1%, plate_depth=%2%")%y %plate_depth;
5867 }
5868
5869 if ((x + w + margin + wp_brim_width) > (float)plate_width) {
5870 x = (float)plate_width - w - margin - wp_brim_width;
5871 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("arrange wipe_tower: exceeds the border, change x to %1%, plate_width=%2%")%y %plate_width;
5872 }
5873 if (x < margin) {
5874 x = margin;
5875 }
5876 if (y < margin) {
5877 y = margin;
5878 }
5879
5884
5885 wipe_x_option->
set_at(&wt_x_opt, plate_to_slice-1, 0);
5886 wipe_y_option->set_at(&wt_y_opt, plate_to_slice-1, 0);
5887
5889
5891 {
scaled(x - wp_brim_width),
scaled(y - wp_brim_width)},
5892 {
scaled(x + w + wp_brim_width),
scaled(y - wp_brim_width)},
5893 {
scaled(x + w + wp_brim_width),
scaled(y + depth + wp_brim_width)},
5894 {
scaled(x - wp_brim_width),
scaled(y + depth + wp_brim_width)}
5895 });
5897 wipe_tower_ap.
setter = NULL;
5898
5902 wipe_tower_ap.
name =
"WipeTower";
5906 unselected.emplace_back(std::move(wipe_tower_ap));
5907 }
5908 }
5909
5910
5911 partplate_list.preprocess_exclude_areas(
5912 unselected,
m_print_config, enable_wrapping_detect, plate_to_slice);
5913 }
5914
5915
5916
5930 }
5931 if (align_to_y_axis.has_value()) {
5933 }
else if (
auto printer_structure_opt =
m_print_config.option<ConfigOptionEnum<PrinterStructure>>(
"printer_structure")) {
5935 }
5936
5941
5943
5944 partplate_list.preprocess_exclude_areas(
5946
5947 {
5948 BOOST_LOG_TRIVIAL(debug) << "arrange bedpts:" << beds[0].transpose() << ", " << beds[1].transpose() << ", " << beds[2].transpose() << ", " << beds[3].transpose();
5949 BOOST_LOG_TRIVIAL(info)<<
"Arrange full params: "<< arrange_cfg.
to_json();
5950 BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items selected before arranging: %1%")%selected.size();
5951 for (auto item : selected)
5952 BOOST_LOG_TRIVIAL(
trace) << item.name <<
", extruder: " << item.extrude_ids.back() <<
", bed: " << item.bed_idx
5953 << ", trans: " << item.translation.transpose();
5954 BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items unselected before arranging: %1%") % unselected.size();
5955 for (auto item : unselected)
5956 BOOST_LOG_TRIVIAL(
trace) << item.name <<
", bed: " << item.bed_idx <<
", trans: " << item.translation.transpose();
5957 }
5958 arrange_cfg.
progressind= [](
unsigned st, std::string str =
"") {
5959
5960 };
5961
5962
5963 BOOST_LOG_TRIVIAL(info) << boost::format("start %1% th arranging...")%arrange_count;
5967 BOOST_LOG_TRIVIAL(info) << boost::format("finished %1% th arranging...")%arrange_count;
5968
5969
5970 int bed_idx_max = 0;
5971 if (duplicate_count == 0)
5972 {
5973 if (plate_to_slice > 0)
5974 {
5975
5976 partplate_list.clear(false, false, true, plate_to_slice-1);
5977
5978 for (ArrangePolygon& ap : selected) {
5979 partplate_list.postprocess_bed_index_for_current_plate(ap);
5980 if (ap.
bed_idx != (plate_to_slice-1))
5981 {
5982 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(
":arrange failed: ap.name %1% ap.bed_idx %2%, plate index %3%")% ap.
name % ap.
bed_idx % (plate_to_slice-1);
5985 }
5986 bed_idx_max = std::max(ap.
bed_idx, bed_idx_max);
5987 }
5988 }
5989 else
5990 {
5991
5992 partplate_list.clear();
5993
5994
5995 for (ArrangePolygon &ap : selected) {
5996
5997 partplate_list.postprocess_bed_index_for_selected(ap);
5998
5999 bed_idx_max = std::max(ap.
bed_idx, bed_idx_max);
6001 }
6002 }
6003 for (ArrangePolygon &ap : locked_aps) {
6004 bed_idx_max = std::max(ap.
bed_idx, bed_idx_max);
6005
6006 partplate_list.postprocess_arrange_polygon(ap, false);
6007
6009 }
6010
6011
6012 for (ArrangePolygon &ap : selected) {
6013
6014 partplate_list.postprocess_arrange_polygon(ap, true);
6015
6017 }
6018
6019
6020 for (ArrangePolygon& ap : unselected)
6021 {
6023 continue;
6024
6025
6026 partplate_list.postprocess_arrange_polygon(ap, false);
6027
6029 }
6030
6031
6032
6033 for (ArrangePolygon& ap : unprintable)
6034 {
6036 partplate_list.postprocess_arrange_polygon(ap, true);
6037
6040 }
6041
6042
6043 if (plate_to_slice > 0)
6044 partplate_list.rebuild_plates_after_arrangement(false, true, plate_to_slice-1);
6045 else
6046 partplate_list.rebuild_plates_after_arrangement();
6047 }
6048 else {
6049
6050 partplate_list.clear(false, false, true, plate_to_slice-1);
6051
6052
6053 bool failed_this_time = false;
6054 for (ArrangePolygon& ap : selected) {
6055 partplate_list.postprocess_bed_index_for_current_plate(ap);
6056 if (ap.
bed_idx != (plate_to_slice-1))
6057 {
6058
6059 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(
":arrange failed: ap.name %1% ap.bed_idx %2%, plate index %3%")% ap.
name % ap.
bed_idx % (plate_to_slice-1);
6060 if (!duplicate_single_object)
6061 {
6062 BOOST_LOG_TRIVIAL(warning) << boost::format("arrange failed when duplicate multiple objects at count %1%, low_duplicate_count %2%, up_duplicate_count %3%")%duplicate_count %low_duplicate_count %up_duplicate_count;
6063
6064 if (duplicate_count == 1)
6065 {
6066 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": failed even on duplicate 1 copy, just print one original model");
6067 duplicate_count = 0;
6068 }
6069 else
6070 {
6071 if (duplicate_count == low_duplicate_count)
6072 {
6073 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": previous success, but currently failed count %1%!!!")%duplicate_count;
6074 up_duplicate_count = duplicate_count;
6075 low_duplicate_count --;
6076 duplicate_count --;
6077 }
6078 else {
6079 up_duplicate_count = duplicate_count;
6080 duplicate_count = (up_duplicate_count + low_duplicate_count)/2;
6081 }
6082 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": try new count %1%, low_duplicate_count %2%, up_duplicate_count %3%")%duplicate_count %low_duplicate_count %up_duplicate_count;
6083 }
6084
6085
6086 failed_this_time = true;
6087 break;
6088 }
6089 }
6090 else {
6091 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(
":arrange success: ap.name %1% ap.bed_idx %2%, plate index %3%")% ap.
name % ap.
bed_idx % (plate_to_slice-1);
6092 real_duplicate_count ++;
6093 }
6094
6095 bed_idx_max = std::max(ap.
bed_idx, bed_idx_max);
6097 }
6098
6099 if (failed_this_time) {
6100 if (duplicate_count == 0)
6101 {
6102
6103 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": restore to the original model and plates, orig_wipe_x %1%, orig_wipe_y %2%")%orig_wipe_x %orig_wipe_y;
6104 finished_arrange = true;
6105 model = original_model;
6106 partplate_list.load_from_3mf_structure(plate_data_src);
6107 partplate_list.reset_size(current_printable_width, current_printable_depth, current_printable_height, true, true);
6108 if ((orig_wipe_x > 0.f) && (orig_wipe_y > 0.f))
6109 {
6114
6115 wipe_x_option->
set_at(&wt_x_opt, plate_to_slice-1, 0);
6116 wipe_y_option->set_at(&wt_y_opt, plate_to_slice-1, 0);
6117 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": restore wipe_tower position to {%1%, %2%}")%orig_wipe_x %orig_wipe_y;
6118 }
6119 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": exit arrange process");
6120 }
6121 continue;
6122 }
6123
6124 if (duplicate_single_object)
6125 {
6126 if (real_duplicate_count <= 1) {
6127 BOOST_LOG_TRIVIAL(warning) << boost::format("no object can be placed under single object mode, restore to the original model and plates also, orig_wipe_x %1%, orig_wipe_y %2%")%orig_wipe_x %orig_wipe_y;
6128
6129
6130 finished_arrange = true;
6131 model = original_model;
6132 partplate_list.load_from_3mf_structure(plate_data_src);
6133 partplate_list.reset_size(current_printable_width, current_printable_depth, current_printable_height, true, true);
6134 duplicate_count = 0;
6135 if ((orig_wipe_x > 0.f) && (orig_wipe_y > 0.f))
6136 {
6141
6142 wipe_x_option->
set_at(&wt_x_opt, plate_to_slice-1, 0);
6143 wipe_y_option->set_at(&wt_y_opt, plate_to_slice-1, 0);
6144 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": restore wipe_tower position to {%1%, %2%}")%orig_wipe_x %orig_wipe_y;
6145 }
6146 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": exit arrange process");
6147 continue;
6148 }
6149 duplicate_count = real_duplicate_count - 1;
6150 }
6151 else {
6152
6153 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": multiple objects mode, arrange success on count %1%, low_duplicate_count %2%, up_duplicate_count %3%")%duplicate_count %low_duplicate_count %up_duplicate_count;
6154 if ((duplicate_count == up_duplicate_count) || (duplicate_count == (up_duplicate_count - 1)))
6155 {
6156 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": found the max arrangeable count %1%")%duplicate_count;
6157 }
6158 else {
6159 low_duplicate_count = duplicate_count;
6160 duplicate_count = (up_duplicate_count + low_duplicate_count)/2;
6161 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": try new count %1%, low_duplicate_count %2%, up_duplicate_count %3%")%duplicate_count %low_duplicate_count %up_duplicate_count;
6162 continue;
6163 }
6164 }
6165
6166
6167 for (ArrangePolygon& ap : unselected)
6168 {
6170 continue;
6171
6172 bed_idx_max = std::max(ap.
bed_idx, bed_idx_max);
6174 }
6175
6176 for (ArrangePolygon& ap : locked_aps)
6177 {
6178 bed_idx_max = std::max(ap.
bed_idx, bed_idx_max);
6179
6180 partplate_list.postprocess_arrange_polygon(ap, false);
6181
6183 }
6184
6185
6186 for (ArrangePolygon& ap : selected) {
6187
6188 partplate_list.postprocess_arrange_polygon(ap, true);
6189
6191 }
6192
6193
6194 for (ArrangePolygon& ap : unselected)
6195 {
6197 continue;
6198
6199
6200 partplate_list.postprocess_arrange_polygon(ap, false);
6201
6203 }
6204
6205
6206
6207 for (ArrangePolygon& ap : unprintable)
6208 {
6210 partplate_list.postprocess_arrange_polygon(ap, true);
6211
6214 }
6215
6216 partplate_list.rebuild_plates_after_arrangement(false, true, plate_to_slice-1);
6217 }
6218 finished_arrange = true;
6219 }
6222 }
6223 }
6224
6225
6226
6227
6228 if (
m_config.opt_bool(
"ensure_on_bed"))
6229 {
6230 BOOST_LOG_TRIVIAL(info) << "ensure_on_bed: need to ensure each object on beds";
6234 }
6235
6236
6237 bool export_to_3mf = false, load_slicedata = false, export_slicedata = false, export_slicedata_error = false;
6238 bool no_check = false;
6239 std::string export_3mf_file, load_slice_data_dir, export_slice_data_dir, export_stls_dir;
6240 std::vector<ThumbnailData*> calibration_thumbnails;
6241 std::vector<int> plate_object_count(partplate_list.get_plate_count(), 0);
6242 int max_slicing_time_per_plate = 0, max_triangle_count_per_plate = 0, sliced_plate = -1;
6243 std::vector<bool> plate_has_skips(partplate_list.get_plate_count(), false);
6244 std::vector<std::vector<size_t>> plate_skipped_objects(partplate_list.get_plate_count());
6245
6247 sliced_info.
prepare_time = (size_t) (global_current_time - global_begin_time);
6248 global_begin_time = global_current_time;
6249
6251 if (opt_key == "help") {
6253 } else if (opt_key == "help_fff") {
6255 } else if (opt_key == "help_sla") {
6257 } else if (opt_key == "pipe") {
6258
6259 } else if (opt_key == "load_slicedata") {
6260 load_slicedata = true;
6261 load_slice_data_dir =
m_config.opt_string(opt_key);
6262 if (export_slicedata) {
6263 BOOST_LOG_TRIVIAL(error) << "should not set load_slicedata and export_slicedata together." << std::endl;
6266 }
6267 else if (duplicate_count > 0)
6268 {
6269 BOOST_LOG_TRIVIAL(error) << "should not set load_slicedata when set repetitions." << std::endl;
6272 }
6273 else if (shrink_to_new_bed > 0)
6274 {
6275 BOOST_LOG_TRIVIAL(warning) << "use load_slicedata when shrink_to_new_bed." << std::endl;
6276
6277
6278 }
6279 } else if (opt_key == "export_settings") {
6280
6281
6282
6283 const std::string &settings_file =
m_config.opt_string(opt_key);
6284 if (settings_file == "-")
6285 m_print_config.save_to_json(boost::nowide::cout,
"project_settings",
"project", SoftFever_VERSION,
true);
6286 else
6287 m_print_config.save_to_json(settings_file, std::string(
"project_settings"), std::string(
"project"), std::string(SoftFever_VERSION));
6288 } else if (opt_key == "info") {
6289
6293 }
6294 } else if (opt_key == "inspect_mesh") {
6295
6296
6300 }
6301 boost::nowide::cout.flush();
6302
6303
6304
6305#if defined(__linux__) || defined(__LINUX__)
6306 if (g_cli_callback_mgr.is_started()) {
6307 PrintBase::SlicingStatus slicing_status{100, "All done, Success"};
6308 cli_status_callback(slicing_status);
6309 }
6310 g_cli_callback_mgr.stop();
6311#endif
6315 boost::nowide::cerr.flush();
6317 } else if (opt_key == "inspect_paint") {
6318
6319
6320
6324 }
6325 boost::nowide::cout.flush();
6326
6327
6328
6329#if defined(__linux__) || defined(__LINUX__)
6330 if (g_cli_callback_mgr.is_started()) {
6331 PrintBase::SlicingStatus slicing_status{100, "All done, Success"};
6332 cli_status_callback(slicing_status);
6333 }
6334 g_cli_callback_mgr.stop();
6335#endif
6339 boost::nowide::cerr.flush();
6341 } else if (opt_key == "uptodate") {
6342
6343 } else if (opt_key == "min_save") {
6344
6345 } else if (opt_key == "load_defaultfila") {
6346
6347 } else if (opt_key == "mtcpp") {
6348 max_triangle_count_per_plate =
m_config.option<ConfigOptionInt>(
"mtcpp")->value;
6349 } else if (opt_key == "mstpp") {
6350 max_slicing_time_per_plate =
m_config.option<ConfigOptionInt>(
"mstpp")->value;
6351 } else if (opt_key == "export_stl") {
6357 }
6358 } else if (opt_key == "export_stls") {
6359 export_stls_dir =
m_config.opt_string(opt_key);
6365 }
6366 } else if (opt_key == "export_obj") {
6372 }
6373 }
6374
6375
6376else if (opt_key == "export_3mf") {
6377 export_to_3mf = true;
6378 export_3mf_file =
m_config.opt_string(opt_key);
6379 }else if(opt_key=="no_check"){
6380 no_check =
m_config.opt_bool(opt_key);
6381 }else if(opt_key=="strict"){
6382
6383
6384 } else if (opt_key == "normative_check") {
6385
6386 } else if (opt_key == "export_slicedata") {
6387 export_slicedata = true;
6388 export_slice_data_dir =
m_config.opt_string(opt_key);
6389 if (load_slicedata) {
6390 BOOST_LOG_TRIVIAL(error) << "should not set load_slicedata and export_slicedata together." << std::endl;
6393 }
6394 } else if (opt_key == "slice") {
6395
6396 plate_to_slice =
m_config.option<ConfigOptionInt>(
"slice")->value;
6397 sliced_plate = plate_to_slice;
6398 bool pre_check = (plate_to_slice == 0)?true:false;
6399 bool finished = false;
6400
6401
6402
6403
6404
6405
6406
6407
6408
6409
6410 BOOST_LOG_TRIVIAL(info) << "Need to slice for plate "<<plate_to_slice <<", total plate count "<<partplate_list.get_plate_count()<<" partplates!" << std::endl;
6411#if defined(__linux__) || defined(__LINUX__)
6412 if (g_cli_callback_mgr.is_started()) {
6413 PrintBase::SlicingStatus slicing_status{3, "Prepare slicing"};
6414 cli_status_callback(slicing_status);
6415 }
6416#endif
6417
6418
6419 Model model_copy;
6420 bool make_copy = &opt_key != &
m_actions.back();
6422 if (make_copy)
6423 model_copy = model_in;
6424 Model &model = make_copy ? model_copy : model_in;
6425
6426
6427
6428
6429 std::string outfile;
6430
6431 std::vector<size_t> plate_triangle_counts(partplate_list.get_plate_count(), 0);
6432
6433
6434
6435
6436 if (!is_belt_printer &&
m_print_config.option<ConfigOptionBool>(
"enable_prime_tower",
true)->value) {
6437 for (int index = 0; index < partplate_list.get_plate_count(); index++) {
6438 if ((plate_to_slice != 0) && (plate_to_slice != (index + 1)))
6439 continue;
6440 Slic3r::GUI::PartPlate *plate = partplate_list.get_plate(index);
6441
6442 bool is_seq_print = false;
6445 continue;
6446
6447
6448 Vec3d wt_pos, wt_size;
6449 Slic3r::GUI::WipeTowerRelocation relocation;
6452 continue;
6453 if (relocation.
moved)
6454 BOOST_LOG_TRIVIAL(warning) << boost::format("plate %1%: the wipe tower no longer fits at its saved position {%2%, %3%} and was moved %4%")
6457 % (relocation.
overlaps_objects ?
"onto an object, as no free space is left" :
"to free space");
6462 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%: wipe tower clamped to {%2%, %3%}, size {%4%, %5%}")
6463 % (index + 1) % wt_pos(0) % wt_pos(1) % wt_size(0) % wt_size(1);
6464 }
6465 }
6466
6467 while(!finished)
6468 {
6469
6470 PrintBase *print=NULL;
6471 Print *print_fff = NULL;
6472
6474 int print_index;
6475 for (int index = 0; index < partplate_list.get_plate_count(); index ++)
6476 {
6477 if ((plate_to_slice != 0) && (plate_to_slice != (index + 1))) {
6478 BOOST_LOG_TRIVIAL(info) << "Skip plate " << index+1 << std::endl;
6479 continue;
6480 }
6482 sliced_plate_info.
plate_id = index+1;
6483
6485 BOOST_LOG_TRIVIAL(info) << boost::format("Plate %1%: pre_check %2%, start")%(index+1)%pre_check;
6486 long long start_time = 0, end_time = 0, temp_time = 0, time_using_cache = 0;
6488
6489 Slic3r::GUI::PartPlate* part_plate = partplate_list.get_plate(index);
6490 part_plate->
get_print(&print, &gcode_result, &print_index);
6491
6492 print_fff = dynamic_cast<Print *>(print);
6493
6494
6495
6496
6497
6498
6499
6500
6501
6502
6503#if 0
6505 print_volume.
max(2) = z;
6506 print_volume.
min(2) = -1e10;
6508 BOOST_LOG_TRIVIAL(info) << boost::format(
"print_volume {%1%,%2%,%3%}->{%4%, %5%, %6%}") % print_volume.
min(0) % print_volume.
min(1)
6509 % print_volume.
min(2) % print_volume.
max(0) % print_volume.
max(1) % print_volume.
max(2) << std::endl;
6510#else
6511 BuildVolume build_volume(part_plate->
get_shape(), print_height, part_plate->
get_extruder_areas(), current_extruder_print_heights);
6512
6514
6516 BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": Nothing to be sliced, Either the print is empty or no object is fully inside the print volume before apply." << std::endl;
6518 if (arranged_without_rotations) {
6519
6520 no_objects_reason = "No object is fully inside the print volume. Arrange ran without rotations."
6521 " If an object only fits the bed when rotated, pass --allow-rotations."
6522 " Otherwise the plate is empty or an object is larger than the printable area or height.";
6523 boost::nowide::cerr << "plate " << index+1 << ": " << no_objects_reason << std::endl;
6524 }
6527 }
6528 else if ((plate_to_slice != 0) || pre_check) {
6529 long long triangle_count = 0;
6530 int printable_instances = 0;
6531 int skipped_count = 0;
6532 std::vector<std::set<int>> unprintable_filament_ids(new_extruder_count, std::set<int>());
6533 for (ModelObject* model_object : model.
objects)
6534 for (ModelInstance *i : model_object->
instances)
6535 {
6537 if (skip_maps.find(i->
loaded_id) != skip_maps.end()) {
6541 skipped_count++;
6542 plate_has_skips[index] = true;
6543 plate_skipped_objects[index].emplace_back(i->
loaded_id);
6544 BOOST_LOG_TRIVIAL(info) << boost::format(
"Plate %1%: skip object %2%.")%(index+1)%i->
loaded_id;
6545
6546 if (plate_data_src.size() > index) {
6547 if (!plate_data_src[index]->thumbnail_file.empty()) {
6548 BOOST_LOG_TRIVIAL(info) << boost::format("Plate %1%: clear loaded thumbnail %2%.")%(index+1)%plate_data_src[index]->thumbnail_file;
6549 plate_data_src[index]->thumbnail_file.clear();
6550 }
6551 if (!plate_data_src[index]->no_light_thumbnail_file.empty()) {
6552 BOOST_LOG_TRIVIAL(info) << boost::format("Plate %1%: clear loaded no_light_thumbnail %2%.")%(index+1)%plate_data_src[index]->no_light_thumbnail_file;
6553 plate_data_src[index]->no_light_thumbnail_file.clear();
6554 }
6555 if (!plate_data_src[index]->top_file.empty()) {
6556 BOOST_LOG_TRIVIAL(info) << boost::format("Plate %1%: clear loaded top_thumbnail %2%.")%(index+1)%plate_data_src[index]->top_file;
6557 plate_data_src[index]->top_file.clear();
6558 }
6559 if (!plate_data_src[index]->pick_file.empty()) {
6560 BOOST_LOG_TRIVIAL(info) << boost::format("Plate %1%: clear loaded pick_thumbnail %2%.")%(index+1)%plate_data_src[index]->pick_file;
6561 plate_data_src[index]->pick_file.clear();
6562 }
6563 }
6564 }
6565 continue;
6566 }
6567
6569 {
6570 BOOST_LOG_TRIVIAL(error) <<
"plate "<< index+1<<
": Found Object " << model_object->
name <<
" partly inside, can not be sliced." << std::endl;
6573 }
6575 {
6577
6578
6579 std::set<int> object_filaments;
6580 for (
const ModelVolume *vol : model_object->
volumes) {
6582 object_filaments.insert(filaments.begin(), filaments.end());
6583 }
6584 for (
const ModelVolume* vol : model_object->
volumes)
6585 {
6588 triangle_count += volume_triangle_count;
6589 BOOST_LOG_TRIVIAL(debug) << boost::format("volume triangle count %1%, total %2%")%volume_triangle_count %triangle_count;
6590 if ((max_triangle_count_per_plate != 0) && (triangle_count > max_triangle_count_per_plate))
6591 {
6592 BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": triangle count " << triangle_count <<" exceeds the limit:" << max_triangle_count_per_plate;
6595 }
6596
6597 if (new_extruder_count > 1) {
6599 std::vector<bool> inside_extruders;
6602 if (object_filaments.size() == 1) {
6603
6604 for (size_t j = 0; j < inside_extruders.size(); ++j) {
6605 if (!inside_extruders[j]) {
6607 unprintable_filament_ids[j].insert(filaments.begin(), filaments.end());
6608 }
6609 }
6610 }
6611 }
6612
6613 }
6614 }
6615 }
6616 }
6617
6619 printable_instances++;
6620 }
6621
6622 if (printable_instances == 0) {
6623 BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": Nothing to be sliced, after skipping "<<skipped_count<<" objects."<< std::endl;
6626 }
6627
6629 std::vector<int> used_tpu_filaments;
6630 for (int f_index = 0; f_index < plate_filaments.size(); f_index++) {
6631 if (plate_filaments[f_index] <= filament_count) {
6635 used_tpu_filaments.push_back(plate_filaments[f_index]);
6636 }
6637 }
6638 }
6640 if (!tpu_valid) {
6641 BOOST_LOG_TRIVIAL(error) << boost::format("plate %1% : Found 2 or more tpu filaments on plate ") % (index + 1);
6644 }
6645
6646
6647
6648
6650 const auto *components_opt =
m_print_config.option<ConfigOptionStrings>(
"filament_mixed_components");
6652 const auto &is_mixed = is_mixed_opt->
values;
6653 const auto &components = components_opt->
values;
6654 const size_t num_physical = static_cast<size_t>(filament_count) - static_cast<size_t>(std::count(is_mixed.begin(), is_mixed.end(), true));
6655 std::vector<std::string> physical_types(num_physical);
6656 for (size_t f_index = 0; f_index < num_physical; ++f_index) {
6657 std::string displayed_type;
6658 physical_types[f_index] =
m_print_config.get_filament_type(displayed_type,
static_cast<int>(f_index));
6659 if (physical_types[f_index].
empty())
6660 physical_types[f_index] = "PLA";
6661 }
6663
6664 const std::vector<int> plate_slots = mismatched_slots.empty() ? std::vector<int>() :
6665 part_plate->get_extruders_under_cli(true,
m_print_config, false);
6666 for (size_t slot : mismatched_slots) {
6667 if (std::find(plate_slots.begin(), plate_slots.end(), static_cast<int>(slot) + 1) == plate_slots.end())
6668 continue;
6669 BOOST_LOG_TRIVIAL(error) << boost::format("plate %1%: mixed filament %2% mixes components of different filament types")
6670 % (index + 1) % (slot + 1);
6673 }
6674 }
6675
6676 if (new_extruder_count > 1) {
6677 std::vector<std::vector<int>> unprintable_filament_vec;
6678 for (const std::set<int>& filamnt_ids : unprintable_filament_ids) {
6679 unprintable_filament_vec.emplace_back(std::vector<int>(filamnt_ids.begin(), filamnt_ids.end()));
6680 }
6681
6683 if (
m_extra_config.option<ConfigOptionEnum<FilamentMapMode>>(
"filament_map_mode"))
6684 mode =
m_extra_config.option<ConfigOptionEnum<FilamentMapMode>>(
"filament_map_mode")->value;
6685 else
6687 BOOST_LOG_TRIVIAL(info) << boost::format("%1% :filament map mode is %2% ") % __LINE__ %(int)mode;
6689 std::vector<int> conflict_filament_vector;
6690 for (int index = 0; index < new_extruder_count; index++)
6691 {
6692 if (!unprintable_filament_vec[index].
empty())
6693 {
6694 std::sort(unprintable_filament_vec[index].
begin(), unprintable_filament_vec[index].
end());
6695 if (index == 0)
6696 conflict_filament_vector = unprintable_filament_vec[index];
6697 else
6698 {
6699 std::vector<int> result_filaments;
6700
6701 std::set_intersection(conflict_filament_vector.begin(), conflict_filament_vector.end(), unprintable_filament_vec[index].begin(),
6702 unprintable_filament_vec[index].end(), std::insert_iterator<std::vector<int>>(result_filaments, result_filaments.begin()));
6703 conflict_filament_vector = result_filaments;
6704 }
6705 }
6706 else
6707 {
6708 conflict_filament_vector.clear();
6709 break;
6710 }
6711 }
6712
6713 if (!conflict_filament_vector.empty())
6714 {
6715 BOOST_LOG_TRIVIAL(error) << boost::format("plate %1% : some filaments can not be mapped under auto mode for multi extruder printer ")% (index + 1);
6718 }
6719 }
6720 else {
6721 std::vector<int> filament_maps;
6724 int default_value = -1;
6725 bool has_invalid_value = false;
6726 for (int f_index = 0; f_index < filament_maps.size(); f_index++)
6727 {
6728 if (filament_maps[f_index] != -1)
6729 {
6730 if (default_value == -1)
6731 default_value = filament_maps[f_index];
6732 else
6733 continue;
6734 }
6735 else
6736 has_invalid_value = true;
6737
6738 if (has_invalid_value && (default_value != -1))
6739 break;
6740 }
6741 BOOST_LOG_TRIVIAL(info) << boost::format("%1% :filament map default_value %2%, has_invalid_value %3% ") % __LINE__ %default_value %has_invalid_value;
6742
6743 if (has_invalid_value)
6744 {
6745 for (int f_index = 0; f_index < filament_maps.size(); f_index++)
6746 {
6747 if (filament_maps[f_index] == -1)
6748 {
6749 if (default_value != -1) {
6750 filament_maps[f_index] = default_value;
6751 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% : set filament_map of filament %2% to first value %3%.")% (index + 1) %(f_index+1) %default_value;
6752 }
6753 else {
6754 filament_maps[f_index] = 1;
6755 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% : set filament_map of filament %2% to default value 1.")% (index + 1) %(f_index+1);
6756 }
6757 }
6758 }
6760 }
6762 }
6763 else
6765
6766
6767
6768
6769
6770
6772
6773 bool support_multi_nozzle =
6774 max_nozzle_counts_opt &&
6775 std::any_of(max_nozzle_counts_opt->values.begin(), max_nozzle_counts_opt->values.end(),
6776 [](int v) { return v > 1 && v != ConfigOptionIntsNullable::nil_value(); });
6778
6779
6780
6784 BOOST_LOG_TRIVIAL(error)
6785 << boost::format("%1%, can not find filament_volume_map/filament_nozzle_map/filament_map under Nozzle Manual mode") % __LINE__;
6788 }
6789
6791
6792
6793
6794 std::vector<NozzleVolumeType> using_nozzle_volume_type = new_nozzle_volume_type;
6795 using_nozzle_volume_type.resize(new_extruder_count,
nvtStandard);
6796 if (
auto extruder_nozzle_stats_opt =
m_print_config.option<ConfigOptionStrings>(
"extruder_nozzle_stats")) {
6798 for (int e_index = 0; e_index < new_extruder_count && e_index < (int) nozzle_stats.size(); e_index++) {
6799 if (nozzle_stats[e_index].size() > 1) {
6800 using_nozzle_volume_type[e_index] =
nvtHybrid;
6801 BOOST_LOG_TRIVIAL(info) << boost::format("%1% : extruder %2%, set nozzle_volume_type to hybrid ") % __LINE__ % (e_index + 1);
6802 }
6803 }
6804 }
6806
6807 manual_volume_maps.resize(filament_count, (
int) (
nvtStandard));
6808 for (int f_index = 0; f_index < filament_count && f_index < (int) filament_maps.size(); f_index++) {
6809 int f_extruder_index = filament_maps[f_index] - 1;
6810 if (f_extruder_index >= 0 && f_extruder_index < new_extruder_count &&
6811 using_nozzle_volume_type[f_extruder_index] !=
nvtHybrid) {
6812 manual_volume_maps[f_index] = int(using_nozzle_volume_type[f_extruder_index]);
6813 BOOST_LOG_TRIVIAL(info) << boost::format("%1% : filament %2% extruder %3%, set filament_volume_map to %4% ") % __LINE__ % (f_index + 1) % (f_extruder_index + 1) % manual_volume_maps[f_index];
6814 }
6815 }
6816 }
6817
6820 }
6823 }
6824 }
6826 BOOST_LOG_TRIVIAL(error)
6827 << boost::format("%1%, Nozzle Manual mode not supported for %2%") % __LINE__ % new_printer_name;
6830 }
6831
6832 for (int index = 0; index < filament_maps.size(); index++)
6833 {
6834 int filament_extruder = filament_maps[index];
6835 if (unprintable_filament_ids[filament_extruder - 1].
find(index + 1) != unprintable_filament_ids[filament_extruder - 1].
end())
6836 {
6837 BOOST_LOG_TRIVIAL(error) << boost::format("plate %1% : some filaments can not be mapped under manual mode for multi extruder printer ") % (index + 1);
6840 }
6841 }
6842
6843 for (int f_index = 0; f_index < plate_filaments.size(); f_index++) {
6844 for (int f_index = 0; f_index < plate_filaments.size(); f_index++) {
6845 if (plate_filaments[f_index] <= filament_count) {
6846 int filament_extruder = filament_maps[plate_filaments[f_index] - 1];
6850 if (filament_printable_status && (filament_printable_status->values.size() >= plate_filaments[f_index])) {
6851 int status = filament_printable_status->values.at(plate_filaments[f_index] - 1);
6852 if (!(status >> (filament_extruder - 1) & 1)) {
6853 BOOST_LOG_TRIVIAL(error)
6854 << boost::format(
6855 "plate %1% : filament %2% can not be printed on extruder %3%, under manual mode for multi extruder printer") %
6860 }
6861 }
6862 }
6863 }
6864 }
6865 }
6866 }
6867
6868 plate_triangle_counts[index] = triangle_count;
6869 plate_object_count[index] = printable_instances;
6870 BOOST_LOG_TRIVIAL(info) << "plate "<< index+1<< ": load cached data success, go on.";
6871 }
6872
6873
6874
6875#endif
6883 if (
m_print_config.option<ConfigOptionPercent>(
"sparse_infill_density"))
6885 if (new_extruder_count > 1) {
6887 if (new_print_config.
option<ConfigOptionEnum<FilamentMapMode>>(
"filament_map_mode"))
6888 map_mode = new_print_config.
option<ConfigOptionEnum<FilamentMapMode>>(
"filament_map_mode")->value;
6889
6891
6892 std::vector<std::string> extruder_ams_count(new_extruder_count, "");
6893 std::vector<std::vector<DynamicPrintConfig>> extruder_filament_info(new_extruder_count, std::vector<DynamicPrintConfig>());
6894 int color_count = 0;
6895
6898
6899 for (int e_index = 0; e_index < new_extruder_count; e_index++)
6900 {
6901 extruder_ams_count[e_index] = "1#0|4#1";
6902 for (int color_index = 0; color_index < 4; color_index++)
6903 {
6904 DynamicPrintConfig temp_config;
6905 std::vector<std::string> temp_colors(1, "#FFFFFFFF");
6906 std::vector<std::string> temp_types(1, "PLA");
6907
6908
6909
6911 temp_types[0] = types[color_count % types.size()];
6912
6913 temp_config.
option<ConfigOptionStrings>(
"filament_colour",
true)->values = temp_colors;
6914 temp_config.
option<ConfigOptionStrings>(
"filament_type",
true)->values = temp_types;
6916 extruder_filament_info[e_index].push_back(std::move(temp_config));
6917 color_count++;
6918 }
6919 }
6920 new_print_config.
option<ConfigOptionStrings>(
"extruder_ams_count",
true)->values = extruder_ams_count;
6922 }
6923 }
6924
6925
6926 std::vector<int>& final_filament_maps = new_print_config.
option<
ConfigOptionInts>(
"filament_map",
true)->values;
6927 if (final_filament_maps.size() < filament_count)
6928 final_filament_maps.resize(filament_count, 1);
6929 if (new_extruder_count == 1) {
6930 for (int index = 0; index < filament_count; index++)
6931 final_filament_maps[index] = 1;
6932 }
6933 if(!new_print_config.
has(
"nozzle_volume_type")) {
6934
6937 }
6938 print->
apply(model, new_print_config);
6939 BOOST_LOG_TRIVIAL(info) << boost::format("set no_check to %1%:")%no_check;
6941
6942
6943 std::string& printer_model_string = new_print_config.
opt_string(
"printer_model",
true);
6944 bool is_bbl_vendor_preset = false;
6945
6946 if (!printer_model_string.empty()) {
6947 is_bbl_vendor_preset = (printer_model_string.compare(0, 9, "Bambu Lab") == 0);
6948 BOOST_LOG_TRIVIAL(info) << boost::format("printer_model_string: %1%, is_bbl_vendor_preset %2%")%printer_model_string %is_bbl_vendor_preset;
6949 }
6950 else {
6951 if (!new_printer_name.empty())
6952 is_bbl_vendor_preset = (new_printer_name.compare(0, 9, "Bambu Lab") == 0);
6953 else if (!current_printer_system_name.empty())
6954 is_bbl_vendor_preset = (current_printer_system_name.compare(0, 9, "Bambu Lab") == 0);
6955 BOOST_LOG_TRIVIAL(info) << boost::format("new_printer_name: %1%, current_printer_system_name %2%, is_bbl_vendor_preset %3%")%new_printer_name %current_printer_system_name %is_bbl_vendor_preset;
6956 }
6957 (dynamic_cast<Print*>(print))->is_BBL_printer() = is_bbl_vendor_preset;
6958
6959 std::vector<StringObjectException> warnings;
6961 auto err = print->
validate(&warnings);
6962 if (!err.string.empty()) {
6964 BOOST_LOG_TRIVIAL(warning) << "got warnings: "<< err.string << std::endl;
6965 }
6966 else {
6967 BOOST_LOG_TRIVIAL(error) << "got error when validate: "<< err.string << std::endl;
6968 boost::nowide::cerr << err.string << std::endl;
6969 int validate_error;
6970 switch (err.type)
6971 {
6974 break;
6977 break;
6980 break;
6983 break;
6984 default:
6986 break;
6987 }
6988 if (no_check)
6989 record_exit_reson(outfile_dir, validate_error, index+1, err.string, sliced_info);
6990 else
6993 }
6994 }
6995 else if (!warnings.empty()) {
6996 for (const auto& w : warnings)
6997 BOOST_LOG_TRIVIAL(warning) << "got warnings: "<< w.string << std::endl;
6998 }
6999
7000 if (print->
empty()) {
7001 BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": Nothing to be sliced, Either the print is empty or no object is fully inside the print volume after apply." << std::endl;
7004 }
7005 else {
7006 if (pre_check && (partplate_list.get_plate_count() > 1))
7007 continue;
7008 try {
7009 std::string outfile_final;
7010 BOOST_LOG_TRIVIAL(info) << "start Print::process for partplate "<<index+1 << std::endl;
7011#if defined(__linux__) || defined(__LINUX__)
7012 BOOST_LOG_TRIVIAL(info) << "cli callback mgr started: "<<g_cli_callback_mgr.m_started << std::endl;
7013 if (g_cli_callback_mgr.is_started()) {
7014 BOOST_LOG_TRIVIAL(info) << "set print's callback to cli_status_callback.";
7016 g_cli_callback_mgr.set_plate_info(index+1, (plate_to_slice== 0)?partplate_list.get_plate_count():1);
7017 if (!warnings.empty()) {
7018 std::string warning_text;
7019 for (const auto& w : warnings) {
7020 if (!warning_text.empty())
7021 warning_text += "\n";
7022 warning_text += w.string;
7023 }
7024 PrintBase::SlicingStatus slicing_status{4, warning_text, 0, 0};
7025 cli_status_callback(slicing_status);
7026 }
7027 else {
7028 PrintBase::SlicingStatus slicing_status{4, "Slicing begins"};
7029 cli_status_callback(slicing_status);
7030 }
7031 }
7032 else {
7033 BOOST_LOG_TRIVIAL(info) << "set print's callback to default_status_callback.";
7035 }
7036#else
7037 BOOST_LOG_TRIVIAL(info) << "set print's callback to default_status_callback.";
7039#endif
7040
7041
7042 const PrintConfig& print_config = print_fff->
config();
7045 if (load_slicedata) {
7046 std::string plate_dir = load_slice_data_dir+"/"+std::to_string(index+1);
7048 if (ret) {
7049 BOOST_LOG_TRIVIAL(warning) << "plate "<< index+1<< ": load Slicing data error, ret=" << ret;
7050 BOOST_LOG_TRIVIAL(warning) << "plate "<< index+1<< ": switch normal slicing";
7052 }
7053 else {
7054 BOOST_LOG_TRIVIAL(info) << "plate "<< index+1<< ": load cached data success, go on.";
7055#if defined(__linux__) || defined(__LINUX__)
7056 if (g_cli_callback_mgr.is_started()) {
7057 PrintBase::SlicingStatus slicing_status{69, "Cache data loaded"};
7058 cli_status_callback(slicing_status);
7059 }
7060#endif
7061 print->
process(
nullptr,
true);
7062 BOOST_LOG_TRIVIAL(info) << "plate "<< index+1<< ": finished print::process.";
7063 }
7064 }
7065 else {
7066 print->
process(&time_using_cache);
7067 BOOST_LOG_TRIVIAL(info) << "print::process: first time_using_cache is " << time_using_cache << " secs.";
7068 }
7070
7071
7072
7073
7074
7075 if (new_extruder_count > 1) {
7080 }
7083 }
7084 }
7085
7087 if (!conflict_result.empty()) {
7088 BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": found slicing result conflict!"<< std::endl;
7091 }
7092
7093
7095 {
7097 {
7100 {
7102
7104 BOOST_LOG_TRIVIAL(warning) <<
"plate "<< index+1<<
": found NON_CRITICAL slicing warnings: "<<status.
text <<std::endl;
7105
7106
7108 nlohmann::json{{
"plate_id", index+1}, {
"text", status.
text}});
7113 }
7114 }
7115 else {
7116 BOOST_LOG_TRIVIAL(warning) << boost::format(
"plate %1%: found slicing warnings: %2%, no_check=%3%")%(index+1) %status.
text %no_check;
7117 if (!no_check) {
7118
7121 {
7125 }
7126 }
7127 }
7128 }
7129 }
7131 }
7133
7134
7135
7136 if (outfile_dir.empty()) {
7138 }
7139 else {
7140 outfile = outfile_dir + "/plate_" + std::to_string(index + 1) + ".gcode";
7142 }
7143 BOOST_LOG_TRIVIAL(info) << "process finished, will export gcode temporarily to " << outfile << std::endl;
7145 outfile = print_fff->
export_gcode(outfile, gcode_result,
nullptr);
7147 BOOST_LOG_TRIVIAL(info) << "export_gcode finished: time_using_cache update to " << time_using_cache << " secs.";
7149
7151 BOOST_LOG_TRIVIAL(error) << "plate " << index + 1 << ": found gcode in unprintable area of the printers! gcode_result->gcode_check_result.error_code = "
7153 else
7154 BOOST_LOG_TRIVIAL(error) << "plate " << index + 1 << ": found gcode in unprintable area of multi extruder printers! gcode_result->gcode_check_result.error_code = "
7158 }
7159
7160 if (export_statistics && !outfile_dir.empty()) {
7161 try {
7163 } catch (const std::exception &ex) {
7164 BOOST_LOG_TRIVIAL(error) << "plate " << index + 1 << ": " << ex.what();
7167 }
7168 }
7169
7170
7171
7172
7173 }
7174
7175
7176
7177
7178
7179
7180
7181
7182
7183
7184
7185
7186
7187
7188
7189 BOOST_LOG_TRIVIAL(info) << "Slicing result exported to " << outfile << std::endl;
7191#if defined(__linux__) || defined(__LINUX__)
7192 if (g_cli_callback_mgr.is_started()) {
7193 PrintBase::SlicingStatus slicing_status{100, "Slicing finished"};
7194 cli_status_callback(slicing_status);
7195 }
7196#endif
7197 if (export_slicedata) {
7198 BOOST_LOG_TRIVIAL(info) << "plate "<< index+1<< ":will export Slicing data to " << export_slice_data_dir;
7199 std::string plate_dir = export_slice_data_dir+"/"+std::to_string(index+1);
7202 if (ret) {
7203 BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": export Slicing data error, ret=" << ret;
7204 export_slicedata_error = true;
7205 if (fs::exists(plate_dir))
7206 fs::remove_all(plate_dir);
7209 }
7210 }
7212 sliced_plate_info.
sliced_time = end_time - start_time;
7214
7215 if (max_slicing_time_per_plate != 0) {
7216 long long time_cost = end_time - start_time;
7217 if (
time_cost > max_slicing_time_per_plate) {
7218 sliced_plate_info.
warning_message = (boost::format(
"plate %1%'s slice time %2% exceeds the limit %3%, return error.")%(index+1) %
time_cost %max_slicing_time_per_plate).str();
7223 }
7224 }
7226 } catch (const Slic3r::SlicingErrors &exs) {
7227 const std::string message = print_fff ? print_fff->
slicing_errors_message(exs) : std::string(exs.what());
7228 BOOST_LOG_TRIVIAL(error) << "found slicing or export error for partplate " << index+1 << ": " << message;
7229 boost::nowide::cerr << message << std::endl;
7232 } catch (const std::exception &ex) {
7233 BOOST_LOG_TRIVIAL(error) << "found slicing or export error for partplate "<<index+1 << std::endl;
7234 boost::nowide::cerr << ex.what() << std::endl;
7235
7238 }
7239 }
7240 }
7241 if (pre_check&& (partplate_list.get_plate_count() > 1))
7242 pre_check = false;
7243 else
7244 finished = true;
7245 }
7246
7247#if defined(__linux__) || defined(__LINUX__)
7248 if (g_cli_callback_mgr.is_started()) {
7249 int plate_count = (plate_to_slice== 0)?partplate_list.get_plate_count():1;
7250 g_cli_callback_mgr.set_plate_info(0, plate_count);
7251 }
7252#endif
7253
7254
7255
7256
7257
7258
7259
7260
7261
7262
7263
7264
7265
7266
7267
7268
7269
7270
7271
7272
7273
7274
7275
7276
7277
7278
7279
7280
7281
7282
7283 }
7284 } else {
7285 boost::nowide::cerr << "error: option not supported yet: " << opt_key << std::endl;
7288 }
7289 }
7290
7292 if (export_to_3mf) {
7293
7294 std::vector<ThumbnailData *> thumbnails, no_light_thumbnails, top_thumbnails, pick_thumbnails;
7295 std::vector<PlateBBoxData*> plate_bboxes;
7297 partplate_list.store_to_3mf_structure(plate_data_list, true, -1, export_statistics);
7298
7299 if (sliced_plate == -1) {
7300 for (int i = 0; i < plate_data_list.size(); i++) {
7301 Slic3r::GUI::PartPlate *part_plate = partplate_list.get_plate(i);
7303 }
7304 }
7305 else if (sliced_plate == 0){
7306
7307 for (int i = 0; i < plate_data_list.size(); i++) {
7308 if (skip_useless_pick && (plate_object_count[i] == 1)) {
7309 BOOST_LOG_TRIVIAL(info) << boost::format("only has 1 object, set plate %1%'s is_label_object_enabled from %2% to false")%(i+1) % (plate_data_list[i]->is_label_object_enabled);
7310 plate_data_list[i]->is_label_object_enabled = false;
7311 }
7312 }
7313 }
7314 else {
7315 if (skip_useless_pick && (plate_object_count[sliced_plate - 1] == 1)) {
7316 BOOST_LOG_TRIVIAL(info) << boost::format("only has 1 object, set plate %1%'s is_label_object_enabled from %2% to false")%sliced_plate % (plate_data_list[sliced_plate - 1]->is_label_object_enabled);
7317 plate_data_list[sliced_plate - 1]->is_label_object_enabled = false;
7318 }
7319 }
7320
7321 if (!outfile_dir.empty()) {
7322 export_3mf_file = outfile_dir + "/"+export_3mf_file;
7323 }
7324
7325#if defined(__linux__) || defined(__LINUX__)
7326 if (g_cli_callback_mgr.is_started()) {
7327 PrintBase::SlicingStatus slicing_status{94, "Generate thumbnails"};
7328 cli_status_callback(slicing_status);
7329 }
7330#endif
7331
7332 bool need_regenerate_thumbnail = oriented_or_arranged || regenerate_thumbnails;
7333 bool need_regenerate_no_light_thumbnail = oriented_or_arranged || regenerate_thumbnails;
7334 bool need_regenerate_top_thumbnail = oriented_or_arranged || regenerate_thumbnails;
7335 bool need_create_thumbnail_group = false, need_create_no_light_group = false, need_create_top_group = false;
7336
7337
7338 const ConfigOptionStrings* filament_color =
dynamic_cast<const ConfigOptionStrings *
>(
m_print_config.option(
"filament_colour"));
7339 auto* filament_id =
dynamic_cast<const ConfigOptionStrings*
>(
m_print_config.option(
"filament_ids"));
7341 std::string nozzle_diameter_str;
7342 if (nozzle_diameter_option)
7343 nozzle_diameter_str = nozzle_diameter_option->
serialize();
7344#ifdef SLIC3R_GUI
7345
7346
7347
7348
7350 const bool is_bbl_printer = printer_model_option && printer_model_option->value.compare(0, 9, "Bambu Lab") == 0;
7351
7352
7353
7354
7355
7356 const BBLPrinterAgent bbl_agent;
7357#endif
7358
7359 for (int i = 0; i < plate_data_list.size(); i++) {
7360 PlateData *plate_data = plate_data_list[i];
7361 bool skip_this_plate = ((plate_to_slice != 0) && (plate_to_slice != (i + 1)))?true:false;
7362
7364 if (!printer_model_id.empty())
7366 if (!nozzle_diameter_str.empty())
7368
7370
7371 std::string display_filament_type;
7372 it->type =
m_print_config.get_filament_type(display_filament_type, it->id);
7373 it->color = (filament_color && !filament_color->
values.empty()) ? filament_color->
get_at(it->id) :
"#FFFFFF";
7374 it->filament_id = (filament_id && !filament_id->values.empty()) ? filament_id->get_at(it->id) : "";
7375#ifdef SLIC3R_GUI
7376 if (is_bbl_printer)
7378#endif
7379 }
7380
7382 if (!oriented_or_arranged && !regenerate_thumbnails && plate_data_src.size() > i)
7384 BOOST_LOG_TRIVIAL(info) << boost::format(
"thumbnails stage: plate %1%'s thumbnail data is invalid, check the file %2% exist or not")%(i+1) %plate_data->
thumbnail_file;
7386 BOOST_LOG_TRIVIAL(info) << boost::format("thumbnails stage: plate %1%'s thumbnail file also not there, need to regenerate")%(i+1);
7387 if (!skip_this_plate) {
7388 need_regenerate_thumbnail = true;
7389 need_create_thumbnail_group = true;
7390 }
7391 }
7392 else {
7393 if (regenerate_thumbnails) {
7394 BOOST_LOG_TRIVIAL(info) << boost::format(
"thumbnails stage: plate %1%'s thumbnail file %2% cleared, need to regenerate")%(i+1) %plate_data->
thumbnail_file;
7396 }
7397 else
7398 BOOST_LOG_TRIVIAL(info) << boost::format("thumbnails stage: plate %1%'s thumbnail file exists, no need to regenerate")%(i+1);
7399 }
7400 }
7401 else {
7402 if (regenerate_thumbnails)
7404
7405 if (!skip_this_plate) {
7406 need_create_thumbnail_group = true;
7407 }
7408 }
7409
7411 if (!regenerate_thumbnails && (plate_data_src.size() > i)) {
7413 }
7415 BOOST_LOG_TRIVIAL(info) << boost::format(
"thumbnails stage: plate %1%'s no_light_thumbnail_file %2% also not there, need to regenerate")%(i+1)%plate_data->
no_light_thumbnail_file;
7416 if (!skip_this_plate) {
7417 need_regenerate_no_light_thumbnail = true;
7418 need_create_no_light_group = true;
7419 }
7420 }
7421 else {
7422 if (regenerate_thumbnails) {
7423 BOOST_LOG_TRIVIAL(info) << boost::format(
"thumbnails stage: plate %1%'s no_light_thumbnail file %2% cleared, need to regenerate")%(i+1) %plate_data->
no_light_thumbnail_file;
7425 }
7426 else
7427 BOOST_LOG_TRIVIAL(info) << boost::format("thumbnails stage: plate %1%'s no_light_thumbnail file exists, no need to regenerate")%(i+1);
7428 }
7429 }
7430
7432 if (!regenerate_thumbnails && (plate_data_src.size() > i)) {
7433 plate_data->
top_file = plate_data_src[i]->top_file;
7434 plate_data->
pick_file = plate_data_src[i]->pick_file;
7435 }
7437 || (!boost::filesystem::exists(plate_data->
top_file)) || (!boost::filesystem::exists(plate_data->
pick_file))) {
7438 BOOST_LOG_TRIVIAL(info) << boost::format(
"thumbnails stage: plate %1%'s top_file %2% also not there, need to regenerate")%(i+1)%plate_data->
top_file;
7439 if (!skip_this_plate) {
7440 need_regenerate_top_thumbnail = true;
7441 need_create_top_group = true;
7442 }
7443 }
7444 else {
7445 if (regenerate_thumbnails) {
7446 BOOST_LOG_TRIVIAL(info) << boost::format(
"thumbnails stage: plate %1%'s top_thumbnail file %2% cleared, need to regenerate")%(i+1) %plate_data->
top_file;
7449 }
7450 else
7451 BOOST_LOG_TRIVIAL(info) << boost::format("thumbnails stage: plate %1%'s top_thumbnail file exists, no need to regenerate")%(i+1);
7452 }
7453 }
7454 }
7455
7456 if (need_regenerate_thumbnail || need_regenerate_no_light_thumbnail || need_regenerate_top_thumbnail) {
7457 std::vector<std::string> colors;
7458 if (filament_color) {
7460 }
7461 else
7462 colors.push_back("#FFFFFFFF");
7463
7464 std::vector<ColorRGBA> colors_out(colors.size());
7465 unsigned char rgb_color[4] = {};
7466 for (const std::string& color : colors) {
7468 size_t color_idx = &color - &colors.front();
7469 colors_out[color_idx] = ColorRGBA(float(rgb_color[0]) / 255.f, float(rgb_color[1]) / 255.f, float(rgb_color[2]) / 255.f, float(rgb_color[3]) / 255.f);
7470 }
7471
7472 int glfw_major, glfw_minor, glfw_revision;
7473 glfwGetVersion(&glfw_major, &glfw_minor, &glfw_revision);
7474 BOOST_LOG_TRIVIAL(info) << boost::format("GLFW version %1%.%2%.%3%") % glfw_major % glfw_minor % glfw_revision;
7475
7476 bool thumbnail_opengl_ready = false;
7478 int ret = glfwInit();
7479 if (ret == GLFW_FALSE) {
7480 const char* error_msg;
7481 int code = glfwGetError(&error_msg);
7482 BOOST_LOG_TRIVIAL(error) << "glfwInit return error, Error code: " << code << ", Error: " << error_msg << std::endl;
7483 }
7484 else {
7485 BOOST_LOG_TRIVIAL(info) << "glfwInit Success."<< std::endl;
7486
7487 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
7488 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
7489 glfwWindowHint(GLFW_RED_BITS, 8);
7490 glfwWindowHint(GLFW_GREEN_BITS, 8);
7491 glfwWindowHint(GLFW_BLUE_BITS, 8);
7492 glfwWindowHint(GLFW_ALPHA_BITS, 8);
7493 glfwWindowHint(GLFW_VISIBLE, false);
7494
7495
7496#ifdef __WXMAC__
7497 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
7498 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT,
GL_TRUE);
7499#else
7500 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);
7501#endif
7502
7503 GLFWwindow* window = glfwCreateWindow(640, 480, "base_window", NULL, NULL);
7504#ifndef __WXMAC__
7505 if (window == NULL) {
7506
7507 BOOST_LOG_TRIVIAL(warning) << "Failed to create OpenGL 3.3 compatibility context, retrying with driver default" << std::endl;
7508 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 1);
7509 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
7510 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_ANY_PROFILE);
7511 window = glfwCreateWindow(640, 480, "base_window", NULL, NULL);
7512 }
7513#endif
7514 if (window == NULL)
7515 {
7516 BOOST_LOG_TRIVIAL(error) << "Failed to create GLFW window; skipping thumbnail rendering for CLI export" << std::endl;
7517 }
7518 else {
7519 glfwMakeContextCurrent(window);
7520 thumbnail_opengl_ready = true;
7521 }
7522 }
7523
7524
7525 if (!thumbnail_opengl_ready) {
7526 BOOST_LOG_TRIVIAL(error) << "OpenGL context unavailable; skip thumbnail generating" << std::endl;
7527 need_create_thumbnail_group = false;
7528 need_create_no_light_group = false;
7529 need_create_top_group = false;
7530 }
7531 else
7532 {
7533 GUI::OpenGLManager opengl_mgr;
7534 bool opengl_valid = opengl_mgr.
init_gl(
false);
7535 if (!opengl_valid) {
7536 BOOST_LOG_TRIVIAL(error) << "init opengl failed! skip thumbnail generating" << std::endl;
7537 }
7538 else {
7539 BOOST_LOG_TRIVIAL(info) << "gladLoadGL Success." << std::endl;
7540 GLVolumeCollection glvolume_collection;
7542 int obj_extruder_id = 1, volume_extruder_id = 1;
7543 for (
unsigned int obj_idx = 0; obj_idx < (
unsigned int)model.
objects.size(); ++ obj_idx) {
7544 const ModelObject &model_object = *model.
objects[obj_idx];
7545 const ConfigOption* option = model_object.
config.
option(
"extruder");
7546 if (option)
7547 obj_extruder_id = (dynamic_cast<const ConfigOptionInt *>(option))->getInt();
7548 else
7549 obj_extruder_id = 1;
7550 for (
int volume_idx = 0; volume_idx < (int)model_object.
volumes.size(); ++ volume_idx) {
7551 const ModelVolume &model_volume = *model_object.
volumes[volume_idx];
7553 if (option)
7554 volume_extruder_id = (dynamic_cast<const ConfigOptionInt *>(option))->getInt();
7555 else
7556 volume_extruder_id = obj_extruder_id;
7557
7558 BOOST_LOG_TRIVIAL(debug) << boost::format("volume %1%'s extruder_id %2%")%volume_idx %volume_extruder_id;
7559
7560
7561 for (
int instance_idx = 0; instance_idx < (int)model_object.
instances.size(); ++ instance_idx) {
7562 const ModelInstance &model_instance = *model_object.
instances[instance_idx];
7563 glvolume_collection.
load_object_volume(&model_object, obj_idx, volume_idx, instance_idx,
"volume",
true,
false,
true);
7564
7565 std::string color = filament_color?filament_color->
get_at(volume_extruder_id - 1):
"#00FF00FF";
7566
7567 BOOST_LOG_TRIVIAL(debug) << boost::format("volume %1%'s color %2%")%volume_idx %color;
7568
7569 unsigned char rgb_color[4] = {};
7571
7572 ColorRGBA new_color;
7573 new_color.
r(
float(rgb_color[0]) / 255.f);
7574 new_color.
g(
float(rgb_color[1]) / 255.f);
7575 new_color.
b(
float(rgb_color[2]) / 255.f);
7576 new_color.
a(
float(rgb_color[3]) / 255.f);
7577
7578 glvolume_collection.
volumes.back()->set_render_color(new_color);
7579 glvolume_collection.
volumes.back()->set_color(new_color);
7581 }
7582 }
7583 }
7584
7585 ThumbnailsParams thumbnail_params;
7586 GLShaderProgram* shader = opengl_mgr.
get_shader(
"thumbnail");
7587 if (!shader) {
7588 BOOST_LOG_TRIVIAL(error) << boost::format("can not get shader for rendering thumbnail");
7589 }
7590 else {
7591 for (int i = 0; i < partplate_list.get_plate_count(); i++) {
7592 Slic3r::GUI::PartPlate *part_plate = partplate_list.get_plate(i);
7593 PlateData *plate_data = plate_data_list[i];
7595 if ((plate_to_slice != 0) && (plate_to_slice != (i + 1))) {
7596 BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: regenerate thumbnail, reset plate %2%'s thumbnail.")%__LINE__%(i+1);
7598 }
7599 else {
7601 }
7602 }
7604 {
7605 if ((plate_to_slice != 0) && (plate_to_slice != (i + 1))) {
7606 BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: regenerate thumbnail, clear plate %2%'s thumbnail file path to empty.")%__LINE__%(i+1);
7608 }
7609 else {
7610 BOOST_LOG_TRIVIAL(info) << boost::format(
"plate %1% has a valid thumbnail %2% extracted from 3mf, directly using it")%(i+1) %plate_data->
thumbnail_file;
7612 if (!dec_ret)
7613 {
7614 BOOST_LOG_TRIVIAL(info) << boost::format("decode png to mem success.");
7615 }
7616 else {
7617 BOOST_LOG_TRIVIAL(warning) << boost::format("decode png to mem failed.");
7618 }
7619 }
7620 }
7621 else {
7623
7624 if ((plate_to_slice != 0) && (plate_to_slice != (i + 1))) {
7625 BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: regenerate thumbnail, Skip plate %2%.")%__LINE__%(i+1);
7626 }
7627 else {
7628 unsigned int thumbnail_width = 512, thumbnail_height = 512;
7629 const ThumbnailsParams thumbnail_params = {{}, false, true, true, true, i};
7630
7631 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s thumbnail, need to regenerate")%(i+1);
7633 {
7635 {
7636 BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: ARB");
7638 thumbnail_width, thumbnail_height, thumbnail_params,
7640 break;
7641 }
7643 {
7644 BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: EXT");
7646 thumbnail_width, thumbnail_height, thumbnail_params,
7648 break;
7649 }
7650 default:
7651 BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: unknown");
7652 break;
7653 }
7654 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s thumbnail,finished rendering")%(i+1);
7655 }
7656 }
7657 if (need_create_thumbnail_group) {
7659 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%: add thumbnail data into group")%(i+1);
7660 }
7661
7662
7664 {
7665 if ((plate_to_slice != 0) && (plate_to_slice != (i + 1))) {
7666 BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: regenerate thumbnail, clear plate %2%'s no_light_thumbnail_file path to empty.")%__LINE__%(i+1);
7668 }
7669 else
7670 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% has valid no_light_thumbnail_file extracted from 3mf, directly using it")%(i+1);
7671 }
7672 else{
7674 if ((plate_to_slice != 0) && (plate_to_slice != (i + 1))) {
7675 BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: regenerate thumbnail, Skip plate %2%.")%__LINE__%(i+1);
7678 }
7679 else {
7680 unsigned int thumbnail_width = 512, thumbnail_height = 512;
7681 const ThumbnailsParams thumbnail_params = { {}, false, true, false, true, i };
7682
7683 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s no_light_thumbnail_file missed, need to regenerate")%(i+1);
7685 {
7687 {
7688 BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: ARB");
7690 thumbnail_width, thumbnail_height, thumbnail_params,
7691 partplate_list, model.
objects, glvolume_collection, colors_out, shader,
7693 false, true);
7694 break;
7695 }
7697 {
7698 BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: EXT");
7700 thumbnail_width, thumbnail_height, thumbnail_params,
7701 partplate_list, model.
objects, glvolume_collection, colors_out, shader,
7703 false, true);
7704 break;
7705 }
7706 default:
7707 BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: unknown");
7708 break;
7709 }
7711 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s no_light thumbnail,finished rendering")%(i+1);
7712 }
7713 }
7714
7715 if (need_create_no_light_group) {
7717 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%: add thumbnail data for no_light into group")%(i+1);
7718 }
7719
7720
7721
7722
7723
7724
7725
7726
7727
7728
7729
7730
7731
7732
7733
7734
7735
7736 if ((!plate_data->
top_file.empty() && (boost::filesystem::exists(plate_data->
top_file)))
7737 &&(!plate_data->
pick_file.empty() && (boost::filesystem::exists(plate_data->
pick_file))))
7738 {
7739 if ((plate_to_slice != 0) && (plate_to_slice != (i + 1))) {
7740 BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: regenerate thumbnail, clear plate %2%'s top/pick thumbnail file path to empty.")%__LINE__%(i+1);
7743 }
7744 else
7745 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% has valid top/pick thumbnail extracted from 3mf, directly using it")%(i+1);
7746 }
7747 else{
7750 if ((plate_to_slice != 0) && (plate_to_slice != (i + 1))) {
7751 BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: regenerate thumbnail, Skip plate %2%.")%__LINE__%(i+1);
7756 }
7757 else {
7758 unsigned int thumbnail_width = 512, thumbnail_height = 512;
7759 const ThumbnailsParams thumbnail_params = { {}, false, true, false, true, i };
7760
7761 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s top/pick thumbnail missed, need to regenerate, objects count %2%, skip_useless_pick %3%")%(i+1) %plate_object_count[i] %skip_useless_pick;
7762 if (skip_useless_pick && ((plate_object_count[i] <= 1) || (plate_object_count[i] > 64)))
7763 {
7764
7769 BOOST_LOG_TRIVIAL(info) << boost::format("skip rendering for top&&pick");
7770 }
7771 else {
7773 {
7775 {
7776 BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: ARB");
7778 thumbnail_width, thumbnail_height, thumbnail_params,
7779 partplate_list, model.
objects, glvolume_collection, colors_out, shader,
7781 false);
7783 thumbnail_width, thumbnail_height, thumbnail_params,
7784 partplate_list, model.
objects, glvolume_collection, colors_out, shader,
7787 break;
7788 }
7790 {
7791 BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: EXT");
7793 thumbnail_width, thumbnail_height, thumbnail_params,
7794 partplate_list, model.
objects, glvolume_collection, colors_out, shader,
7798 thumbnail_width, thumbnail_height, thumbnail_params, partplate_list, model.
objects,
7799 glvolume_collection, colors_out, shader,
7802 true,true);
7803 break;
7804 }
7805 default:
7806 BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: unknown");
7807 break;
7808 }
7809 plate_data->
top_file =
"valid_top";
7811 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s top_thumbnail,finished rendering")%(i+1);
7812 }
7813 }
7814 }
7815
7816 if (need_create_top_group) {
7819 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%: add thumbnail data for top and pick into group")%(i+1);
7820 }
7821 }
7822 }
7823 }
7824 }
7825
7826 glfwTerminate();
7827 }
7828 else {
7829 BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: use previous thumbnails, no need to regenerate")%__LINE__;
7830 for (int i = 0; i < partplate_list.get_plate_count(); i++) {
7831 PlateData *plate_data = plate_data_list[i];
7832 bool skip_this_plate = ((plate_to_slice != 0) && (plate_to_slice != (i + 1)))?true:false;
7833 Slic3r::GUI::PartPlate *part_plate = partplate_list.get_plate(i);
7834
7835 if (skip_this_plate) {
7836 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s all the thumbnails skipped, reset here")%(i+1);
7841
7846 }
7848 {
7849 BOOST_LOG_TRIVIAL(info) << boost::format(
"no need to generate: plate %1% has a valid thumbnail %2% extracted from 3mf, convert to data")%(i+1) %plate_data->
thumbnail_file;
7851 if (!dec_ret)
7852 {
7853 BOOST_LOG_TRIVIAL(info) << boost::format("decode png to mem success.");
7854 need_create_thumbnail_group = true;
7855 }
7856 else {
7857 BOOST_LOG_TRIVIAL(warning) << boost::format("decode png to mem failed.");
7858 }
7859 }
7860 }
7861
7862 for (int i = 0; i < partplate_list.get_plate_count(); i++) {
7863 PlateData *plate_data = plate_data_list[i];
7864 Slic3r::GUI::PartPlate *part_plate = partplate_list.get_plate(i);
7865
7866 if (need_create_thumbnail_group) {
7868 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%: add thumbnail data into group")%(i+1);
7869 }
7870
7871 if (need_create_no_light_group) {
7873 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%: add thumbnail data into group")%(i+1);
7874 }
7875
7876 if (need_create_top_group) {
7879 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%: add thumbnail data for top and pick into group")%(i+1);
7880 }
7881 }
7882 }
7883
7884
7885 for (int i = 0; i < partplate_list.get_plate_count(); i++) {
7886 if ((plate_to_slice != 0) && (plate_to_slice != (i + 1))) {
7887 BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: generate bbox, Skip plate %2%.")%__LINE__%(i+1);
7888 plate_bboxes.push_back(new PlateBBoxData());
7889 continue;
7890 }
7891 Slic3r::GUI::PartPlate *part_plate = partplate_list.get_plate(i);
7892
7894 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% doesn't have a valid sliced result, skip it")%(i+1);
7895
7896 plate_bboxes.push_back(new PlateBBoxData());
7897 continue;
7898 }
7899 PrintBase *print_base=NULL;
7901 int print_index;
7902 part_plate->
get_print(&print_base, &gcode_result, &print_index);
7903
7904 Print *print = dynamic_cast<Print *>(print_base);
7905
7906
7907
7908
7909
7910
7911
7912
7913
7914
7915
7916
7917
7918
7919
7920
7921
7922
7923
7924
7925
7926
7927
7928
7929 PlateBBoxData* plate_bbox = new PlateBBoxData();
7930 std::vector<BBoxData>& id_bboxes = plate_bbox->
bbox_objs;
7931 BoundingBoxf bbox_all;
7934 auto seq_print =
m_print_config.option<ConfigOptionEnum<PrintSequence>>(
"print_sequence");
7936 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% print by object, set from global")%(i+1);
7938 }
7939 }
7941 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% print by object, set from plate self")%(i+1);
7943 }
7945
7948 auto cur_bed_type =
m_print_config.option<ConfigOptionEnum<BedType>>(
"curr_bed_type");
7949 if (cur_bed_type) {
7950 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% bed type: %2%, set from global")%(i+1) %cur_bed_type->serialize();
7952 }
7953 }
7954 else {
7955 BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% bed type: %2%, set from plate self")%(i+1) %plate_bed_type;
7957 }
7958
7960 if (opt_nozzle_diameters != nullptr)
7962
7963 auto objects = print->
objects();
7965 Vec2d orig2d = { orig[0], orig[1] };
7966
7967 for (auto obj : objects)
7968 {
7969 BBoxData data;
7974 data.
id = obj->id().id;
7976 id_bboxes.emplace_back(std::move(data));
7977 }
7978
7980 BBoxData data;
7982
7983 if (!wt_corners.empty()) {
7984 BoundingBox bb_scaled = {wt_corners[0], wt_corners[2]};
7989 data.
name =
"wipe_tower";
7990 data.
id = partplate_list.get_curr_plate()->get_index() + 1000;
7992 id_bboxes.emplace_back(std::move(data));
7993 }
7994 }
7995 plate_bbox->
bbox_all = { bbox_all.
min.x(),bbox_all.
min.y(),bbox_all.
max.x(),bbox_all.
max.y() };
7996
7997 PlateData *plate_data = plate_data_list[i];
8001 }
8002 plate_bboxes.push_back(plate_bbox);
8003 }
8004
8005
8006#if defined(__linux__) || defined(__LINUX__)
8007 if (g_cli_callback_mgr.is_started()) {
8008 PrintBase::SlicingStatus slicing_status{97, "Exporting 3mf"};
8009 cli_status_callback(slicing_status);
8010 }
8011#endif
8012
8013 BOOST_LOG_TRIVIAL(info) << "will export 3mf to " << export_3mf_file << std::endl;
8014 if (!makerlab_name.empty()) {
8016
8017 model.
mk_name = makerlab_name;
8019 BOOST_LOG_TRIVIAL(info) << boost::format("mk_name %1%, mk_version %2%")%makerlab_name %makerlab_version;
8020 }
8021
8022 if (!metadata_name.empty()) {
8024
8026 model.
md_name = metadata_name;
8027 for (unsigned int i = 0; i < metadata_name.size(); i++)
8028 {
8029 BOOST_LOG_TRIVIAL(info) << boost::format("index %1% metadata_name %2%, metadata_value %3%")%i %metadata_name[i] %metadata_value[i];
8030 }
8031 }
8032
8033 if (!this->
export_project(&
m_models[0], export_3mf_file, plate_data_list, project_presets, thumbnails, no_light_thumbnails, top_thumbnails, pick_thumbnails,
8034 calibration_thumbnails, plate_bboxes, &
m_print_config, minimum_save, plate_to_slice - 1))
8035 {
8039 }
8040
8041 for (unsigned int i = 0; i < thumbnails.size(); i++)
8042 thumbnails[i]->reset();
8043 for (unsigned int i = 0; i < no_light_thumbnails.size(); i++)
8044 no_light_thumbnails[i]->reset();
8045 for (unsigned int i = 0; i < top_thumbnails.size(); i++)
8046 top_thumbnails[i]->reset();
8047 for (unsigned int i = 0; i < pick_thumbnails.size(); i++)
8048 pick_thumbnails[i]->reset();
8049
8051
8052 for (unsigned int i = 0; i < calibration_thumbnails.size(); i++)
8053 delete calibration_thumbnails[i];
8054
8055 for (int i = 0; i < plate_bboxes.size(); i++)
8056 delete plate_bboxes[i];
8057 }
8058
8059 if (plate_data_src.size() > 0)
8060 {
8062 }
8063
8064#if defined(__linux__) || defined(__LINUX__)
8065 if (g_cli_callback_mgr.is_started()) {
8066 PrintBase::SlicingStatus slicing_status{100, "All done, Success"};
8067 cli_status_callback(slicing_status);
8068 }
8069
8070 g_cli_callback_mgr.stop();
8071#endif
8072
8075 }
8076
8077 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", Finished" << std::endl;
8079 sliced_info.
export_time = (size_t) (global_current_time - global_begin_time);
8080
8081
8082 if (duplicate_count > 0)
8083 {
8084 record_key_values["sliced_count"] = std::to_string(duplicate_count+1);
8086 }
8087 else {
8089 }
8090
8091 boost::nowide::cout.flush();
8092 boost::nowide::cerr.flush();
8093
8094 return 0;
8095}
#define BED_SHRINK_SEQ_PRINT
Definition Arrange.hpp:17
static unsigned int count
Definition AuxiliaryDataViewModel.cpp:246
#define EPSILON
Definition ColorUtils.cpp:64
void serialize(Archive &ar, FacenamesSerializer &t, const std::uint32_t version)
Definition GLGizmoEmboss.cpp:3407
void default_status_callback(const PrintBase::SlicingStatus &slicing_status)
Definition OrcaSlicer.cpp:466
static int construct_assemble_list(std::vector< assemble_plate_info_t > &assemble_plate_info_list, Model &model, PlateDataPtrs &plate_list, std::vector< RGBA > &all_colours)
Definition OrcaSlicer.cpp:805
void record_exit_reson(std::string outputdir, int code, int plate_id, std::string error_message, sliced_info_t &sliced_info, std::map< std::string, std::string > key_values=std::map< std::string, std::string >())
Definition OrcaSlicer.cpp:518
static Pointfs legacy_bed_exclude_area_points(const DynamicPrintConfig &config)
Definition OrcaSlicer.cpp:187
int wall_loops
Definition OrcaSlicer.cpp:262
const float bed3d_ax3s_default_tip_radius
Definition OrcaSlicer.cpp:610
static void load_downward_settings_list_from_config(std::string config_file, std::string printer_name, std::string printer_model, std::vector< std::string > &downward_settings)
Definition OrcaSlicer.cpp:1086
float sparse_infill_density
Definition OrcaSlicer.cpp:261
int plate_id
Definition OrcaSlicer.cpp:246
bool strict_mode
Definition OrcaSlicer.cpp:267
static void glfw_callback(int error_code, const char *description)
Definition OrcaSlicer.cpp:603
static void load_default_gcodes_to_config(DynamicPrintConfig &config, Preset::Type type)
Definition OrcaSlicer.cpp:653
size_t triangle_count
Definition OrcaSlicer.cpp:249
std::string warning_message
Definition OrcaSlicer.cpp:250
size_t sliced_time_with_cache
Definition OrcaSlicer.cpp:248
static PrinterTechnology get_printer_technology(const DynamicConfig &config)
Definition OrcaSlicer.cpp:477
struct _sliced_plate_info sliced_plate_info_t
std::vector< std::string > downward_machines
Definition OrcaSlicer.cpp:264
struct _sliced_info sliced_info_t
#define flush_and_exit(ret)
Definition OrcaSlicer.cpp:494
std::vector< PrintBase::SlicingStatus > g_slicing_warnings
Definition OrcaSlicer.cpp:269
size_t sliced_time
Definition OrcaSlicer.cpp:247
std::vector< sliced_plate_info_t > sliced_plates
Definition OrcaSlicer.cpp:257
float layer_height
Definition OrcaSlicer.cpp:260
#define MAX_CLONEABLE_SIZE
Definition OrcaSlicer.cpp:185
size_t export_time
Definition OrcaSlicer.cpp:259
static int load_key_values_from_json(const std::string &file, std::map< std::string, std::string > &key_values)
Definition OrcaSlicer.cpp:613
std::map< int, std::string > cli_errors
Definition OrcaSlicer.cpp:193
static void cli_record_warning(sliced_info_t &sliced_info, const std::string &cls, nlohmann::json details=nlohmann::json::object())
Definition OrcaSlicer.cpp:511
std::vector< std::string > upward_machines
Definition OrcaSlicer.cpp:263
static int decode_png_to_thumbnail(std::string png_file, ThumbnailData &thumbnail_data)
Definition OrcaSlicer.cpp:570
size_t prepare_time
Definition OrcaSlicer.cpp:258
const float WIPE_TOWER_DEFAULT_Y_POS
Definition PartPlate.cpp:143
const float WIPE_TOWER_DEFAULT_X_POS
Definition PartPlate.cpp:142
const float I3_WIPE_TOWER_DEFAULT_X_POS
Definition PartPlate.cpp:147
const float I3_WIPE_TOWER_DEFAULT_Y_POS
Definition PartPlate.cpp:148
#define MAX_PLATE_COUNT
Definition PartPlate.hpp:59
#define BBL_JSON_KEY_NAME
Definition Preset.hpp:58
#define BBL_JSON_KEY_TYPE
Definition Preset.hpp:66
#define BBL_JSON_KEY_FROM
Definition Preset.hpp:67
#define BBL_JSON_KEY_FILAMENT_ID
Definition Preset.hpp:71
#define BBL_JSON_KEY_INHERITS
Definition Preset.hpp:75
void reset()
Definition AppConfig.cpp:122
std::string load_if_exists()
Definition AppConfig.cpp:1940
std::string from_orca_filament_id(const std::string &orca_filament_id) const override
Definition BBLPrinterAgent.cpp:135
PointType center() const
Definition BoundingBox.cpp:237
PointType size() const
Definition BoundingBox.cpp:187
void merge(const PointType &point)
Definition BoundingBox.cpp:139
PointType max
Definition BoundingBox.hpp:21
void merge(const PointType &point)
Definition BoundingBox.cpp:75
PointType min
Definition BoundingBox.hpp:20
ObjectState
Definition BuildVolume.hpp:94
@ Limited
Definition BuildVolume.hpp:105
std::vector< std::string > m_input_files
Definition OrcaSlicer.hpp:68
bool export_models(IO::ExportFormat format, std::string path=std::string())
Exports loaded models to a file of the specified format, according to the options affecting output fi...
Definition OrcaSlicer.cpp:8284
bool export_project(Model *model, std::string &path, PlateDataPtrs &partplate_data, std::vector< Preset * > &project_presets, std::vector< ThumbnailData * > &thumbnails, std::vector< ThumbnailData * > &no_light_thumbnails, std::vector< ThumbnailData * > &top_thumbnails, std::vector< ThumbnailData * > &pick_thumbnails, std::vector< ThumbnailData * > &calibration_thumbnails, std::vector< PlateBBoxData * > &plate_bboxes, const DynamicPrintConfig *config, bool minimum_save, int plate_to_export=-1)
Definition OrcaSlicer.cpp:8329
DynamicPrintConfig m_extra_config
Definition OrcaSlicer.hpp:67
std::vector< std::string > m_actions
Definition OrcaSlicer.hpp:69
std::set< std::string > m_given_option_keys
Definition OrcaSlicer.hpp:72
bool setup(int argc, char **argv)
Definition OrcaSlicer.cpp:8097
void print_help(bool include_print_options=false, PrinterTechnology printer_technology=ptAny) const
Prints usage of the CLI.
Definition OrcaSlicer.cpp:8249
DynamicPrintConfig m_print_config
Definition OrcaSlicer.hpp:66
std::vector< std::string > m_transforms
Definition OrcaSlicer.hpp:70
float a() const
Definition Color.hpp:108
float b() const
Definition Color.hpp:107
float r() const
Definition Color.hpp:105
float g() const
Definition Color.hpp:106
void apply(const ConfigBase &other, bool ignore_nonexistent=false)
Definition Config.hpp:2802
ConfigOption * option(const t_config_option_key &opt_key, bool create=false)
Definition Config.hpp:2768
void apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent=false)
Definition Config.cpp:484
void set(const std::string &opt_key, bool value, bool create=false)
Definition Config.hpp:2822
bool & get_at(size_t i)
Definition Config.hpp:1986
std::string serialize() const override
Definition Config.hpp:1994
t_config_option_key opt_key
Definition Config.hpp:2342
std::string serialize() const override
Definition Config.hpp:909
bool deserialize(const std::string &str, bool append=false) override
Definition Config.hpp:932
bool has(const t_config_option_key &opt_key) const
Definition Config.hpp:2697
T value
Definition Config.hpp:329
bool empty() const
Definition Config.hpp:1170
std::vector< std::string > vserialize() const override
Definition Config.hpp:1212
virtual void resize(size_t n, const ConfigOption *opt_default=nullptr)=0
virtual void set_with_restore_2(const ConfigOptionVectorBase *rhs, std::vector< int > &restore_index, int start, int len, bool skip_error=false)=0
virtual void set_at(const ConfigOption *rhs, size_t i, size_t j)=0
virtual size_t size() const =0
virtual void set_with_restore(const ConfigOptionVectorBase *rhs, std::vector< int > &restore_index, int stride)=0
bool empty() const override
Definition Config.hpp:723
size_t size() const override
Definition Config.hpp:722
std::vector< T > values
Definition Config.hpp:418
const int & get_at(size_t i) const
Definition Config.hpp:676
void resize(size_t n, const ConfigOption *opt_default=nullptr) override
Definition Config.hpp:687
void set_at(const ConfigOption *rhs, size_t i, size_t j) override
Definition Config.hpp:451
virtual ConfigOption * clone() const =0
virtual void set(const ConfigOption *option)=0
virtual double getFloat() const
Definition Config.hpp:295
bool is_scalar() const
Definition Config.hpp:301
virtual std::string serialize() const =0
bool set_key_value(const std::string &opt_key, ConfigOption *opt)
Definition Config.hpp:3022
bool erase(const t_config_option_key &opt_key)
Definition Config.hpp:2992
bool empty() const
Definition Config.hpp:3017
std::string & opt_string(const t_config_option_key &opt_key, bool create=false)
Definition Config.hpp:3042
t_config_option_keys keys() const override
Definition Config.cpp:1919
t_config_option_keys diff(const DynamicConfig &other) const
Definition Config.cpp:2066
double & opt_float(const t_config_option_key &opt_key)
Definition Config.hpp:3047
int update_values_from_multi_to_multi_2(const std::vector< std::string > &src_extruder_variants, const std::vector< std::string > &dst_extruder_variants, const DynamicPrintConfig &dst_config, const std::set< std::string > &key_sets)
Definition PrintConfig.cpp:11275
Polygon contour
Definition ExPolygon.hpp:42
GLVolumePtrs volumes
Definition 3DScene.hpp:468
int load_object_volume(const ModelObject *model_object, int obj_idx, int volume_idx, int instance_idx, const std::string &color_by, bool opengl_initialized, bool in_assemble_view=false, bool use_loaded_id=false, bool need_raycaster=true)
Definition 3DScene.cpp:893
static bool parse_color4(const std::string &scolor, unsigned char *rgba_out)
Definition BitmapCache.cpp:559
static void render_thumbnail_framebuffer_ext(ThumbnailData &thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams &thumbnail_params, PartPlateList &partplate_list, ModelObjectPtrs &model_objects, const GLVolumeCollection &volumes, std::vector< ColorRGBA > &extruder_colors, GLShaderProgram *shader, Camera::EType camera_type, Camera::ViewAngleType camera_view_angle_type=Camera::ViewAngleType::Iso, bool for_picking=false, bool ban_light=false)
Definition GLCanvas3D.cpp:7250
static void render_thumbnail_framebuffer(ThumbnailData &thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams &thumbnail_params, PartPlateList &partplate_list, ModelObjectPtrs &model_objects, const GLVolumeCollection &volumes, std::vector< ColorRGBA > &extruder_colors, GLShaderProgram *shader, Camera::EType camera_type, Camera::ViewAngleType camera_view_angle_type=Camera::ViewAngleType::Iso, bool for_picking=false, bool ban_light=false)
Definition GLCanvas3D.cpp:7137
bool init_gl(bool popup_error=true)
Definition OpenGLManager.cpp:256
GLShaderProgram * get_shader(const std::string &shader_name)
Definition OpenGLManager.hpp:96
static EFramebufferType get_framebuffers_type()
Definition OpenGLManager.hpp:102
@ Arb
Definition OpenGLManager.hpp:23
@ Ext
Definition OpenGLManager.hpp:24
void translate_all_instance(Vec3d position)
Definition PartPlate.cpp:4744
ThumbnailData pick_thumbnail_data
Definition PartPlate.hpp:432
const std::vector< Pointfs > & get_extruder_areas() const
Definition PartPlate.hpp:579
bool intersect_instance(int obj_id, int instance_id, BoundingBoxf3 *bounding_box=nullptr)
Definition PartPlate.cpp:4600
arrangement::ArrangePolygon estimate_wipe_tower_polygon(const DynamicPrintConfig &config, int plate_index, Vec3d &wt_pos, Vec3d &wt_size, int plate_extruder_size=0, bool use_global_objects=false, WipeTowerRelocation *relocation=nullptr) const
Definition PartPlate.cpp:4065
void lock(bool state)
Definition PartPlate.hpp:612
bool contain_instance(int obj_id, int instance_id)
Definition PartPlate.cpp:4432
GCodeProcessorResult * get_slice_result()
Definition PartPlate.hpp:698
int printable_instance_size()
Definition PartPlate.cpp:4921
void set_filament_maps(const std::vector< int > &f_maps)
Definition PartPlate.cpp:5800
Vec3d get_origin()
Definition PartPlate.hpp:479
void set_tmp_gcode_path(std::string new_path)
Definition PartPlate.hpp:703
WipeTowerFootprint estimate_wipe_tower_footprint(const DynamicPrintConfig &config, int plate_extruder_size=0, bool use_global_objects=false) const
Definition PartPlate.cpp:3982
const Pointfs & get_shape() const
Definition PartPlate.hpp:577
std::vector< int > get_extruders_under_cli(bool conside_custom_gcode, DynamicPrintConfig &full_config, bool expand_mixed_slots=true) const
Definition PartPlate.cpp:3252
void set_filament_volume_maps(const std::vector< int > &f_maps)
Definition PartPlate.cpp:5822
void duplicate_all_instance(unsigned int dup_count, bool need_skip, std::map< int, bool > &skip_objects)
Definition PartPlate.cpp:4766
BedType get_bed_type(bool load_from_project=false) const
Definition PartPlate.cpp:266
ThumbnailData no_light_thumbnail_data
Definition PartPlate.hpp:426
bool check_tpu_printable_status(const DynamicPrintConfig &config, const std::vector< int > &tpu_filaments)
Definition PartPlate.cpp:3710
void get_print(PrintBase **print, GCodeResult **result, int *index)
Definition PartPlate.cpp:4361
ThumbnailData top_thumbnail_data
Definition PartPlate.hpp:431
DynamicPrintConfig * config()
Definition PartPlate.hpp:337
void set_filament_nozzle_maps(const std::vector< int > &f_maps)
Definition PartPlate.cpp:5842
FilamentMapMode get_real_filament_map_mode(const DynamicConfig &g_config, bool *use_global_param=nullptr) const
Definition PartPlate.cpp:408
const BoundingBoxf3 & get_bounding_box(bool extended=false)
Definition PartPlate.hpp:595
PrintSequence get_print_seq() const
Definition PartPlate.cpp:358
std::vector< int > get_real_filament_maps(const DynamicConfig &g_config, bool *use_global_param=nullptr) const
Definition PartPlate.cpp:384
bool is_slice_result_valid() const
Definition PartPlate.hpp:660
void update_slice_result_valid_state(bool valid=false)
Definition PartPlate.cpp:5423
std::string get_tmp_gcode_path()
Definition PartPlate.cpp:5465
int extruder() const
Definition PrintConfig.hpp:2654
bool set_key_value(const std::string &opt_key, ConfigOption *opt)
Definition PrintConfig.hpp:2635
void assign_config(const ModelConfig &rhs)
Definition PrintConfig.hpp:2612
const DynamicPrintConfig & get() const
Definition PrintConfig.hpp:2645
const ConfigOption * option(const t_config_option_key &opt_key) const
Definition PrintConfig.hpp:2652
bool printable
Definition Model.hpp:1432
size_t loaded_id
Definition Model.hpp:1435
ModelInstanceEPrintVolumeState print_volume_state
Definition Model.hpp:1430
void set_offset(const Vec3d &offset)
Definition Model.hpp:1473
Vec3d get_offset() const
Definition Model.hpp:1470
const Geometry::Transformation & get_transformation() const
Definition Model.hpp:1447
bool use_loaded_id_for_label
Definition Model.hpp:1433
void ensure_on_bed(bool allow_negative_z=false)
Definition Model.cpp:1896
bool has_custom_layering() const
Definition Model.hpp:463
ModelConfigObject config
Definition Model.hpp:395
std::string name
Definition Model.hpp:384
t_layer_config_ranges layer_config_ranges
Definition Model.hpp:397
std::string input_file
Definition Model.hpp:387
void rotate(double angle, Axis axis)
Definition Model.cpp:1958
ModelInstancePtrs instances
Definition Model.hpp:390
ModelVolume * add_volume(const TriangleMesh &mesh, bool modify_to_center_geometry=true)
Definition Model.cpp:1389
void scale(const Vec3d &versor)
Definition Model.cpp:1950
void translate_instances(const Vec3d &vector)
Definition Model.cpp:1923
ModelInstance * add_instance()
Definition Model.cpp:1554
BoundingBoxf3 instance_bounding_box(size_t instance_idx, bool dont_translate=false) const
Definition Model.cpp:1778
ModelVolumePtrs volumes
Definition Model.hpp:393
void scale_to_fit(const Vec3d &size)
Scale the current ModelObject to fit by altering the scaling factor of ModelInstances....
Definition Model.cpp:3059
bool repair(bool keep_painting, MeshRepairStats *stats=nullptr, std::string *error=nullptr, const std::function< void(int)> &progress={})
Definition Model.cpp:3029
const TriangleMesh & mesh() const
Definition Model.hpp:892
bool is_model_part() const
Definition Model.hpp:1025
bool is_modifier() const
Definition Model.hpp:1027
ModelConfigObject config
Definition Model.hpp:904
const TriangleMesh & get_convex_hull() const
Definition Model.cpp:2904
const Transform3d & get_matrix() const
Definition Model.hpp:1139
std::string name
Definition Model.hpp:834
std::vector< int > get_extruders() const
Definition Model.cpp:2713
void convert_from_meters(bool only_small_volumes)
Definition Model.cpp:1030
void delete_object(size_t idx)
Definition Model.cpp:672
void convert_from_imperial_units(bool only_small_volumes)
Definition Model.cpp:1003
void clear_materials()
Definition Model.cpp:776
bool looks_like_saved_in_meters() const
Definition Model.cpp:1018
void print_info() const
Definition Model.hpp:1858
ModelObjectPtrs objects
Definition Model.hpp:1702
void remove_backup_path_if_exist()
Definition Model.cpp:1147
static Model read_from_file(const std::string &input_file, DynamicPrintConfig *config=nullptr, ConfigSubstitutionContext *config_substitutions=nullptr, LoadStrategy options=LoadStrategy::AddDefaultInstances, PlateDataPtrs *plate_data=nullptr, std::vector< Preset * > *project_presets=nullptr, bool *is_xxx=nullptr, Semver *file_version=nullptr, Import3mfProgressFn proFn=nullptr, ImportstlProgressFn stlFn=nullptr, BBLProject *project=nullptr, int plate_id=0)
Definition Model.cpp:318
int curr_plate_index
Definition Model.hpp:1742
void translate(coordf_t x, coordf_t y, coordf_t z)
Definition Model.hpp:1841
static void setPrintSpeedTable(const DynamicPrintConfig &config, const PrintConfig &print_config)
Definition Model.cpp:3209
ModelObject * add_object()
Definition Model.cpp:607
void clear_objects()
Definition Model.cpp:717
bool looks_like_imperial_units() const
Definition Model.cpp:978
std::vector< std::string > md_value
Definition Model.hpp:1724
bool add_default_instances()
Definition Model.cpp:805
unsigned int update_print_volume_state(const BuildVolume &build_volume)
Definition Model.cpp:839
std::string mk_version
Definition Model.hpp:1722
std::vector< std::string > md_name
Definition Model.hpp:1723
bool center_instances_around_point(const Vec2d &point)
Definition Model.cpp:850
std::string mk_name
Definition Model.hpp:1721
BoundingBoxf3 bounding_box_exact() const
Definition Model.cpp:823
TriangleMesh mesh() const
Definition Model.cpp:872
void set_backup_path(const std::string &path)
Definition Model.cpp:1174
static void setExtruderParams(const DynamicPrintConfig &config, int extruders_count)
Definition Model.cpp:3267
ObjectID id() const
Definition ObjectID.hpp:69
size_t id
Definition ObjectID.hpp:39
PrinterPresetCollection printers
Definition PresetBundle.hpp:503
bool resolve_preset_config_type(DynamicPrintConfig &config, Preset::Type &type, const std::string &source_file, ForwardCompatibilitySubstitutionRule compatibility_rule, std::string &error, bool allow_source_manifest=true)
Definition PresetBundle.cpp:689
static void convert_filament_preset_name(const std::string &machine_name, std::string &filament_name)
Definition PresetBundle.cpp:6107
PresetCollection prints
Definition PresetBundle.hpp:497
PresetCollection filaments
Definition PresetBundle.hpp:499
bool resolve_preset_config(DynamicPrintConfig &config, Preset::Type type, const std::string &source_file, ForwardCompatibilitySubstitutionRule compatibility_rule, std::string &error, bool allow_source_manifest=true)
Definition PresetBundle.cpp:556
static std::set< std::string > project_different_keys(const std::string &different_settings)
Definition PresetBundle.cpp:5489
Preset * find_preset2(const std::string &name, bool auto_match=true)
Definition Preset.cpp:3790
Preset & default_preset(size_t idx=0)
Definition Preset.hpp:786
std::string name
Definition Preset.hpp:288
bool is_project_embedded
Definition Preset.hpp:281
static std::string get_type_string(Preset::Type type)
Definition Preset.cpp:590
static DynamicPrintConfig load_external_config(Type type, const DynamicPrintConfig &default_config, const DynamicPrintConfig &project_config, const std::set< std::string > &different_settings_list, const std::function< DynamicPrintConfig *(const std::string &inherits)> &find_base, t_config_option_keys *keys=nullptr)
Definition Preset.cpp:1059
DynamicPrintConfig config
Definition Preset.hpp:300
static const std::vector< std::string > & print_options()
Definition Preset.cpp:1705
static const std::vector< std::string > & printer_options()
Definition Preset.cpp:1715
Type type
Definition Preset.hpp:261
static const std::vector< std::string > & filament_options()
Definition Preset.cpp:1706
Type
Definition Preset.hpp:244
@ TYPE_PRINTER
Definition Preset.hpp:250
@ TYPE_PRINT
Definition Preset.hpp:246
@ TYPE_FILAMENT
Definition Preset.hpp:248
virtual bool empty() const =0
virtual ApplyStatus apply(const Model &model, DynamicPrintConfig config, bool extruder_applied=false)=0
virtual void process(long long *time_cost_with_cache=nullptr, bool use_cache=false)=0
void set_no_check_flag(bool no_check)
Definition PrintBase.hpp:529
virtual int load_cached_data(const std::string &directory)
Definition PrintBase.hpp:438
virtual StringObjectException validate(std::vector< StringObjectException > *warnings=nullptr, Polygons *collison_polygons=nullptr, std::vector< std::pair< Polygon, float > > *height_polygons=nullptr) const
Definition PrintBase.hpp:408
void set_status_callback(status_callback_type cb)
Definition PrintBase.hpp:488
virtual int export_cached_data(const std::string &dir_path, bool with_space=false)
Definition PrintBase.hpp:437
@ SlicingGcodeOverlap
Definition PrintBase.hpp:72
@ SlicingEmptyGcodeLayers
Definition PrintBase.hpp:71
@ SlicingDefaultNotification
Definition PrintBase.hpp:68
@ NON_CRITICAL
Definition PrintBase.hpp:62
ConstPrintObjectPtrsAdaptor objects() const
Definition Print.hpp:1134
void set_extruder_filament_info(const std::vector< std::vector< DynamicPrintConfig > > &filament_info)
Definition Print.hpp:1238
std::vector< int > get_filament_maps() const
Definition Print.cpp:4888
std::string get_conflict_string() const
Definition Print.hpp:1321
std::string export_gcode(const std::string &path_template, GCodeProcessorResult *result, ThumbnailsGeneratorCallback thumbnail_cb=nullptr)
Definition Print.cpp:3977
std::vector< int > get_filament_nozzle_maps() const
Definition Print.cpp:4893
const ToolOrdering & get_tool_ordering() const
Definition Print.hpp:1291
std::string slicing_errors_message(const SlicingErrors &errors) const
Definition Print.cpp:1952
std::vector< int > get_filament_volume_maps() const
Definition Print.cpp:4898
void set_check_multi_filaments_compatibility(bool check)
Definition Print.hpp:1356
bool has_wipe_tower() const
Definition Print.cpp:5183
const PrintConfig & config() const
Definition Print.hpp:1131
Points first_layer_wipe_tower_corners(bool check_wipe_tower_existance=true) const
Definition Print.cpp:4462
const Preset & default_preset_for(const DynamicPrintConfig &config) const override
Definition Preset.cpp:4499
int min() const
Definition Semver.hpp:109
static boost::optional< Semver > parse(const std::string &str)
Definition Semver.hpp:63
int maj() const
Definition Semver.hpp:108
std::string to_string() const
Definition Semver.hpp:158
BoundingBoxf3 transformed_bounding_box(const Transform3d &trafo) const
Definition TriangleMesh.cpp:456
size_t facets_count() const
Definition TriangleMesh.hpp:145
static bool SupportsForceSharedMemory()
Definition WebView.cpp:446
static bool NeedsCompositingWorkaround()
Definition WebView.cpp:435
#define GL_TRUE
Definition gl.h:1892
#define CLI_ENVIRONMENT_ERROR
Definition Utils.hpp:43
#define CLI_OBJECT_COLLISION_IN_LAYER_PRINT
Definition Utils.hpp:85
#define CLI_POSTPROCESS_NOT_SUPPORTED
Definition Utils.hpp:62
#define CLI_3MF_NEW_MACHINE_NOT_SUPPORTED
Definition Utils.hpp:59
#define CLI_OBJECT_ARRANGE_FAILED
Definition Utils.hpp:64
#define CLI_EXPORT_OBJ_ERROR
Definition Utils.hpp:55
#define CLI_GCODE_PATH_CONFLICTS
Definition Utils.hpp:93
#define CLI_SLICING_ERROR
Definition Utils.hpp:92
#define CLI_MODIFIED_PARAMS_TO_PRINTER
Definition Utils.hpp:66
#define CLI_FILAMENTS_NOT_SUPPORTED_BY_EXTRUDER
Definition Utils.hpp:89
#define CLI_NO_SUITABLE_OBJECTS
Definition Utils.hpp:71
#define CLI_SUCCESS
Definition Utils.hpp:42
#define CLI_PROCESS_NOT_COMPATIBLE
Definition Utils.hpp:60
#define CLI_UNSUPPORTED_OPERATION
Definition Utils.hpp:50
#define CLI_TRIANGLE_COUNT_EXCEEDS_LIMIT
Definition Utils.hpp:80
#define CLI_MIXED_FILAMENT_INVALID
Definition Utils.hpp:90
#define CLI_CONFIG_FILE_ERROR
Definition Utils.hpp:47
#define CLI_EXPORT_STL_ERROR
Definition Utils.hpp:54
#define CLI_FILAMENTS_DIFFERENT_TEMP
Definition Utils.hpp:83
#define CLI_OBJECT_COLLISION_IN_SEQ_PRINT
Definition Utils.hpp:84
#define CLI_INVALID_VALUES_IN_3MF
Definition Utils.hpp:61
#define CLI_SCALE_TO_FIT_ERROR
Definition Utils.hpp:53
#define CLI_FILAMENT_CAN_NOT_MAP
Definition Utils.hpp:87
#define CLI_GCODE_PATH_IN_UNPRINTABLE_AREA
Definition Utils.hpp:94
#define CLI_FILE_VERSION_NOT_SUPPORTED
Definition Utils.hpp:67
#define CLI_EXPORT_STATISTICS_ERROR
Definition Utils.hpp:68
#define CLI_ONLY_ONE_TPU_SUPPORTED
Definition Utils.hpp:88
#define CLI_EXPORT_3MF_ERROR
Definition Utils.hpp:56
#define CLI_FILE_NOTFOUND
Definition Utils.hpp:45
#define CLI_INVALID_PARAMS
Definition Utils.hpp:44
#define CLI_NO_SUITABLE_OBJECTS_AFTER_SKIP
Definition Utils.hpp:81
#define CLI_COPY_OBJECTS_ERROR
Definition Utils.hpp:52
#define CLI_OBJECTS_PARTLY_INSIDE
Definition Utils.hpp:73
#define CLI_FILAMENT_NOT_MATCH_BED_TYPE
Definition Utils.hpp:82
#define CLI_INVALID_PRINTER_TECH
Definition Utils.hpp:49
#define CLI_DATA_FILE_ERROR
Definition Utils.hpp:48
#define CLI_FILELIST_INVALID_ORDER
Definition Utils.hpp:46
#define CLI_SLICING_TIME_EXCEEDS_LIMIT
Definition Utils.hpp:79
#define CLI_VALIDATE_ERROR
Definition Utils.hpp:72
double SCALING_FACTOR
Definition libslic3r.cpp:3
#define scale_(val)
Definition libslic3r.h:106
#define SLIC3R_APP_FULL_NAME
Definition libslic3r.h:11
static constexpr double WIPE_TOWER_MARGIN
Definition libslic3r.h:100
T * begin(Slic3r::Mat< N, M, T > &mat)
Definition Point.hpp:838
T * end(Slic3r::Mat< N, M, T > &mat)
Definition Point.hpp:841
@ Custom
Definition CustomGCode.hpp:23
bool input_gcode
Definition GUI_Init.hpp:37
std::vector< std::string > input_files
Definition GUI_Init.hpp:29
int argc
Definition GUI_Init.hpp:21
arrangement::ArrangePolygon ArrangePolygon
Definition ArrangeJob.cpp:51
bool moved
Definition PartPlate.hpp:103
bool overlaps_objects
Definition PartPlate.hpp:104
DynamicPrintConfig extra_config
Definition GUI_Init.hpp:28
int GUI_Run(GUI_InitParams ¶ms)
Definition GUI_Init.cpp:34
GCodeProcessorResult GCodeResult
Definition PartPlate.hpp:98
char ** argv
Definition GUI_Init.hpp:22
std::vector< std::string > load_configs
Definition GUI_Init.hpp:27
std::vector< int > get_min_flush_volumes(const DynamicPrintConfig &full_config, size_t nozzle_id)
Definition Plater.cpp:1246
constexpr T deg2rad(const T angle)
Definition Geometry.hpp:312
void inspect_to_json(const Model &model, const std::vector< std::string > &source_paths, std::ostream &out, size_t max_planes)
Definition MeshInspect.cpp:30
void inspect_to_json(const Model &model, const std::vector< std::string > &source_paths, std::ostream &out)
Definition PaintCLI.cpp:137
time_t get_current_time_utc()
Definition Time.cpp:183
void update_arrange_params(ArrangeParams ¶ms, const DynamicPrintConfig *print_cfg, const ArrangePolygons &selected)
Definition Arrange.cpp:148
std::vector< ArrangePolygon > ArrangePolygons
Definition Arrange.hpp:126
void update_selected_items_inflation(ArrangePolygons &selected, const DynamicPrintConfig *print_cfg, ArrangeParams ¶ms)
Definition Arrange.cpp:163
void update_selected_items_axis_align(ArrangePolygons &selected, const DynamicPrintConfig *print_cfg, const ArrangeParams ¶ms)
Definition Arrange.cpp:234
Points get_shrink_bedpts(const DynamicPrintConfig *print_cfg, const ArrangeParams ¶ms)
Definition Arrange.cpp:339
void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const Points &bed, const ArrangeParams ¶ms)
Definition Arrange.cpp:1280
void update_unselected_items_inflation(ArrangePolygons &unselected, const DynamicPrintConfig *print_cfg, const ArrangeParams ¶ms)
Definition Arrange.cpp:213
void orient(OrientMeshs &arrangables, const OrientMeshs &excludes, const OrientParams ¶ms)
Orients the input polygons.
Definition Orient.cpp:613
int printable_width
Definition OrcaSlicer.hpp:35
zaa_minimize_perimeter_height ConfigOptionFloat
Definition PrintConfig.hpp:1954
void lay_on_face(ModelObject &object, size_t instance_idx, const Vec3d &normal)
Definition LayOnFace.cpp:233
void normalize_filament_values_to_variants(DynamicPrintConfig &config)
Definition PrintConfig.cpp:11431
std::vector< PlateData * > PlateDataPtrs
Definition bbs_3mf.hpp:278
ForwardCompatibilitySubstitutionRule
Definition Config.hpp:241
@ Enable
Definition Config.hpp:245
const int g_max_flush_volume
Definition FlushVolCalc.cpp:15
void release_PlateData_list(PlateDataPtrs &plate_data_list)
Definition bbs_3mf.cpp:9740
int find_plane_at_point(const std::vector< LayOnFacePlane > &planes, const Transform3d &instance_matrix_no_offset, const Vec3d &point, double tolerance)
Definition LayOnFace.cpp:185
bool is_compatible_with_printer(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_printer, const DynamicPrintConfig *extra_config)
Definition Preset.cpp:909
NozzleVolumeType
Definition PrintConfig.hpp:618
@ nvtHybrid
Definition PrintConfig.hpp:621
@ nvtStandard
Definition PrintConfig.hpp:619
bool has_any_mixed_filament(const std::vector< unsigned char > &is_mixed)
Definition FilamentMixer.cpp:486
bool unescape_strings_cstyle(const std::string &str, std::vector< std::string > &out)
Definition Config.cpp:173
AssembleListResult load_assemble_plate_list(const std::string &config_file, std::vector< assemble_plate_info_t > &assemble_plate_info_list, int max_plate_count)
Definition AssembleList.cpp:44
std::string get_extruder_variant_string(ExtruderType extruder_type, NozzleVolumeType nozzle_volume_type)
Definition PrintConfig.cpp:777
std::vector< ConfigSubstitution > ConfigSubstitutions
Definition Config.hpp:269
BoundingBox scaled(const BoundingBoxf &bb)
Definition BoundingBox.hpp:284
void set_filament_dev_options(DynamicPrintConfig &config, const std::vector< const DynamicPrintConfig * > &filament_configs)
Definition PrintConfig.cpp:11459
double height
Definition WipeTowerEstimate.hpp:22
zaa_minimize_perimeter_height nozzle_height((ConfigOptionStrings, extruder_colour))((ConfigOptionPoints
std::set< std::string > printer_options_with_variant_1
Definition PrintConfig.cpp:10236
Eigen::Matrix< double, 3, 1, Eigen::DontAlign > Vec3d
Definition Point.hpp:68
@ STRING_EXCEPT_LAYER_HEIGHT_EXCEEDS_LIMIT
Definition PrintBase.hpp:32
@ STRING_EXCEPT_OBJECT_COLLISION_IN_SEQ_PRINT
Definition PrintBase.hpp:30
@ STRING_EXCEPT_OBJECT_COLLISION_IN_LAYER_PRINT
Definition PrintBase.hpp:31
@ STRING_EXCEPT_FILAMENTS_DIFFERENT_TEMP
Definition PrintBase.hpp:29
@ STRING_EXCEPT_FILAMENT_NOT_MATCH_BED_TYPE
Definition PrintBase.hpp:28
int exclude_x
Definition OrcaSlicer.hpp:41
int printable_height
Definition OrcaSlicer.hpp:37
std::string printer_name
Definition OrcaSlicer.hpp:34
struct Slic3r::_printer_plate_info printer_plate_info_t
AssembleListResult
Definition AssembleList.hpp:48
@ ConfigError
Definition AssembleList.hpp:52
@ FileNotFound
Definition AssembleList.hpp:50
ArrangePolygon get_instance_arrange_poly(ModelInstance *instance, const Slic3r::DynamicPrintConfig &config)
Definition ModelArrange.cpp:135
printer_technology((ConfigOptionPoints, printable_area))((ConfigOptionFloat
ConfigOptionEnumsGenericTempl< false > ConfigOptionEnumsGeneric
Definition Config.hpp:2311
Eigen::Transform< double, 3, Eigen::Affine, Eigen::DontAlign > Transform3d
Definition Point.hpp:96
double brim_width
Definition WipeTowerEstimate.hpp:23
std::vector< std::map< NozzleVolumeType, int > > get_extruder_nozzle_stats(const std::vector< std::string > &strs)
Definition PrintConfig.cpp:940
layer_height((ConfigOptionInt, faded_layers))((ConfigOptionFloat
bool modified
Definition MeshRepair.hpp:20
BedType
Definition PrintConfig.hpp:507
@ btDefault
Definition PrintConfig.hpp:508
int find_largest_plane(const std::vector< LayOnFacePlane > &planes)
Definition LayOnFace.cpp:160
void duplicate(Model &model, Slic3r::arrangement::ArrangePolygons &copies, VirtualBedFn vfn)
Definition ModelArrange.cpp:77
std::set< std::string > filament_dev_options
Definition PrintConfig.cpp:10291
ConfigOptionIntsTempl< true > ConfigOptionIntsNullable
Definition Config.hpp:1155
PrinterTechnology
Definition Config.hpp:229
@ ptSLA
Definition Config.hpp:233
@ ptFFF
Definition Config.hpp:231
@ ptUnknown
Definition Config.hpp:235
zaa_minimize_perimeter_height filament_type((ConfigOptionBools, filament_soluble))((ConfigOptionStrings
std::vector< Vec2d > Pointfs
Definition Point.hpp:77
int exclude_y
Definition OrcaSlicer.hpp:42
std::vector< size_t > check_mixed_filament_type_consistency(const std::vector< unsigned char > &is_mixed, const std::vector< std::string > &comp_strs, const std::vector< std::string > &filament_types)
Definition FilamentMixer.cpp:564
Pointfs make_counter_clockwise(const Pointfs &pointfs)
Definition ClipperUtils.cpp:1568
int filaments_count
Definition AssembleList.hpp:40
void save_main_thread_id()
Definition Thread.cpp:206
int wrapping_y
Definition OrcaSlicer.hpp:47
bool arrange_objects(Model &model, const TBed &bed, const ArrangeParams ¶ms, VirtualBedFn vfn=throw_if_out_of_bed)
Definition ModelArrange.hpp:39
void resize_mixed_filament_metadata(DynamicPrintConfig &config, size_t old_slot_count, size_t new_slot_count)
Definition PrintConfig.cpp:11475
bool is_gcode_file(const std::string &path)
Definition utils.cpp:1208
std::string t_config_option_key
Definition Config.hpp:96
static void set_flush_volumes_matrix(std::vector< T > &out_matrix, const std::vector< T > &fv_matrix, size_t extruder_id=-1, size_t nozzle_nums=1)
Definition PrintConfig.hpp:2698
static std::set< std::string > gcodes_key_set
Definition PresetBundle.cpp:3121
nlohmann::json json
Definition AssembleList.cpp:42
ConfigOptionFloatsTempl< true > ConfigOptionFloatsNullable
Definition Config.hpp:1016
const ConfigOptionDef * opt_def
Definition Config.hpp:264
const int g_min_flush_volume_from_support
Definition FlushVolCalc.cpp:12
@ Preset
Definition calib.hpp:39
int wrapping_depth
Definition OrcaSlicer.hpp:45
std::string per_user_temp_id()
Definition utils.cpp:1514
static std::vector< T > get_flush_volumes_matrix(const std::vector< T > &fv_matrix, size_t extruder_id=-1, size_t nozzle_nums=1)
Definition PrintConfig.hpp:2685
@ tlSmooth
Definition PrintConfig.hpp:470
std::vector< std::string > t_config_option_keys
Definition Config.hpp:97
int exclude_width
Definition OrcaSlicer.hpp:39
void set_logging_level(unsigned int level)
Definition utils.cpp:171
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:582
bool set_current_thread_name(const char *thread_name)
Definition Thread.cpp:187
std::string old_value
Definition Config.hpp:265
double depth
Definition WipeTowerEstimate.hpp:21
bool need_arrange
Definition AssembleList.hpp:39
PrintSequence
Definition PrintConfig.hpp:310
@ ByObject
Definition PrintConfig.hpp:312
@ ByDefault
Definition PrintConfig.hpp:313
struct Slic3r::_assemble_plate_info assemble_plate_info_t
double width
Definition WipeTowerEstimate.hpp:20
std::string per_user_temp_dir(const std::string &base, const std::string &user_id)
Definition utils.cpp:1523
ConfigOptionIntsTempl< false > ConfigOptionInts
Definition Config.hpp:1154
int wrapping_width
Definition OrcaSlicer.hpp:44
static std::string bed_type_to_gcode_string(const BedType type)
Definition PrintConfig.hpp:701
zaa_minimize_perimeter_height nozzle_volume_type((ConfigOptionStrings, extruder_ams_count))((ConfigOptionStrings
ExtruderType
Definition PrintConfig.hpp:612
@ etDirectDrive
Definition PrintConfig.hpp:613
constexpr Eigen::Matrix< Tout, 2, EigenArgs... > unscaled(const Slic3r::Point &v) noexcept
Definition Arrange.cpp:81
ConfigOptionBoolsTempl< false > ConfigOptionBools
Definition Config.hpp:2066
ConfigOptionEnum< PrinterTechnology >
Definition PrintConfig.hpp:2358
std::vector< LayOnFacePlane > lay_on_face_planes(const ModelObject &object, const Transform3d &inst_matrix)
Definition LayOnFace.cpp:21
const std::string & resources_dir()
Definition utils.cpp:296
std::set< std::string > printer_options_with_variant_2
Definition PrintConfig.cpp:10270
std::set< std::string > empty_options
Definition PrintConfig.cpp:10289
ColorRGB to_rgb(const ColorRGBA &other_rgba)
Definition Color.cpp:406
const int g_flush_volume_to_support
Definition FlushVolCalc.cpp:13
Point normal(Point pt, double scale)
Definition TreeSupport.cpp:112
std::vector< Point, PointsAllocator< Point > > Points
Definition Point.hpp:73
SupportType
Definition PrintConfig.hpp:378
@ stTreeAuto
Definition PrintConfig.hpp:379
@ stNormalAuto
Definition PrintConfig.hpp:379
FilamentMapMode
Definition PrintConfig.hpp:632
@ fmmNozzleManual
Definition PrintConfig.hpp:636
@ fmmAutoForFlush
Definition PrintConfig.hpp:633
@ fmmManual
Definition PrintConfig.hpp:635
zaa_minimize_perimeter_height ConfigOptionString
Definition PrintConfig.hpp:1702
void export_gcode_statistics(const GCodeProcessorResult &result, const std::string &path)
Definition GCodeStatistics.cpp:190
@ ModelInstancePVS_Inside
Definition Model.hpp:1411
@ ModelInstancePVS_Partly_Outside
Definition Model.hpp:1413
T unscale(Q v)
Definition libslic3r.h:138
LoadStrategy
Definition bbs_3mf.hpp:218
@ LoadModel
Definition bbs_3mf.hpp:222
@ LoadConfig
Definition bbs_3mf.hpp:223
@ LoadAuxiliary
Definition bbs_3mf.hpp:224
@ AddDefaultInstances
Definition bbs_3mf.hpp:220
@ psI3
Definition PrintConfig.hpp:560
SupportMaterialStyle
Definition PrintConfig.hpp:362
@ smsDefault
Definition PrintConfig.hpp:363
@ smsTreeOrganic
Definition PrintConfig.hpp:363
struct Slic3r::_plate_obj_size_info plate_obj_size_info_t
void set_temporary_dir(const std::string &dir)
Definition utils.cpp:303
int find_plane_by_normal(const std::vector< LayOnFacePlane > &planes, const Vec3d &direction)
Definition LayOnFace.cpp:172
std::vector< ModelObject * > ModelObjectPtrs
Definition CutUtils.hpp:13
unsigned get_logging_level()
Definition utils.cpp:221
void set_logging_file(const std::string &file)
Definition utils.cpp:190
Eigen::Matrix< double, 2, 1, Eigen::DontAlign > Vec2d
Definition Point.hpp:67
@ wtwRectangle
Definition PrintConfig.hpp:606
zaa_minimize_perimeter_height time_cost((ConfigOptionString, layer_change_gcode))((ConfigOptionString
std::set< std::string > filament_options_with_variant
Definition PrintConfig.cpp:10150
@ Y
Definition libslic3r.h:142
@ Z
Definition libslic3r.h:143
@ X
Definition libslic3r.h:141
bool empty(const BoundingBoxBase< PointType, PointsType > &bb)
Definition BoundingBox.hpp:273
zaa_minimize_perimeter_height wipe_tower_y((ConfigOptionFloat, prime_tower_width))((ConfigOptionFloat
std::string escape_strings_cstyle(const std::vector< std::string > &strs)
Definition Config.cpp:99
std::set< std::string > print_options_with_variant
Definition PrintConfig.cpp:10102
ConfigOptionFloatsTempl< false > ConfigOptionFloats
Definition Config.hpp:1015
bool is_auto_filament_map_mode(FilamentMapMode mode)
Definition PrintConfig.hpp:649
Points get_bed_shape(const DynamicPrintConfig &config, bool use_share)
Definition PrintConfig.cpp:13837
int exclude_depth
Definition OrcaSlicer.hpp:40
std::string gcode_statistics_path(const std::string &gcode_path)
Definition GCodeStatistics.cpp:185
int printable_depth
Definition OrcaSlicer.hpp:36
int wrapping_x
Definition OrcaSlicer.hpp:46
ConfigOptionUniquePtr new_value
Definition Config.hpp:266
Slic3r::Polygon Polygon
Definition Emboss.cpp:101
RaycastManager::TrItems::iterator find(RaycastManager::TrItems &items, const RaycastManager::TrKey &key)
Definition RaycastManager.cpp:298
#define _u8L(s)
Definition I18N.hpp:11
int id
Definition ThumbnailData.hpp:51
float layer_height
Definition ThumbnailData.hpp:54
std::string name
Definition ThumbnailData.hpp:55
std::vector< coordf_t > bbox
Definition ThumbnailData.hpp:52
float area
Definition ThumbnailData.hpp:53
void from_json(const nlohmann::json &j)
Definition CustomGCode.cpp:33
std::vector< Item > gcodes
Definition CustomGCode.hpp:71
int error_code
Definition GCodeProcessor.hpp:177
GCodeCheckResult gcode_check_result
Definition GCodeProcessor.hpp:211
@ Ortho
Definition Camera.hpp:39
@ Iso
Definition Camera.hpp:44
@ Top_Plate
Definition Camera.hpp:53
std::string bed_type
Definition ThumbnailData.hpp:69
std::vector< BBoxData > bbox_objs
Definition ThumbnailData.hpp:63
std::vector< std::string > filament_colors
Definition ThumbnailData.hpp:65
bool is_seq_print
Definition ThumbnailData.hpp:66
std::vector< coordf_t > bbox_all
Definition ThumbnailData.hpp:62
std::vector< int > filament_ids
Definition ThumbnailData.hpp:64
float nozzle_diameter
Definition ThumbnailData.hpp:68
int first_extruder
Definition ThumbnailData.hpp:67
std::string no_light_thumbnail_file
Definition bbs_3mf.hpp:107
std::string pick_file
Definition bbs_3mf.hpp:110
ThumbnailData plate_thumbnail
Definition bbs_3mf.hpp:108
std::vector< size_t > skipped_objects
Definition bbs_3mf.hpp:121
std::vector< FilamentInfo > slice_filaments_info
Definition bbs_3mf.hpp:118
std::string printer_model_id
Definition bbs_3mf.hpp:99
std::string nozzle_diameters
Definition bbs_3mf.hpp:100
std::string top_file
Definition bbs_3mf.hpp:109
std::string thumbnail_file
Definition bbs_3mf.hpp:106
PrintStateBase::WarningLevel warning_level
Definition PrintBase.hpp:480
std::string text
Definition PrintBase.hpp:460
PrintStateBase::SlicingNotificationType message_type
Definition PrintBase.hpp:479
int warning_step
Definition PrintBase.hpp:477
unsigned int height
Definition ThumbnailData.hpp:19
unsigned int width
Definition ThumbnailData.hpp:18
void reset()
Definition ThumbnailData.cpp:78
bool is_valid() const
Definition ThumbnailData.cpp:85
bool align_to_y_axis
Definition Arrange.hpp:149
float printable_height
Definition Arrange.hpp:158
ArrangePolygons excluded_regions
Definition Arrange.hpp:168
float bed_shrink_y
Definition Arrange.hpp:151
Vec2d align_center
Definition Arrange.hpp:159
coord_t min_obj_distance
The minimum distance which is allowed for any pair of items on the print bed in any direction.
Definition Arrange.hpp:132
float clearance_radius
Definition Arrange.hpp:155
float bed_shrink_x
Definition Arrange.hpp:150
std::function< void(unsigned, std::string)> progressind
Progress indicator callback called when an object gets packed. The unsigned argument is the number of...
Definition Arrange.hpp:173
float clearance_height_to_lid
Definition Arrange.hpp:154
bool avoid_extrusion_cali_region
Definition Arrange.hpp:147
float nozzle_height
Definition Arrange.hpp:157
std::string to_json() const
Definition Arrange.hpp:185
bool is_seq_print
Definition Arrange.hpp:148
bool allow_rotations
Definition Arrange.hpp:141
bool allow_multi_materials_on_same_plate
Definition Arrange.hpp:146
float clearance_height_to_rod
Definition Arrange.hpp:153
bool is_wipe_tower
Definition Arrange.hpp:69
ExPolygon poly
Definition Arrange.hpp:59
void apply()
Helper function to call the setter with the arrange data arguments.
Definition Arrange.hpp:106
int itemid
Definition Arrange.hpp:81
Vec2crd translation
The 2D silhouette to be arranged.
Definition Arrange.hpp:60
std::function< void(const ArrangePolygon &)> setter
Optional setter function which can store arbitrary data in its closure.
Definition Arrange.hpp:103
double rotation
The translation of the poly.
Definition Arrange.hpp:61
int priority
To which logical bed does poly belong...
Definition Arrange.hpp:64
bool is_virt_object
Definition Arrange.hpp:67
std::string name
Definition Arrange.hpp:96
int bed_idx
Arrange with inflated polygon.
Definition Arrange.hpp:63