Skip to content

FILT: Adds a 'Matrix Calculator' filter and supporting files #1217

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/Plugins/SimplnxCore/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ set(FilterList
CombineAttributeArraysFilter
CombineNodeBasedGeometriesFilter
CombineStlFilesFilter
ComputeArrayHistogramFilter
CombineTransformationMatricesFilter
ComputeArrayHistogramByFeatureFilter
ComputeArrayHistogramFilter
ComputeArrayStatisticsFilter
ComputeBiasedFeaturesFilter
ComputeBoundaryCellsFilter
Expand Down Expand Up @@ -171,6 +172,7 @@ set(AlgorithmList
CombineAttributeArrays
CombineNodeBasedGeometries
CombineStlFiles
CombineTransformationMatrices
ComputeArrayHistogram
ComputeArrayHistogramByFeature
ComputeArrayStatistics
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Combine Transformation Matrices Filter

## Group (Subgroup)


## Description


% Auto generated parameter table will be inserted here

## License & Copyright

Please see the description file distributed with this **Plugin**

## DREAM3D-NX Help

If you need help, need to file a bug report or want to request a new feature, please head over to the [DREAM3DNX-Issues](https://github.com/BlueQuartzSoftware/DREAM3DNX-Issues/discussions) GitHub site where the community of DREAM3D-NX users can help answer your questions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#include "CombineTransformationMatrices.hpp"

#include "simplnx/DataStructure/DataArray.hpp"
#include "simplnx/DataStructure/Geometry/ImageGeom.hpp"
#include "simplnx/Utilities/FilterUtilities.hpp"
#include "simplnx/Utilities/ImageRotationUtilities.hpp"

#include <Eigen/Dense>

using namespace nx::core;

namespace
{
template <typename T>
Eigen::Matrix<T, 4, 4, Eigen::RowMajor> CreateEigenMatrix(const AbstractDataStore<T>& dataStore)
{
Eigen::Matrix<T, 4, 4, Eigen::RowMajor> matrix;
matrix.fill(0);
matrix << dataStore[0], dataStore[1], dataStore[2], dataStore[3], dataStore[4], dataStore[5], dataStore[6], dataStore[7], dataStore[8], dataStore[9], dataStore[10], dataStore[11], dataStore[12],
dataStore[13], dataStore[14], dataStore[15];

return matrix;
}

struct MatrixOperationFunctor
{
template <typename ScalarType>
Result<> operator()(const IDataArray& array1, const IDataArray& array2, IDataArray& outputArray)
{
using MatrixType = Eigen::Matrix<ScalarType, 4, 4, Eigen::RowMajor>;
using StoreType = AbstractDataStore<ScalarType>;
const auto& array1StoreRef = array1.getIDataStoreRefAs<StoreType>();
const auto& array2StoreRef = array2.getIDataStoreRefAs<StoreType>();

auto eigenMatrix1 = CreateEigenMatrix<ScalarType>(array1StoreRef);
auto eigenMatrix2 = CreateEigenMatrix<ScalarType>(array2StoreRef);

MatrixType output = eigenMatrix1 * eigenMatrix2;

auto& dataStore = outputArray.getIDataStoreRefAs<StoreType>();

dataStore[0] = output(0, 0);
dataStore[1] = output(0, 1);
dataStore[2] = output(0, 2);
dataStore[3] = output(0, 3);
dataStore[4] = output(1, 0);
dataStore[5] = output(1, 1);
dataStore[6] = output(1, 2);
dataStore[7] = output(1, 3);
dataStore[8] = output(2, 0);
dataStore[9] = output(2, 1);
dataStore[10] = output(2, 2);
dataStore[11] = output(2, 3);
dataStore[12] = output(3, 0);
dataStore[13] = output(3, 1);
dataStore[14] = output(3, 2);
dataStore[15] = output(3, 3);

return {};
}
};

} // namespace

// -----------------------------------------------------------------------------
CombineTransformationMatrices::CombineTransformationMatrices(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel,
CombineTransformationMatricesInputValues* inputValues)
: m_DataStructure(dataStructure)
, m_InputValues(inputValues)
, m_ShouldCancel(shouldCancel)
, m_MessageHandler(mesgHandler)
{
}

// -----------------------------------------------------------------------------
CombineTransformationMatrices::~CombineTransformationMatrices() noexcept = default;

// -----------------------------------------------------------------------------
const std::atomic_bool& CombineTransformationMatrices::getCancel()
{
return m_ShouldCancel;
}

// -----------------------------------------------------------------------------
Result<> CombineTransformationMatrices::operator()()
{
auto& outputArray = m_DataStructure.getDataRefAs<IDataArray>(m_InputValues->OutputPath);
auto pathsIter = m_InputValues->SelectedPaths.begin();

const auto& array1 = m_DataStructure.getDataRefAs<IDataArray>(*pathsIter++);
const auto& array2 = m_DataStructure.getDataRefAs<IDataArray>(*pathsIter++);
if(array1.getDataType() != array2.getDataType())
{
return MakeErrorResult(-89750, "DataType mismatch");
}
// Combine first two matrices: second * first
ExecuteDataFunction(MatrixOperationFunctor{}, array1.getDataType(), array2, array1, outputArray);

for(; pathsIter != m_InputValues->SelectedPaths.end(); ++pathsIter)
{
const auto& arrayRef = m_DataStructure.getDataRefAs<IDataArray>(*pathsIter);
ExecuteDataFunction(MatrixOperationFunctor{}, outputArray.getDataType(), arrayRef, outputArray, outputArray);
}

return {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#pragma once

#include "SimplnxCore/SimplnxCore_export.hpp"

#include "simplnx/DataStructure/DataPath.hpp"
#include "simplnx/DataStructure/DataStructure.hpp"
#include "simplnx/Filter/IFilter.hpp"
#include "simplnx/Parameters/ArrayCreationParameter.hpp"
#include "simplnx/Parameters/ArraySelectionParameter.hpp"
#include "simplnx/Parameters/ChoicesParameter.hpp"
#include "simplnx/Parameters/MultiArraySelectionParameter.hpp"

namespace nx::core
{

struct SIMPLNXCORE_EXPORT CombineTransformationMatricesInputValues
{
MultiArraySelectionParameter::ValueType SelectedPaths;
ArrayCreationParameter::ValueType OutputPath;
};

/**
* @class
*/
class SIMPLNXCORE_EXPORT CombineTransformationMatrices
{
public:
CombineTransformationMatrices(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, CombineTransformationMatricesInputValues* inputValues);
~CombineTransformationMatrices() noexcept;

CombineTransformationMatrices(const CombineTransformationMatrices&) = delete;
CombineTransformationMatrices(CombineTransformationMatrices&&) noexcept = delete;
CombineTransformationMatrices& operator=(const CombineTransformationMatrices&) = delete;
CombineTransformationMatrices& operator=(CombineTransformationMatrices&&) noexcept = delete;

// Error Codes
enum class ErrorCodes : int32
{
EmptyInputArrays = -2350,
OneInputArray = -2351,
NonPositiveTupleDimValue = -2352,
TypeNameMismatch = -2353,
ComponentShapeMismatch = -2354,
InputArraysEqualAny = -2355,
InputArraysUnsupported = -2356
};

Result<> operator()();

const std::atomic_bool& getCancel();

private:
DataStructure& m_DataStructure;
const CombineTransformationMatricesInputValues* m_InputValues = nullptr;
const std::atomic_bool& m_ShouldCancel;
const IFilter::MessageHandler& m_MessageHandler;
};

} // namespace nx::core
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
#include "CombineTransformationMatricesFilter.hpp"

#include "SimplnxCore/Filters/Algorithms/CombineTransformationMatrices.hpp"

#include "simplnx/DataStructure/DataPath.hpp"
#include "simplnx/DataStructure/Geometry/ImageGeom.hpp"
#include "simplnx/Filter/Actions/CreateArrayAction.hpp"
#include "simplnx/Parameters/ArrayCreationParameter.hpp"
#include "simplnx/Parameters/DataObjectNameParameter.hpp"
#include "simplnx/Parameters/MultiArraySelectionParameter.hpp"
#include "simplnx/Utilities/SIMPLConversion.hpp"

#include <random>

using namespace nx::core;

namespace nx::core
{
//------------------------------------------------------------------------------
std::string CombineTransformationMatricesFilter::name() const
{
return FilterTraits<CombineTransformationMatricesFilter>::name.str();
}

//------------------------------------------------------------------------------
std::string CombineTransformationMatricesFilter::className() const
{
return FilterTraits<CombineTransformationMatricesFilter>::className;
}

//------------------------------------------------------------------------------
Uuid CombineTransformationMatricesFilter::uuid() const
{
return FilterTraits<CombineTransformationMatricesFilter>::uuid;
}

//------------------------------------------------------------------------------
std::string CombineTransformationMatricesFilter::humanName() const
{
return "Combine Transformation Matrices";
}

//------------------------------------------------------------------------------
std::vector<std::string> CombineTransformationMatricesFilter::defaultTags() const
{
return {className(), "Matrix", "Calculate", "Multiplication"};
}

//------------------------------------------------------------------------------
Parameters CombineTransformationMatricesFilter::parameters() const
{
Parameters params;

// Create the parameter descriptors that are needed for this filter
params.insertSeparator(Parameters::Separator{"Input Parameter(s)"});
params.insert(std::make_unique<MultiArraySelectionParameter>(k_InputArrays_Key, "Input Matrices", "The list of Attribute Arrays that represent Square Matrices of all the same dimensions",
MultiArraySelectionParameter::ValueType{}, MultiArraySelectionParameter::AllowedTypes{IArray::ArrayType::DataArray},
MultiArraySelectionParameter::AllowedDataTypes{}, MultiArraySelectionParameter::AllowedComponentShapes{{1}}));

params.insertSeparator(Parameters::Separator{"Output Parameters"});
params.insert(std::make_unique<ArrayCreationParameter>(k_OutputArray_Key, "Output Array", "The output array that contains the output from the operations.", DataPath({""})));

return params;
}

//------------------------------------------------------------------------------
IFilter::VersionType CombineTransformationMatricesFilter::parametersVersion() const
{
return 1;
}

//------------------------------------------------------------------------------
IFilter::UniquePointer CombineTransformationMatricesFilter::clone() const
{
return std::make_unique<CombineTransformationMatricesFilter>();
}

//------------------------------------------------------------------------------
IFilter::PreflightResult CombineTransformationMatricesFilter::preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler,
const std::atomic_bool& shouldCancel, const ExecutionContext& executionContext) const
{
auto inputArrayPaths = filterArgs.value<MultiArraySelectionParameter::ValueType>(k_InputArrays_Key);
auto outputArrayPath = filterArgs.value<ArrayCreationParameter::ValueType>(k_OutputArray_Key);

PreflightResult preflightResult;
nx::core::Result<OutputActions> resultOutputActions;
std::vector<PreflightValue> preflightUpdatedValues;

if(inputArrayPaths.empty())
{
return MakePreflightErrorResult(to_underlying(CombineTransformationMatrices::ErrorCodes::EmptyInputArrays), "No input arrays have been selected. Please select at least 2 input arrays.");
}

if(inputArrayPaths.size() == 1)
{
return MakePreflightErrorResult(to_underlying(CombineTransformationMatrices::ErrorCodes::OneInputArray), "Only one input array has been selected. Please select at least 2 input arrays.");
}

// Check for unequal array types, data types, and component dimensions
std::vector<usize> cDims;
IArray::ArrayType arrayType;
std::string arrayTypeName;
usize numTuples = 0;
nx::core::DataType arrayDataType;
for(usize i = 0; i < inputArrayPaths.size(); ++i)
{
const auto& inputDataArray = dataStructure.getDataRefAs<IDataArray>(inputArrayPaths[i]);

for(usize j = i + 1; j < inputArrayPaths.size(); ++j)
{
const auto& inputDataArray2 = dataStructure.getDataRefAs<IDataArray>(inputArrayPaths[j]);

if(inputDataArray.getDataType() != inputDataArray2.getDataType())
{
return MakePreflightErrorResult(to_underlying(CombineTransformationMatrices::ErrorCodes::TypeNameMismatch),
fmt::format("Input array '{}' has array type '{}', but input array '{}' has array type '{}'. The array types must match.", inputArrayPaths[i].toString(),
inputDataArray.getTypeName(), inputArrayPaths[j].toString(), inputDataArray2.getTypeName()));
}

if(inputDataArray.getNumberOfComponents() != 1)

{
return MakePreflightErrorResult(to_underlying(CombineTransformationMatrices::ErrorCodes::ComponentShapeMismatch),
fmt::format("Input array '{}' has component shape '{}'. Input arrays must only have a single component.", inputArrayPaths[i].toString(),
fmt::join(inputDataArray.getComponentShape(), ","), inputArrayPaths[j].toString()));
}

cDims = inputDataArray.getComponentShape();
arrayType = inputDataArray.getArrayType();
arrayTypeName = inputDataArray.getTypeName();
arrayDataType = inputDataArray.getDataType();
}

auto tupleShape = inputDataArray.getTupleShape();
numTuples = std::accumulate(tupleShape.begin(), tupleShape.end(), static_cast<usize>(1), std::multiplies<>());
}

// create the destination array for the calculated results
{
auto createArrayAction = std::make_unique<CreateArrayAction>(DataType::float32, IArray::ShapeType{numTuples}, IArray::ShapeType{1}, outputArrayPath);
resultOutputActions.value().appendAction(std::move(createArrayAction));
}

// Return both the resultOutputActions and the preflightUpdatedValues via std::move()
return {std::move(resultOutputActions), std::move(preflightUpdatedValues)};
}

//------------------------------------------------------------------------------
Result<> CombineTransformationMatricesFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler,
const std::atomic_bool& shouldCancel, const ExecutionContext& executionContext) const
{
CombineTransformationMatricesInputValues inputValues;
inputValues.SelectedPaths = filterArgs.value<MultiArraySelectionParameter::ValueType>(k_InputArrays_Key);
inputValues.OutputPath = filterArgs.value<ArrayCreationParameter::ValueType>(k_OutputArray_Key);

return CombineTransformationMatrices(dataStructure, messageHandler, shouldCancel, &inputValues)();
}
} // namespace nx::core
Loading
Loading