23_3mf.t 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use Slic3r::XS;
  5. use Test::More;
  6. use IO::Uncompress::Unzip qw(unzip $UnzipError) ;
  7. use Cwd qw(abs_path);
  8. use File::Basename qw(dirname);
  9. require Encode;
  10. # Removes '\n' and '\r\n' from a string.
  11. sub clean {
  12. my $text = shift;
  13. $text =~ s/\n//g;
  14. $text =~ s/\r//g;
  15. return $text;
  16. }
  17. my $current_path = Encode::decode_utf8(abs_path($0));
  18. my $expected_content_types = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> \n"
  19. ."<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">\n"
  20. ."<Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/>\n"
  21. ."<Default Extension=\"model\" ContentType=\"application/vnd.ms-package.3dmanufacturing-3dmodel+xml\"/>\n"
  22. ."</Types>\n";
  23. my $expected_relationships = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> \n"
  24. ."<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n"
  25. ."<Relationship Id=\"rel0\" Target=\"/3D/3dmodel.model\" Type=\"http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel\" /></Relationships>\n";
  26. # Test 1: Check read/write.
  27. {
  28. my $input_path = dirname($current_path). "/models/3mf/box.3mf";
  29. my $output_path = dirname($current_path). "/models/3mf/box2.3mf";
  30. # Create a new model.
  31. my $model = Slic3r::Model->new;
  32. my $result = $model->read_tmf($input_path);
  33. is($result, 1, 'Basic 3mf read test.');
  34. $result = $model->write_tmf($output_path);
  35. is($result, 1, 'Basic 3mf write test.');
  36. # Delete the created file.
  37. unlink($output_path);
  38. }
  39. # Test 2: Check read metadata/ objects/ components/ build items w/o or with tansformation matrics.
  40. {
  41. my $input_path = dirname($current_path). "/models/3mf/gimblekeychain.3mf";
  42. # Create a new model.
  43. my $model = Slic3r::Model->new;
  44. $model->read_tmf($input_path);
  45. # Check the number of read matadata.
  46. is($model->metadata_count(), 8, 'Test 2: metadata count check.');
  47. # Check the number of read objects.
  48. is($model->objects_count(), 1, 'Test 2: objects count check.');
  49. # Check the number of read instances.
  50. is($model->get_object(0)->instances_count(), 1, 'Test 2: object instances count check.');
  51. # Check the read object part number.
  52. is($model->get_object(0)->part_number(), -1, 'Test 2: object part number check.');
  53. # Check the number of read volumes.
  54. is($model->get_object(0)->volumes_count(), 3, 'Test 2: object volumes count check.');
  55. # Check the number of read number of facets (triangles).
  56. is($model->get_object(0)->facets_count(), 19884, 'Test 2: object number of facets check.');
  57. # Check the affine transformation matrix decomposition.
  58. # Check translation.
  59. cmp_ok($model->get_object(0)->get_instance(0)->offset()->x(), '<=', 0.0001, 'Test 2: X translation check.');
  60. cmp_ok($model->get_object(0)->get_instance(0)->offset()->y(), '<=', 0.0001, 'Test 2: Y translation check.');
  61. cmp_ok($model->get_object(0)->get_instance(0)->z_translation() - 0.0345364, '<=', 0.0001, 'Test 2: Z translation check.');
  62. # Check scale.
  63. cmp_ok($model->get_object(0)->get_instance(0)->scaling_vector()->x() - 25.4, '<=', 0.0001, 'Test 2: X scale check.');
  64. cmp_ok($model->get_object(0)->get_instance(0)->scaling_vector()->y() - 25.4, '<=', 0.0001, 'Test 2: Y scale check.');
  65. cmp_ok($model->get_object(0)->get_instance(0)->scaling_vector()->z() - 25.4, '<=', 0.0001, 'Test 2: Z scale check.');
  66. # Check X, Y, & Z rotation.
  67. cmp_ok($model->get_object(0)->get_instance(0)->x_rotation() - 6.2828, '<=', 0.0001, 'Test 2: X rotation check.');
  68. cmp_ok($model->get_object(0)->get_instance(0)->y_rotation() - 6.2828, '<=', 0.0001, 'Test 2: Y rotation check.');
  69. cmp_ok($model->get_object(0)->get_instance(0)->rotation(), '<=', 0.0001, 'Test 2: Z rotation check.');
  70. }
  71. # Test 3: Read an STL and write it as 3MF.
  72. {
  73. my $input_path = dirname($current_path). "/models/stl/spikey_top.stl";
  74. my $output_path = dirname($current_path). "/models/3mf/spikey_top.3mf";
  75. my $model = Slic3r::Model->new;
  76. my $result = $model->read_stl($input_path);
  77. is($result, 1, 'Test 3: read the stl model file.');
  78. # Check initialization of 3mf specific atttributes.
  79. is($model->metadata_count(), 0, 'Test 3: read stl model metadata count check .');
  80. is($model->get_object(0)->instances_count(), 0, 'Test 3: object instances count check.');
  81. is($model->get_object(0)->part_number(), -1, 'Test 3: object partnumber check.');
  82. is($model->material_count(), 0, 'Test 3: model materials count check.');
  83. $result = $model->write_tmf($output_path);
  84. is($result, 1, 'Test 3: Write the 3mf model file.');
  85. unlink($output_path);
  86. }
  87. # Test 4: Read an 3MF containig multiple objects and volumes and write it as STL.
  88. {
  89. my $input_path = dirname($current_path). "/models/3mf/gimblekeychain.3mf";
  90. my $output_path = dirname($current_path). "/models/stl/gimblekeychain.stl";
  91. my $model = Slic3r::Model->new;
  92. my $result = $model->read_tmf($input_path);
  93. is($result, 1, 'Test 4: Read 3MF file check.');
  94. $result = $model->write_stl($output_path);
  95. is($result, 1, 'Test 4: convert to stl check.');
  96. unlink($output_path);
  97. }
  98. # Test 5: Basic Test with model containing vertices and triangles.
  99. {
  100. my $amf_test_file = dirname($current_path). "/models/amf/FaceColors.amf.xml";
  101. my $tmf_output_file = dirname($current_path). "/models/3mf/FaceColors.3mf";
  102. my $expected_model = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  103. ."<model unit=\"millimeter\" xml:lang=\"en-US\" xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\" xmlns:slic3r=\"http://schemas.slic3r.org/3mf/2017/06\"> \n"
  104. ." <slic3r:metadata version=\"" . Slic3r::VERSION() . "\"/>\n"
  105. ." <resources> \n"
  106. ." <object id=\"1\" type=\"model\">\n"
  107. ." <mesh>\n"
  108. ." <vertices>\n"
  109. ." <vertex x=\"-1\" y=\"-0.999998\" z=\"0.999998\"/>\n"
  110. ." <vertex x=\"-1\" y=\"-0.999998\" z=\"-1\"/>\n"
  111. ." <vertex x=\"1\" y=\"-1\" z=\"-0.999998\"/>\n"
  112. ." <vertex x=\"0.999996\" y=\"-1\" z=\"1\"/>\n"
  113. ." <vertex x=\"-1\" y=\"1\" z=\"0.999997\"/>\n"
  114. ." <vertex x=\"1\" y=\"0.999998\" z=\"1\"/>\n"
  115. ." <vertex x=\"1\" y=\"0.999998\" z=\"-0.999998\"/>\n"
  116. ." <vertex x=\"-0.999995\" y=\"1\" z=\"-1\"/>\n"
  117. ." </vertices>\n"
  118. ." <triangles>\n"
  119. ." <triangle v1=\"0\" v2=\"1\" v3=\"2\"/>\n"
  120. ." <triangle v1=\"0\" v2=\"2\" v3=\"3\"/>\n"
  121. ." <triangle v1=\"4\" v2=\"5\" v3=\"6\"/>\n"
  122. ." <triangle v1=\"4\" v2=\"6\" v3=\"7\"/>\n"
  123. ." <triangle v1=\"0\" v2=\"4\" v3=\"7\"/>\n"
  124. ." <triangle v1=\"0\" v2=\"7\" v3=\"1\"/>\n"
  125. ." <triangle v1=\"1\" v2=\"7\" v3=\"6\"/>\n"
  126. ." <triangle v1=\"1\" v2=\"6\" v3=\"2\"/>\n"
  127. ." <triangle v1=\"2\" v2=\"6\" v3=\"5\"/>\n"
  128. ." <triangle v1=\"2\" v2=\"5\" v3=\"3\"/>\n"
  129. ." <triangle v1=\"4\" v2=\"0\" v3=\"3\"/>\n"
  130. ." <triangle v1=\"4\" v2=\"3\" v3=\"5\"/>\n"
  131. ." </triangles>\n"
  132. ." <slic3r:volumes>\n"
  133. ." <slic3r:volume ts=\"0\" te=\"11\" modifier=\"0\" >\n"
  134. ." </slic3r:volume>\n"
  135. ." </slic3r:volumes>\n"
  136. ." </mesh>\n"
  137. ." </object>\n"
  138. ." </resources> \n"
  139. ." <build> \n"
  140. ." </build> \n"
  141. ."</model>\n";
  142. # Create a new model.
  143. my $model = Slic3r::Model->new;
  144. # Read a simple AMF file.
  145. $model->read_amf($amf_test_file);
  146. # Write in 3MF format.
  147. $model->write_tmf($tmf_output_file);
  148. # Check contents in 3dmodel.model.
  149. my $model_output ;
  150. unzip $tmf_output_file => \$model_output, Name => "3D/3dmodel.model"
  151. or die "unzip failed: $UnzipError\n";
  152. is (clean($model_output), clean($expected_model), "Test 5: 3dmodel.model file matching");
  153. # Check contents in content_types.xml.
  154. my $content_types_output ;
  155. unzip $tmf_output_file => \$content_types_output, Name => "[Content_Types].xml"
  156. or die "unzip failed: $UnzipError\n";
  157. is (clean($content_types_output), clean($expected_content_types), "Test 5: [Content_Types].xml file matching");
  158. # Check contents in _rels.xml.
  159. my $relationships_output ;
  160. unzip $tmf_output_file => \$relationships_output, Name => "_rels/.rels"
  161. or die "unzip failed: $UnzipError\n";
  162. is (clean($relationships_output), clean($expected_relationships), "Test 5: _rels/.rels file matching");
  163. unlink($tmf_output_file);
  164. }
  165. # Test 6: Read a Slic3r exported 3MF file.
  166. {
  167. my $input_path = dirname($current_path). "/models/3mf/chess.3mf";
  168. my $output_path = dirname($current_path). "/models/3mf/chess_2.3mf";
  169. # Read a 3MF model.
  170. my $model = Slic3r::Model->new;
  171. my $result = $model->read_tmf($input_path);
  172. is($result, 1, 'Test 6: Read 3MF file check.');
  173. # Export the 3MF file.
  174. $result = $model->write_tmf($output_path);
  175. is($result, 1, 'Test 6: Write 3MF file check.');
  176. # Re-read the exported file.
  177. my $model_2 = Slic3r::Model->new;
  178. $result = $model_2->read_tmf($output_path);
  179. is($result, 1, 'Test 6: Read second 3MF file check.');
  180. is($model->metadata_count(), $model_2->metadata_count(), 'Test 6: metadata match check.');
  181. # Check the number of read objects.
  182. is($model->objects_count(), $model_2->objects_count(), 'Test 6: objects match check.');
  183. unlink($output_path);
  184. }
  185. # Finish finish test cases.
  186. done_testing();
  187. __END__