test_fan_mover.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. //#define CATCH_CONFIG_DISABLE
  2. #include <catch_main.hpp>
  3. #include "test_data.hpp"
  4. #include <libslic3r/GCode/FanMover.hpp>
  5. #include <libslic3r/ExtrusionEntity.hpp>
  6. #include <boost/algorithm/string.hpp>
  7. using namespace Slic3r;
  8. using namespace Slic3r::Geometry;
  9. using namespace Slic3r::Test;
  10. // note: F600: 10mm/s
  11. TEST_CASE("Simple gcode") {
  12. GCodeWriter writer;
  13. //what's used from the writer:
  14. writer.config.gcode_flavor.value = gcfMarlinFirmware;
  15. writer.config.gcode_comments.value = false;
  16. writer.config.fan_percentage.value = false; //0 -> 255
  17. //writer.tool[0] = nullptr;
  18. assert(writer.tool() == nullptr);
  19. assert(writer.get_tool(0) == nullptr);
  20. const std::string gcode = []() {
  21. std::string gcode;
  22. gcode += "M107\n";
  23. gcode += "G1 X0 Y0 F600\n"; // shouldn't move
  24. gcode += "G1 X20 Y0 E20\n"; // 2 sec
  25. gcode += "M106 S153\n"; // activate at 60%
  26. gcode += "G1 X40 Y0 E20\n"; // 2sec
  27. gcode += "M107\n"; // disable
  28. gcode += "G1 X60 Y0 E20\n"; // 2sec
  29. return gcode;
  30. }();
  31. SECTION("disable evrything")
  32. {
  33. Slic3r::FanMover fan_mover(writer,
  34. 0, // fan_speedup_time.value,
  35. false, // with_D_option
  36. true, // use_relative_e_distances.value,
  37. false, // fan_speedup_overhangs.value,
  38. 0 // fan_kickstart.value));
  39. );
  40. std::string processed_gcode = fan_mover.process_gcode(gcode, true);
  41. REQUIRE(gcode == processed_gcode);
  42. }
  43. SECTION("only kickstart 1sec")
  44. {
  45. Slic3r::FanMover fan_mover(writer,
  46. 0, // fan_speedup_time.value,
  47. false, // with_D_option
  48. true, // use_relative_e_distances.value,
  49. false, // fan_speedup_overhangs.value,
  50. 1 // fan_kickstart.value));
  51. );
  52. const std::string processed_gcode = fan_mover.process_gcode(gcode, true);
  53. std::string wanted_gcode;
  54. wanted_gcode += "M107\n";
  55. wanted_gcode += "G1 X0 Y0 F600\n"; //shouldn't move
  56. wanted_gcode += "G1 X20 Y0 E20\n"; // 2 sec
  57. wanted_gcode += "M106 S255\n"; //activate with kickstart
  58. wanted_gcode += "G1 X26 Y0 E6\n"; // 1*0.6 = 0.6sec
  59. wanted_gcode += "M106 S153\n"; //go to good speed 60% of 1 second
  60. wanted_gcode += "G1 X40 Y0 E14\n"; // 2 - 1*0.6 = 1.4sec
  61. wanted_gcode += "M107\n"; //disable
  62. wanted_gcode += "G1 X60 Y0 E20\n"; // 2sec
  63. REQUIRE(wanted_gcode == processed_gcode);
  64. }
  65. SECTION("only speedup 1sec")
  66. {
  67. Slic3r::FanMover fan_mover(writer,
  68. 1, // fan_speedup_time.value,
  69. false, // with_D_option
  70. true, // use_relative_e_distances.value,
  71. false, // fan_speedup_overhangs.value,
  72. 0 // fan_kickstart.value));
  73. );
  74. std::string processed_gcode = fan_mover.process_gcode(gcode, true);
  75. std::string wanted_gcode;
  76. wanted_gcode += "M107\n";
  77. wanted_gcode += "G1 X0 Y0 F600\n"; //shouldn't move
  78. wanted_gcode += "G1 X10 Y0 E10\n"; // 1 sec
  79. wanted_gcode += "M106 S153\n"; //activate
  80. wanted_gcode += "G1 X20 Y0 E10\n"; // 1 sec
  81. wanted_gcode += "G1 X40 Y0 E20\n"; // 2sec
  82. wanted_gcode += "M107\n"; //disable
  83. wanted_gcode += "G1 X60 Y0 E20\n"; // 2sec
  84. REQUIRE(wanted_gcode == processed_gcode);
  85. }
  86. SECTION("speedup deactivated on not-overhangs")
  87. {
  88. Slic3r::FanMover fan_mover(writer,
  89. 1, // fan_speedup_time.value,
  90. false, // with_D_option
  91. true, // use_relative_e_distances.value,
  92. true, // fan_speedup_overhangs.value,
  93. 0 // fan_kickstart.value));
  94. );
  95. std::string type_not_overhang;
  96. SECTION("erNone") { type_not_overhang = std::string(";TYPE:") + ExtrusionEntity::role_to_string(ExtrusionRole::erNone) + "\n"; }
  97. SECTION("erPerimeter") { type_not_overhang = std::string(";TYPE:") + ExtrusionEntity::role_to_string(ExtrusionRole::erPerimeter) + "\n"; }
  98. SECTION("erExternalPerimeter") { type_not_overhang = std::string(";TYPE:") + ExtrusionEntity::role_to_string(ExtrusionRole::erExternalPerimeter) + "\n"; }
  99. SECTION("erInternalInfill") { type_not_overhang = std::string(";TYPE:") + ExtrusionEntity::role_to_string(ExtrusionRole::erInternalInfill) + "\n"; }
  100. SECTION("erSolidInfill") { type_not_overhang = std::string(";TYPE:") + ExtrusionEntity::role_to_string(ExtrusionRole::erSolidInfill) + "\n"; }
  101. SECTION("erTopSolidInfill") { type_not_overhang = std::string(";TYPE:") + ExtrusionEntity::role_to_string(ExtrusionRole::erTopSolidInfill) + "\n"; }
  102. SECTION("erBridgeInfill") { type_not_overhang = std::string(";TYPE:") + ExtrusionEntity::role_to_string(ExtrusionRole::erBridgeInfill) + "\n"; } //note: bridge infill isn't overhang
  103. SECTION("erInternalBridgeInfill") { type_not_overhang = std::string(";TYPE:") + ExtrusionEntity::role_to_string(ExtrusionRole::erInternalBridgeInfill) + "\n"; }
  104. SECTION("erThinWall") { type_not_overhang = std::string(";TYPE:") + ExtrusionEntity::role_to_string(ExtrusionRole::erThinWall) + "\n"; }
  105. SECTION("erGapFill") { type_not_overhang = std::string(";TYPE:") + ExtrusionEntity::role_to_string(ExtrusionRole::erGapFill) + "\n"; }
  106. SECTION("erSkirt") { type_not_overhang = std::string(";TYPE:") + ExtrusionEntity::role_to_string(ExtrusionRole::erSkirt) + "\n"; }
  107. SECTION("erSupportMaterial") { type_not_overhang = std::string(";TYPE:") + ExtrusionEntity::role_to_string(ExtrusionRole::erSupportMaterial) + "\n"; }
  108. SECTION("erSupportMaterialInterface") { type_not_overhang = std::string(";TYPE:") + ExtrusionEntity::role_to_string(ExtrusionRole::erSupportMaterialInterface) + "\n"; }
  109. SECTION("erWipeTower") { type_not_overhang = std::string(";TYPE:") + ExtrusionEntity::role_to_string(ExtrusionRole::erWipeTower) + "\n"; }
  110. SECTION("erMilling") { type_not_overhang = std::string(";TYPE:") + ExtrusionEntity::role_to_string(ExtrusionRole::erMilling) + "\n"; }
  111. SECTION("erCustom") { type_not_overhang = std::string(";TYPE:") + ExtrusionEntity::role_to_string(ExtrusionRole::erCustom) + "\n"; }
  112. SECTION("erMixed") { type_not_overhang = std::string(";TYPE:") + ExtrusionEntity::role_to_string(ExtrusionRole::erMixed) + "\n"; }
  113. SECTION("erTravel") { type_not_overhang = std::string(";TYPE:") + ExtrusionEntity::role_to_string(ExtrusionRole::erTravel) + "\n"; }
  114. std::string processed_gcode = fan_mover.process_gcode(type_not_overhang + gcode, true);
  115. REQUIRE(type_not_overhang + gcode == processed_gcode);
  116. }
  117. SECTION("speedup activated on overhangs")
  118. {
  119. Slic3r::FanMover fan_mover(writer,
  120. 1, // fan_speedup_time.value,
  121. false, // with_D_option
  122. true, // use_relative_e_distances.value,
  123. true, // fan_speedup_overhangs.value,
  124. 0 // fan_kickstart.value));
  125. );
  126. std::string type_overhang;
  127. SECTION("erOverhangPerimeter") { type_overhang = std::string(";TYPE:") + ExtrusionEntity::role_to_string(ExtrusionRole::erOverhangPerimeter) + "\n"; }
  128. std::string processed_gcode = fan_mover.process_gcode(type_overhang + gcode, true);
  129. std::string wanted_gcode;
  130. wanted_gcode += "M107\n";
  131. wanted_gcode += "G1 X0 Y0 F600\n"; //shouldn't move
  132. wanted_gcode += "G1 X10 Y0 E10\n"; // 1 sec
  133. wanted_gcode += "M106 S153\n"; //activate
  134. wanted_gcode += "G1 X20 Y0 E10\n"; // 1 sec
  135. wanted_gcode += "G1 X40 Y0 E20\n"; // 2sec
  136. wanted_gcode += "M107\n"; //disable
  137. wanted_gcode += "G1 X60 Y0 E20\n"; // 2sec
  138. REQUIRE(type_overhang + wanted_gcode == processed_gcode);
  139. }
  140. SECTION("erase double M107")
  141. {
  142. Slic3r::FanMover fan_mover(writer,
  143. 0, // fan_speedup_time.value,
  144. false, // with_D_option
  145. true, // use_relative_e_distances.value,
  146. false, // fan_speedup_overhangs.value,
  147. 0 // fan_kickstart.value));
  148. );
  149. std::string m107 = "M107\n";
  150. std::string processed_gcode = fan_mover.process_gcode(m107+gcode+m107, false);
  151. processed_gcode += fan_mover.process_gcode(gcode+m107, true);
  152. REQUIRE(gcode+gcode.substr(5) == processed_gcode); // substr to remove first m107
  153. }
  154. SECTION("erase M107-like M106 -> M107")
  155. {
  156. Slic3r::FanMover fan_mover(writer,
  157. 0, // fan_speedup_time.value,
  158. false, // with_D_option
  159. true, // use_relative_e_distances.value,
  160. false, // fan_speedup_overhangs.value,
  161. 0 // fan_kickstart.value));
  162. );
  163. std::string m106 = "M106 S0\n";
  164. std::string processed_gcode = fan_mover.process_gcode(gcode+m106, false);
  165. processed_gcode += fan_mover.process_gcode(gcode, true);
  166. REQUIRE(gcode+gcode.substr(5) == processed_gcode); // substr to remove first m107
  167. }
  168. //TODO?
  169. //SECTION("erase M106 -> M107")
  170. //{
  171. // Slic3r::FanMover fan_mover(writer,
  172. // 0, // fan_speedup_time.value,
  173. // false, // with_D_option
  174. // true, // use_relative_e_distances.value,
  175. // false, // fan_speedup_overhangs.value,
  176. // 0 // fan_kickstart.value));
  177. // );
  178. // std::string m106 = "M106 S125\n";
  179. // std::string processed_gcode = fan_mover.process_gcode(m106+gcode+m106, false);
  180. // processed_gcode += fan_mover.process_gcode(gcode, true);
  181. // REQUIRE(gcode+m106 == processed_gcode); // substr to remove first m107
  182. //}
  183. }
  184. TEST_CASE("Simple gcode (absoute)")
  185. {
  186. GCodeWriter writer;
  187. // what's used from the writer:
  188. writer.config.gcode_flavor.value = gcfMarlinFirmware;
  189. writer.config.gcode_comments.value = false;
  190. writer.config.fan_percentage.value = false; // 0 -> 255
  191. // writer.tool[0] = nullptr;
  192. assert(writer.tool() == nullptr);
  193. assert(writer.get_tool(0) == nullptr);
  194. const std::string gcode = []() {
  195. std::string gcode;
  196. gcode += "M107\n";
  197. gcode += "G1 X0 Y0 F600\n"; // shouldn't move
  198. gcode += "G1 X20 Y0 E20\n"; // 2 sec
  199. gcode += "M106 S153\n"; // activate at 60%
  200. gcode += "G1 X40 Y0 E40\n"; // 2sec
  201. gcode += "M107\n"; // disable
  202. gcode += "G1 X60 Y0 E60\n"; // 2sec
  203. return gcode;
  204. }();
  205. SECTION("disable evrything")
  206. {
  207. Slic3r::FanMover fan_mover(writer,
  208. 0, // fan_speedup_time.value,
  209. false, // with_D_option
  210. false, // use_relative_e_distances.value,
  211. false, // fan_speedup_overhangs.value,
  212. 0 // fan_kickstart.value));
  213. );
  214. std::string processed_gcode = fan_mover.process_gcode(gcode, true);
  215. REQUIRE(gcode == processed_gcode);
  216. }
  217. SECTION("only kickstart 1sec")
  218. {
  219. Slic3r::FanMover fan_mover(writer,
  220. 0, // fan_speedup_time.value,
  221. false, // with_D_option
  222. false, // use_relative_e_distances.value,
  223. false, // fan_speedup_overhangs.value,
  224. 1 // fan_kickstart.value));
  225. );
  226. const std::string processed_gcode = fan_mover.process_gcode(gcode, true);
  227. std::string wanted_gcode;
  228. wanted_gcode += "M107\n";
  229. wanted_gcode += "G1 X0 Y0 F600\n"; //shouldn't move
  230. wanted_gcode += "G1 X20 Y0 E20\n"; // 2 sec
  231. wanted_gcode += "M106 S255\n"; //activate with kickstart
  232. wanted_gcode += "G1 X26 Y0 E26\n"; // 1*0.6 = 0.6sec
  233. wanted_gcode += "M106 S153\n"; //go to good speed 60% of 1 second
  234. wanted_gcode += "G1 X40 Y0 E40\n"; // 2 - 1*0.6 = 1.4sec
  235. wanted_gcode += "M107\n"; //disable
  236. wanted_gcode += "G1 X60 Y0 E60\n"; // 2sec
  237. REQUIRE(wanted_gcode == processed_gcode);
  238. }
  239. SECTION("only speedup 1sec")
  240. {
  241. Slic3r::FanMover fan_mover(writer,
  242. 1, // fan_speedup_time.value,
  243. false, // with_D_option
  244. false, // use_relative_e_distances.value,
  245. false, // fan_speedup_overhangs.value,
  246. 0 // fan_kickstart.value));
  247. );
  248. std::string processed_gcode = fan_mover.process_gcode(gcode, true);
  249. std::string wanted_gcode;
  250. wanted_gcode += "M107\n";
  251. wanted_gcode += "G1 X0 Y0 F600\n"; //shouldn't move
  252. wanted_gcode += "G1 X10 Y0 E10\n"; // 1 sec
  253. wanted_gcode += "M106 S153\n"; //activate
  254. wanted_gcode += "G1 X20 Y0 E20\n"; // 1 sec
  255. wanted_gcode += "G1 X40 Y0 E40\n"; // 2sec
  256. wanted_gcode += "M107\n"; //disable
  257. wanted_gcode += "G1 X60 Y0 E60\n"; // 2sec
  258. REQUIRE(wanted_gcode == processed_gcode);
  259. }
  260. }
  261. //TODO: complex gcode
  262. ////////////// issue 4061: G2/G3: currently, it can't split g2/G3 (TODO)
  263. TEST_CASE("G2/G3 gcode")
  264. {
  265. auto create_gcode =
  266. [](bool remove_useless, bool move_useful) -> std::string {
  267. std::string s = ";LAYER_CHANGE\n";
  268. s += ";Z:18.4\n";
  269. s += ";HEIGHT:0.199999\n";
  270. s += "G92 E0\n";
  271. s += "G10 ; retract\n";
  272. s += "; stop printing object Star_face.stl id:0 copy 0\n";
  273. s += "EXCLUDE_OBJECT_END NAME=Star_face_stl_id_0_copy_0\n";
  274. s += "M204 S10000\n";
  275. s += "G1 Z18.4 F1800\n";
  276. s += "G92 E0\n";
  277. s += "; printing object Star_face.stl id:0 copy 0\n";
  278. s += "EXCLUDE_OBJECT_START NAME=Star_face_stl_id_0_copy_0\n";
  279. s += "; acceleration to travel\n";
  280. s += "G1 X163.229 Y127.604 F18000\n";
  281. s += "G1 X146.967 Y135.013\n";
  282. s += "G1 X146.61 Y135.175\n";
  283. s += "G1 X123.351 Y145.771\n";
  284. s += "G1 X122.18 Y146.428\n";
  285. s += "; decel to extrusion\n";
  286. s += "M204 S5000\n";
  287. s += "G1 X118.537 Y148.471\n";
  288. s += "G1 X117.236 Y148.733\n";
  289. s += "G1 X116.744 Y148.781\n";
  290. s += "G1 X116.452 Y148.95\n";
  291. s += "; end travel\n";
  292. s += "G11 ; unretract\n";
  293. s += "G92 E0\n";
  294. s += ";TYPE:External perimeter\n";
  295. s += ";WIDTH:0.698815\n";
  296. s += "M106 S25.5\n";
  297. s += "G1 F4650\n";
  298. s += "G1 X115.957 Y148.975 E0.02567\n";
  299. s += "G3 X105.872 Y142.185 I-.066 J-10.787 E.69483\n";
  300. s += "G1 X105.745 Y141.815 E0.71508\n";
  301. s += "G3 X106.128 Y133.713 I10.705 J-3.555 E1.14496\n";
  302. if(!remove_useless) s += "M106 S25.5\n";
  303. s += ";WIDTH:0.728025\n";
  304. if(!remove_useless) s += "M106 S25.5\n";
  305. s += "G3 X108.063 Y130.539 I11.385 J4.764 E1.34692\n";
  306. if(!remove_useless) s += "M106 S25.5\n";
  307. s += ";WIDTH:0.75984\n";
  308. if(!remove_useless) s += "M106 S25.5\n";
  309. s += "G3 X112.6 Y127.602 I6.872 J5.643 E1.65789\n";
  310. if(!remove_useless) s += "M106 S25.5\n";
  311. s += ";WIDTH:0.789218\n";
  312. if(!remove_useless) s += "M106 S25.5\n";
  313. s += "G3 X125.102 Y132.013 I3.494 J10.021 E2.50206\n";
  314. if(!remove_useless) s += "M106 S25.5\n";
  315. s += ";WIDTH:0.755247\n";
  316. if(!remove_useless) s += "M106 S25.5\n";
  317. s += "G3 X126.771 Y137.462 I-9.904 J6.012 E2.82604\n";
  318. if(!remove_useless) s += "M106 S25.5\n";
  319. if(!remove_useless) s += "M106 S25.5\n";
  320. s += "G1 X126.775 Y137.806 E2.84539\n";
  321. if(!remove_useless) s += "M106 S25.5\n";
  322. s += ";WIDTH:0.727549\n";
  323. if(!remove_useless) s += "M106 S25.5\n";
  324. s += "G3 X123.57 Y145.764 I-11.051 J.175 E3.32189\n";
  325. if(!remove_useless) s += "M106 S25.5\n";
  326. s += ";WIDTH:0.698815\n";
  327. if(!remove_useless) s += "M106 S25.5\n";
  328. s += "G3 X116.606 Y148.952 I-7.679 J-7.576 E3.72755\n";
  329. s += "G1 X116.527 Y148.951 E3.73167\n";
  330. if(!remove_useless) s += "M106 S25.5\n";
  331. s += ";WIPE_START\n";
  332. s += "M204 S10000\n";
  333. s += "G1 X116.189 Y148.524 F18000\n";
  334. s += ";WIPE_END\n";
  335. s += "; acceleration to travel\n";
  336. s += "G1 X115.678 Y148.359\n";
  337. s += "; decel to extrusion\n";
  338. s += "M204 S5000\n";
  339. s += "G1 X115.422 Y148.276\n";
  340. s += "; end travel\n";
  341. s += ";WIDTH:0.720254\n";
  342. if(!remove_useless) s += "M106 S25.5\n";
  343. s += "G1 F4650\n";
  344. s += "G1 X116.001 Y148.314 E3.76269\n";
  345. s += "G2 X122.624 Y145.725 I-.12 J-10.072 E4.15158\n";
  346. s += "G2 X123.751 Y144.568 I-8.904 J-9.799 E4.23803\n";
  347. if(!remove_useless) s += "M106 S25.5\n";
  348. s += ";WIDTH:0.748162\n";
  349. if(!remove_useless) s += "M106 S25.5\n";
  350. s += "G2 X126.066 Y137.801 I-7.967 J-6.506 E4.64496\n";
  351. if(!remove_useless) s += "M106 S25.5\n";
  352. s += ";WIDTH:0.77744\n";
  353. if(!remove_useless) s += "M106 S25.5\n";
  354. s += "G2 X124.935 Y133.225 I-11.113 J.321 E4.92054\n";
  355. if(!remove_useless) s += "M106 S25.5\n";
  356. s += ";WIDTH:0.805275\n";
  357. if(!remove_useless) s += "M106 S25.5\n";
  358. s += "G2 X119.271 Y128.291 I-8.81 J4.395 E5.38463\n";
  359. if(!remove_useless) s += "M106 S25.5\n";
  360. s += ";WIDTH:0.773006\n";
  361. if(!remove_useless) s += "M106 S25.5\n";
  362. s += "G2 X113.961 Y127.995 I-3.206 J9.712 E5.69495\n";
  363. if(!remove_useless) s += "M106 S25.5\n";
  364. s += ";WIDTH:0.76111\n";
  365. if(!remove_useless) s += "M106 S25.5\n";
  366. s += "G1 X113.76 Y128.037 E5.70656\n";
  367. s += "G2 X110.376 Y129.391 I2.27 J10.575 E5.91434\n";
  368. if(!remove_useless) s += "M106 S25.5\n";
  369. s += ";WIDTH:0.728025\n";
  370. if(!remove_useless) s += "M106 S25.5\n";
  371. s += "G2 X108.025 Y131.708 I5.15 J7.579 E6.09394\n";
  372. if(!remove_useless) s += "M106 S25.5\n";
  373. s += ";WIDTH:0.692664\n";
  374. if(!remove_useless) s += "M106 S25.5\n";
  375. s += "G2 X105.869 Y139.349 I8.98 J6.658 E6.51053\n";
  376. if(!remove_useless) s += "M106 S25.5\n";
  377. s += ";WIDTH:0.720254\n";
  378. if(!remove_useless) s += "M106 S25.5\n";
  379. s += "G2 X115.208 Y148.292 I10.012 J-1.107 E7.26171\n";
  380. s += "G1 X115.348 Y148.282 E7.26918\n";
  381. if(!remove_useless) s += "M106 S25.5\n";
  382. s += ";WIPE_START\n";
  383. s += "M204 S10000\n";
  384. s += "G1 X115.664 Y148.713 F18000\n";
  385. s += ";WIPE_END\n";
  386. s += "G92 E0\n";
  387. s += "G10 ; retract\n";
  388. s += "; acceleration to travel\n";
  389. s += "G1 X115.662 Y148.808\n";
  390. s += "G1 X120.932 Y147.524\n";
  391. s += "G1 X121.226 Y147.362\n";
  392. s += "G1 X150.16 Y140.336\n";
  393. s += "; decel to extrusion\n";
  394. s += "M204 S5000\n";
  395. s += "G1 X156.209 Y138.866\n";
  396. s += "G1 X156.22 Y138.976\n";
  397. s += "; end travel\n";
  398. s += "G11 ; unretract\n";
  399. s += ";WIDTH:0.649924\n";
  400. if(!remove_useless) s += "M106 S25.5\n";
  401. s += "G1 F4650\n";
  402. s += "G1 X155.801 Y139.034 E0.02026\n";
  403. s += "G3 X153.702 Y138.948 I-.587 J-11.382 E.12117\n";
  404. s += "G3 X152.849 Y138.822 I.823 J-8.513 E.16252\n";
  405. if(!remove_useless) s += "M106 S25.5\n";
  406. s += ";WIDTH:0.683858\n";
  407. if(!remove_useless) s += "M106 S25.5\n";
  408. s += "G3 X145.878 Y134.51 I2.171 J-11.301 E.58686\n";
  409. if(!remove_useless) s += "M106 S25.5\n";
  410. s += ";WIDTH:0.711771\n";
  411. if(!remove_useless) s += "M106 S25.5\n";
  412. s += "G3 X143.804 Y130.663 I9.809 J-7.768 E.81894\n";
  413. if(!remove_useless) s += "M106 S25.5\n";
  414. s += ";WIDTH:0.74297\n";
  415. if(!remove_useless) s += "M106 S25.5\n";
  416. s += "G3 X148.219 Y117.616 I10.583 J-3.69 E1.63918\n";
  417. if(!remove_useless) s += "M106 S25.5\n";
  418. s += ";WIDTH:0.711031\n";
  419. if(!remove_useless) s += "M106 S25.5\n";
  420. s += "G3 X152.826 Y115.811 I6.908 J10.85 E1.90195\n";
  421. if(!remove_useless) s += "M106 S25.5\n";
  422. s += ";WIDTH:0.680045\n";
  423. if(!remove_useless) s += "M106 S25.5\n";
  424. s += "G3 X154.402 Y115.729 I1.097 J5.903 E1.9816\n";
  425. if(!remove_useless) s += "M106 S25.5\n";
  426. s += ";WIDTH:0.643995\n";
  427. if(!remove_useless) s += "M106 S25.5\n";
  428. s += "G3 X157.534 Y116.615 I-.943 J9.313 E2.13698\n";
  429. s += "G3 X165.073 Y124.528 I-4.996 J12.307 E2.67179\n";
  430. s += "G1 X165.155 Y124.808 E2.68563\n";
  431. s += "G3 X165.6 Y127.286 I-12.334 J3.496 E2.80535\n";
  432. if(!remove_useless) s += "M106 S25.5\n";
  433. s += ";WIDTH:0.649924\n";
  434. if(!remove_useless) s += "M106 S25.5\n";
  435. s += "G1 X165.609 Y127.779 E2.82901\n";
  436. s += "G3 X163.67 Y134.419 I-11.681 J.192 E3.1657\n";
  437. s += "G3 X161.835 Y136.929 I-6.919 J-3.132 E3.31587\n";
  438. s += "G3 X156.616 Y138.963 I-6.621 J-9.277 E3.58724\n";
  439. s += "G1 X156.295 Y138.974 E3.60263\n";
  440. if(!remove_useless) s += "M106 S25.5\n";
  441. s += ";WIPE_START\n";
  442. s += "M204 S10000\n";
  443. s += "G1 X155.927 Y138.571 F18000\n";
  444. s += ";WIPE_END\n";
  445. s += "M204 S5000\n";
  446. s += "G1 X155.863 Y138.403\n";
  447. s += ";WIDTH:0.638248\n";
  448. if(!remove_useless) s += "M106 S25.5\n";
  449. s += "G1 F4650\n";
  450. s += "G1 X155.909 Y138.419 E3.60495\n";
  451. s += "G2 X161.549 Y136.388 I-.727 J-10.866 E3.89052\n";
  452. s += "G2 X163.15 Y134.126 I-4.753 J-5.062 E4.02169\n";
  453. s += "G2 X164.82 Y125.892 I-9.372 J-6.188 E4.42665\n";
  454. s += "G1 X164.74 Y125.556 E4.4429\n";
  455. s += "G2 X159.719 Y118.49 I-11.601 J2.927 E4.86006\n";
  456. if(!remove_useless) s += "M106 S25.5\n";
  457. s += ";WIDTH:0.667068\n";
  458. if(!remove_useless) s += "M106 S25.5\n";
  459. s += "G2 X154.678 Y116.365 I-7.59 J10.96 E5.13167\n";
  460. if (move_useful) {
  461. s += "G1 X154.511 Y116.36 E5.13992\n";
  462. s += "M106 S140.25\n";
  463. }
  464. s += "G1 X154.256 Y116.352 E5.15251\n";
  465. if(!remove_useless) s += "M106 S25.5\n";
  466. s += ";WIDTH:0.707201\n";
  467. if(!remove_useless) s += "M106 S25.5\n";
  468. s += "G2 X152.007 Y116.669 I.061 J8.587 E5.27203\n";
  469. if(!remove_useless) s += "M106 S25.5\n";
  470. s += ";WIDTH:0.741124\n";
  471. if(!remove_useless) s += "M106 S25.5\n";
  472. s += "G2 X143.911 Y126.283 I2.509 J10.329 E6.01375\n";
  473. if(!remove_useless) s += "M106 S25.5\n";
  474. s += ";WIDTH:0.713385\n";
  475. if(!remove_useless) s += "M106 S25.5\n";
  476. s += "G2 X144.261 Y129.843 I10.983 J.716 E6.20405\n";
  477. if(!remove_useless) s += "M106 S25.5\n";
  478. s += ";WIDTH:0.681374\n";
  479. if(!remove_useless) s += "M106 S25.5\n";
  480. s += "G2 X146.03 Y133.648 I11.334 J-2.956 E6.41684\n";
  481. if(!remove_useless) s += "M106 S25.5\n";
  482. s += ";WIDTH:0.649924\n";
  483. if(!remove_useless) s += "M106 S25.5\n";
  484. s += "G2 X153.408 Y138.302 I9.116 J-6.276 E6.84676\n";
  485. if(!remove_useless) s += "M106 S25.5\n";
  486. s += ";WIDTH:0.638248\n";
  487. if(!remove_useless) s += "M106 S25.5\n";
  488. s += "G1 X153.561 Y138.322 E6.85401\n";
  489. s += "G2 X155.003 Y138.441 I1.621 J-10.769 E6.9221\n";
  490. s += "G1 X155.788 Y138.406 E6.95905\n";
  491. if(!remove_useless) s += "M106 S25.5\n";
  492. s += ";WIPE_START\n";
  493. s += "M204 S10000\n";
  494. s += "G1 X156.022 Y138.877 F18000\n";
  495. s += ";WIPE_END\n";
  496. s += "G92 E0\n";
  497. s += "G10 ; retract\n";
  498. s += "; acceleration to travel\n";
  499. s += "G1 X155.991 Y138.508\n";
  500. s += "G1 X163.054 Y127.686\n";
  501. s += "G1 X163.042 Y127.702\n";
  502. s += "; decel to extrusion\n";
  503. s += "M204 S500\n";
  504. s += "G1 X162.795 Y128.055\n";
  505. s += "; end travel\n";
  506. s += "G11 ; unretract\n";
  507. s += ";TYPE:Overhang perimeter\n";
  508. s += ";WIDTH:0.542919\n";
  509. s += ";HEIGHT:0.5\n";
  510. if(!move_useful) s += "M106 S140.25\n";
  511. s += "G1 F1800\n";
  512. s += "G3 X163.624 Y127.86 I.327 J-.467 E.10369\n";
  513. s += "G3 X163.258 Y128.142 I-.531 J-.312 E.1224\n";
  514. s += "G3 X162.86 Y128.094 I-.135 J-.555 E.13857\n";
  515. s += "M106 S25.5\n";
  516. s += "; acceleration to travel\n";
  517. s += "M204 S10000\n";
  518. s += "G1 X163.052 Y127.812 F18000\n";
  519. s += "; decel to extrusion\n";
  520. s += "M204 S5000\n";
  521. s += "G1 X163.2 Y127.595\n";
  522. s += "; end travel\n";
  523. s += ";TYPE:Internal perimeter\n";
  524. s += ";WIDTH:0.702708\n";
  525. s += ";HEIGHT:0.2\n";
  526. if(!remove_useless) s += "M106 S25.5\n";
  527. s += "G1 F4650\n";
  528. s += "G3 X163.159 Y127.523 I-.077 J-.003 E.15938\n";
  529. if(!remove_useless) s += "M106 S25.5\n";
  530. return s;
  531. };
  532. const std::string gcode = create_gcode(false, false);
  533. //"M106 S25.5\n";
  534. GCodeWriter writer;
  535. // what's used from the writer:
  536. writer.config.gcode_flavor.value = gcfMarlinFirmware;
  537. writer.config.gcode_comments.value = false;
  538. writer.config.fan_percentage.value = false; // 0 -> 255
  539. // writer.tool[0] = nullptr;
  540. assert(writer.tool() == nullptr);
  541. assert(writer.get_tool(0) == nullptr);
  542. SECTION("disable evrything")
  543. {
  544. Slic3r::FanMover fan_mover(writer,
  545. 0, // fan_speedup_time.value,
  546. false, // with_D_option
  547. false, // use_relative_e_distances.value,
  548. false, // fan_speedup_overhangs.value,
  549. 0 // fan_kickstart.value));
  550. );
  551. std::string processed_gcode = fan_mover.process_gcode(gcode, true);
  552. std::string good_gcode = create_gcode(true, false);
  553. //remove
  554. REQUIRE(good_gcode == processed_gcode);
  555. }
  556. SECTION("4061 bug")
  557. {
  558. Slic3r::FanMover fan_mover(writer,
  559. .486, // fan_speedup_time.value,
  560. false, // with_D_option
  561. false, // use_relative_e_distances.value,
  562. true, // fan_speedup_overhangs.value,
  563. 0 // fan_kickstart.value));
  564. );
  565. std::string processed_gcode = fan_mover.process_gcode(gcode, true);
  566. std::string good_gcode = create_gcode(true, true);
  567. REQUIRE(good_gcode == processed_gcode);
  568. }
  569. }
  570. TEST_CASE("4113 bug (erase all fan command after a point)") {
  571. std::string gcode_input = read_to_string(std::string(TEST_DATA_DIR) + "/test_gcode/4113_fan_mover.gcode");
  572. std::string gcode_output = read_to_string(std::string(TEST_DATA_DIR) + "/test_gcode/4113_fan_mover_ok.gcode");
  573. //"M106 S25.5\n";
  574. GCodeWriter writer;
  575. // what's used from the writer:
  576. writer.config.gcode_flavor.value = gcfMarlinFirmware;
  577. writer.config.gcode_comments.value = false;
  578. writer.config.fan_percentage.value = false; // 0 -> 255
  579. // writer.tool[0] = nullptr;
  580. assert(writer.tool() == nullptr);
  581. assert(writer.get_tool(0) == nullptr);
  582. SECTION("disable evrything")
  583. {
  584. Slic3r::FanMover fan_mover(writer,
  585. 1, // fan_speedup_time.value,
  586. false, // with_D_option
  587. true, // use_relative_e_distances.value,
  588. true, // fan_speedup_overhangs.value,
  589. 0.5 // fan_kickstart.value));
  590. );
  591. std::string processed_gcode = fan_mover.process_gcode(gcode_input, true);
  592. //remove
  593. //REQUIRE(good_gcode == processed_gcode);
  594. REQUIRE(processed_gcode.find("M106 S51") != std::string::npos);
  595. REQUIRE(gcode_output == processed_gcode);
  596. }
  597. }