From 093c79f53b1de8110be524762f448e1d46f6031a Mon Sep 17 00:00:00 2001 From: Michael Jackson Date: Sun, 24 Nov 2024 09:36:57 -0500 Subject: [PATCH] ENH: Refactors the calculation of triangle normals and areas into utility functions (#1142) Refactors the calculation of triangle normals and areas into utility functions Signed-off-by: Michael Jackson --- .../Filters/ComputeTriangleAreasFilter.cpp | 58 +--------- .../Filters/TriangleNormalFilter.cpp | 58 +--------- .../test/TriangleNormalFilterTest.cpp | 10 +- src/simplnx/Utilities/GeometryUtilities.cpp | 108 ++++++++++++++++++ src/simplnx/Utilities/GeometryUtilities.hpp | 20 ++++ 5 files changed, 138 insertions(+), 116 deletions(-) diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ComputeTriangleAreasFilter.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ComputeTriangleAreasFilter.cpp index e2c962c486..8a67e51eee 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ComputeTriangleAreasFilter.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ComputeTriangleAreasFilter.cpp @@ -8,11 +8,10 @@ #include "simplnx/Parameters/DataGroupSelectionParameter.hpp" #include "simplnx/Parameters/DataObjectNameParameter.hpp" #include "simplnx/Parameters/GeometrySelectionParameter.hpp" +#include "simplnx/Utilities/GeometryUtilities.hpp" #include "simplnx/Utilities/Math/MatrixMath.hpp" - -#include "simplnx/Utilities/SIMPLConversion.hpp" - #include "simplnx/Utilities/ParallelDataAlgorithm.hpp" +#include "simplnx/Utilities/SIMPLConversion.hpp" using namespace nx::core; @@ -20,52 +19,6 @@ namespace { constexpr nx::core::int32 k_MissingFeatureAttributeMatrix = -75769; -/** - * @brief The CalculateAreasImpl class implements a threaded algorithm that computes the area of each - * triangle for a set of triangles - */ -class CalculateAreasImpl -{ -public: - CalculateAreasImpl(const TriangleGeom* triangleGeom, Float64AbstractDataStore& areas, const std::atomic_bool& shouldCancel) - : m_TriangleGeom(triangleGeom) - , m_Areas(areas) - , m_ShouldCancel(shouldCancel) - { - } - virtual ~CalculateAreasImpl() = default; - - void convert(size_t start, size_t end) const - { - std::array cross = {0.0f, 0.0f, 0.0f}; - for(size_t triangleIndex = start; triangleIndex < end; triangleIndex++) - { - if(m_ShouldCancel) - { - break; - } - std::array vertCoords; - m_TriangleGeom->getFaceCoordinates(triangleIndex, vertCoords); - - auto vecA = (vertCoords[0] - vertCoords[1]).toArray(); - auto vecB = (vertCoords[0] - vertCoords[2]).toArray(); - - MatrixMath::CrossProduct(vecA.data(), vecB.data(), cross.data()); - - m_Areas[triangleIndex] = 0.5F * MatrixMath::Magnitude3x1(cross.data()); - } - } - - void operator()(const Range& range) const - { - convert(range.min(), range.max()); - } - -private: - const TriangleGeom* m_TriangleGeom = nullptr; - Float64AbstractDataStore& m_Areas; - const std::atomic_bool& m_ShouldCancel; -}; } // namespace namespace nx::core @@ -173,12 +126,7 @@ Result<> ComputeTriangleAreasFilter::executeImpl(DataStructure& dataStructure, c DataPath pCalculatedAreasDataPath = pTriangleGeometryDataPath.createChildPath(faceAttributeMatrix->getName()).createChildPath(pCalculatedAreasName); auto& faceAreas = dataStructure.getDataAs(pCalculatedAreasDataPath)->getDataStoreRef(); - // Parallel algorithm to find duplicate nodes - ParallelDataAlgorithm dataAlg; - dataAlg.setRange(0ULL, static_cast(triangleGeom->getNumberOfFaces())); - dataAlg.execute(CalculateAreasImpl(triangleGeom, faceAreas, shouldCancel)); - - return {}; + return nx::core::GeometryUtilities::ComputeTriangleAreas(triangleGeom, faceAreas, shouldCancel); } namespace diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/TriangleNormalFilter.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/TriangleNormalFilter.cpp index 336bd8f20f..7f2e5061e2 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/TriangleNormalFilter.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/TriangleNormalFilter.cpp @@ -7,6 +7,7 @@ #include "simplnx/Parameters/DataGroupSelectionParameter.hpp" #include "simplnx/Parameters/DataObjectNameParameter.hpp" #include "simplnx/Parameters/GeometrySelectionParameter.hpp" +#include "simplnx/Utilities/GeometryUtilities.hpp" #include "simplnx/Utilities/Math/MatrixMath.hpp" #include "simplnx/Utilities/ParallelDataAlgorithm.hpp" #include "simplnx/Utilities/SIMPLConversion.hpp" @@ -18,56 +19,6 @@ namespace constexpr nx::core::int32 k_MissingFeatureAttributeMatrix = -75969; -/** - * @brief The CalculateAreasImpl class implements a threaded algorithm that computes the normal of each - * triangle for a set of triangles - */ -class CalculateNormalsImpl -{ -public: - CalculateNormalsImpl(const TriangleGeom* triangleGeom, Float64AbstractDataStore& normals, const std::atomic_bool& shouldCancel) - : m_TriangleGeom(triangleGeom) - , m_Normals(normals) - , m_ShouldCancel(shouldCancel) - { - } - virtual ~CalculateNormalsImpl() = default; - - void generate(size_t start, size_t end) const - { - std::array normal = {0.0f, 0.0f, 0.0f}; - for(size_t triangleIndex = start; triangleIndex < end; triangleIndex++) - { - - if(m_ShouldCancel) - { - break; - } - std::array vertCoords; - m_TriangleGeom->getFaceCoordinates(triangleIndex, vertCoords); - - auto vecA = (vertCoords[1] - vertCoords[0]).toArray(); - auto vecB = (vertCoords[2] - vertCoords[0]).toArray(); - - MatrixMath::CrossProduct(vecA.data(), vecB.data(), normal.data()); - MatrixMath::Normalize3x1(normal.data()); - - m_Normals[triangleIndex * 3] = static_cast(normal[0]); - m_Normals[triangleIndex * 3 + 1] = static_cast(normal[1]); - m_Normals[triangleIndex * 3 + 2] = static_cast(normal[2]); - } - } - - void operator()(const Range& range) const - { - generate(range.min(), range.max()); - } - -private: - const TriangleGeom* m_TriangleGeom = nullptr; - Float64AbstractDataStore& m_Normals; - const std::atomic_bool& m_ShouldCancel; -}; } // namespace namespace nx::core @@ -172,12 +123,7 @@ Result<> TriangleNormalFilter::executeImpl(DataStructure& dataStructure, const A DataPath pNormalsArrayPath = pTriangleGeometryDataPath.createChildPath(faceAttributeMatrix->getName()).createChildPath(pNormalsName); auto& normals = dataStructure.getDataAs(pNormalsArrayPath)->getDataStoreRef(); - // Parallel algorithm to find duplicate nodes - ParallelDataAlgorithm dataAlg; - dataAlg.setRange(0ULL, static_cast(triangleGeom->getNumberOfFaces())); - dataAlg.execute(CalculateNormalsImpl(triangleGeom, normals, shouldCancel)); - - return {}; + return nx::core::GeometryUtilities::ComputeTriangleNormals(triangleGeom, normals, shouldCancel); } namespace diff --git a/src/Plugins/SimplnxCore/test/TriangleNormalFilterTest.cpp b/src/Plugins/SimplnxCore/test/TriangleNormalFilterTest.cpp index abde556032..b38bdc5f67 100644 --- a/src/Plugins/SimplnxCore/test/TriangleNormalFilterTest.cpp +++ b/src/Plugins/SimplnxCore/test/TriangleNormalFilterTest.cpp @@ -78,6 +78,11 @@ TEST_CASE("SimplnxCore::TriangleNormalFilter", "[SimplnxCore][TriangleNormalFilt auto executeResult = filter.execute(dataStructure, args); SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result); + // Write the DataStructure out to the file system +#ifdef SIMPLNX_WRITE_TEST_OUTPUT + nx::core::UnitTest::WriteTestDataStructure(dataStructure, fs::path(fmt::format("{}/TriangleNormals.dream3d", unit_test::k_BinaryTestOutputDir))); +#endif + DataPath triangleNormalsDataPath = geometryPath.createChildPath(triangleFaceDataGroupName).createChildPath(triangleNormalsName); // Let's compare the normals. @@ -91,9 +96,4 @@ TEST_CASE("SimplnxCore::TriangleNormalFilter", "[SimplnxCore][TriangleNormalFilt REQUIRE(result < ::k_max_difference); } } - - // Write the DataStructure out to the file system -#ifdef SIMPLNX_WRITE_TEST_OUTPUT - WriteTestDataStructure(dataStructure, fs::path(fmt::format("{}/TriangleNormals.dream3d", unit_test::k_BinaryTestOutputDir))); -#endif } diff --git a/src/simplnx/Utilities/GeometryUtilities.cpp b/src/simplnx/Utilities/GeometryUtilities.cpp index 400231ef3c..74ef30b406 100644 --- a/src/simplnx/Utilities/GeometryUtilities.cpp +++ b/src/simplnx/Utilities/GeometryUtilities.cpp @@ -2,6 +2,7 @@ #include "simplnx/Common/Array.hpp" #include "simplnx/Common/Result.hpp" +#include "simplnx/Utilities/Math/MatrixMath.hpp" using namespace nx::core; @@ -142,3 +143,110 @@ Result GeometryUtilities::CalculatePartitionLengthsOfBoundingBox(cons FloatVec3 lengthPerPartition = {lengthX, lengthY, lengthZ}; return Result{lengthPerPartition}; } + +/** + * @brief The ComputeTriangleAreasImpl class implements a threaded algorithm that computes the area of each + * triangle for a set of triangles + */ +class ComputeTriangleAreasImpl +{ +public: + ComputeTriangleAreasImpl(const TriangleGeom* triangleGeom, Float64AbstractDataStore& areas, const std::atomic_bool& shouldCancel) + : m_TriangleGeom(triangleGeom) + , m_Areas(areas) + , m_ShouldCancel(shouldCancel) + { + } + virtual ~ComputeTriangleAreasImpl() = default; + + void convert(size_t start, size_t end) const + { + std::array cross = {0.0f, 0.0f, 0.0f}; + for(size_t triangleIndex = start; triangleIndex < end; triangleIndex++) + { + if(m_ShouldCancel) + { + break; + } + std::array vertCoords; + m_TriangleGeom->getFaceCoordinates(triangleIndex, vertCoords); + m_Areas[triangleIndex] = 0.5F * (vertCoords[0] - vertCoords[1]).cross(vertCoords[0] - vertCoords[2]).magnitude(); + } + } + + void operator()(const Range& range) const + { + convert(range.min(), range.max()); + } + +private: + const TriangleGeom* m_TriangleGeom = nullptr; + Float64AbstractDataStore& m_Areas; + const std::atomic_bool& m_ShouldCancel; +}; + +Result<> GeometryUtilities::ComputeTriangleAreas(const nx::core::TriangleGeom* triangleGeom, Float64AbstractDataStore& faceAreas, const std::atomic_bool& shouldCancel) +{ + // Parallel algorithm to find duplicate nodes + ParallelDataAlgorithm dataAlg; + dataAlg.setRange(0ULL, static_cast(triangleGeom->getNumberOfFaces())); + dataAlg.execute(ComputeTriangleAreasImpl(triangleGeom, faceAreas, shouldCancel)); + + return {}; +} + +/** + * @brief The CalculateAreasImpl class implements a threaded algorithm that computes the normal of each + * triangle for a set of triangles + */ +class CalculateNormalsImpl +{ +public: + CalculateNormalsImpl(const TriangleGeom* triangleGeom, Float64AbstractDataStore& normals, const std::atomic_bool& shouldCancel) + : m_TriangleGeom(triangleGeom) + , m_Normals(normals) + , m_ShouldCancel(shouldCancel) + { + } + virtual ~CalculateNormalsImpl() = default; + + void generate(size_t start, size_t end) const + { + for(size_t triangleIndex = start; triangleIndex < end; triangleIndex++) + { + if(m_ShouldCancel) + { + break; + } + std::array vertCoords; + m_TriangleGeom->getFaceCoordinates(triangleIndex, vertCoords); + + auto normal = (vertCoords[1] - vertCoords[0]).cross(vertCoords[2] - vertCoords[0]); + normal = normal / normal.magnitude(); + + m_Normals[triangleIndex * 3] = static_cast(normal[0]); + m_Normals[triangleIndex * 3 + 1] = static_cast(normal[1]); + m_Normals[triangleIndex * 3 + 2] = static_cast(normal[2]); + } + } + + void operator()(const Range& range) const + { + generate(range.min(), range.max()); + } + +private: + const TriangleGeom* m_TriangleGeom = nullptr; + Float64AbstractDataStore& m_Normals; + const std::atomic_bool& m_ShouldCancel; +}; + +Result<> GeometryUtilities::ComputeTriangleNormals(const nx::core::TriangleGeom* triangleGeom, Float64AbstractDataStore& normals, const std::atomic_bool& shouldCancel) +{ + // Parallel algorithm to find duplicate nodes + ParallelDataAlgorithm dataAlg; + dataAlg.setRange(0ULL, static_cast(triangleGeom->getNumberOfFaces())); + dataAlg.execute(CalculateNormalsImpl(triangleGeom, normals, shouldCancel)); + + return {}; +} diff --git a/src/simplnx/Utilities/GeometryUtilities.hpp b/src/simplnx/Utilities/GeometryUtilities.hpp index 8fcb789100..29fea11bcf 100644 --- a/src/simplnx/Utilities/GeometryUtilities.hpp +++ b/src/simplnx/Utilities/GeometryUtilities.hpp @@ -5,6 +5,7 @@ #include "simplnx/DataStructure/Geometry/INodeGeometry3D.hpp" #include "simplnx/DataStructure/Geometry/ImageGeom.hpp" #include "simplnx/DataStructure/Geometry/RectGridGeom.hpp" +#include "simplnx/DataStructure/Geometry/TriangleGeom.hpp" #include "simplnx/Filter/IFilter.hpp" #include "simplnx/Utilities/ParallelDataAlgorithm.hpp" @@ -251,4 +252,23 @@ Result<> EliminateDuplicateNodes(GeometryType& geom, std::optional scal return {}; } + +/** + * @brief This will compute, in parallel, the area of each triangle in a triangle geometry + * @param triangleGeom + * @param faceAreas + * @param shouldCancel + * @return + */ +SIMPLNX_EXPORT Result<> ComputeTriangleAreas(const nx::core::TriangleGeom* triangleGeom, Float64AbstractDataStore& faceAreas, const std::atomic_bool& shouldCancel); + +/** + * @brief This will compute, in parallel, the normal of each triangle in a triangle geometry + * @param triangleGeom + * @param normals + * @param shouldCancel + * @return + */ +SIMPLNX_EXPORT Result<> ComputeTriangleNormals(const nx::core::TriangleGeom* triangleGeom, Float64AbstractDataStore& normals, const std::atomic_bool& shouldCancel); + } // namespace nx::core::GeometryUtilities