From 78f1f06d3e934f53fdbda83c2a5b8e6af967ffbf Mon Sep 17 00:00:00 2001 From: Jan Orend <56254096+3dJan@users.noreply.github.com> Date: Thu, 5 Dec 2024 09:45:50 +0100 Subject: [PATCH 1/4] Add example for creating a gyroid surface and a box mesh --- .../Cpp/Source/FillMeshWithGyroid.cpp | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 SDK/Examples/Cpp/Source/FillMeshWithGyroid.cpp diff --git a/SDK/Examples/Cpp/Source/FillMeshWithGyroid.cpp b/SDK/Examples/Cpp/Source/FillMeshWithGyroid.cpp new file mode 100644 index 00000000..f3076342 --- /dev/null +++ b/SDK/Examples/Cpp/Source/FillMeshWithGyroid.cpp @@ -0,0 +1,118 @@ +#include + +#include "lib3mf_implicit.hpp" + +Lib3MF::PImplicitFunction createGyroidFunction(Lib3MF::CModel& model) +{ + Lib3MF::PImplicitFunction gyroidFunction = model.AddImplicitFunction(); + gyroidFunction->SetDisplayName("gyroid"); + + auto inputPos = gyroidFunction->AddInput("pos", "position", + Lib3MF::eImplicitPortType::Vector); + + auto decomposePos = gyroidFunction->AddDecomposeVectorNode( + "decomposePos", "decompose pos", "group_a"); + gyroidFunction->AddLink(inputPos, decomposePos->GetInputA()); + + auto composeYZX = gyroidFunction->AddComposeVectorNode( + "composeYZX", "compose yzx", "group_a"); + gyroidFunction->AddLink(decomposePos->GetOutputZ(), + composeYZX->GetInputX()); + gyroidFunction->AddLink(decomposePos->GetOutputY(), + composeYZX->GetInputY()); + gyroidFunction->AddLink(decomposePos->GetOutputX(), + composeYZX->GetInputZ()); + + auto sinNode = gyroidFunction->AddSinNode( + "sin", Lib3MF::eImplicitNodeConfiguration::VectorToVector, "sinus", + "group_a"); + gyroidFunction->AddLink(inputPos, sinNode->GetInputA()); + + auto cosNode = gyroidFunction->AddCosNode( + "cos", Lib3MF::eImplicitNodeConfiguration::VectorToVector, "cosinus", + "group_a"); + gyroidFunction->AddLink(composeYZX->GetOutputResult(), + cosNode->GetInputA()); + + auto dotNode = gyroidFunction->AddDotNode("dot", "dot product", "group_a"); + gyroidFunction->AddLink(sinNode->GetOutputResult(), dotNode->GetInputA()); + gyroidFunction->AddLink(cosNode->GetOutputResult(), dotNode->GetInputB()); + + auto output = + gyroidFunction->AddOutput("shape", "signed distance to the surface", + Lib3MF::eImplicitPortType::Scalar); + gyroidFunction->AddLink(dotNode->GetOutputResult(), output); + + return gyroidFunction; +} + +Lib3MF::PMeshObject createBoxAsMesh(Lib3MF::CModel& model, float sizeX, + float sizeY, float sizeZ) +{ + Lib3MF::PMeshObject meshObject = model.AddMeshObject(); + meshObject->SetName("Box"); + + // Create mesh structure of a cube + std::vector vertices(8); + std::vector triangles(12); + + // Manually create vertices + vertices[0] = {0.0f, 0.0f, 0.0f}; + vertices[1] = {sizeX, 0.0f, 0.0f}; + vertices[2] = {sizeX, sizeY, 0.0f}; + vertices[3] = {0.0f, sizeY, 0.0f}; + vertices[4] = {0.0f, 0.0f, sizeZ}; + vertices[5] = {sizeX, 0.0f, sizeZ}; + vertices[6] = {sizeX, sizeY, sizeZ}; + vertices[7] = {0.0f, sizeY, sizeZ}; + + // Manually create triangles + triangles[0] = {0, 1, 2}; + triangles[1] = {0, 2, 3}; + triangles[2] = {4, 5, 6}; + triangles[3] = {4, 6, 7}; + triangles[4] = {0, 1, 5}; + triangles[5] = {0, 5, 4}; + triangles[6] = {1, 2, 6}; + triangles[7] = {1, 6, 5}; + triangles[8] = {2, 3, 7}; + triangles[9] = {2, 7, 6}; + triangles[10] = {3, 0, 4}; + triangles[11] = {3, 4, 7}; + + // Add vertices and triangles to the mesh object + meshObject->SetGeometry(vertices, triangles); + + return meshObject; +} + +int main() +{ + Lib3MF::PWrapper wrapper = Lib3MF::CWrapper::loadLibrary(); + auto model = wrapper->CreateModel(); + + // First we create the resourees we want to use + //================================================================================================== + // In this example we just create a box as a mesh, but you could as well + // extend it to load a 3mf file that already contains a mesh object + auto box = createBoxAsMesh(*model, 10.0f, 10.0f, 10.0f); + + auto gyroidFunction = createGyroidFunction(*model); + + // Now we create the gyroid surface as level set, with the mesh definining + // the evaluation domain + auto theLevelSet = model->AddLevelSet(); + theLevelSet->SetFunction(gyroidFunction.get()); + theLevelSet->SetChannelName("shape"); + theLevelSet->SetMesh(box.get()); + theLevelSet->SetMeshBBoxOnly( + true); // Treating the mesh as a bounding box only makes the evaluation + // faster. Disable this for abritrary meshes. + + // Add a build item for the level set + model->AddBuildItem(theLevelSet.get(), wrapper->GetIdentityTransform()); + + // write the model to a file + auto writer = model->QueryWriter("3mf"); + writer->WriteToFile("GyroidBox.3mf"); +} \ No newline at end of file From 4c937dced96bda00257ccacd07713f47e2e2f765 Mon Sep 17 00:00:00 2001 From: Jan Orend <56254096+3dJan@users.noreply.github.com> Date: Thu, 5 Dec 2024 09:46:31 +0100 Subject: [PATCH 2/4] Fix for classParam --- .../Bindings/Cpp/lib3mf_implicit.hpp | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/Autogenerated/Bindings/Cpp/lib3mf_implicit.hpp b/Autogenerated/Bindings/Cpp/lib3mf_implicit.hpp index 3c978144..e674c69c 100644 --- a/Autogenerated/Bindings/Cpp/lib3mf_implicit.hpp +++ b/Autogenerated/Bindings/Cpp/lib3mf_implicit.hpp @@ -540,25 +540,26 @@ typedef PModel PLib3MFModel; template class classParam { private: - const T* m_ptr; + std::shared_ptr m_sharedPtr; + const T* m_ptr; public: - classParam(const T* ptr) - : m_ptr (ptr) - { - } + classParam(const T* ptr) + : m_ptr(ptr) + { + } - classParam(std::shared_ptr sharedPtr) - : m_ptr (sharedPtr.get()) - { - } + classParam(std::shared_ptr sharedPtr) + : m_sharedPtr(sharedPtr), m_ptr(sharedPtr.get()) + { + } - Lib3MFHandle GetHandle() - { - if (m_ptr != nullptr) - return m_ptr->handle(); - return nullptr; - } + Lib3MFHandle GetHandle() + { + if (m_ptr != nullptr) + return m_ptr->handle(); + return nullptr; + } }; /************************************************************************************************************************* From 8c51ef27bc0893052a4d398fee29fa065ab7e99b Mon Sep 17 00:00:00 2001 From: Jan Orend <56254096+3dJan@users.noreply.github.com> Date: Thu, 5 Dec 2024 09:47:33 +0100 Subject: [PATCH 3/4] Add example for filling a mesh with a gyroid surface --- SDK/Examples/Cpp/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SDK/Examples/Cpp/CMakeLists.txt b/SDK/Examples/Cpp/CMakeLists.txt index 2449a2af..13ec2b9b 100644 --- a/SDK/Examples/Cpp/CMakeLists.txt +++ b/SDK/Examples/Cpp/CMakeLists.txt @@ -80,6 +80,8 @@ CopySharedLibrary(Example_VolumeCombineFunctions) add_executable(Example_VolumeImageStack Source/VolumeImageStack.cpp) CopySharedLibrary(Example_VolumeImageStack) +add_executable(Example_FillMeshWithGyroid Source/FillMeshWithGyroid.cpp) +CopySharedLibrary(Example_FillMeshWithGyroid) if (${MSVC}) IF(${CMAKE_VERSION} VERSION_LESS 3.6.3) From d52535ecbc4db43c61e09d808e3408c9e3a92856 Mon Sep 17 00:00:00 2001 From: Jan Orend <56254096+3dJan@users.noreply.github.com> Date: Thu, 5 Dec 2024 10:13:53 +0100 Subject: [PATCH 4/4] Refactor gyroid function to correct input linking and add subtraction node for thickness adjustment --- .../Cpp/Source/FillMeshWithGyroid.cpp | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/SDK/Examples/Cpp/Source/FillMeshWithGyroid.cpp b/SDK/Examples/Cpp/Source/FillMeshWithGyroid.cpp index f3076342..5f077225 100644 --- a/SDK/Examples/Cpp/Source/FillMeshWithGyroid.cpp +++ b/SDK/Examples/Cpp/Source/FillMeshWithGyroid.cpp @@ -17,9 +17,9 @@ Lib3MF::PImplicitFunction createGyroidFunction(Lib3MF::CModel& model) auto composeYZX = gyroidFunction->AddComposeVectorNode( "composeYZX", "compose yzx", "group_a"); gyroidFunction->AddLink(decomposePos->GetOutputZ(), - composeYZX->GetInputX()); - gyroidFunction->AddLink(decomposePos->GetOutputY(), composeYZX->GetInputY()); + gyroidFunction->AddLink(decomposePos->GetOutputY(), + composeYZX->GetInputX()); gyroidFunction->AddLink(decomposePos->GetOutputX(), composeYZX->GetInputZ()); @@ -38,10 +38,28 @@ Lib3MF::PImplicitFunction createGyroidFunction(Lib3MF::CModel& model) gyroidFunction->AddLink(sinNode->GetOutputResult(), dotNode->GetInputA()); gyroidFunction->AddLink(cosNode->GetOutputResult(), dotNode->GetInputB()); + auto absNode = gyroidFunction->AddAbsNode( + "abs", Lib3MF::eImplicitNodeConfiguration::ScalarToScalar, "abs", + "group_a"); + gyroidFunction->AddLink(dotNode->GetOutputResult(), absNode->GetInputA()); + + auto substractionNode = gyroidFunction->AddSubtractionNode( + "sub", Lib3MF::eImplicitNodeConfiguration::ScalarToScalar, "substract", + "group_a"); + + auto halfThicknessNode = + gyroidFunction->AddConstantNode("half_thickness", "hafl of the thickness", "group_a"); + halfThicknessNode->SetConstant(0.4); + + gyroidFunction->AddLink(absNode->GetOutputResult(), + substractionNode->GetInputA()); + gyroidFunction->AddLink(halfThicknessNode->GetOutputValue(), + substractionNode->GetInputB()); + auto output = gyroidFunction->AddOutput("shape", "signed distance to the surface", Lib3MF::eImplicitPortType::Scalar); - gyroidFunction->AddLink(dotNode->GetOutputResult(), output); + gyroidFunction->AddLink(substractionNode->GetOutputResult(), output); return gyroidFunction; } @@ -95,7 +113,7 @@ int main() //================================================================================================== // In this example we just create a box as a mesh, but you could as well // extend it to load a 3mf file that already contains a mesh object - auto box = createBoxAsMesh(*model, 10.0f, 10.0f, 10.0f); + auto box = createBoxAsMesh(*model, 50.0f, 23.0f, 45.0f); auto gyroidFunction = createGyroidFunction(*model);