diff --git a/gladius/src/ImageStackResource.cpp b/gladius/src/ImageStackResource.cpp index b6156ca..38c22d8 100644 --- a/gladius/src/ImageStackResource.cpp +++ b/gladius/src/ImageStackResource.cpp @@ -21,6 +21,8 @@ namespace gladius return 3; case io::PixelFormat::GRAYSCALE_16BIT: case io::PixelFormat::GRAYSCALE_8BIT: + case io::PixelFormat::GRAYSCALE_2BIT: + case io::PixelFormat::GRAYSCALE_1BIT: return 1; case io::PixelFormat::GRAYSCALE_ALPHA_16BIT: case io::PixelFormat::GRAYSCALE_ALPHA_8BIT: diff --git a/gladius/src/io/3mf/ImageExtractor.cpp b/gladius/src/io/3mf/ImageExtractor.cpp index 106d385..9bcb7c0 100644 --- a/gladius/src/io/3mf/ImageExtractor.cpp +++ b/gladius/src/io/3mf/ImageExtractor.cpp @@ -125,13 +125,36 @@ namespace gladius::io return fileContents; } + std::string colorTypeToString(LodePNGColorType colorType) + { + switch (colorType) + { + case LCT_GREY: + return "LCT_GREY"; + case LCT_RGB: + return "LCT_RGB"; + case LCT_PALETTE: + return "LCT_PALETTE"; + case LCT_GREY_ALPHA: + return "LCT_GREY_ALPHA"; + case LCT_RGBA: + return "LCT_RGBA"; + default: + return "unknown"; + } + } + PixelFormat fromPngColorType(LodePNGColorMode const & colorMode) { if (colorMode.bitdepth == 1) { return PixelFormat::GRAYSCALE_1BIT; } - if (colorMode.bitdepth == 8) + if (colorMode.bitdepth == 2) + { + return PixelFormat::GRAYSCALE_8BIT; + } + if (colorMode.bitdepth == 4 || colorMode.bitdepth == 8) { switch (colorMode.colortype) { @@ -143,8 +166,10 @@ namespace gladius::io return PixelFormat::RGB_8BIT; case LCT_RGBA: return PixelFormat::RGBA_8BIT; + case LCT_PALETTE: + return PixelFormat::RGBA_8BIT; default: - throw std::runtime_error("Error: unsupported PNG color type"); + throw std::runtime_error(fmt::format("Error: unsupported PNG color type {}", colorTypeToString(colorMode.colortype))); } } if (colorMode.bitdepth == 16) @@ -159,12 +184,14 @@ namespace gladius::io return PixelFormat::RGB_16BIT; case LCT_RGBA: return PixelFormat::RGBA_16BIT; + case LCT_PALETTE: + return PixelFormat::RGBA_16BIT; default: - throw std::runtime_error("Error: unsupported PNG color type"); + throw std::runtime_error(fmt::format("Error: unsupported PNG color type {}", colorTypeToString(colorMode.colortype))); } } - throw std::runtime_error("Error: unsupported PNG bit depth"); + throw std::runtime_error(fmt::format("Error: unsupported PNG bit depth {}", colorMode.bitdepth)); } ImageStack ImageExtractor::loadImageStack(FileList const & filenames) diff --git a/gladius/src/io/3mf/ImageStack.h b/gladius/src/io/3mf/ImageStack.h index 3117c1c..a7bd580 100644 --- a/gladius/src/io/3mf/ImageStack.h +++ b/gladius/src/io/3mf/ImageStack.h @@ -9,6 +9,7 @@ namespace gladius::io enum class PixelFormat { GRAYSCALE_1BIT, + GRAYSCALE_2BIT, RGBA_8BIT, RGB_8BIT, GRAYSCALE_8BIT, diff --git a/gladius/src/io/ImageStackExporter.cpp b/gladius/src/io/ImageStackExporter.cpp index 8800833..90ce06c 100644 --- a/gladius/src/io/ImageStackExporter.cpp +++ b/gladius/src/io/ImageStackExporter.cpp @@ -23,18 +23,29 @@ namespace gladius::io auto v6 = mesh->AddVertex({bb.max.x, bb.max.y, bb.max.z}); auto v7 = mesh->AddVertex({bb.min.x, bb.max.y, bb.max.z}); - mesh->AddTriangle({v0, v1, v2}); - mesh->AddTriangle({v0, v2, v3}); + // Bottom face + mesh->AddTriangle({v0, v2, v1}); + mesh->AddTriangle({v0, v3, v2}); + + // Top face mesh->AddTriangle({v4, v5, v6}); mesh->AddTriangle({v4, v6, v7}); - mesh->AddTriangle({v0, v4, v7}); - mesh->AddTriangle({v0, v7, v3}); - mesh->AddTriangle({v1, v5, v6}); - mesh->AddTriangle({v1, v6, v2}); - mesh->AddTriangle({v0, v1, v5}); + + // Front face mesh->AddTriangle({v0, v5, v4}); - mesh->AddTriangle({v3, v7, v6}); + mesh->AddTriangle({v0, v1, v5}); + + // Back face mesh->AddTriangle({v3, v6, v2}); + mesh->AddTriangle({v3, v7, v6}); + + // Left face + mesh->AddTriangle({v0, v7, v3}); + mesh->AddTriangle({v0, v4, v7}); + + // Right face + mesh->AddTriangle({v1, v6, v5}); + mesh->AddTriangle({v1, v2, v6}); mesh->SetName("Bounding Box"); @@ -265,9 +276,9 @@ namespace gladius::io for (int y = 0; y < height; y++) { - for (int x = 0 ; x < width; x++) + for (int x = 0; x < width; x++) { - unsigned int indexTarget = (y * width + x) * numChannels; + unsigned int indexTarget = (y * width + width - x - 1) * numChannels; unsigned int indexSource = ((height - y - 1) * width + x) * numChannels; for (unsigned int i = 0; i < numChannels; ++i) { @@ -275,8 +286,8 @@ namespace gladius::io } } } - - data = std::move(swappedData); + + data = std::move(swappedData); } bool ImageStackExporter::advanceExport(ComputeCore & generator) @@ -340,11 +351,13 @@ namespace gladius::io Lib3MF_uint32 ImageStackExporter::getColumnCountPng() const { - return m_rowCountWorld; + // return m_rowCountWorld; + return m_columnCountWorld; } Lib3MF_uint32 ImageStackExporter::getRowCountPng() const { - return m_columnCountWorld; + // return m_columnCountWorld; + return m_rowCountWorld; } } \ No newline at end of file diff --git a/gladius/src/io/ImageStackExporter.h b/gladius/src/io/ImageStackExporter.h index c952ec4..645df4f 100644 --- a/gladius/src/io/ImageStackExporter.h +++ b/gladius/src/io/ImageStackExporter.h @@ -2,6 +2,7 @@ #include "IExporter.h" #include "EventLogger.h" +#include "kernel/types.h" #include #include @@ -11,16 +12,13 @@ namespace gladius::io { - - - - + Lib3MF::PMeshObject addBoundingBoxAsMesh(Lib3MF::PModel model, BoundingBox const & bb); class ImageStackExporter : public IExporter { public: explicit ImageStackExporter(events::SharedLogger logger); - + void beginExport(const std::filesystem::path & fileName, ComputeCore & generator) override; bool advanceExport(ComputeCore & generator) override; @@ -38,7 +36,7 @@ namespace gladius::io std::filesystem::path m_outputFilename{}; - float m_layerIncrement_mm = 0.1f; + float m_layerIncrement_mm = 0.04f; float m_bandwidth_mm = m_layerIncrement_mm * 2.f; size_t m_qualityLevel = 1; // 3 = best quality, but insane high memory usage double m_progress = 0.; @@ -54,8 +52,6 @@ namespace gladius::io Lib3MF_uint32 m_columnCountWorld = 0u; Lib3MF_uint32 m_rowCountWorld = 0u; - - events::SharedLogger m_logger; }; } \ No newline at end of file diff --git a/gladius/tests/unittests/CMakeLists.txt b/gladius/tests/unittests/CMakeLists.txt index 5c93e51..be13152 100644 --- a/gladius/tests/unittests/CMakeLists.txt +++ b/gladius/tests/unittests/CMakeLists.txt @@ -37,15 +37,4 @@ file(GLOB FONT_FILES ) file(COPY ${FONT_FILES} DESTINATION "misc/fonts/") -# if(WIN32 AND NOT UNIX) -# configure_file(${CMAKE_SOURCE_DIR}/components/lib3mf/Bin/lib3mf.dll lib3mf.dll COPYONLY) -# endif() - -# if(WIN32 AND NOT UNIX) -# configure_file(${CMAKE_SOURCE_DIR}/components/lib3mf/Bin/lib3mf.dll src/lib3mf.dll COPYONLY) -# else() -# configure_file(${CMAKE_SOURCE_DIR}/components/lib3mf/Bin/lib3mf.so src/lib3mf.so COPYONLY) -# configure_file(${CMAKE_SOURCE_DIR}/components/lib3mf/Bin/lib3mf.so src/lib3mf.so.2 COPYONLY) -# endif() - gtest_add_tests(TARGET ${BINARY}) \ No newline at end of file diff --git a/gladius/tests/unittests/ComputeCore_tests.cpp b/gladius/tests/unittests/ComputeCore_tests.cpp index bcf1edc..b897eb0 100644 --- a/gladius/tests/unittests/ComputeCore_tests.cpp +++ b/gladius/tests/unittests/ComputeCore_tests.cpp @@ -54,16 +54,15 @@ namespace gladius_tests auto const & payloadData = core->getPrimitives().data.getData(); auto const payloadDataHash = helper::computeHash(payloadData.cbegin(), payloadData.cend()); - EXPECT_EQ(payloadDataHash, 9060768986935382616u); + EXPECT_EQ(payloadDataHash, 9702363036366401599u); - auto const parameter = core->getResourceContext().getParameterBuffer().getData(); - for (auto const & param : parameter) + auto const parameter = core->getResourceContext().getParameterBuffer().getData(); for (auto const & param : parameter) { std::cout << param << std::endl; } auto const parameterHash = helper::computeHash(parameter.cbegin(), parameter.cend()); - constexpr auto expectedHash = 16527889583062519464u; + constexpr auto expectedHash = 15121003317986780364u; EXPECT_EQ(parameterHash, expectedHash); EXPECT_TRUE(core->precomputeSdfForWholeBuildPlatform()); @@ -82,7 +81,7 @@ namespace gladius_tests auto const & data = preComp.getData(); auto const hash = helper::computeHash(data.cbegin(), data.cend()); - EXPECT_EQ(hash, 8853725864174386457); + EXPECT_EQ(hash, 17803807128366017585); auto bBox = core->getBoundingBox(); EXPECT_TRUE(bBox.has_value()); diff --git a/gladius/tests/unittests/ImageExtractor_tests.cpp b/gladius/tests/unittests/ImageExtractor_tests.cpp index 2c1fd13..552b378 100644 --- a/gladius/tests/unittests/ImageExtractor_tests.cpp +++ b/gladius/tests/unittests/ImageExtractor_tests.cpp @@ -9,7 +9,7 @@ namespace gladius_tests struct TestFiles { - static auto constexpr Boundary3mf = "testdata/Boundary.3mf"; + static auto constexpr Volumetric3mf = "testdata/box.imagestack.3mf"; }; TEST(ImageExtractor, Open_Valid3mfFile_ReturnsTrue) @@ -18,7 +18,7 @@ namespace gladius_tests io::ImageExtractor extractor; // act - auto const result = extractor.loadFromArchive(TestFiles::Boundary3mf); + auto const result = extractor.loadFromArchive(TestFiles::Volumetric3mf); // assert EXPECT_TRUE(result); @@ -37,10 +37,17 @@ namespace gladius_tests { // arrange io::ImageExtractor extractor; - extractor.loadFromArchive(TestFiles::Boundary3mf); + + std::filesystem::path currentPath = std::filesystem::current_path(); + std::cout << "Current path is: " << currentPath << std::endl; + auto const completeFilePath = currentPath / TestFiles::Volumetric3mf; + std::cout << "Complete file path is: " << completeFilePath << std::endl; + ASSERT_TRUE(std::filesystem::exists(completeFilePath)); + + extractor.loadFromArchive(TestFiles::Volumetric3mf); // act - auto const result = extractor.loadFileFromArchive("volume/layer_01.png"); + auto const result = extractor.loadFileFromArchive("volume/1/layer_001.png"); // assert EXPECT_FALSE(result.empty()); @@ -63,16 +70,16 @@ namespace gladius_tests { // arrange io::ImageExtractor extractor; - extractor.loadFromArchive(TestFiles::Boundary3mf); + extractor.loadFromArchive(TestFiles::Volumetric3mf); // act - io::ImageStack const imgStack = extractor.loadImageStack({"volume/layer_01.png"}); + io::ImageStack const imgStack = extractor.loadImageStack({"volume/1/layer_001.png"}); auto firstImage = imgStack.front(); auto pngInfo = extractor.getPNGInfo(); constexpr auto numChannels = 4; // lodepng always decodes to RGBA auto numPixels = firstImage.getWidth() * firstImage.getHeight(); - auto numBytes = numPixels * numChannels * pngInfo.color.bitdepth / 8; + auto numBytes = numPixels * numChannels; // assert EXPECT_EQ(firstImage.getData().size(), numBytes); } diff --git a/gladius/tests/unittests/ImageStackExporter_tests.cpp b/gladius/tests/unittests/ImageStackExporter_tests.cpp index 45ccc02..760feb8 100644 --- a/gladius/tests/unittests/ImageStackExporter_tests.cpp +++ b/gladius/tests/unittests/ImageStackExporter_tests.cpp @@ -1,27 +1,29 @@ -#include -#include #include "io/ImageStackExporter.h" #include "io/vdb.h" #include +#include +#include #include #include // Mock classes for filesystem and OpenVDB grid -class MockFileSystem { -public: - MOCK_METHOD(bool, exists, (const std::filesystem::path&), (const)); - MOCK_METHOD(void, create_directories, (const std::filesystem::path&)); +class MockFileSystem +{ + public: + MOCK_METHOD(bool, exists, (const std::filesystem::path &), (const)); + MOCK_METHOD(void, create_directories, (const std::filesystem::path &) ); }; -class MockFloatGrid : public openvdb::FloatGrid { -public: +class MockFloatGrid : public openvdb::FloatGrid +{ + public: using Ptr = std::shared_ptr; MOCK_METHOD(openvdb::GridClass, getGridClass, (), (const override)); MOCK_METHOD(openvdb::math::Transform::Ptr, transformPtr, (), (const)); template - bool isType() const + bool isType() const { return isTypeMock(typeid(T)); } @@ -30,13 +32,16 @@ class MockFloatGrid : public openvdb::FloatGrid { // Add more mocked methods as needed for the test }; -class ImageStackExporterTest : public ::testing::Test { -protected: - void SetUp() override { +class ImageStackExporterTest : public ::testing::Test +{ + protected: + void SetUp() override + { // Setup code for each test } - void TearDown() override { + void TearDown() override + { // Cleanup code for each test } @@ -44,20 +49,106 @@ class ImageStackExporterTest : public ::testing::Test { MockFloatGrid::Ptr mockGrid = std::make_shared(); }; -// TEST_F(ImageStackExporterTest, ExportValidGrid) { -// // Setup expectations +bool operator==(Lib3MF::sPosition const & lhs, Lib3MF::sPosition const & rhs) +{ + return lhs.m_Coordinates[0] == rhs.m_Coordinates[0] && + lhs.m_Coordinates[1] == rhs.m_Coordinates[1] && + lhs.m_Coordinates[2] == rhs.m_Coordinates[2]; +} + +TEST(ImageStackExporterTest, AddBoundingBoxAsMesh) +{ + using namespace gladius::io; + using namespace gladius; + + // Create a bounding box + BoundingBox bb; + bb.min = {0.0, 0.0, 0.0}; + bb.max = {1.0, 2.0, 3.0}; + + // create a model + auto model = Lib3MF::CWrapper::loadLibrary()->CreateModel(); + auto mesh = addBoundingBoxAsMesh(model, bb); + + // Check if the mesh has the correct number of vertices and triangles + ASSERT_EQ(mesh->GetVertexCount(), 8); + ASSERT_EQ(mesh->GetTriangleCount(), 12); + + // Check if the mesh has the correct name + ASSERT_EQ(mesh->GetName(), "Bounding Box"); + + // Check if the vertices are correct + auto v0 = mesh->GetVertex(0); + auto v1 = mesh->GetVertex(1); + auto v2 = mesh->GetVertex(2); + auto v3 = mesh->GetVertex(3); + auto v4 = mesh->GetVertex(4); + auto v5 = mesh->GetVertex(5); + auto v6 = mesh->GetVertex(6); + auto v7 = mesh->GetVertex(7); + + ASSERT_TRUE(v0 == Lib3MF::sPosition({0.0, 0.0, 0.0})); + ASSERT_TRUE(v1 == Lib3MF::sPosition({1.0, 0.0, 0.0})); + ASSERT_TRUE(v2 == Lib3MF::sPosition({1.0, 2.0, 0.0})); + ASSERT_TRUE(v3 == Lib3MF::sPosition({0.0, 2.0, 0.0})); + + ASSERT_TRUE(v4 == Lib3MF::sPosition({0.0, 0.0, 3.0})); + ASSERT_TRUE(v5 == Lib3MF::sPosition({1.0, 0.0, 3.0})); + ASSERT_TRUE(v6 == Lib3MF::sPosition({1.0, 2.0, 3.0})); + ASSERT_TRUE(v7 == Lib3MF::sPosition({0.0, 2.0, 3.0})); + + // Check if the triangles are correct + ASSERT_EQ(mesh->GetTriangle(0).m_Indices[0], 0); + ASSERT_EQ(mesh->GetTriangle(0).m_Indices[1], 2); + ASSERT_EQ(mesh->GetTriangle(0).m_Indices[2], 1); + + ASSERT_EQ(mesh->GetTriangle(1).m_Indices[0], 0); + ASSERT_EQ(mesh->GetTriangle(1).m_Indices[1], 3); + ASSERT_EQ(mesh->GetTriangle(1).m_Indices[2], 2); + + ASSERT_EQ(mesh->GetTriangle(2).m_Indices[0], 4); + ASSERT_EQ(mesh->GetTriangle(2).m_Indices[1], 5); + ASSERT_EQ(mesh->GetTriangle(2).m_Indices[2], 6); + + ASSERT_EQ(mesh->GetTriangle(3).m_Indices[0], 4); + ASSERT_EQ(mesh->GetTriangle(3).m_Indices[1], 6); + ASSERT_EQ(mesh->GetTriangle(3).m_Indices[2], 7); + + ASSERT_EQ(mesh->GetTriangle(4).m_Indices[0], 0); + ASSERT_EQ(mesh->GetTriangle(4).m_Indices[1], 5); + ASSERT_EQ(mesh->GetTriangle(4).m_Indices[2], 4); + + ASSERT_EQ(mesh->GetTriangle(5).m_Indices[0], 0); + ASSERT_EQ(mesh->GetTriangle(5).m_Indices[1], 1); + ASSERT_EQ(mesh->GetTriangle(5).m_Indices[2], 5); + + ASSERT_EQ(mesh->GetTriangle(6).m_Indices[0], 3); + ASSERT_EQ(mesh->GetTriangle(6).m_Indices[1], 6); + ASSERT_EQ(mesh->GetTriangle(6).m_Indices[2], 2); + + ASSERT_EQ(mesh->GetTriangle(7).m_Indices[0], 3); + ASSERT_EQ(mesh->GetTriangle(7).m_Indices[1], 7); + ASSERT_EQ(mesh->GetTriangle(7).m_Indices[2], 6); -// // Assuming mockGrid is a mocked object of the grid being exported -// // EXPECT_CALL(*mockGrid, getGridClass()).WillOnce(testing::Return(openvdb::GRID_LEVEL_SET)); - + ASSERT_EQ(mesh->GetTriangle(8).m_Indices[0], 0); + ASSERT_EQ(mesh->GetTriangle(8).m_Indices[1], 7); + ASSERT_EQ(mesh->GetTriangle(8).m_Indices[2], 3); -// // You can add expectations for specific methods called on mockGrid if needed + ASSERT_EQ(mesh->GetTriangle(9).m_Indices[0], 0); + ASSERT_EQ(mesh->GetTriangle(9).m_Indices[1], 4); + ASSERT_EQ(mesh->GetTriangle(9).m_Indices[2], 7); -// // Call the method under test + ASSERT_EQ(mesh->GetTriangle(10).m_Indices[0], 1); + ASSERT_EQ(mesh->GetTriangle(10).m_Indices[1], 6); + ASSERT_EQ(mesh->GetTriangle(10).m_Indices[2], 5); + ASSERT_EQ(mesh->GetTriangle(11).m_Indices[0], 1); + ASSERT_EQ(mesh->GetTriangle(11).m_Indices[1], 2); + ASSERT_EQ(mesh->GetTriangle(11).m_Indices[2], 6); -// // Assertions to verify the correct behavior -// // For example, check if the correct files were created -// } + // Check if the mesh has the correct number of vertices and triangles + ASSERT_EQ(mesh->GetVertexCount(), 8); + ASSERT_EQ(mesh->GetTriangleCount(), 12); +} // Additional tests can be added here \ No newline at end of file diff --git a/gladius/tests/unittests/testdata/box.imagestack.3mf b/gladius/tests/unittests/testdata/box.imagestack.3mf new file mode 100644 index 0000000..afb6f44 Binary files /dev/null and b/gladius/tests/unittests/testdata/box.imagestack.3mf differ