Skip to content

Commit 891f7ba

Browse files
nyoungbqimikejackson
authored andcommitted
Move MapPointCloudToRegularGrid to algorithm class
1 parent b908f01 commit 891f7ba

File tree

4 files changed

+263
-160
lines changed

4 files changed

+263
-160
lines changed

src/Plugins/SimplnxCore/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ set(AlgorithmList
208208
IterativeClosestPoint
209209
LabelTriangleGeometry
210210
LaplacianSmoothing
211+
MapPointCloudToRegularGrid
211212
NearestPointFuseRegularGrids
212213
PadImageGeometry
213214
PartitionGeometry
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
#include "MapPointCloudToRegularGrid.hpp"
2+
3+
#include "simplnx/DataStructure/Geometry/ImageGeom.hpp"
4+
#include "simplnx/DataStructure/Geometry/VertexGeom.hpp"
5+
#include "simplnx/Utilities/MaskCompareUtilities.hpp"
6+
7+
using namespace nx::core;
8+
9+
namespace
10+
{
11+
constexpr nx::core::StringLiteral k_SilentMode = "Silent";
12+
constexpr nx::core::StringLiteral k_WarningMode = "Warning with Count";
13+
constexpr nx::core::StringLiteral k_ErrorMode = "Error at First Instance";
14+
const nx::core::ChoicesParameter::ValueType k_SilentModeIndex = 0;
15+
const nx::core::ChoicesParameter::ValueType k_WarningModeIndex = 1;
16+
const nx::core::ChoicesParameter::ValueType k_ErrorModeIndex = 2;
17+
18+
constexpr int64 k_MaskCompareInvalid = -2605;
19+
constexpr int64 k_ErrorOutOfBounds = -2607;
20+
constexpr int64 k_WarningOutOfBounds = -2608;
21+
constexpr int64 k_InvalidHandlingValue = -2609;
22+
23+
template <bool UseSilent, bool UseWarning, bool UseError>
24+
struct OutOfBoundsType
25+
{
26+
// Compile time checks for bounding, no runtime overhead
27+
static_assert((UseSilent && !UseWarning && !UseError) || (!UseSilent && UseWarning && !UseError) || (!UseSilent && !UseWarning && UseError),
28+
"struct `OutOfBoundsType` can only have one true bool in its instantiation");
29+
30+
static constexpr bool UsingSilent = UseSilent;
31+
static constexpr bool UsingWarning = UseWarning;
32+
static constexpr bool UsingError = UseError;
33+
};
34+
35+
using SilentType = OutOfBoundsType<true, false, false>;
36+
using WarningType = OutOfBoundsType<false, true, false>;
37+
using ErrorType = OutOfBoundsType<false, false, true>;
38+
39+
template <class OutOfBoundsType = SilentType, bool UseMask = false>
40+
Result<> ProcessVertices(const IFilter::MessageHandler& messageHandler, const VertexGeom& vertices, const ImageGeom& image, UInt64AbstractDataStore& voxelIndices,
41+
const std::unique_ptr<MaskCompareUtilities::MaskCompare>& maskCompare, uint64 outOfBoundsValue)
42+
{
43+
// Out of Bounds Counter
44+
usize count = 0;
45+
46+
// Execution
47+
usize numVerts = vertices.getNumberOfVertices();
48+
auto start = std::chrono::steady_clock::now();
49+
for(int64 i = 0; i < numVerts; i++)
50+
{
51+
if constexpr(UseMask)
52+
{
53+
if(!maskCompare->isTrue(i))
54+
{
55+
continue;
56+
}
57+
}
58+
59+
auto coords = vertices.getVertexCoordinate(i);
60+
const auto indexResult = image.getIndex(coords[0], coords[1], coords[2]);
61+
if(indexResult.has_value())
62+
{
63+
voxelIndices[i] = indexResult.value();
64+
}
65+
else
66+
{
67+
if constexpr(OutOfBoundsType::UsingError)
68+
{
69+
BoundingBox3Df imageBounds = image.getBoundingBoxf();
70+
const Point3Df& minPoint = imageBounds.getMinPoint();
71+
const Point3Df& maxPoint = imageBounds.getMaxPoint();
72+
return MakeErrorResult(
73+
k_ErrorOutOfBounds,
74+
fmt::format("Out of bounds value encountered.\nVertex Index: {}\nVertex Coordinates [X,Y,Z]: [{},{},{}]\nImage Coordinate Bounds:\nX: {} to {}\nY: {} to {}\nZ: {} to {}", i, coords[0],
75+
coords[1], coords[2], minPoint.getX(), maxPoint.getX(), minPoint.getY(), maxPoint.getY(), minPoint.getZ(), maxPoint.getZ()));
76+
}
77+
78+
// Out of bounds value
79+
voxelIndices[i] = outOfBoundsValue;
80+
count++;
81+
}
82+
83+
auto now = std::chrono::steady_clock::now();
84+
if(std::chrono::duration_cast<std::chrono::milliseconds>(now - start).count() > 1000)
85+
{
86+
messageHandler(fmt::format("Computing Point Cloud Voxel Indices || {}% Completed", static_cast<int64>((static_cast<float32>(i) / numVerts) * 100.0f)));
87+
start = now;
88+
}
89+
}
90+
91+
if constexpr(OutOfBoundsType::UsingWarning)
92+
{
93+
if(count > 0)
94+
{
95+
return MakeWarningVoidResult(k_WarningOutOfBounds, fmt::format("Mapping Complete. Number of value outside image bounds: {}", count));
96+
}
97+
}
98+
99+
return {};
100+
}
101+
} // namespace
102+
103+
// -----------------------------------------------------------------------------
104+
MapPointCloudToRegularGrid::MapPointCloudToRegularGrid(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel,
105+
MapPointCloudToRegularGridInputValues* inputValues)
106+
: m_DataStructure(dataStructure)
107+
, m_InputValues(inputValues)
108+
, m_ShouldCancel(shouldCancel)
109+
, m_MessageHandler(mesgHandler)
110+
{
111+
}
112+
113+
// -----------------------------------------------------------------------------
114+
MapPointCloudToRegularGrid::~MapPointCloudToRegularGrid() noexcept = default;
115+
116+
// -----------------------------------------------------------------------------
117+
void MapPointCloudToRegularGrid::updateProgress(const std::string& message)
118+
{
119+
m_MessageHandler(IFilter::Message::Type::Info, message);
120+
}
121+
122+
// -----------------------------------------------------------------------------
123+
const std::atomic_bool& MapPointCloudToRegularGrid::getCancel()
124+
{
125+
return m_ShouldCancel;
126+
}
127+
128+
// -----------------------------------------------------------------------------
129+
Result<> MapPointCloudToRegularGrid::operator()()
130+
{
131+
// Get the target image as a pointer
132+
const auto& image = m_DataStructure.getDataRefAs<ImageGeom>(m_InputValues->ImageGeomPath);
133+
134+
// Create the Mask
135+
std::unique_ptr<MaskCompareUtilities::MaskCompare> maskCompare;
136+
try
137+
{
138+
maskCompare = MaskCompareUtilities::InstantiateMaskCompare(m_DataStructure, m_InputValues->MaskArrayPath);
139+
} catch(const std::out_of_range& exception)
140+
{
141+
// This really should NOT be happening as the path was verified during preflight BUT we may be calling this from
142+
// somewhere else that is NOT going through the normal nx::core::IFilter API of Preflight and Execute
143+
std::string message = fmt::format("Mask Array DataPath does not exist or is not of the correct type (Bool | UInt8) {}", m_InputValues->MaskArrayPath.toString());
144+
return MakeErrorResult(k_MaskCompareInvalid, message);
145+
}
146+
147+
// Cache all the needed objects for ::ProcessVertices
148+
const auto& vertices = m_DataStructure.getDataRefAs<VertexGeom>(m_InputValues->VertexGeomPath);
149+
auto& voxelIndices = m_DataStructure.getDataAs<UInt64Array>(m_InputValues->VoxelIndicesPath)->getDataStoreRef();
150+
151+
// Execute the correct ::ProcessVertices, else error out
152+
if(m_InputValues->UseMask)
153+
{
154+
switch(m_InputValues->OutOfBoundsHandling)
155+
{
156+
case k_SilentModeIndex: {
157+
return ProcessVertices<SilentType, true>(m_MessageHandler, vertices, image, voxelIndices, maskCompare, m_InputValues->OutOfBoundsValue);
158+
}
159+
case k_WarningModeIndex: {
160+
return ProcessVertices<WarningType, true>(m_MessageHandler, vertices, image, voxelIndices, maskCompare, m_InputValues->OutOfBoundsValue);
161+
}
162+
case k_ErrorModeIndex: {
163+
return ProcessVertices<ErrorType, true>(m_MessageHandler, vertices, image, voxelIndices, maskCompare, m_InputValues->OutOfBoundsValue);
164+
}
165+
default: {
166+
return MakeErrorResult(k_InvalidHandlingValue, fmt::format("Unexpected Out of Bounds Handing Option. Received : {}. Expected: {} ({}), {} ({}), {} ({})", m_InputValues->OutOfBoundsHandling,
167+
k_SilentMode, k_SilentModeIndex, k_WarningMode, k_WarningModeIndex, k_ErrorMode, k_ErrorModeIndex));
168+
}
169+
}
170+
}
171+
else
172+
{
173+
switch(m_InputValues->OutOfBoundsHandling)
174+
{
175+
case k_SilentModeIndex: {
176+
return ProcessVertices<SilentType, false>(m_MessageHandler, vertices, image, voxelIndices, maskCompare, m_InputValues->OutOfBoundsValue);
177+
}
178+
case k_WarningModeIndex: {
179+
return ProcessVertices<WarningType, false>(m_MessageHandler, vertices, image, voxelIndices, maskCompare, m_InputValues->OutOfBoundsValue);
180+
}
181+
case k_ErrorModeIndex: {
182+
return ProcessVertices<ErrorType, false>(m_MessageHandler, vertices, image, voxelIndices, maskCompare, m_InputValues->OutOfBoundsValue);
183+
}
184+
default: {
185+
return MakeErrorResult(k_InvalidHandlingValue, fmt::format("Unexpected Out of Bounds Handing Option. Received : {}. Expected: {} ({}), {} ({}), {} ({})", m_InputValues->OutOfBoundsHandling,
186+
k_SilentMode, k_SilentModeIndex, k_WarningMode, k_WarningModeIndex, k_ErrorMode, k_ErrorModeIndex));
187+
}
188+
}
189+
}
190+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#pragma once
2+
3+
#include "SimplnxCore/SimplnxCore_export.hpp"
4+
5+
#include "simplnx/DataStructure/DataPath.hpp"
6+
#include "simplnx/DataStructure/DataStructure.hpp"
7+
#include "simplnx/Filter/IFilter.hpp"
8+
#include "simplnx/Parameters/ChoicesParameter.hpp"
9+
10+
namespace nx::core
11+
{
12+
13+
struct SIMPLNXCORE_EXPORT MapPointCloudToRegularGridInputValues
14+
{
15+
bool UseMask;
16+
DataPath ImageGeomPath;
17+
DataPath MaskArrayPath;
18+
DataPath VertexGeomPath;
19+
DataPath VoxelIndicesPath;
20+
uint64 OutOfBoundsValue;
21+
ChoicesParameter::ValueType OutOfBoundsHandling;
22+
};
23+
24+
/**
25+
* @class
26+
*/
27+
class SIMPLNXCORE_EXPORT MapPointCloudToRegularGrid
28+
{
29+
public:
30+
MapPointCloudToRegularGrid(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, MapPointCloudToRegularGridInputValues* inputValues);
31+
~MapPointCloudToRegularGrid() noexcept;
32+
33+
MapPointCloudToRegularGrid(const MapPointCloudToRegularGrid&) = delete;
34+
MapPointCloudToRegularGrid(MapPointCloudToRegularGrid&&) noexcept = delete;
35+
MapPointCloudToRegularGrid& operator=(const MapPointCloudToRegularGrid&) = delete;
36+
MapPointCloudToRegularGrid& operator=(MapPointCloudToRegularGrid&&) noexcept = delete;
37+
38+
Result<> operator()();
39+
void updateProgress(const std::string& message);
40+
const std::atomic_bool& getCancel();
41+
42+
private:
43+
DataStructure& m_DataStructure;
44+
const MapPointCloudToRegularGridInputValues* m_InputValues = nullptr;
45+
const std::atomic_bool& m_ShouldCancel;
46+
const IFilter::MessageHandler& m_MessageHandler;
47+
};
48+
49+
} // namespace nx::core

0 commit comments

Comments
 (0)