From 734fc82df9060b31fae3d21dea8ae87ae326af61 Mon Sep 17 00:00:00 2001 From: Michael Jackson Date: Mon, 25 Sep 2023 17:54:38 -0400 Subject: [PATCH 1/4] STLFileReader: Fix crash when all points are on a single plane. Signed-off-by: Michael Jackson --- .../Filters/Algorithms/StlFileReader.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/StlFileReader.cpp b/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/StlFileReader.cpp index f976c394d7..3a373093b0 100644 --- a/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/StlFileReader.cpp +++ b/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/StlFileReader.cpp @@ -312,9 +312,18 @@ Result<> StlFileReader::eliminate_duplicate_nodes() int32_t bin = 0, xBin = 0, yBin = 0, zBin = 0; for(size_t i = 0; i < nNodes; i++) { - xBin = static_cast((vertices[i * 3] - m_MinMaxCoords[0]) / stepX); - yBin = static_cast((vertices[i * 3 + 1] - m_MinMaxCoords[2]) / stepY); - zBin = static_cast((vertices[i * 3 + 2] - m_MinMaxCoords[4]) / stepZ); + if(stepX != 0.0) + { + xBin = static_cast((vertices[i * 3] - m_MinMaxCoords[0]) / stepX); + } + if(stepY != 0.0) + { + yBin = static_cast((vertices[i * 3 + 1] - m_MinMaxCoords[2]) / stepY); + } + if(zBin != 0.0) + { + zBin = static_cast((vertices[i * 3 + 2] - m_MinMaxCoords[4]) / stepZ); + } if(xBin == 100) { xBin = 99; From 4bc136983a6620b56d18e9c03c91e994340123e5 Mon Sep 17 00:00:00 2001 From: Michael Jackson Date: Mon, 25 Sep 2023 17:56:19 -0400 Subject: [PATCH 2/4] SampleSurfaceMesh: Sped up the computation, but the output is still wrong. Output does match D3D 6.6 though which is good. Signed-off-by: Michael Jackson --- src/complex/Utilities/Math/GeometryMath.hpp | 29 +++++++++++-- src/complex/Utilities/SampleSurfaceMesh.cpp | 46 ++++++++++++--------- src/complex/Utilities/SampleSurfaceMesh.hpp | 2 +- 3 files changed, 53 insertions(+), 24 deletions(-) diff --git a/src/complex/Utilities/Math/GeometryMath.hpp b/src/complex/Utilities/Math/GeometryMath.hpp index 89ace4d61b..453edc018b 100644 --- a/src/complex/Utilities/Math/GeometryMath.hpp +++ b/src/complex/Utilities/Math/GeometryMath.hpp @@ -525,7 +525,7 @@ char RayIntersectsTriangle(const Ray& ray, const complex::Point3D& p0, con * @return bool */ template -char IsPointInPolyhedron(const complex::TriangleGeom& faces, const std::vector& faceIds, const std::vector>& faceBBs, const Point3D& point, +char IsPointInPolyhedron(const complex::TriangleGeom& triangleGeom, const std::vector& faceIds, const std::vector>& faceBBs, const Point3D& point, const complex::BoundingBox3D& bounds, T radius) { usize iter = 0, crossings = 0; @@ -542,6 +542,16 @@ char IsPointInPolyhedron(const complex::TriangleGeom& faces, const std::vector distribution(0.0, 1.0); + const IGeometry::SharedVertexList& vertexListRef = triangleGeom.getVerticesRef(); + const IGeometry::SharedFaceList& faceListRef = triangleGeom.getFacesRef(); + + const auto& vertexListDataStore = vertexListRef.getDataStoreRef(); + const auto& faceListDataStore = faceListRef.getDataStoreRef(); + + Point3D v0; + Point3D v1; + Point3D v2; + usize numFaces = faceIds.size(); while(iter++ < numFaces) { @@ -570,9 +580,20 @@ char IsPointInPolyhedron(const complex::TriangleGeom& faces, const std::vector, 3> coords; - faces.getFaceCoordinates(faceIds[face], coords); - code = RayIntersectsTriangle(ray, coords[0], coords[1], coords[2]); + // std::array, 3> coords; + // triangleGeom.getFaceCoordinates(faceIds[face], coords); + usize faceId = static_cast(faceIds[face]); + + usize vertId = faceListDataStore[faceId * 3]; + v0 = {vertexListDataStore[vertId * 3], vertexListDataStore[vertId * 3 + 1], vertexListDataStore[vertId * 3 + 2]}; + + vertId = faceListDataStore[faceId * 3 + 1]; + v1 = {vertexListDataStore[vertId * 3], vertexListDataStore[vertId * 3 + 1], vertexListDataStore[vertId * 3 + 2]}; + + vertId = faceListDataStore[faceId * 3 + 2]; + v2 = {vertexListDataStore[vertId * 3], vertexListDataStore[vertId * 3 + 1], vertexListDataStore[vertId * 3 + 2]}; + + code = RayIntersectsTriangle(ray, v0, v1, v2); } /* If ray is degenerate, then goto outer while to generate another. */ diff --git a/src/complex/Utilities/SampleSurfaceMesh.cpp b/src/complex/Utilities/SampleSurfaceMesh.cpp index 8968019066..1d8cc6c0ac 100644 --- a/src/complex/Utilities/SampleSurfaceMesh.cpp +++ b/src/complex/Utilities/SampleSurfaceMesh.cpp @@ -105,6 +105,8 @@ class SampleSurfaceMeshImplByPoints void checkPoints(usize start, usize end) const { + auto startTime = std::chrono::steady_clock::now(); + usize iter = m_FeatureId; // find bounding box for current feature @@ -115,6 +117,15 @@ class SampleSurfaceMeshImplByPoints // check points in vertex array to see if they are in the bounding box of the feature for(usize i = start; i < end; i++) { + auto now = std::chrono::steady_clock::now(); + // Only send updates every 1 second + if(std::chrono::duration_cast(now - startTime).count() > 1000) + { + std::string message = fmt::format("{}", i); + m_Filter->sendThreadSafeProgressMessage(i, i - start, m_Points.size()); + startTime = std::chrono::steady_clock::now(); + } + Point3Df point = m_Points[i]; if(m_PolyIds[i] == 0) { @@ -126,11 +137,6 @@ class SampleSurfaceMeshImplByPoints } pointsVisited++; - // Send some feedback - if(pointsVisited % 1000 == 0) - { - m_Filter->sendThreadSafeProgressMessage(m_FeatureId, 1000, m_Points.size()); - } // Check for the filter being cancelled. if(m_ShouldCancel) { @@ -288,8 +294,11 @@ Result<> SampleSurfaceMesh::execute(SampleSurfaceMeshInputValues& inputValues) { for(int32 featureId = 0; featureId < numFeatures; featureId++) { + updateProgress(fmt::format("Sampling FeatureID: {} ", featureId)); + ParallelDataAlgorithm dataAlg; dataAlg.setRange(0, points.size()); + dataAlg.setParallelizationEnabled(true); dataAlg.execute(SampleSurfaceMeshImplByPoints(this, triangleGeom, faceLists[featureId], faceBBs, points, featureId, polyIds, m_ShouldCancel)); } } @@ -306,21 +315,20 @@ void SampleSurfaceMesh::sendThreadSafeProgressMessage(usize featureId, usize num m_ProgressCounter += numCompleted; auto now = std::chrono::steady_clock::now(); - auto diff = std::chrono::duration_cast(m_InitialTime - now).count(); - if(diff > 1000) + if(std::chrono::duration_cast(now - m_LastUpdateTime).count() > 1000) { - std::string progMessage = fmt::format("Feature {} | Points Completed: {} of {}", featureId, m_ProgressCounter, totalFeatures); - float inverseRate = static_cast(diff) / static_cast(m_ProgressCounter - m_LastProgressInt); - auto remainMillis = std::chrono::milliseconds(static_cast(inverseRate * (totalFeatures - m_ProgressCounter))); - auto secs = std::chrono::duration_cast(remainMillis); - remainMillis -= std::chrono::duration_cast(secs); - auto mins = std::chrono::duration_cast(secs); - secs -= std::chrono::duration_cast(mins); - auto hour = std::chrono::duration_cast(mins); - mins -= std::chrono::duration_cast(hour); - progMessage += fmt::format(" || Est. Time Remain: {} hours {} minutes {} seconds", hour.count(), mins.count(), secs.count()); + std::string progMessage = fmt::format("{}", m_ProgressCounter); + // float inverseRate = static_cast(diff) / static_cast(m_ProgressCounter - m_LastProgressInt); + // auto remainMillis = std::chrono::milliseconds(static_cast(inverseRate * (totalFeatures - m_ProgressCounter))); + // auto secs = std::chrono::duration_cast(remainMillis); + // remainMillis -= std::chrono::duration_cast(secs); + // auto mins = std::chrono::duration_cast(secs); + // secs -= std::chrono::duration_cast(mins); + // auto hour = std::chrono::duration_cast(mins); + // mins -= std::chrono::duration_cast(hour); + // progMessage += fmt::format(" || Est. Time Remain: {} hours {} minutes {} seconds", hour.count(), mins.count(), secs.count()); m_MessageHandler({IFilter::Message::Type::Info, progMessage}); - m_InitialTime = std::chrono::steady_clock::now(); - m_LastProgressInt = m_ProgressCounter; + m_LastUpdateTime = std::chrono::steady_clock::now(); + // m_LastProgressInt = m_ProgressCounter; } } diff --git a/src/complex/Utilities/SampleSurfaceMesh.hpp b/src/complex/Utilities/SampleSurfaceMesh.hpp index fd37e0fe57..142c7a884d 100644 --- a/src/complex/Utilities/SampleSurfaceMesh.hpp +++ b/src/complex/Utilities/SampleSurfaceMesh.hpp @@ -52,6 +52,6 @@ class COMPLEX_EXPORT SampleSurfaceMesh mutable std::mutex m_ProgressMessage_Mutex; usize m_ProgressCounter = 0; usize m_LastProgressInt = 0; - std::chrono::steady_clock::time_point m_InitialTime = std::chrono::steady_clock::now(); + std::chrono::steady_clock::time_point m_LastUpdateTime = std::chrono::steady_clock::now(); }; } // namespace complex From d4d00f1d5cc8ab8be474c8ad701e174ff2685c07 Mon Sep 17 00:00:00 2001 From: Michael Jackson Date: Mon, 25 Sep 2023 17:57:05 -0400 Subject: [PATCH 3/4] Adjust Parameter Order. Signed-off-by: Michael Jackson --- .../Filters/RegularGridSampleSurfaceMeshFilter.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/RegularGridSampleSurfaceMeshFilter.cpp b/src/Plugins/ComplexCore/src/ComplexCore/Filters/RegularGridSampleSurfaceMeshFilter.cpp index 990b5a3c73..be115f956d 100644 --- a/src/Plugins/ComplexCore/src/ComplexCore/Filters/RegularGridSampleSurfaceMeshFilter.cpp +++ b/src/Plugins/ComplexCore/src/ComplexCore/Filters/RegularGridSampleSurfaceMeshFilter.cpp @@ -57,10 +57,11 @@ Parameters RegularGridSampleSurfaceMeshFilter::parameters() const params.insertSeparator(Parameters::Separator{"Parameters"}); params.insert(std::make_unique(k_Dimensions_Key, "Dimensions (Voxels)", "The dimensions of the created Image geometry", std::vector{128, 128, 128}, std::vector{"x", "y", "z"})); - params.insert( - std::make_unique(k_Spacing_Key, "Spacing", "The spacing of the created Image geometry", std::vector{1.0F, 1.0F, 1.0F}, std::vector{"x", "y", "z"})); params.insert( std::make_unique(k_Origin_Key, "Origin", "The origin of the created Image geometry", std::vector{0.0F, 0.0F, 0.0F}, std::vector{"x", "y", "z"})); + params.insert( + std::make_unique(k_Spacing_Key, "Spacing", "The spacing of the created Image geometry", std::vector{1.0F, 1.0F, 1.0F}, std::vector{"x", "y", "z"})); + params.insert(std::make_unique(k_LengthUnit_Key, "Length Units (For Description Only)", "The units to be displayed below", to_underlying(IGeometry::LengthUnit::Micrometer), IGeometry::GetAllLengthUnitStrings())); From 5e432784e270c828f90e8f90b2a3abea8bcf4d38 Mon Sep 17 00:00:00 2001 From: Michael Jackson Date: Mon, 25 Sep 2023 18:22:55 -0400 Subject: [PATCH 4/4] WriteSTLFile: Ensure output path is created when executing filter. Signed-off-by: Michael Jackson --- .../ComplexCore/Filters/Algorithms/WriteStlFile.cpp | 11 ++++++++++- .../src/ComplexCore/Filters/WriteStlFileFilter.cpp | 10 ---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/WriteStlFile.cpp b/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/WriteStlFile.cpp index fee1e33685..79e01d647d 100644 --- a/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/WriteStlFile.cpp +++ b/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/WriteStlFile.cpp @@ -1,6 +1,7 @@ #include "WriteStlFile.hpp" #include "complex/DataStructure/Geometry/TriangleGeom.hpp" +#include "complex/Utilities/FilterUtilities.hpp" #include "complex/Utilities/StringUtilities.hpp" using namespace complex; @@ -65,7 +66,15 @@ Result<> WriteStlFile::operator()() const IGeometry::MeshIndexArrayType& triangles = triangleGeom.getFacesRef(); const IGeometry::MeshIndexType nTriangles = triangleGeom.getNumberOfFaces(); const auto& featureIds = m_DataStructure.getDataRefAs(m_InputValues->FeatureIdsPath); - // const auto& normals = m_DataStructure.getDataRefAs(m_InputValues->FaceNormalsPath); + + const std::filesystem::path outputPath = m_InputValues->OutputStlDirectory; + // Make sure any directory path is also available as the user may have just typed + // in a path without actually creating the full path + Result<> createDirectoriesResult = complex::CreateOutputDirectories(outputPath); + if(createDirectoriesResult.invalid()) + { + return createDirectoriesResult; + } // Store all the unique Spins std::map uniqueGrainIdToPhase; diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/WriteStlFileFilter.cpp b/src/Plugins/ComplexCore/src/ComplexCore/Filters/WriteStlFileFilter.cpp index 68eed1d215..66ec38fbc8 100644 --- a/src/Plugins/ComplexCore/src/ComplexCore/Filters/WriteStlFileFilter.cpp +++ b/src/Plugins/ComplexCore/src/ComplexCore/Filters/WriteStlFileFilter.cpp @@ -123,16 +123,6 @@ IFilter::PreflightResult WriteStlFileFilter::preflightImpl(const DataStructure& return MakePreflightErrorResult(-27873, fmt::format("Feature Ids Array doesn't exist at: {}", pFeatureIdsPathValue.toString())); } - // if(auto* normals = dataStructure.getDataAs(pFaceNormalsPathValue); normals == nullptr) - // { - // return MakePreflightErrorResult(-27874, fmt::format("Face Normals Array doesn't exist at: {}", pFaceNormalsPathValue.toString())); - // } - - if(!exists(pOutputStlDirectoryValue)) - { - return MakePreflightErrorResult(-27875, fmt::format("Directory {} doesn't exist.", pOutputStlDirectoryValue.string())); - } - // Return both the resultOutputActions and the preflightUpdatedValues via std::move() return {std::move(resultOutputActions), std::move(preflightUpdatedValues)}; }