diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ITKArrayHelper.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ITKArrayHelper.cpp index d43ef391f3..83e8e581a4 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ITKArrayHelper.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ITKArrayHelper.cpp @@ -20,37 +20,6 @@ DataType ITK::detail::ConvertChoiceToDataType(types::usize choice) return DataType::uint8; } -bool ITK::DoTuplesMatch(const IDataStore& dataStore, const ImageGeom& imageGeom) -{ - return imageGeom.getNumberOfCells() == dataStore.getNumberOfTuples(); -} - -bool ITK::DoDimensionsMatch(const IDataStore& dataStore, const ImageGeom& imageGeom) -{ - // Stored fastest to slowest i.e. X Y Z - SizeVec3 geomDims = imageGeom.getDimensions(); - - // Stored slowest to fastest i.e. Z Y X - auto imageArrayDims = dataStore.getTupleShape(); - - SizeVec3 orderedArrayDims; - - if(imageArrayDims.size() == 3) - { - orderedArrayDims = SizeVec3(imageArrayDims[2], imageArrayDims[1], imageArrayDims[0]); - } - else if(imageArrayDims.size() == 2 && geomDims.getZ() == 1) - { - orderedArrayDims = SizeVec3(imageArrayDims[1], imageArrayDims[0], 1); - } - else - { - return false; - } - - return orderedArrayDims == geomDims; -} - Result<> ITK::CheckImageType(const std::vector& types, const DataStructure& dataStructure, const DataPath& path) { const auto& dataArray = dataStructure.getDataRefAs(path); diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ITKArrayHelper.hpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ITKArrayHelper.hpp index 827a7f7812..b3f2b65e7d 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ITKArrayHelper.hpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ITKArrayHelper.hpp @@ -13,6 +13,7 @@ #include "simplnx/Filter/Actions/CreateArrayAction.hpp" #include "simplnx/Filter/Output.hpp" #include "simplnx/Utilities/DataArrayUtilities.hpp" +#include "simplnx/Utilities/ImageIO/ImageIOUtilities.hpp" #include "simplnx/Utilities/StringUtilities.hpp" #include @@ -158,22 +159,6 @@ inline constexpr int32 k_OutOfCoreDataNotSupported = -2002; } // namespace Constants -/** - * @brief Compares the total number of cells of the image geometry and the total number of tuples from the data store - * @param dataStore - * @param imageGeom - * @return True if the Image Geometry's numCells() == the DataStore's numberOfTuples() - */ -bool DoTuplesMatch(const IDataStore& dataStore, const ImageGeom& imageGeom); - -/** - * @brief Checks to see if the dimensions of the Image Geometry and the DataStore are the same. - * @param dataStore - * @param imageGeom - * @return - */ -bool DoDimensionsMatch(const IDataStore& dataStore, const ImageGeom& imageGeom); - /** * @brief Attempts to convert itk::IOComponentEnum to nx::core::NumericType * @param component @@ -569,7 +554,7 @@ Result DataCheckImpl(const DataStructure& dataStructure, const Da const IDataStore& dataStore = dataArray.getIDataStoreRef(); - if(!nx::core::ITK::DoDimensionsMatch(dataStore, imageGeom) && !nx::core::ITK::DoTuplesMatch(dataStore, imageGeom)) + if(!nx::core::DoDimensionsMatch(dataStore, imageGeom) && !nx::core::DoTuplesMatch(dataStore, imageGeom)) { std::string errMessage = fmt::format("DataArray '{}' dimensions ({}) do not match Image Geometry '{}' dimensions ({}).", inputArrayPath.toString(), diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageWriterFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageWriterFilter.cpp index 8bc48f5877..d4df693d3c 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageWriterFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageWriterFilter.cpp @@ -15,6 +15,7 @@ #include "simplnx/Parameters/GeometrySelectionParameter.hpp" #include "simplnx/Parameters/NumberParameter.hpp" #include "simplnx/Parameters/StringParameter.hpp" +#include "simplnx/Utilities/ImageIO/ImageIOUtilities.hpp" #include "simplnx/Utilities/StringUtilities.hpp" #include @@ -347,7 +348,7 @@ IFilter::PreflightResult ITKImageWriterFilter::preflightImpl(const DataStructure const IDataStore& imageArrayStore = imageArray.getIDataStoreRef(); - if(!ITK::DoDimensionsMatch(imageArrayStore, imageGeom)) + if(!nx::core::DoDimensionsMatch(imageArrayStore, imageGeom)) { return {MakeErrorResult(-25600, fmt::format("Image array '{}' dimensions ({}) do not match image geometry '{}' dimensions ({}).", imageArrayPath.toString(), StringUtilities::formatTupleShape3D(imageArray.getTupleShape()), imageGeomPath.toString(), @@ -379,11 +380,12 @@ IFilter::PreflightResult ITKImageWriterFilter::preflightImpl(const DataStructure break; } - std::stringstream ss; - ss << fs::absolute(filePath).parent_path().string() << "/" << filePath.stem().string(); - ss << "_" << std::setw(totalDigits) << std::setfill(fillChar[0]) << maxSlice; - ss << filePath.extension().string(); - preflightUpdatedValues.push_back({"Example Output File", ss.str()}); + // Generate example filename for PreflightValues + const std::string indexStr = CreateIndexString(maxSlice, static_cast(totalDigits), fillChar); + const std::string exampleFileName = fmt::format("{}/{}_{}{}", fs::absolute(filePath).parent_path().string(), filePath.stem().string(), indexStr, filePath.extension().string()); + + preflightUpdatedValues.push_back({"Example Output File", exampleFileName}); + return {std::move(resultOutputActions), std::move(preflightUpdatedValues)}; } diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ComputeFaceIPFColoringFilter.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ComputeFaceIPFColoringFilter.cpp index 35a50dfc83..8db442ea60 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ComputeFaceIPFColoringFilter.cpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ComputeFaceIPFColoringFilter.cpp @@ -42,7 +42,7 @@ std::string ComputeFaceIPFColoringFilter::humanName() const //------------------------------------------------------------------------------ std::vector ComputeFaceIPFColoringFilter::defaultTags() const { - return {className(), "Processing", "Crystallography", "Generate"}; + return {className(), "Processing", "Crystallography", "Generate", "IPF Colors", "Surface Mesh", "Triangles"}; } //------------------------------------------------------------------------------ diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ComputeKernelAvgMisorientationsFilter.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ComputeKernelAvgMisorientationsFilter.cpp index 89f67aa5a8..b667109f2d 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ComputeKernelAvgMisorientationsFilter.cpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ComputeKernelAvgMisorientationsFilter.cpp @@ -44,7 +44,7 @@ std::string ComputeKernelAvgMisorientationsFilter::humanName() const //------------------------------------------------------------------------------ std::vector ComputeKernelAvgMisorientationsFilter::defaultTags() const { - return {className(), "Statistics", "Crystallography", "Misorientation"}; + return {className(), "Statistics", "Crystallography", "Misorientation", "KAM"}; } //------------------------------------------------------------------------------ diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ComputeGroupingDensity.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ComputeGroupingDensity.cpp index 3082220c8c..3d0eacaa67 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ComputeGroupingDensity.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ComputeGroupingDensity.cpp @@ -71,7 +71,7 @@ class FindDensityGrouping // Start the Parent Outer Loop for(usize currentParentId = 1; currentParentId < numParents; currentParentId++) { - throttledMessenger.sendThrottledMessage([&]() { return fmt::format("{}/{} {}%", currentParentId, numParents, CalculatePercentComplete(currentParentId, numParents)); }); + throttledMessenger.sendThrottledMessage([&]() { return fmt::format("{}/{} {:.1f}%", currentParentId, numParents, CalculatePercentComplete(currentParentId, numParents)); }); if(m_ShouldCancel) { diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/CreateColorMapFilter.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/CreateColorMapFilter.cpp index a9874d487b..8a2c26a840 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/CreateColorMapFilter.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/CreateColorMapFilter.cpp @@ -7,15 +7,13 @@ #include "simplnx/Filter/Actions/CreateArrayAction.hpp" #include "simplnx/Parameters/ArraySelectionParameter.hpp" #include "simplnx/Parameters/BoolParameter.hpp" +#include "simplnx/Parameters/CreateColorMapParameter.hpp" #include "simplnx/Parameters/DataObjectNameParameter.hpp" #include "simplnx/Parameters/StringParameter.hpp" - +#include "simplnx/Parameters/VectorParameter.hpp" #include "simplnx/Utilities/ColorTableUtilities.hpp" #include "simplnx/Utilities/SIMPLConversion.hpp" -#include "simplnx/Parameters/CreateColorMapParameter.hpp" -#include "simplnx/Parameters/VectorParameter.hpp" - using namespace nx::core; namespace { diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteImageFilter.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteImageFilter.cpp index 62ae7241df..a7d35c4e97 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteImageFilter.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteImageFilter.cpp @@ -17,6 +17,7 @@ #include "simplnx/Parameters/StringParameter.hpp" #include "simplnx/Utilities/ImageIO/ImageIOFactory.hpp" #include "simplnx/Utilities/ImageIO/ImageIOUtilities.hpp" +#include "simplnx/Utilities/StringUtilities.hpp" #include #include @@ -140,6 +141,15 @@ IFilter::PreflightResult WriteImageFilter::preflightImpl(const DataStructure& da -27011, fmt::format("Unsupported data type '{}' for image writing. Supported types: int8, uint8, int16, uint16, int32, uint32, float32.", DataTypeToString(arrayDataType)))}; } + const IDataStore& imageArrayStore = imageArray.getIDataStoreRef(); + + if(!nx::core::DoDimensionsMatch(imageArrayStore, imageGeom)) + { + return {MakeErrorResult(-25600, fmt::format("Image array '{}' dimensions ({}) do not match image geometry '{}' dimensions ({}).", imageArrayPath.toString(), + StringUtilities::formatTupleShape3D(imageArray.getTupleShape()), imageGeomPath.toString(), + StringUtilities::formatDimensions3D(imageGeom.getDimensions())))}; + } + // Compute slice count based on plane and geometry dims auto imageGeomDims = imageGeom.getDimensions(); usize maxSlice = 1; diff --git a/src/simplnx/Parameters/EnsembleInfoParameter.cpp b/src/simplnx/Parameters/EnsembleInfoParameter.cpp index 94818a802a..a345c4b4d7 100644 --- a/src/simplnx/Parameters/EnsembleInfoParameter.cpp +++ b/src/simplnx/Parameters/EnsembleInfoParameter.cpp @@ -70,16 +70,20 @@ Result EnsembleInfoParameter::fromJsonImpl(const nlohmann::json& json, { static constexpr StringLiteral prefix = "FilterParameter 'EnsembleInfoParameter' Error: "; - if(!json.is_array()) + if(!json.is_array() && !json.is_null()) { return MakeErrorResult(FilterParameter::Constants::k_Json_Missing_Entry, fmt::format("{}The JSON data entry for key '{}' is not an array.", prefix.view(), name())); } - usize numRows = json.size(); + usize numRows = 0; + if(!json.is_null()) + { + numRows = json.size(); + } ValueType table; table.reserve(numRows); - for(usize i = 0; i < json.size(); i++) + for(usize i = 0; i < numRows; i++) { const auto& rowJson = json[i]; if(!rowJson.is_array()) @@ -133,7 +137,7 @@ Result<> EnsembleInfoParameter::validate(const std::any& valueRef) const usize numRows = table.size(); if(numRows == 0) { - return MakeErrorResult<>(FilterParameter::Constants::k_Validate_TupleShapeValue, "{}You must add at least one row (ensemble phase)"); + return MakeErrorResult<>(FilterParameter::Constants::k_Validate_TupleShapeValue, "You must add at least one row (ensemble phase)"); } usize lastNumCols = table.front().size(); for(usize i = 1; i < numRows; i++) diff --git a/src/simplnx/Utilities/ImageIO/ImageIOUtilities.hpp b/src/simplnx/Utilities/ImageIO/ImageIOUtilities.hpp index 10abbed73a..231f521538 100644 --- a/src/simplnx/Utilities/ImageIO/ImageIOUtilities.hpp +++ b/src/simplnx/Utilities/ImageIO/ImageIOUtilities.hpp @@ -1,8 +1,9 @@ #pragma once -#include "simplnx/simplnx_export.hpp" - #include "simplnx/Common/Types.hpp" +#include "simplnx/DataStructure/Geometry/ImageGeom.hpp" +#include "simplnx/DataStructure/IDataStore.hpp" +#include "simplnx/simplnx_export.hpp" #include @@ -13,6 +14,49 @@ namespace nx::core { +/** + * @brief Compares the total number of cells of the image geometry and the total number of tuples from the data store + * @param dataStore + * @param imageGeom + * @return True if the Image Geometry's numCells() == the DataStore's numberOfTuples() + */ +inline bool DoTuplesMatch(const IDataStore& dataStore, const ImageGeom& imageGeom) +{ + return imageGeom.getNumberOfCells() == dataStore.getNumberOfTuples(); +} + +/** + * @brief Checks to see if the dimensions of the Image Geometry and the DataStore are the same. + * @param dataStore + * @param imageGeom + * @return + */ +inline bool DoDimensionsMatch(const IDataStore& dataStore, const ImageGeom& imageGeom) +{ + // Stored fastest to slowest i.e. X Y Z + SizeVec3 geomDims = imageGeom.getDimensions(); + + // Stored slowest to fastest i.e. Z Y X + auto imageArrayDims = dataStore.getTupleShape(); + + SizeVec3 orderedArrayDims; + + if(imageArrayDims.size() == 3) + { + orderedArrayDims = SizeVec3(imageArrayDims[2], imageArrayDims[1], imageArrayDims[0]); + } + else if(imageArrayDims.size() == 2 && geomDims.getZ() == 1) + { + orderedArrayDims = SizeVec3(imageArrayDims[1], imageArrayDims[0], 1); + } + else + { + return false; + } + + return orderedArrayDims == geomDims; +} + /** * @brief Formats an integer as a fill-padded string with the requested total digit count. * Used by the image-stack writers to build per-slice filenames such as "slice_007.tif". diff --git a/test/FilterValidationTest.cpp b/test/FilterValidationTest.cpp index ed6ded308e..58f2ede86f 100644 --- a/test/FilterValidationTest.cpp +++ b/test/FilterValidationTest.cpp @@ -94,7 +94,7 @@ void GenerateParameterList() ADD_PARAMETER_TRAIT(simplnx.VectorFloat64Parameter, "57cbdfdf-9d1a-4de8-95d7-71d0c01c5c96") } -TEST_CASE("nx::core::Test Filter Parameter Keys", "[simplnx][Filter]") +TEST_CASE("nx::core::FilterValidation::Filter Parameter Keys", "[simplnx][Filter]") { UnitTest::LoadPlugins(); @@ -182,7 +182,7 @@ TEST_CASE("nx::core::Test Filter Parameter Keys", "[simplnx][Filter]") REQUIRE(output.str().empty() == true); } -TEST_CASE("nx::core::Test Filter Parameter Help Text", "[simplnx][Filter]") +TEST_CASE("nx::core::FilterValidation::Filter Parameter Help Text", "[simplnx][Filter]") { UnitTest::LoadPlugins(); @@ -229,7 +229,7 @@ TEST_CASE("nx::core::Test Filter Parameter Help Text", "[simplnx][Filter]") REQUIRE(output.str().empty() == true); } -TEST_CASE("nx::core::Test Filter Name", "[simplnx][Filter]") +TEST_CASE("nx::core::FilterValidation::Filter Name", "[simplnx][Filter]") { UnitTest::LoadPlugins(); @@ -269,7 +269,7 @@ TEST_CASE("nx::core::Test Filter Name", "[simplnx][Filter]") REQUIRE(output.str().empty() == true); } -TEST_CASE("nx::core::Test Filter Version", "[simplnx][Filter]") +TEST_CASE("nx::core::FilterValidation::Filter Version", "[simplnx][Filter]") { UnitTest::LoadPlugins(); @@ -297,7 +297,7 @@ TEST_CASE("nx::core::Test Filter Version", "[simplnx][Filter]") REQUIRE(Application::Instance() == nullptr); } -TEST_CASE("nx::core::Test Filter Clone", "[simplnx][Filter]") +TEST_CASE("nx::core::FilterValidation::Test Filter Clone", "[simplnx][Filter]") { UnitTest::LoadPlugins(); @@ -323,4 +323,4 @@ TEST_CASE("nx::core::Test Filter Clone", "[simplnx][Filter]") Application::DeleteInstance(); REQUIRE(Application::Instance() == nullptr); -} \ No newline at end of file +}