diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/RemoveFlaggedFeatures.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/RemoveFlaggedFeatures.cpp index 314bc7a124..9d61add6a2 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/RemoveFlaggedFeatures.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/RemoveFlaggedFeatures.cpp @@ -429,7 +429,7 @@ Result<> RemoveFlaggedFeatures::operator()() m_MessageHandler(IFilter::ProgressMessage{IFilter::Message::Type::Info, fmt::format("Stripping excess inactive objects from model...")}); DataPath featureGroupPath = m_InputValues->FlaggedFeaturesArrayPath.getParent(); - if(!RemoveInactiveObjects(m_DataStructure, featureGroupPath, activeObjects, featureIds, flaggedFeatures->getNumberOfTuples())) + if(!RemoveInactiveObjects(m_DataStructure, featureGroupPath, activeObjects, featureIds, flaggedFeatures->getNumberOfTuples(), m_MessageHandler)) { return MakeErrorResult(-45434, "The removal has failed!"); } diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ResampleImageGeom.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ResampleImageGeom.cpp index 1aeb05825c..6d451f7a28 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ResampleImageGeom.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ResampleImageGeom.cpp @@ -202,7 +202,7 @@ Result<> ResampleImageGeom::operator()() // NOW DO THE ACTUAL RENUMBERING and updating. DataPath destFeatureIdsPath = destImagePath.createChildPath(srcCellDataAM.getName()).createChildPath(featureIdsArrayPath.getTargetName()); - return Sampling::RenumberFeatures(m_DataStructure, destImagePath, destCellFeatureAMPath, featureIdsArrayPath, destFeatureIdsPath, m_ShouldCancel); + return Sampling::RenumberFeatures(m_DataStructure, destImagePath, destCellFeatureAMPath, featureIdsArrayPath, destFeatureIdsPath, m_MessageHandler, m_ShouldCancel); } return {}; diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/CropImageGeometry.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/CropImageGeometry.cpp index f0c2ffe45c..31fcca7d10 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/CropImageGeometry.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/CropImageGeometry.cpp @@ -672,7 +672,7 @@ Result<> CropImageGeometry::executeImpl(DataStructure& dataStructure, const Argu // NOW DO THE ACTUAL RENUMBERING and updating. DataPath destFeatureIdsPath = destImagePath.createChildPath(srcCellDataAM.getName()).createChildPath(featureIdsArrayPath.getTargetName()); - return Sampling::RenumberFeatures(dataStructure, destImagePath, destCellFeatureAMPath, featureIdsArrayPath, destFeatureIdsPath, shouldCancel); + return Sampling::RenumberFeatures(dataStructure, destImagePath, destCellFeatureAMPath, featureIdsArrayPath, destFeatureIdsPath, messageHandler, shouldCancel); } // The deferred actions will take care of removing the original and renaming the output if diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/MinNeighbors.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/MinNeighbors.cpp index 266db27d02..4517c876e9 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/MinNeighbors.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/MinNeighbors.cpp @@ -2,6 +2,7 @@ #include "simplnx/DataStructure/DataArray.hpp" #include "simplnx/DataStructure/Geometry/ImageGeom.hpp" +#include "simplnx/Filter/Actions/DeleteDataAction.hpp" #include "simplnx/Parameters/ArraySelectionParameter.hpp" #include "simplnx/Parameters/AttributeMatrixSelectionParameter.hpp" #include "simplnx/Parameters/BoolParameter.hpp" @@ -21,6 +22,8 @@ namespace constexpr int64 k_TupleCountInvalidError = -250; constexpr int64 k_MissingFeaturePhasesError = -251; constexpr int32 k_InconsistentTupleCount = -252; +constexpr int32 k_NeighborListRemoval = -5558; +constexpr int32 k_FetchChildArrayError = -5559; void assignBadPoints(DataStructure& data, const Arguments& args, const std::atomic_bool& shouldCancel) { @@ -401,12 +404,42 @@ IFilter::PreflightResult MinNeighbors::preflightImpl(const DataStructure& dataSt // Feature Data is going to be modified nx::core::AppendDataObjectModifications(dataStructure, resultOutputActions.value().modifiedActions, numNeighborsPath.getParent(), {}); + // This section gives a warning to the user about NeighborLists possibly being removed + { + DataPath featureGroupDataPath = numNeighborsPath.getParent(); + + // Throw a warning to inform the user that the neighbor list arrays could be deleted by this filter + std::string ss = fmt::format("If this filter modifies the Cell Level Array '{}', all arrays of type NeighborList will be deleted from the feature data group '{}'. These arrays are:\n", + featureIdsPath.toString(), featureGroupDataPath.toString()); + + auto result = nx::core::GetAllChildDataPaths(dataStructure, featureGroupDataPath, DataObject::Type::NeighborList); + if(!result.has_value()) + { + return {nonstd::make_unexpected( + std::vector{Error{k_FetchChildArrayError, fmt::format("Errors were encountered trying to retrieve the neighbor list children of group '{}'", featureGroupDataPath.toString())}})}; + } + std::vector featureNeighborListArrays = result.value(); + for(const auto& featureNeighborList : featureNeighborListArrays) + { + ss.append(" " + featureNeighborList.toString() + "\n"); + auto action = std::make_unique(featureNeighborList); + resultOutputActions.value().actions.emplace_back(std::move(action)); + } + + // Inform users that the following arrays are going to be modified in place + // Feature Data is going to be modified + nx::core::AppendDataObjectModifications(dataStructure, resultOutputActions.value().modifiedActions, featureGroupDataPath, {}); + + resultOutputActions.warnings().push_back(Warning{k_NeighborListRemoval, ss}); + } + // Return both the resultOutputActions and the preflightUpdatedValues via std::move() return {std::move(resultOutputActions), std::move(preflightUpdatedValues)}; } //------------------------------------------------------------------------------ -Result<> MinNeighbors::executeImpl(DataStructure& data, const Arguments& args, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const +Result<> MinNeighbors::executeImpl(DataStructure& dataStructure, const Arguments& args, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel) const { auto featurePhasesPath = args.value(k_FeaturePhasesPath_Key); auto applyToSinglePhase = args.value(k_ApplyToSinglePhase_Key); @@ -418,7 +451,7 @@ Result<> MinNeighbors::executeImpl(DataStructure& data, const Arguments& args, c // we don't have access to the data yet if(applyToSinglePhase) { - auto& featurePhasesArray = data.getDataRefAs(featurePhasesPath); + auto& featurePhasesArray = dataStructure.getDataRefAs(featurePhasesPath); auto& featurePhases = featurePhasesArray.getDataStoreRef(); usize numFeatures = featurePhasesArray.getNumberOfTuples(); @@ -439,27 +472,27 @@ Result<> MinNeighbors::executeImpl(DataStructure& data, const Arguments& args, c } } - auto activeObjectsResult = mergeContainedFeatures(data, args, shouldCancel); + auto activeObjectsResult = mergeContainedFeatures(dataStructure, args, shouldCancel); if(!activeObjectsResult.has_value()) { return {nonstd::make_unexpected(std::vector{activeObjectsResult.error()})}; } auto cellDataAttrMatrix = args.value(MinNeighbors::k_CellDataAttributeMatrixPath_Key); - auto result = nx::core::GetAllChildDataPaths(data, cellDataAttrMatrix, DataObject::Type::DataArray); + auto result = nx::core::GetAllChildDataPaths(dataStructure, cellDataAttrMatrix, DataObject::Type::DataArray); if(!result.has_value()) { return MakeErrorResult(-5556, fmt::format("Error fetching all Data Arrays from Group '{}'", cellDataAttrMatrix.toString())); } // Run the algorithm. - assignBadPoints(data, args, shouldCancel); + assignBadPoints(dataStructure, args, shouldCancel); auto featureIdsPath = args.value(MinNeighbors::k_FeatureIdsPath_Key); - auto& featureIdsArray = data.getDataRefAs(featureIdsPath); + auto& featureIdsArray = dataStructure.getDataRefAs(featureIdsPath); auto numNeighborsPath = args.value(MinNeighbors::k_NumNeighborsPath_Key); - auto& numNeighborsArray = data.getDataRefAs(numNeighborsPath); + auto& numNeighborsArray = dataStructure.getDataRefAs(numNeighborsPath); DataPath cellFeatureGroupPath = numNeighborsPath.getParent(); size_t currentFeatureCount = numNeighborsArray.getNumberOfTuples(); @@ -473,7 +506,7 @@ Result<> MinNeighbors::executeImpl(DataStructure& data, const Arguments& args, c std::string message = fmt::format("Feature Count Changed: Previous: {} New: {}", currentFeatureCount, count); messageHandler(nx::core::IFilter::Message{nx::core::IFilter::Message::Type::Info, message}); - nx::core::RemoveInactiveObjects(data, cellFeatureGroupPath, activeObjects, featureIdsArray, currentFeatureCount); + nx::core::RemoveInactiveObjects(dataStructure, cellFeatureGroupPath, activeObjects, featureIdsArray, currentFeatureCount, messageHandler); return {}; } diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/RemoveMinimumSizeFeaturesFilter.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/RemoveMinimumSizeFeaturesFilter.cpp index ae3a0da6e4..6f5b8c352b 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/RemoveMinimumSizeFeaturesFilter.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/RemoveMinimumSizeFeaturesFilter.cpp @@ -318,7 +318,7 @@ IFilter::UniquePointer RemoveMinimumSizeFeaturesFilter::clone() const return std::make_unique(); } -IFilter::PreflightResult RemoveMinimumSizeFeaturesFilter::preflightImpl(const DataStructure& data, const Arguments& args, const MessageHandler& messageHandler, +IFilter::PreflightResult RemoveMinimumSizeFeaturesFilter::preflightImpl(const DataStructure& dataStructure, const Arguments& args, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const { auto featurePhasesPath = args.value(k_FeaturePhasesPath_Key); @@ -336,12 +336,12 @@ IFilter::PreflightResult RemoveMinimumSizeFeaturesFilter::preflightImpl(const Da return {nonstd::make_unexpected(std::vector{Error{-k_BadMinAllowedFeatureSize, ss}})}; } - const FeatureIdsArrayType* featureIdsPtr = data.getDataAs(featureIdsPath); + const FeatureIdsArrayType* featureIdsPtr = dataStructure.getDataAs(featureIdsPath); if(featureIdsPtr == nullptr) { return {nonstd::make_unexpected(std::vector{Error{k_BadNumCellsPath, "FeatureIds not provided as an Int32 Array."}})}; } - const NumCellsArrayType* numCellsPtr = data.getDataAs(numCellsPath); + const NumCellsArrayType* numCellsPtr = dataStructure.getDataAs(numCellsPath); if(numCellsPtr == nullptr) { return {nonstd::make_unexpected(std::vector{Error{k_BadNumCellsPath, "Num Cells not provided as an Int32 Array."}})}; @@ -350,19 +350,19 @@ IFilter::PreflightResult RemoveMinimumSizeFeaturesFilter::preflightImpl(const Da if(applyToSinglePhase) { - const PhasesArrayType* featurePhasesPtr = data.getDataAs(featurePhasesPath); - const PhasesArrayType::store_type* featurePhases = nullptr; + const PhasesArrayType* featurePhasesPtr = dataStructure.getDataAs(featurePhasesPath); + // const PhasesArrayType::store_type* featurePhases = nullptr; if(featurePhasesPtr != nullptr) { dataArrayPaths.push_back(featurePhasesPath); - featurePhases = featurePhasesPtr->getDataStore(); + // featurePhases = featurePhasesPtr->getDataStore(); } } - data.validateNumberOfTuples(dataArrayPaths); + dataStructure.validateNumberOfTuples(dataArrayPaths); DataPath featureGroupDataPath = numCellsPath.getParent(); - const BaseGroup* featureDataGroup = data.getDataAs(featureGroupDataPath); + const BaseGroup* featureDataGroup = dataStructure.getDataAs(featureGroupDataPath); if(nullptr == featureDataGroup) { return {nonstd::make_unexpected(std::vector{Error{k_ParentlessPathError, "The provided NumCells DataPath does not have a parent."}})}; @@ -372,30 +372,32 @@ IFilter::PreflightResult RemoveMinimumSizeFeaturesFilter::preflightImpl(const Da nx::core::Result resultOutputActions; std::vector preflightUpdatedValues; - // Throw a warning to inform the user that the neighbor list arrays could be deleted by this filter - std::string ss = fmt::format("If this filter modifies the Cell Level Array '{}', all arrays of type NeighborList will be deleted from the feature data group '{}'. These arrays are:\n", - featureIdsPath.toString(), featureGroupDataPath.toString()); - - auto result = nx::core::GetAllChildDataPaths(data, featureGroupDataPath, DataObject::Type::NeighborList); - if(!result.has_value()) - { - return {nonstd::make_unexpected( - std::vector{Error{k_FetchChildArrayError, fmt::format("Errors were encountered trying to retrieve the neighbor list children of group '{}'", featureGroupDataPath.toString())}})}; - } - std::vector featureNeighborListArrays = result.value(); - for(const auto& featureNeighborList : featureNeighborListArrays) + // This section gives a warning to the user about NeighborLists possibly being removed { - ss.append(" " + featureNeighborList.toString() + "\n"); - auto action = std::make_unique(featureNeighborList); - resultOutputActions.value().actions.emplace_back(std::move(action)); - } + // Throw a warning to inform the user that the neighbor list arrays could be deleted by this filter + std::string ss = fmt::format("If this filter modifies the Cell Level Array '{}', all arrays of type NeighborList will be deleted from the feature data group '{}'. These arrays are:\n", + featureIdsPath.toString(), featureGroupDataPath.toString()); - // Inform users that the following arrays are going to be modified in place - // Feature Data is going to be modified - nx::core::AppendDataObjectModifications(data, resultOutputActions.value().modifiedActions, featureGroupDataPath, {}); + auto result = nx::core::GetAllChildDataPaths(dataStructure, featureGroupDataPath, DataObject::Type::NeighborList); + if(!result.has_value()) + { + return {nonstd::make_unexpected( + std::vector{Error{k_FetchChildArrayError, fmt::format("Errors were encountered trying to retrieve the neighbor list children of group '{}'", featureGroupDataPath.toString())}})}; + } + std::vector featureNeighborListArrays = result.value(); + for(const auto& featureNeighborList : featureNeighborListArrays) + { + ss.append(" " + featureNeighborList.toString() + "\n"); + auto action = std::make_unique(featureNeighborList); + resultOutputActions.value().actions.emplace_back(std::move(action)); + } - resultOutputActions.warnings().push_back(Warning{k_NeighborListRemoval, ss}); + // Inform users that the following arrays are going to be modified in place + // Feature Data is going to be modified + nx::core::AppendDataObjectModifications(dataStructure, resultOutputActions.value().modifiedActions, featureGroupDataPath, {}); + resultOutputActions.warnings().push_back(Warning{k_NeighborListRemoval, ss}); + } // Return both the resultOutputActions and the preflightUpdatedValues via std::move() return {std::move(resultOutputActions), std::move(preflightUpdatedValues)}; } @@ -466,7 +468,7 @@ Result<> RemoveMinimumSizeFeaturesFilter::executeImpl(DataStructure& dataStructu std::string message = fmt::format("Feature Count Changed: Previous: {} New: {}", currentFeatureCount, count); messageHandler(nx::core::IFilter::Message{nx::core::IFilter::Message::Type::Info, message}); - nx::core::RemoveInactiveObjects(dataStructure, cellFeatureGroupPath, activeObjects, featureIdsArrayRef, currentFeatureCount); + nx::core::RemoveInactiveObjects(dataStructure, cellFeatureGroupPath, activeObjects, featureIdsArrayRef, currentFeatureCount, messageHandler); return {}; } diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/RemoveMinimumSizeFeaturesFilter.hpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/RemoveMinimumSizeFeaturesFilter.hpp index 189623f884..e592d004ae 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/RemoveMinimumSizeFeaturesFilter.hpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/RemoveMinimumSizeFeaturesFilter.hpp @@ -84,12 +84,12 @@ class SIMPLNXCORE_EXPORT RemoveMinimumSizeFeaturesFilter : public IFilter protected: /** * @brief - * @param data + * @param dataStructure * @param args * @param messageHandler * @return PreflightResult */ - PreflightResult preflightImpl(const DataStructure& data, const Arguments& args, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const override; + PreflightResult preflightImpl(const DataStructure& dataStructure, const Arguments& args, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const override; /** * @brief diff --git a/src/simplnx/Utilities/DataGroupUtilities.cpp b/src/simplnx/Utilities/DataGroupUtilities.cpp index d07d3213d3..c4592465bd 100644 --- a/src/simplnx/Utilities/DataGroupUtilities.cpp +++ b/src/simplnx/Utilities/DataGroupUtilities.cpp @@ -5,7 +5,8 @@ namespace nx::core { -bool RemoveInactiveObjects(DataStructure& dataStructure, const DataPath& featureDataGroupPath, const std::vector& activeObjects, Int32Array& cellFeatureIds, size_t currentFeatureCount) +bool RemoveInactiveObjects(DataStructure& dataStructure, const DataPath& featureDataGroupPath, const std::vector& activeObjects, Int32Array& cellFeatureIds, size_t currentFeatureCount, + const IFilter::MessageHandler& messageHandler) { bool acceptableMatrix = true; @@ -97,6 +98,8 @@ bool RemoveInactiveObjects(DataStructure& dataStructure, const DataPath& feature std::vector neighborListDataPaths = result.value(); for(const auto& neighborListDataPath : neighborListDataPaths) { + messageHandler( + nx::core::IFilter::Message{nx::core::IFilter::Message::Type::Warning, fmt::format("NeighborList '{}' was removed from the DataStructure.", neighborListDataPath.toString())}); dataStructure.removeData(neighborListDataPath); } } diff --git a/src/simplnx/Utilities/DataGroupUtilities.hpp b/src/simplnx/Utilities/DataGroupUtilities.hpp index db713aa810..a2ea32c77f 100644 --- a/src/simplnx/Utilities/DataGroupUtilities.hpp +++ b/src/simplnx/Utilities/DataGroupUtilities.hpp @@ -4,6 +4,7 @@ #include "simplnx/DataStructure/DataPath.hpp" #include "simplnx/DataStructure/DataStructure.hpp" #include "simplnx/DataStructure/IDataArray.hpp" +#include "simplnx/Filter/IFilter.hpp" #include "simplnx/simplnx_export.hpp" #include @@ -19,10 +20,11 @@ namespace nx::core * @param featureDataGroupPath * @param activeObjects * @param cellFeatureIds + * @param messageHandler * @return */ SIMPLNX_EXPORT bool RemoveInactiveObjects(DataStructure& dataStructure, const DataPath& featureDataGroupPath, const std::vector& activeObjects, Int32Array& cellFeatureIds, - size_t currentFeatureCount); + size_t currentFeatureCount, const IFilter::MessageHandler& messageHandler); /** * @brief This function will gather all of the sibling DataArrays to the input DataPath, then filter out all the 'IgnoredDataPaths` diff --git a/src/simplnx/Utilities/SamplingUtils.hpp b/src/simplnx/Utilities/SamplingUtils.hpp index 3b94544725..ce0d51df5a 100644 --- a/src/simplnx/Utilities/SamplingUtils.hpp +++ b/src/simplnx/Utilities/SamplingUtils.hpp @@ -12,7 +12,7 @@ namespace nx::core namespace Sampling { inline Result<> RenumberFeatures(DataStructure& dataStructure, const DataPath& newGeomPath, const DataPath& destCellFeatAttributeMatrixPath, const DataPath& featureIdsArrayPath, - const DataPath& destFeatureIdsArrayPath, const std::atomic_bool& shouldCancel = false) + const DataPath& destFeatureIdsArrayPath, const IFilter::MessageHandler& messageHandler, const std::atomic_bool& shouldCancel = false) { auto& destImageGeom = dataStructure.getDataRefAs(newGeomPath); // This just sanity checks to make sure there were existing features before the cropping @@ -58,7 +58,7 @@ inline Result<> RenumberFeatures(DataStructure& dataStructure, const DataPath& n } } - if(!RemoveInactiveObjects(dataStructure, destCellFeatAttributeMatrixPath, activeObjects, destFeatureIdsRef, totalFeatures)) + if(!RemoveInactiveObjects(dataStructure, destCellFeatAttributeMatrixPath, activeObjects, destFeatureIdsRef, totalFeatures, messageHandler)) { std::string ss = fmt::format("An error occurred while trying to remove the inactive objects from Attribute Matrix '{}'", destCellFeatAttributeMatrixPath.toString()); return MakeErrorResult(-606, ss);