PrintBase.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. ///|/ Copyright (c) Prusa Research 2018 - 2023 Oleksandra Iushchenko @YuSanka, Pavel Mikuš @Godrak, Vojtěch Bubník @bubnikv, Roman Beránek @zavorka, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966
  2. ///|/
  3. ///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
  4. ///|/
  5. #include "Exception.hpp"
  6. #include "PrintBase.hpp"
  7. #include <boost/filesystem.hpp>
  8. #include <boost/lexical_cast.hpp>
  9. #include <regex>
  10. #include "I18N.hpp"
  11. namespace Slic3r
  12. {
  13. void PrintTryCancel::operator()() const
  14. {
  15. m_print->throw_if_canceled();
  16. }
  17. size_t PrintStateBase::g_last_timestamp = 0;
  18. // Update "scale", "input_filename", "input_filename_base" placeholders from the current m_objects.
  19. void PrintBase::update_object_placeholders(DynamicConfig &config, const std::string & /* default_output_ext */) const
  20. {
  21. // get the first input file name
  22. std::string input_file;
  23. std::vector<std::string> v_scale;
  24. int num_objects = 0;
  25. int num_instances = 0;
  26. for (const ModelObject *model_object : m_model.objects) {
  27. ModelInstance *printable = nullptr;
  28. for (ModelInstance *model_instance : model_object->instances)
  29. if (model_instance->is_printable()) {
  30. printable = model_instance;
  31. ++ num_instances;
  32. }
  33. if (printable) {
  34. ++ num_objects;
  35. // CHECK_ME -> Is the following correct ?
  36. v_scale.push_back("x:" + boost::lexical_cast<std::string>(printable->get_scaling_factor(X) * 100) +
  37. "% y:" + boost::lexical_cast<std::string>(printable->get_scaling_factor(Y) * 100) +
  38. "% z:" + boost::lexical_cast<std::string>(printable->get_scaling_factor(Z) * 100) + "%");
  39. if (input_file.empty())
  40. input_file = model_object->name.empty() ? model_object->input_file : model_object->name;
  41. }
  42. }
  43. config.set_key_value("num_objects", new ConfigOptionInt(num_objects));
  44. config.set_key_value("num_instances", new ConfigOptionInt(num_instances));
  45. config.set_key_value("scale", new ConfigOptionStrings(v_scale));
  46. if (! input_file.empty()) {
  47. // get basename with and without suffix
  48. const std::string input_filename = boost::filesystem::path(input_file).filename().string();
  49. const std::string input_filename_base = input_filename.substr(0, input_filename.find_last_of("."));
  50. // config.set_key_value("input_filename", new ConfigOptionString(input_filename_base + default_output_ext));
  51. config.set_key_value("input_filename_base", new ConfigOptionString(input_filename_base));
  52. }
  53. }
  54. // Generate an output file name based on the format template, default extension, and template parameters
  55. // (timestamps, object placeholders derived from the model, current placeholder prameters, print statistics - config_override)
  56. std::string PrintBase::output_filename(const std::string &format, const std::string &default_ext, const std::string &filename_base, const DynamicConfig *config_override) const
  57. {
  58. DynamicConfig cfg;
  59. if (config_override != nullptr)
  60. cfg = *config_override;
  61. cfg.set_key_value("version", new ConfigOptionString(std::string(SLIC3R_VERSION)));
  62. PlaceholderParser::update_timestamp(cfg);
  63. this->update_object_placeholders(cfg, default_ext);
  64. if (! filename_base.empty()) {
  65. // cfg.set_key_value("input_filename", new ConfigOptionString(filename_base + default_ext));
  66. cfg.set_key_value("input_filename_base", new ConfigOptionString(filename_base));
  67. }
  68. try {
  69. uint16_t extruder_initial = config_override->option("initial_extruder") != nullptr && config_override->option("initial_extruder")->type() == coInt ? config_override->option("initial_extruder")->get_int() : 0;
  70. boost::filesystem::path filepath = format.empty() ?
  71. cfg.opt_string("input_filename_base") + default_ext :
  72. this->placeholder_parser().process(format, extruder_initial, &cfg);
  73. //remove unwanted characters
  74. std::string forbidden_base;
  75. if (const ConfigOptionString* opt = this->placeholder_parser().external_config()->option<ConfigOptionString>("gcode_filename_illegal_char")) {
  76. forbidden_base = opt->value;
  77. }
  78. if (!forbidden_base.empty()) {
  79. const std::string filename_init = filepath.stem().string();
  80. std::string filename = filename_init;
  81. std::string extension = filepath.extension().string();
  82. //remove {print_time} and things like that that may be computed after, and re-put them inside it after the replace.
  83. std::regex placehoder = std::regex("\\{[a-z_]+\\}");
  84. std::smatch matches;
  85. std::string::const_iterator searchStart(filename_init.cbegin());
  86. while (std::regex_search(searchStart, filename_init.cend(), matches, placehoder)) {
  87. for (size_t i = 0; i < matches.size(); i++) {
  88. filename.replace(matches.position(i), matches.length(i), matches.length(i), '_');
  89. }
  90. searchStart = matches.suffix().first;
  91. }
  92. //remove unwanted characters from the cleaned string
  93. bool regexp_used = false;
  94. if (forbidden_base.front() == '(' || forbidden_base.front() == '[') {
  95. try {
  96. filename = std::regex_replace(filename, std::regex(forbidden_base), "_");
  97. regexp_used = true;
  98. }catch(std::exception){}
  99. }
  100. if (!regexp_used) {
  101. for(size_t i = 0; i < forbidden_base.size(); i++)
  102. std::replace(filename.begin(), filename.end(), forbidden_base.at(i), '_');
  103. }
  104. //re-put {print_time} and things like that
  105. searchStart = (filename_init.cbegin());
  106. while (std::regex_search(searchStart, filename_init.cend(), matches, placehoder)) {
  107. for (size_t i = 0; i < matches.size(); i++) {
  108. filename.replace(matches.position(i), matches.length(i), matches.str());
  109. }
  110. searchStart = matches.suffix().first;
  111. }
  112. // set the path var
  113. filepath = filename + extension;
  114. }
  115. if (filepath.extension().empty())
  116. filepath.replace_extension(default_ext);
  117. return filepath.string();
  118. } catch (std::runtime_error &err) {
  119. throw Slic3r::PlaceholderParserError(_u8L("Failed processing of the output_filename_format template.") + "\n" + err.what());
  120. }
  121. }
  122. std::string PrintBase::output_filepath(const std::string &path, const std::string &filename_base) const
  123. {
  124. // if we were supplied no path, generate an automatic one based on our first object's input file
  125. if (path.empty())
  126. // get the first input file name
  127. return (boost::filesystem::path(m_model.propose_export_file_name_and_path()).parent_path() / this->output_filename(filename_base)).make_preferred().string();
  128. // if we were supplied a directory, use it and append our automatically generated filename
  129. boost::filesystem::path p(path);
  130. if (boost::filesystem::is_directory(p))
  131. return (p / this->output_filename(filename_base)).make_preferred().string();
  132. // if we were supplied a file which is not a directory, use it
  133. return path;
  134. }
  135. void PrintBase::status_update_warnings(int step, PrintStateBase::WarningLevel /* warning_level */, const std::string &message, const PrintObjectBase* print_object)
  136. {
  137. if (m_status_callback) {
  138. auto status = print_object ? SlicingStatus(*print_object, step) : SlicingStatus(*this, step);
  139. m_status_callback(status);
  140. }
  141. else if (! message.empty())
  142. printf("%s warning: %s\n", print_object ? "print_object" : "print", message.c_str());
  143. }
  144. std::mutex& PrintObjectBase::state_mutex(PrintBase *print)
  145. {
  146. return print->state_mutex();
  147. }
  148. std::function<void()> PrintObjectBase::cancel_callback(PrintBase *print)
  149. {
  150. return print->cancel_callback();
  151. }
  152. void PrintObjectBase::status_update_warnings(PrintBase *print, int step, PrintStateBase::WarningLevel warning_level, const std::string &message)
  153. {
  154. print->status_update_warnings(step, warning_level, message, this);
  155. }
  156. } // namespace Slic3r