23_3mf.t 9.8 KB

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