test_arachne.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  1. #include <catch2/catch.hpp>
  2. #include "libslic3r/Arachne/WallToolPaths.hpp"
  3. #include "libslic3r/ClipperUtils.hpp"
  4. #include "libslic3r/SVG.hpp"
  5. #include "libslic3r/Utils.hpp"
  6. using namespace Slic3r;
  7. using namespace Slic3r::Arachne;
  8. //#define ARACHNE_DEBUG_OUT
  9. #ifdef ARACHNE_DEBUG_OUT
  10. static void export_perimeters_to_svg(const std::string &path, const Polygons &contours, const std::vector<Arachne::VariableWidthLines> &perimeters, const ExPolygons &infill_area)
  11. {
  12. coordf_t stroke_width = scale_(0.03);
  13. BoundingBox bbox = get_extents(contours);
  14. bbox.offset(scale_(1.));
  15. ::Slic3r::SVG svg(path.c_str(), bbox);
  16. svg.draw(infill_area, "cyan");
  17. for (const Arachne::VariableWidthLines &perimeter : perimeters)
  18. for (const Arachne::ExtrusionLine &extrusion_line : perimeter) {
  19. ThickPolyline thick_polyline = to_thick_polyline(extrusion_line);
  20. svg.draw({thick_polyline}, "green", "blue", stroke_width);
  21. }
  22. for (const Line &line : to_lines(contours))
  23. svg.draw(line, "red", stroke_width);
  24. }
  25. #endif
  26. TEST_CASE("Arachne - Closed ExtrusionLine", "[ArachneClosedExtrusionLine]") {
  27. Polygon poly = {
  28. Point(-40000000, 10000000),
  29. Point(-62480000, 10000000),
  30. Point(-62480000, -7410000),
  31. Point(-58430000, -7330000),
  32. Point(-58400000, -5420000),
  33. Point(-58720000, -4710000),
  34. Point(-58940000, -3870000),
  35. Point(-59020000, -3000000),
  36. };
  37. Polygons polygons = {poly};
  38. coord_t spacing = 407079;
  39. coord_t inset_count = 5;
  40. Arachne::WallToolPaths wallToolPaths(polygons, spacing, spacing, inset_count, 0, 0.2, PrintObjectConfig::defaults(), PrintConfig::defaults());
  41. wallToolPaths.generate();
  42. std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths();
  43. #ifdef ARACHNE_DEBUG_OUT
  44. export_perimeters_to_svg(debug_out_path("arachne-closed-extrusion-line.svg"), polygons, perimeters, union_ex(wallToolPaths.getInnerContour()));
  45. #endif
  46. for (VariableWidthLines &perimeter : perimeters)
  47. for (ExtrusionLine &el : perimeter)
  48. if (el.is_closed) {
  49. REQUIRE(el.junctions.front().p == el.junctions.back().p);
  50. }
  51. }
  52. // This test case was distilled from GitHub issue #8472.
  53. // Where for wall_distribution_count == 3 sometime middle perimeter was missing.
  54. TEST_CASE("Arachne - Missing perimeter - #8472", "[ArachneMissingPerimeter8472]") {
  55. Polygon poly = {
  56. Point(-9000000, 8054793),
  57. Point( 7000000, 8054793),
  58. Point( 7000000, 10211874),
  59. Point(-8700000, 10211874),
  60. Point(-9000000, 9824444)
  61. };
  62. Polygons polygons = {poly};
  63. coord_t spacing = 437079;
  64. coord_t inset_count = 3;
  65. PrintObjectConfig print_object_config = PrintObjectConfig::defaults();
  66. print_object_config.wall_distribution_count.setInt(3);
  67. Arachne::WallToolPaths wallToolPaths(polygons, spacing, spacing, inset_count, 0, 0.2, print_object_config, PrintConfig::defaults());
  68. wallToolPaths.generate();
  69. std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths();
  70. #ifdef ARACHNE_DEBUG_OUT
  71. export_perimeters_to_svg(debug_out_path("arachne-missing-perimeter-8472.svg"), polygons, perimeters, union_ex(wallToolPaths.getInnerContour()));
  72. #endif
  73. REQUIRE(perimeters.size() == 3);
  74. }
  75. // This test case was distilled from GitHub issue #8593.
  76. // Where on the symmetrical model, there were missing parts of extrusions in gear teeth based on model rotation.
  77. TEST_CASE("Arachne - #8593 - Missing a part of the extrusion", "[ArachneMissingPartOfExtrusion8593]") {
  78. const Polygon poly_orig = {
  79. Point( 1800000, 28500000),
  80. Point( 1100000, 30000000),
  81. Point( 1000000, 30900000),
  82. Point( 600000, 32300000),
  83. Point( -600000, 32300000),
  84. Point(-1000000, 30900000),
  85. Point(-1100000, 30000000),
  86. Point(-1800000, 29000000),
  87. };
  88. coord_t spacing = 377079;
  89. coord_t inset_count = 3;
  90. PrintObjectConfig print_object_config = PrintObjectConfig::defaults();
  91. print_object_config.min_bead_width = ConfigOptionFloatOrPercent(0.315, false);
  92. print_object_config.wall_transition_angle = ConfigOptionFloat(40.);
  93. print_object_config.wall_transition_length = ConfigOptionFloatOrPercent(1., false);
  94. // This behavior seems to be related to the rotation of the input polygon.
  95. // There are specific angles in which this behavior is always triggered.
  96. for (const double angle : {0., -PI / 2., -PI / 15.}) {
  97. Polygon poly = poly_orig;
  98. if (angle != 0.)
  99. poly.rotate(angle);
  100. Polygons polygons = {poly};
  101. Arachne::WallToolPaths wall_tool_paths(polygons, spacing, spacing, inset_count, 0, 0.2, print_object_config, PrintConfig::defaults());
  102. wall_tool_paths.generate();
  103. std::vector<Arachne::VariableWidthLines> perimeters = wall_tool_paths.getToolPaths();
  104. #ifdef ARACHNE_DEBUG_OUT
  105. {
  106. static int iRun = 0;
  107. export_perimeters_to_svg(debug_out_path("arachne-missing-part-of-extrusion-8593-%d.svg", iRun++), polygons, perimeters, union_ex(wall_tool_paths.getInnerContour()));
  108. }
  109. #endif
  110. }
  111. }
  112. // This test case was distilled from GitHub issue #8573.
  113. TEST_CASE("Arachne - #8573 - A gap in the perimeter - 1", "[ArachneGapInPerimeter8573_1]") {
  114. const Polygon poly = {
  115. Point(13960000, 500000),
  116. Point(13920000, 1210000),
  117. Point(13490000, 2270000),
  118. Point(12960000, 3400000),
  119. Point(12470000, 4320000),
  120. Point(12160000, 4630000),
  121. Point(12460000, 3780000),
  122. Point(12700000, 2850000),
  123. Point(12880000, 1910000),
  124. Point(12950000, 1270000),
  125. Point(13000000, 500000),
  126. };
  127. Polygons polygons = {poly};
  128. coord_t spacing = 407079;
  129. coord_t inset_count = 2;
  130. PrintObjectConfig print_object_config = PrintObjectConfig::defaults();
  131. // print_object_config.wall_transition_angle = ConfigOptionFloat(20.);
  132. Arachne::WallToolPaths wallToolPaths(polygons, spacing, spacing, inset_count, 0, 0.2, print_object_config, PrintConfig::defaults());
  133. wallToolPaths.generate();
  134. std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths();
  135. #ifdef ARACHNE_DEBUG_OUT
  136. export_perimeters_to_svg(debug_out_path("arachne-gap-in-perimeter-1-8573.svg"), polygons, perimeters, union_ex(wallToolPaths.getInnerContour()));
  137. #endif
  138. }
  139. // This test case was distilled from GitHub issue #8444.
  140. TEST_CASE("Arachne - #8444 - A gap in the perimeter - 2", "[ArachneGapInPerimeter8444_2]") {
  141. const Polygon poly = {
  142. Point(14413938, 3825902),
  143. Point(16817613, 711749),
  144. Point(19653030, 67154),
  145. Point(20075592, 925370),
  146. Point(20245428, 1339788),
  147. Point(20493219, 2121894),
  148. Point(20570295, 2486625),
  149. Point(20616559, 2835232),
  150. Point(20631964, 3166882),
  151. Point(20591800, 3858877),
  152. Point(19928267, 2153012),
  153. Point(19723020, 1829802),
  154. Point(19482017, 1612364),
  155. Point(19344810, 1542433),
  156. Point(19200249, 1500902),
  157. Point(19047680, 1487200),
  158. Point(18631073, 1520777),
  159. Point(18377524, 1567627),
  160. Point(18132517, 1641174),
  161. Point(17896307, 1741360),
  162. Point(17669042, 1868075),
  163. Point(17449999, 2021790),
  164. };
  165. Polygons polygons = {poly};
  166. coord_t spacing = 594159;
  167. coord_t inset_count = 2;
  168. PrintObjectConfig print_object_config = PrintObjectConfig::defaults();
  169. // print_object_config.wall_transition_angle = ConfigOptionFloat(20.);
  170. Arachne::WallToolPaths wallToolPaths(polygons, spacing, spacing, inset_count, 0, 0.4, print_object_config, PrintConfig::defaults());
  171. wallToolPaths.generate();
  172. std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths();
  173. #ifdef ARACHNE_DEBUG_OUT
  174. export_perimeters_to_svg(debug_out_path("arachne-gap-in-perimeter-2-8444.svg"), polygons, perimeters, union_ex(wallToolPaths.getInnerContour()));
  175. #endif
  176. }
  177. // This test case was distilled from GitHub issue #8528.
  178. // There is a hole in the place where the number of perimeters is changing from 6 perimeters to 7 perimeters.
  179. TEST_CASE("Arachne - #8528 - A hole when number of perimeters is changing", "[ArachneHoleOnPerimetersChange8528]") {
  180. const Polygon poly = {
  181. Point(-30000000, 27650000),
  182. Point(-30000000, 33500000),
  183. Point(-40000000, 33500000),
  184. Point(-40500000, 33500000),
  185. Point(-41100000, 33400000),
  186. Point(-41600000, 33200000),
  187. Point(-42100000, 32900000),
  188. Point(-42600000, 32600000),
  189. Point(-43000000, 32200000),
  190. Point(-43300000, 31700000),
  191. Point(-43600000, 31200000),
  192. Point(-43800000, 30700000),
  193. Point(-43900000, 30100000),
  194. Point(-43900000, 29600000),
  195. Point(-43957080, 25000000),
  196. Point(-39042920, 25000000),
  197. Point(-39042920, 27650000),
  198. };
  199. Polygons polygons = {poly};
  200. coord_t spacing = 814159;
  201. coord_t inset_count = 5;
  202. PrintObjectConfig print_object_config = PrintObjectConfig::defaults();
  203. print_object_config.min_bead_width = ConfigOptionFloatOrPercent(0.68, false);
  204. // Changing min_bead_width to 0.66 seems that resolve this issue, at least in this case.
  205. print_object_config.min_bead_width = ConfigOptionFloatOrPercent(0.66, false);
  206. Arachne::WallToolPaths wallToolPaths(polygons, spacing, spacing, inset_count, 0, 0.4, print_object_config, PrintConfig::defaults());
  207. wallToolPaths.generate();
  208. std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths();
  209. #ifdef ARACHNE_DEBUG_OUT
  210. export_perimeters_to_svg(debug_out_path("arachne-hole-on-perimeters-change-8528.svg"), polygons, perimeters, union_ex(wallToolPaths.getInnerContour()));
  211. #endif
  212. }
  213. // This test case was distilled from GitHub issue #8528.
  214. // There is an inconsistency between layers in length of the single perimeters.
  215. TEST_CASE("Arachne - #8555 - Inconsistent single perimeter", "[ArachneInconsistentSinglePerimeter8555]") {
  216. const Polygon poly_0 = {
  217. Point(5527411, -38490007),
  218. Point(11118814, -36631169),
  219. Point(13529600, -36167120),
  220. Point(11300145, -36114514),
  221. Point(10484024, -36113916),
  222. Point(5037323, -37985945),
  223. Point(4097054, -39978866)
  224. };
  225. const Polygon poly_1 = {
  226. Point(5566841, -38517205),
  227. Point(11185208, -36649404),
  228. Point(13462719, -36211009),
  229. Point(11357290, -36161329),
  230. Point(10583855, -36160763),
  231. Point(5105952, -38043516),
  232. Point(4222019, -39917031)
  233. };
  234. const Polygon poly_2 = {
  235. Point(5606269, -38544404),
  236. Point(11251599, -36667638),
  237. Point(13391666, -36255700),
  238. Point(10683552, -36207653),
  239. Point(5174580, -38101085),
  240. Point(4346981, -39855197)
  241. };
  242. const Polygon poly_3 = {
  243. Point(5645699, -38571603),
  244. Point(11317993, -36685873),
  245. Point(13324786, -36299588),
  246. Point(10783383, -36254499),
  247. Point(5243209, -38158655),
  248. Point(4471947, -39793362)
  249. };
  250. const Polygon poly_4 = {
  251. Point(5685128, -38598801),
  252. Point(11384385, -36704108),
  253. Point(13257907, -36343476),
  254. Point(10883211, -36301345),
  255. Point(5311836, -38216224),
  256. Point(4596909, -39731528)
  257. };
  258. const Polygon poly_5 = {
  259. Point(5724558, -38626000),
  260. Point(11450778, -36722343),
  261. Point(13191026, -36387365),
  262. Point(10983042, -36348191),
  263. Point(5380466, -38273795),
  264. Point(4721874, -39669693)
  265. };
  266. Polygons polygons = {poly_0, poly_1, poly_2, poly_3, poly_4, poly_5};
  267. coord_t spacing = 417809;
  268. coord_t inset_count = 2;
  269. for (size_t poly_idx = 0; poly_idx < polygons.size(); ++poly_idx) {
  270. Polygons input_polygons{polygons[poly_idx]};
  271. Arachne::WallToolPaths wallToolPaths(input_polygons, spacing, spacing, inset_count, 0, 0.15, PrintObjectConfig::defaults(), PrintConfig::defaults());
  272. wallToolPaths.generate();
  273. std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths();
  274. #ifdef ARACHNE_DEBUG_OUT
  275. export_perimeters_to_svg(debug_out_path("arachne-inconsistent-single-perimeter-8555-%d.svg", poly_idx), input_polygons, perimeters, union_ex(wallToolPaths.getInnerContour()));
  276. #endif
  277. }
  278. }
  279. // This test case was distilled from GitHub issue #8633.
  280. // Open perimeter extrusion is shorter on endpoints in comparison to closed perimeter.
  281. TEST_CASE("Arachne - #8633 - Shorter open perimeter", "[ArachneShorterOpenPerimeter8633]") {
  282. const Polygon poly_0 = {
  283. Point(6507498, 4189461),
  284. Point(6460382, 3601960),
  285. Point(6390896, 3181097),
  286. Point(6294072, 2765838),
  287. Point(6170293, 2357794),
  288. Point(7090581, 2045388),
  289. Point(7232821, 2514293),
  290. Point(7344089, 2991501),
  291. Point(7423910, 3474969),
  292. Point(7471937, 3962592),
  293. Point(7487443, 4436235),
  294. Point(6515575, 4436235),
  295. };
  296. const Polygon poly_1 = {
  297. Point(6507498, 4189461),
  298. Point(6460382, 3601960),
  299. Point(6390896, 3181097),
  300. Point(6294072, 2765838),
  301. Point(6170293, 2357794),
  302. Point(6917958, 1586830),
  303. Point(7090552, 2045398),
  304. Point(7232821, 2514293),
  305. Point(7344089, 2991501),
  306. Point(7423910, 3474969),
  307. Point(7471937, 3962592),
  308. Point(7487443, 4436235),
  309. Point(6515575, 4436235),
  310. };
  311. Polygons polygons = {poly_0, poly_1};
  312. coord_t spacing = 617809;
  313. coord_t inset_count = 1;
  314. PrintObjectConfig print_object_config = PrintObjectConfig::defaults();
  315. print_object_config.min_bead_width = ConfigOptionFloatOrPercent(0.51, false);
  316. print_object_config.min_feature_size = ConfigOptionFloatOrPercent(0.15, false);
  317. print_object_config.wall_transition_length = ConfigOptionFloatOrPercent(0.6, false);
  318. for (size_t poly_idx = 0; poly_idx < polygons.size(); ++poly_idx) {
  319. Polygons input_polygons{polygons[poly_idx]};
  320. Arachne::WallToolPaths wallToolPaths(input_polygons, spacing, spacing, inset_count, 0, 0.15, print_object_config, PrintConfig::defaults());
  321. wallToolPaths.generate();
  322. std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths();
  323. #ifdef ARACHNE_DEBUG_OUT
  324. export_perimeters_to_svg(debug_out_path("arachne-shorter-open-perimeter-8633-%d.svg", poly_idx), input_polygons, perimeters, union_ex(wallToolPaths.getInnerContour()));
  325. #endif
  326. }
  327. }
  328. // This test case was distilled from GitHub issue #8597.
  329. // There was just an issue with decrementing std::vector::begin() in a specific case.
  330. TEST_CASE("Arachne - #8597 - removeSmallAreas", "[ArachneRemoveSmallAreas8597]") {
  331. const Polygon poly_0 = {
  332. Point(-38768167, -3636556),
  333. Point(-38763631, -3617883),
  334. Point(-38763925, -3617820),
  335. Point(-38990169, -3919539),
  336. Point(-38928506, -3919539),
  337. };
  338. const Polygon poly_1 = {
  339. Point(-39521732, -4480560),
  340. Point(-39383333, -4398498),
  341. Point(-39119825, -3925307),
  342. Point(-39165608, -3926212),
  343. Point(-39302205, -3959445),
  344. Point(-39578719, -4537002),
  345. };
  346. Polygons polygons = {poly_0, poly_1};
  347. coord_t spacing = 407079;
  348. coord_t inset_count = 2;
  349. Arachne::WallToolPaths wallToolPaths(polygons, spacing, spacing, inset_count, 0, 0.2, PrintObjectConfig::defaults(), PrintConfig::defaults());
  350. wallToolPaths.generate();
  351. std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths();
  352. #ifdef ARACHNE_DEBUG_OUT
  353. export_perimeters_to_svg(debug_out_path("arachne-remove-small-areas-8597.svg"), polygons, perimeters, union_ex(wallToolPaths.getInnerContour()));
  354. #endif
  355. REQUIRE(perimeters.size() == 1);
  356. }
  357. // Test case for missing infill that is probably caused by PolylineStitcher, which produced an open polyline.
  358. TEST_CASE("Arachne - Missing infill", "[ArachneMissingInfill]") {
  359. const Polygon poly_0 = {
  360. Point( 5525881, 3649657),
  361. Point( 452351, -2035297),
  362. Point(-1014702, -2144286),
  363. Point(-5142096, -9101108),
  364. Point( 5525882, -9101108),
  365. };
  366. const Polygon poly_1 = {
  367. Point(1415524, -2217520),
  368. Point(1854189, -2113857),
  369. Point(1566974, -2408538),
  370. };
  371. const Polygon poly_2 = {
  372. Point(-42854, -3771357),
  373. Point(310500, -3783332),
  374. Point( 77735, -4059215),
  375. };
  376. Polygons polygons = {poly_0, poly_1, poly_2};
  377. coord_t spacing = 357079;
  378. coord_t inset_count = 2;
  379. Arachne::WallToolPaths wallToolPaths(polygons, spacing, spacing, inset_count, 0, 0.2, PrintObjectConfig::defaults(), PrintConfig::defaults());
  380. wallToolPaths.generate();
  381. std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths();
  382. #ifdef ARACHNE_DEBUG_OUT
  383. export_perimeters_to_svg(debug_out_path("arachne-missing-infill.svg"), polygons, perimeters, union_ex(wallToolPaths.getInnerContour()));
  384. #endif
  385. // REQUIRE(wallToolPaths.getInnerContour().size() == 1);
  386. }
  387. // This test case was distilled from GitHub issue #8849.
  388. // Missing part of the model after simplifying generated tool-paths by simplifyToolPaths.
  389. TEST_CASE("Arachne - #8849 - Missing part of model", "[ArachneMissingPart8849]") {
  390. const Polygon poly_0 = {
  391. Point(-29700000, -10600000),
  392. Point(-28200000, -10600000),
  393. Point( 20000000, -10600000),
  394. Point( 20000000, - 9900000),
  395. Point(-28200000, - 9900000),
  396. Point(-28200000, 0),
  397. Point(-29700000, 0),
  398. };
  399. Polygons polygons = {poly_0};
  400. coord_t ext_perimeter_spacing = 449999;
  401. coord_t perimeter_spacing = 757079;
  402. coord_t inset_count = 2;
  403. Arachne::WallToolPaths wall_tool_paths(polygons, ext_perimeter_spacing, perimeter_spacing, inset_count, 0, 0.32, PrintObjectConfig::defaults(), PrintConfig::defaults());
  404. wall_tool_paths.generate();
  405. std::vector<Arachne::VariableWidthLines> perimeters = wall_tool_paths.getToolPaths();
  406. #ifdef ARACHNE_DEBUG_OUT
  407. export_perimeters_to_svg(debug_out_path("arachne-missing-part-8849.svg"), polygons, perimeters, union_ex(wall_tool_paths.getInnerContour()));
  408. #endif
  409. int64_t total_extrusion_length = 0;
  410. for (Arachne::VariableWidthLines &perimeter : perimeters)
  411. for (Arachne::ExtrusionLine &extrusion_line : perimeter)
  412. total_extrusion_length += extrusion_line.getLength();
  413. // Total extrusion length should be around 30mm when the part is missing and around 120 when everything is ok.
  414. // REQUIRE(total_extrusion_length >= scaled<int64_t>(120.));
  415. }
  416. // This test case was distilled from GitHub issue #8446.
  417. // Boost Voronoi generator produces non-planar Voronoi diagram with two intersecting linear Voronoi edges.
  418. // Those intersecting edges are causing that perimeters are also generated in places where they shouldn't be.
  419. TEST_CASE("Arachne - #8446 - Degenerated Voronoi diagram - Linear edges", "[ArachneDegeneratedDiagram8446LinearEdges]") {
  420. Polygon poly_0 = {
  421. Point( 42240656, 9020315),
  422. Point( 4474248, 42960681),
  423. Point( -4474248, 42960681),
  424. Point( -4474248, 23193537),
  425. Point( -6677407, 22661038),
  426. Point( -8830542, 21906307),
  427. Point( -9702935, 21539826),
  428. Point(-13110431, 19607811),
  429. Point(-18105334, 15167780),
  430. Point(-20675743, 11422461),
  431. Point(-39475413, 17530840),
  432. Point(-42240653, 9020315)
  433. };
  434. Polygons polygons = {poly_0};
  435. coord_t ext_perimeter_spacing = 407079;
  436. coord_t perimeter_spacing = 407079;
  437. coord_t inset_count = 1;
  438. Arachne::WallToolPaths wall_tool_paths(polygons, ext_perimeter_spacing, perimeter_spacing, inset_count, 0, 0.2, PrintObjectConfig::defaults(), PrintConfig::defaults());
  439. wall_tool_paths.generate();
  440. std::vector<Arachne::VariableWidthLines> perimeters = wall_tool_paths.getToolPaths();
  441. #ifdef ARACHNE_DEBUG_OUT
  442. export_perimeters_to_svg(debug_out_path("arachne-degenerated-diagram-8446-linear-edges.svg"), polygons, perimeters, union_ex(wall_tool_paths.getInnerContour()));
  443. #endif
  444. int64_t total_extrusion_length = 0;
  445. for (Arachne::VariableWidthLines &perimeter : perimeters)
  446. for (Arachne::ExtrusionLine &extrusion_line : perimeter)
  447. total_extrusion_length += extrusion_line.getLength();
  448. // Total extrusion length should be around 211.2mm when the part is ok and 212.1mm when it has perimeters in places where they shouldn't be.
  449. REQUIRE(total_extrusion_length <= scaled<int64_t>(211.5));
  450. }
  451. // This test case was distilled from GitHub issue #8846.
  452. // Boost Voronoi generator produces degenerated Voronoi diagram with one parabolic edge intersecting linear Voronoi edge.
  453. // Those intersecting edges are causing that perimeters are also generated in places where they shouldn't be.
  454. TEST_CASE("Arachne - #8846 - Degenerated Voronoi diagram - One Parabola", "[ArachneDegeneratedDiagram8846OneParabola]") {
  455. const Polygon poly_0 = {
  456. Point(101978540, -41304489), Point(101978540, 41304489),
  457. Point(94709788, 42514051), Point(94709788, 48052315),
  458. Point(93352716, 48052315), Point(93352716, 42514052),
  459. Point(75903540, 42514051), Point(75903540, 48052315),
  460. Point(74546460, 48052315), Point(74546460, 42514052),
  461. Point(69634788, 42514051), Point(69634788, 48052315),
  462. Point(68277708, 48052315), Point(68277708, 42514051),
  463. Point(63366040, 42514051), Point(63366040, 48052315),
  464. Point(62008960, 48052315), Point(62008960, 42514051),
  465. Point(57097292, 42514051), Point(57097292, 48052315),
  466. Point(55740212, 48052315), Point(55740212, 42514052),
  467. Point(50828540, 42514052), Point(50828540, 48052315),
  468. Point(49471460, 48052315), Point(49471460, 42514051),
  469. Point(25753540, 42514051), Point(25753540, 48052315),
  470. Point(24396460, 48052315), Point(24396460, 42514051),
  471. Point(19484790, 42514052), Point(19484790, 48052315),
  472. Point(18127710, 48052315), Point(18127710, 42514051),
  473. Point(-5590210, 42514051), Point(-5590210, 48052315),
  474. Point(-6947290, 48052315), Point(-6947290, 42514051),
  475. Point(-11858960, 42514051), Point(-11858960, 48052315),
  476. Point(-13216040, 48052315), Point(-13216040, 42514051),
  477. Point(-18127710, 42514051), Point(-18127710, 48052315),
  478. Point(-19484790, 48052315), Point(-19484790, 42514052),
  479. Point(-49471460, 42514051), Point(-49471460, 48052315),
  480. Point(-50828540, 48052315), Point(-50828540, 42514052),
  481. Point(-55740212, 42514052), Point(-55740212, 48052315),
  482. Point(-57097292, 48052315), Point(-57097292, 42514051),
  483. Point(-68277708, 42514051), Point(-68277708, 48052315),
  484. Point(-69634788, 48052315), Point(-69634788, 42514051),
  485. Point(-74546460, 42514052), Point(-74546460, 48052315),
  486. Point(-75903540, 48052315), Point(-75903540, 42514051),
  487. Point(-80815204, 42514051), Point(-80815204, 48052315),
  488. Point(-82172292, 48052315), Point(-82172292, 42514051),
  489. Point(-87083956, 42514051), Point(-87083956, 48052315),
  490. Point(-88441044, 48052315), Point(-88441044, 42514051),
  491. Point(-99621460, 42514051), Point(-99621460, 48052315),
  492. Point(-100978540, 48052315), Point(-100978540, 42528248),
  493. Point(-101978540, 41304489), Point(-101978540, -41304489),
  494. Point(-100978540, -48052315), Point(-99621460, -48052315),
  495. };
  496. Polygon poly_1 = {
  497. Point(-100671460, -40092775),
  498. Point(-100671460, 40092775),
  499. Point(100671460, 40092775),
  500. Point(100671460, -40092775),
  501. };
  502. Polygons polygons = {poly_0, poly_1};
  503. coord_t ext_perimeter_spacing = 607079;
  504. coord_t perimeter_spacing = 607079;
  505. coord_t inset_count = 1;
  506. Arachne::WallToolPaths wall_tool_paths(polygons, ext_perimeter_spacing, perimeter_spacing, inset_count, 0, 0.2, PrintObjectConfig::defaults(), PrintConfig::defaults());
  507. wall_tool_paths.generate();
  508. std::vector<Arachne::VariableWidthLines> perimeters = wall_tool_paths.getToolPaths();
  509. #ifdef ARACHNE_DEBUG_OUT
  510. export_perimeters_to_svg(debug_out_path("arachne-degenerated-diagram-8846-one-parabola.svg"), polygons, perimeters, union_ex(wall_tool_paths.getInnerContour()));
  511. #endif
  512. int64_t total_extrusion_length = 0;
  513. for (Arachne::VariableWidthLines &perimeter : perimeters)
  514. for (Arachne::ExtrusionLine &extrusion_line : perimeter)
  515. total_extrusion_length += extrusion_line.getLength();
  516. // Total extrusion length should be around 1335mm when the part is ok and 1347mm when it has perimeters in places where they shouldn't be.
  517. REQUIRE(total_extrusion_length <= scaled<int64_t>(1335.));
  518. }
  519. // This test case was distilled from GitHub issue #9357.
  520. // Boost Voronoi generator produces degenerated Voronoi diagram with two intersecting parabolic Voronoi edges.
  521. // Those intersecting edges are causing that perimeters are also generated in places where they shouldn't be.
  522. TEST_CASE("Arachne - #9357 - Degenerated Voronoi diagram - Two parabolas", "[ArachneDegeneratedDiagram9357TwoParabolas]") {
  523. const Polygon poly_0 = {
  524. Point(78998946, -11733905),
  525. Point(40069507, -7401251),
  526. Point(39983905, -6751055),
  527. Point(39983905, 8251054),
  528. Point(79750000, 10522762),
  529. Point(79983905, 10756667),
  530. Point(79983905, 12248946),
  531. Point(79950248, 12504617),
  532. Point(79709032, 12928156),
  533. Point(79491729, 13102031),
  534. Point(78998946, 13233905),
  535. Point(38501054, 13233905),
  536. Point(37258117, 12901005),
  537. Point(36349000, 11991885),
  538. Point(36100868, 11392844),
  539. Point(36016095, 10748947),
  540. Point(36016095, -6751054),
  541. Point(35930493, -7401249),
  542. Point(4685798, -11733905),
  543. };
  544. Polygons polygons = {poly_0};
  545. coord_t ext_perimeter_spacing = 407079;
  546. coord_t perimeter_spacing = 407079;
  547. coord_t inset_count = 1;
  548. Arachne::WallToolPaths wall_tool_paths(polygons, ext_perimeter_spacing, perimeter_spacing, inset_count, 0, 0.2, PrintObjectConfig::defaults(), PrintConfig::defaults());
  549. wall_tool_paths.generate();
  550. std::vector<Arachne::VariableWidthLines> perimeters = wall_tool_paths.getToolPaths();
  551. #ifdef ARACHNE_DEBUG_OUT
  552. export_perimeters_to_svg(debug_out_path("arachne-degenerated-diagram-9357-two-parabolas.svg"), polygons, perimeters, union_ex(wall_tool_paths.getInnerContour()));
  553. #endif
  554. int64_t total_extrusion_length = 0;
  555. for (Arachne::VariableWidthLines &perimeter : perimeters)
  556. for (Arachne::ExtrusionLine &extrusion_line : perimeter)
  557. total_extrusion_length += extrusion_line.getLength();
  558. // Total extrusion length should be around 256mm when the part is ok and 293mm when it has perimeters in places where they shouldn't be.
  559. REQUIRE(total_extrusion_length <= scaled<int64_t>(256.));
  560. }
  561. // This test case was distilled from GitHub issue #8846.
  562. // Boost Voronoi generator produces degenerated Voronoi diagram with some Voronoi edges intersecting input segments.
  563. // Those Voronoi edges intersecting input segments are causing that perimeters are also generated in places where they shouldn't be.
  564. TEST_CASE("Arachne - #8846 - Degenerated Voronoi diagram - Voronoi edges intersecting input segment", "[ArachneDegeneratedDiagram8846IntersectingInputSegment]") {
  565. const Polygon poly_0 = {
  566. Point( 60000000, 58000000),
  567. Point(-20000000, 53229451),
  568. Point( 49312250, 53229452),
  569. Point( 49443687, 53666225),
  570. Point( 55358348, 50908580),
  571. Point( 53666223, 49443687),
  572. Point( 53229452, 49312250),
  573. Point( 53229452, -49312250),
  574. Point( 53666014, -49443623),
  575. Point(-10000000, -58000000),
  576. Point( 60000000, -58000000),
  577. };
  578. Polygons polygons = {poly_0};
  579. coord_t ext_perimeter_spacing = 407079;
  580. coord_t perimeter_spacing = 407079;
  581. coord_t inset_count = 1;
  582. Arachne::WallToolPaths wall_tool_paths(polygons, ext_perimeter_spacing, perimeter_spacing, inset_count, 0, 0.32, PrintObjectConfig::defaults(), PrintConfig::defaults());
  583. wall_tool_paths.generate();
  584. std::vector<Arachne::VariableWidthLines> perimeters = wall_tool_paths.getToolPaths();
  585. #ifdef ARACHNE_DEBUG_OUT
  586. export_perimeters_to_svg(debug_out_path("arachne-degenerated-diagram-8846-intersecting-input-segment.svg"), polygons, perimeters, union_ex(wall_tool_paths.getInnerContour()));
  587. #endif
  588. int64_t total_extrusion_length = 0;
  589. for (Arachne::VariableWidthLines &perimeter : perimeters)
  590. for (Arachne::ExtrusionLine &extrusion_line : perimeter)
  591. total_extrusion_length += extrusion_line.getLength();
  592. // Total extrusion length should be around 500mm when the part is ok and 680mm when it has perimeters in places where they shouldn't be.
  593. REQUIRE(total_extrusion_length <= scaled<int64_t>(500.));
  594. }
  595. // This test case was distilled from GitHub issue #10034.
  596. // In this test case previous rotation by PI / 6 wasn't able to fix non-planar Voronoi diagram.
  597. TEST_CASE("Arachne - #10034 - Degenerated Voronoi diagram - That wasn't fixed by rotation by PI / 6", "[ArachneDegeneratedDiagram10034RotationNotWorks]") {
  598. Polygon poly_0 = {
  599. Point(43612632, -25179766), Point(58456010, 529710), Point(51074898, 17305660), Point(49390982, 21042355),
  600. Point(48102357, 23840161), Point(46769686, 26629546), Point(45835761, 28472742), Point(45205450, 29623133),
  601. Point(45107431, 29878059), Point(45069846, 30174950), Point(45069846, 50759533), Point(-45069846, 50759533),
  602. Point(-45069852, 29630557), Point(-45105780, 29339980), Point(-45179725, 29130704), Point(-46443313, 26398986),
  603. Point(-52272109, 13471493), Point(-58205450, 95724), Point(-29075091, -50359531), Point(29075086, -50359531),
  604. };
  605. Polygon poly_1 = {
  606. Point(-37733905, 45070445), Point(-37813254, 45116257), Point(-39353851, 47784650), Point(-39353851, 47876274),
  607. Point(-38632470, 49125743), Point(-38553121, 49171555), Point(-33833475, 49171555), Point(-33754126, 49125743),
  608. Point(-33032747, 47876277), Point(-33032747, 47784653), Point(-34007855, 46095721), Point(-34573350, 45116257),
  609. Point(-34652699, 45070445),
  610. };
  611. Polygon poly_2 = {
  612. Point(-44016799, 40706401), Point(-44116953, 40806555), Point(-44116953, 46126289), Point(-44016799, 46226443),
  613. Point(-42211438, 46226443), Point(-42132089, 46180631), Point(-40591492, 43512233), Point(-40591492, 43420609),
  614. Point(-41800123, 41327194), Point(-42132089, 40752213), Point(-42211438, 40706401),
  615. };
  616. Polygon poly_3 = {
  617. Point(6218189, 10966609), Point(6138840, 11012421), Point(4598238, 13680817), Point(4598238, 13772441), Point(6138840, 16440843),
  618. Point(6218189, 16486655), Point(9299389, 16486655), Point(9378738, 16440843), Point(10919340, 13772441), Point(10919340, 13680817),
  619. Point(10149039, 12346618), Point(9378738, 11012421), Point(9299389, 10966609),
  620. };
  621. Polygon poly_4 = {
  622. Point(13576879, 6718065), Point(13497530, 6763877), Point(11956926, 9432278), Point(11956926, 9523902),
  623. Point(13497528, 12192302), Point(13576877, 12238114), Point(16658079, 12238112), Point(16737428, 12192300),
  624. Point(18278031, 9523904), Point(18278031, 9432280), Point(17507729, 8098077), Point(16737428, 6763877),
  625. Point(16658079, 6718065),
  626. };
  627. Polygons polygons = {
  628. poly_0, poly_1, poly_2, poly_3, poly_4,
  629. };
  630. coord_t ext_perimeter_spacing = 407079;
  631. coord_t perimeter_spacing = 407079;
  632. coord_t inset_count = 1;
  633. Arachne::WallToolPaths wall_tool_paths(polygons, ext_perimeter_spacing, perimeter_spacing, inset_count, 0, 0.2, PrintObjectConfig::defaults(), PrintConfig::defaults());
  634. wall_tool_paths.generate();
  635. std::vector<Arachne::VariableWidthLines> perimeters = wall_tool_paths.getToolPaths();
  636. #ifdef ARACHNE_DEBUG_OUT
  637. export_perimeters_to_svg(debug_out_path("arachne-degenerated-diagram-10034-rotation-not-works.svg"), polygons, perimeters, union_ex(wall_tool_paths.getInnerContour()));
  638. #endif
  639. }
  640. TEST_CASE("Arachne - SPE-1837 - No perimeters generated", "[ArachneNoPerimetersGeneratedSPE1837]") {
  641. Polygon poly_0 = {
  642. Point( 10000000, 10000000),
  643. Point(-10000000, 10000000),
  644. Point(-10000000, -10000000),
  645. Point( 10000000, -10000000)
  646. };
  647. Polygons polygons = {poly_0};
  648. coord_t ext_perimeter_spacing = 300000;
  649. coord_t perimeter_spacing = 700000;
  650. coord_t inset_count = 1;
  651. Arachne::WallToolPaths wall_tool_paths(polygons, ext_perimeter_spacing, perimeter_spacing, inset_count, 0, 0.2, PrintObjectConfig::defaults(), PrintConfig::defaults());
  652. wall_tool_paths.generate();
  653. std::vector<Arachne::VariableWidthLines> perimeters = wall_tool_paths.getToolPaths();
  654. REQUIRE(!perimeters.empty());
  655. }