From 8ba8129a1d1c3d1d1bbc0f8b310a13d5e914f20c Mon Sep 17 00:00:00 2001 From: Nathan Young Date: Mon, 16 Oct 2023 21:54:25 -0700 Subject: [PATCH] FILTER: EDAX .ang file Hex Grid To Sqaure Grid Converter (#738) * DOC: Update docs, add comments to source codes. Adjust human name of filter --------- Signed-off-by: Michael Jackson Co-authored-by: Michael Jackson --- .../OrientationAnalysis/CMakeLists.txt | 2 + .../docs/ConvertHexGridToSquareGridFilter.md | 25 ++ .../docs/ReadAngDataFilter.md | 10 + .../Algorithms/ConvertHexGridToSquareGrid.cpp | 368 ++++++++++++++++++ .../Algorithms/ConvertHexGridToSquareGrid.hpp | 56 +++ .../ConvertHexGridToSquareGridFilter.cpp | 204 ++++++++++ .../ConvertHexGridToSquareGridFilter.hpp | 104 +++++ .../OrientationAnalysis/test/CMakeLists.txt | 4 +- .../test/ConvertHexGridToSquareGridTest.cpp | 148 +++++++ src/complex/Utilities/FilePathGenerator.cpp | 4 +- src/complex/Utilities/FilePathGenerator.hpp | 4 +- 11 files changed, 923 insertions(+), 6 deletions(-) create mode 100644 src/Plugins/OrientationAnalysis/docs/ConvertHexGridToSquareGridFilter.md create mode 100644 src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ConvertHexGridToSquareGrid.cpp create mode 100644 src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ConvertHexGridToSquareGrid.hpp create mode 100644 src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ConvertHexGridToSquareGridFilter.cpp create mode 100644 src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ConvertHexGridToSquareGridFilter.hpp create mode 100644 src/Plugins/OrientationAnalysis/test/ConvertHexGridToSquareGridTest.cpp diff --git a/src/Plugins/OrientationAnalysis/CMakeLists.txt b/src/Plugins/OrientationAnalysis/CMakeLists.txt index 9fd9d64369..2fd722e2f0 100644 --- a/src/Plugins/OrientationAnalysis/CMakeLists.txt +++ b/src/Plugins/OrientationAnalysis/CMakeLists.txt @@ -31,6 +31,7 @@ set(FilterList AlignSectionsMutualInformationFilter BadDataNeighborOrientationCheckFilter CAxisSegmentFeaturesFilter + ConvertHexGridToSquareGridFilter ConvertOrientations ConvertQuaternionFilter CreateEnsembleInfoFilter @@ -165,6 +166,7 @@ set(filter_algorithms AlignSectionsMutualInformation BadDataNeighborOrientationCheck CAxisSegmentFeatures + ConvertHexGridToSquareGrid ConvertQuaternion CreateEnsembleInfo EBSDSegmentFeatures diff --git a/src/Plugins/OrientationAnalysis/docs/ConvertHexGridToSquareGridFilter.md b/src/Plugins/OrientationAnalysis/docs/ConvertHexGridToSquareGridFilter.md new file mode 100644 index 0000000000..8bfcdc460d --- /dev/null +++ b/src/Plugins/OrientationAnalysis/docs/ConvertHexGridToSquareGridFilter.md @@ -0,0 +1,25 @@ +# Convert Hexagonal Grid Data to Square Grid Data (TSL - .ang) + +## Group (Subgroup) + +Sampling (Resolution) + +## Description + +This **Filter** will convert TSL .ang files on hexagonal grids to TSL .ang files on square grids by means of interpolation between points. Note that the resulting square grid .ang files may have more or less rows of data and that some data may be interpolated based on its neighbor data. By default, the spacing of the square grid will be the spacing between columns in the hexagonal grid. + +This **Filter** is useful since most DREAM3D-NX routines for analyzing Ebsd data require a square grid. After using this **Filter** to bulk convert the EDAX/TSL .ang files to square grids, it is suggested to use the {ref}`Import Orientation File(s) to H5Ebsd ` **Filter** to convert the square grid .ang files to the H5Ebsd format. The user can then use the {ref}`Read H5Ebsd File ` **Filter** to import the H5Ebsd file into DREAM.3D for analysis. + +The use of this **Filter** is similar to the use of the {ref}`Import Orientation File(s) to H5Ebsd ` **Filter**. Please consult that **Filter's** documentation for a detailed description of the various user interface elements. Note that unlike the {ref}`Import Orientation File(s) to H5Ebsd ` **Filter**, this **Filter** does not require either the *Stacking Order* or the *Reference Frame* to be modified. + +% Auto generated parameter table will be inserted here + +## Example Pipelines + +## 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) GItHub site where the community of DREAM3D-NX users can help answer your questions. diff --git a/src/Plugins/OrientationAnalysis/docs/ReadAngDataFilter.md b/src/Plugins/OrientationAnalysis/docs/ReadAngDataFilter.md index faad519864..0bc1fc14b3 100644 --- a/src/Plugins/OrientationAnalysis/docs/ReadAngDataFilter.md +++ b/src/Plugins/OrientationAnalysis/docs/ReadAngDataFilter.md @@ -17,6 +17,16 @@ If the data has come from a TSL acquisition system and the settings of the acqui The user also may want to assign un-indexed pixels to be ignored by flagging them as "bad". The Threshold Objects **Filter** can be used to define this *mask* by thresholding on values such as *Confidence Index* > 0.1 or *Image Quality* > desired quality. +### Note About Sample Grid + +OIMAnalysis can create EBSD data sampled on a hexagonal grid. The user can look in the .ang file into the header (those lines starting with the "#" character) for a line that is: + +```text +# GRID: HexGrid +``` + +If the user's .ang files are hexagonal grid files then they will need to run the {ref}`Convert EDAX Hex Grid to Square Grid (.ang)` filter to first convert the input files square gridded files. + % Auto generated parameter table will be inserted here ## Example Pipelines diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ConvertHexGridToSquareGrid.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ConvertHexGridToSquareGrid.cpp new file mode 100644 index 0000000000..8a525dd042 --- /dev/null +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ConvertHexGridToSquareGrid.cpp @@ -0,0 +1,368 @@ +#include "ConvertHexGridToSquareGrid.hpp" + +#include "complex/DataStructure/DataArray.hpp" +#include "complex/DataStructure/DataGroup.hpp" +#include "complex/Parameters/ChoicesParameter.hpp" +#include "complex/Utilities/FilePathGenerator.hpp" +#include "complex/Utilities/StringUtilities.hpp" + +#include "EbsdLib/IO/TSL/AngConstants.h" +#include "EbsdLib/IO/TSL/AngReader.h" + +#include +#include + +using namespace complex; + +namespace +{ +constexpr ChoicesParameter::ValueType k_ToScalarVector = 0; +constexpr ChoicesParameter::ValueType k_ToVectorScalar = 1; + +class Converter +{ +public: + Converter(const std::atomic_bool& shouldCancel, const fs::path& outputDirPath, const std::string& outputFilePrefix, const std::vector& spacingXY) + : m_ShouldCancel(shouldCancel) + , m_OutputPath(outputDirPath) + , m_FilePrefix(outputFilePrefix) + , m_SqrXStep(spacingXY.at(0)) + , m_SqrYStep(spacingXY.at(1)) + { + } + ~Converter() noexcept = default; + + Converter(const Converter&) = delete; // Copy Constructor Default Implemented + Converter(Converter&&) = delete; // Move Constructor Not Implemented + Converter& operator=(const Converter&) = delete; // Copy Assignment Not Implemented + Converter& operator=(Converter&&) = delete; // Move Assignment Not Implemented + + Result<> operator()(const fs::path& inputPath) + { + // Write the Manufacturer of the OIM file here + // This list will grow to be the number of EBSD file formats we support + if(inputPath.extension() == ("." + EbsdLib::Ang::FileExt)) + { + AngReader reader; + reader.setFileName(inputPath.string()); + reader.setReadHexGrid(true); + int32 err = reader.readFile(); + if(err < 0 && err != -600) + { + return MakeErrorResult(reader.getErrorCode(), reader.getErrorMessage()); + } + if(err == -600) + { + return MakeWarningVoidResult(reader.getErrorCode(), reader.getErrorMessage()); + } + if(reader.getGrid().find(EbsdLib::Ang::SquareGrid) == 0) + { + return MakeErrorResult(-55000, fmt::format("Ang file is already a square grid: {}", inputPath.string())); + } + + std::string origHeader = reader.getOriginalHeader(); + if(origHeader.empty()) + { + return MakeErrorResult(-55001, fmt::format("Header for input hex grid file was empty: {}", inputPath.string())); + } + + std::istringstream headerStream(origHeader, std::ios_base::in | std::ios_base::binary); + fs::path outPath = fs::absolute(m_OutputPath) / (m_FilePrefix + inputPath.filename().string()); + + if(outPath == inputPath) + { + return MakeErrorResult(-201, "New ang file is the same as the old ang file. Overwriting is NOT allowed"); + } + + std::ofstream outFile(outPath, std::ios_base::out | std::ios_base::binary); + // Ensure the output path exists by creating it if necessary + if(!fs::exists(outPath.parent_path())) + { + return MakeErrorResult(-77750, fmt::format("The parent path was not created and does not exist: {}", outPath.parent_path().string())); + } + + if(!outFile.is_open()) + { + return MakeErrorResult(-200, fmt::format("Ang square output file could not be opened for writing: {}", outPath.string())); + } + + m_HeaderIsComplete = false; + + float32 hexXStep = reader.getXStep(); + float32 hexYStep = reader.getYStep(); + int32 hexNumColsOdd = reader.getNumOddCols(); + int32 hexNumColsEven = reader.getNumEvenCols(); + int32 hexNumRows = reader.getNumRows(); + m_SqrNumCols = static_cast((static_cast(hexNumColsOdd) * hexXStep) / m_SqrXStep); + m_SqrNumRows = static_cast((static_cast(hexNumRows) * hexYStep) / m_SqrYStep); + + // Get the hex grid data from the input file + float32* phi1 = reader.getPhi1Pointer(); + float32* PHI = reader.getPhiPointer(); + float32* phi2 = reader.getPhi2Pointer(); + float32* ci = reader.getConfidenceIndexPointer(); + float32* iq = reader.getImageQualityPointer(); + float32* semSig = reader.getSEMSignalPointer(); + float32* fit = reader.getFitPointer(); + int32* phase = reader.getPhaseDataPointer(); + + // Loop on the header part of the file and modify the header while writing to the output file + // the updated information + while(!headerStream.eof()) + { + std::string buf; + std::getline(headerStream, buf); + if(buf.empty()) + { + continue; + } + std::string line = modifyAngHeaderLine(buf); + if(!m_HeaderIsComplete) + { + outFile << line << "\n"; + } + } + + // Reusable variables for the loop + int32 hexGridIndex, hexGridIndex1, hexGridIndex2; + float32 xHex1, xHex2; + + // Now loop on every cell in the replacement square grid + for(int32 j = 0; j < m_SqrNumRows; j++) + { + if(m_ShouldCancel) + { + return {}; + } + for(int32 i = 0; i < m_SqrNumCols; i++) + { + // Calculate the center point of the current Square grid cell + float32 xSqr = static_cast(i) * m_SqrXStep; + float32 ySqr = static_cast(j) * m_SqrYStep; + + // Calculate hex grid rows that will be used to for the conversion for this square grid point + int32 hexRowIndex1 = static_cast(ySqr / hexYStep); + float32 yHex1 = static_cast(hexRowIndex1) * hexYStep; + + int32 hexRowIndex2 = hexRowIndex1 + 1; + float32 yHex2 = static_cast(hexRowIndex2) * hexYStep; + + // If we are on an even row + if(hexRowIndex1 % 2 == 0) + { + int32 hexGridColIndex1 = static_cast(xSqr / (hexXStep)); // Compute the hex column index that the square grid coord falls into + xHex1 = static_cast(hexGridColIndex1) * hexXStep; // Compute the X Hex Grid coordinate + hexGridIndex1 = ((hexRowIndex1 / 2) * hexNumColsEven) + ((hexRowIndex1 / 2) * hexNumColsOdd) + hexGridColIndex1; // Compute the index into hex grid data + + int32 hexGridColIndex2 = static_cast((xSqr - (hexXStep / 2.0)) / (hexXStep)); + xHex2 = static_cast(static_cast(hexGridColIndex2) * hexXStep + (hexXStep / 2.0)); + hexGridIndex2 = ((hexRowIndex1 / 2) * hexNumColsEven) + (((hexRowIndex1 / 2) + 1) * hexNumColsOdd) + hexGridColIndex2; + } + else // If we are on an odd row + { + int32 hexGridColIndex1 = static_cast((xSqr - (hexXStep / 2.0)) / (hexXStep)); + xHex1 = static_cast(static_cast(hexGridColIndex1) * hexXStep + (hexXStep / 2.0)); + hexGridIndex1 = ((hexRowIndex1 / 2) * hexNumColsEven) + (((hexRowIndex1 / 2) + 1) * hexNumColsOdd) + hexGridColIndex1; + + int32 hexGridColIndex2 = static_cast(xSqr / hexXStep); + xHex2 = static_cast(hexGridColIndex2) * hexXStep; + hexGridIndex2 = (((hexRowIndex1 / 2) + 1) * hexNumColsEven) + (((hexRowIndex1 / 2) + 1) * hexNumColsOdd) + hexGridColIndex2; + } + + // Compute the distance from the square grid coordinate to the hex grid coordinate. + float32 dist1 = ((xSqr - xHex1) * (xSqr - xHex1)) + ((ySqr - yHex1) * (ySqr - yHex1)); + float32 dist2 = ((xSqr - xHex2) * (xSqr - xHex2)) + ((ySqr - yHex2) * (ySqr - yHex2)); + // Select the closest hex grid point. + if(dist1 <= dist2 || hexRowIndex1 == (hexNumRows - 1)) + { + hexGridIndex = hexGridIndex1; + } + else + { + hexGridIndex = hexGridIndex2; + } + + // Write to the output file + outFile << " " << phi1[hexGridIndex] << " " << PHI[hexGridIndex] << " " << phi2[hexGridIndex] << " " << xSqr << " " << ySqr << " " << iq[hexGridIndex] << " " << ci[hexGridIndex] + << " " << phase[hexGridIndex] << " " << semSig[hexGridIndex] << " " << fit[hexGridIndex] << " " + << "\n"; + } + } + } + + return {}; + } + +private: + const std::atomic_bool& m_ShouldCancel; + const fs::path& m_OutputPath; + const std::string& m_FilePrefix; + + const float32 m_SqrXStep; + const float32 m_SqrYStep; + int32 m_SqrNumCols = 0; + int32 m_SqrNumRows = 0; + bool m_HeaderIsComplete = false; + + // ----------------------------------------------------------------------------- + std::string modifyAngHeaderLine(std::string& buf) + { + std::string line; + if(buf.at(0) != '#') + { + line = buf; + m_HeaderIsComplete = true; + return line; + } + if(buf.at(0) == '#' && buf.size() == 1) + { + line = buf; + return line; + } + // Start at the first character and walk until you find another non-space character + usize i = 1; + while(buf.at(i) == ' ') + { + ++i; + } + usize wordStart = i; + while(true) + { + if(buf.at(i) == 45 || buf.at(i) == 95 || (buf.at(i) >= 65 && buf.at(i) <= 90) || (buf.at(i) >= 97 && buf.at(i) <= 122)) + { + ++i; + } // "-" or "_" character + else + { + break; + } + } + + std::string word(buf.substr(wordStart)); + + if(word.empty()) + { + line = buf; + return line; + } + + if(StringUtilities::contains(buf, EbsdLib::Ang::HexGrid)) + { + line = StringUtilities::replace(buf, EbsdLib::Ang::HexGrid, EbsdLib::Ang::SquareGrid); + } + else if(StringUtilities::contains(buf, EbsdLib::Ang::XStep)) + { + line = "# " + EbsdLib::Ang::XStep + ": " + StringUtilities::number(m_SqrXStep); + } + else if(StringUtilities::contains(buf, EbsdLib::Ang::YStep)) + { + line = "# " + EbsdLib::Ang::YStep + ": " + StringUtilities::number(m_SqrYStep); + } + else if(StringUtilities::contains(buf, EbsdLib::Ang::NColsOdd)) + { + line = "# " + EbsdLib::Ang::NColsOdd + ": " + StringUtilities::number(m_SqrNumCols); + } + else if(StringUtilities::contains(buf, EbsdLib::Ang::NColsEven)) + { + line = "# " + EbsdLib::Ang::NColsEven + ": " + StringUtilities::number(m_SqrNumCols); + } + else if(StringUtilities::contains(buf, EbsdLib::Ang::NRows)) + { + line = "# " + EbsdLib::Ang::NRows + ": " + StringUtilities::number(m_SqrNumRows); + } + else + { + line = buf; + } + + return line; + } +}; +} // namespace + +// ----------------------------------------------------------------------------- +ConvertHexGridToSquareGrid::ConvertHexGridToSquareGrid(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, + ConvertHexGridToSquareGridInputValues* inputValues) +: m_DataStructure(dataStructure) +, m_InputValues(inputValues) +, m_ShouldCancel(shouldCancel) +, m_MessageHandler(mesgHandler) +{ +} + +// ----------------------------------------------------------------------------- +ConvertHexGridToSquareGrid::~ConvertHexGridToSquareGrid() noexcept = default; + +// ----------------------------------------------------------------------------- +const std::atomic_bool& ConvertHexGridToSquareGrid::getCancel() +{ + return m_ShouldCancel; +} + +// ----------------------------------------------------------------------------- +Result<> ConvertHexGridToSquareGrid::operator()() +{ + if(!m_InputValues->MultiFile) + { + return ::Converter(getCancel(), m_InputValues->OutputPath, m_InputValues->OutputFilePrefix, m_InputValues->XYSpacing)(m_InputValues->InputPath); + } + + // Now generate all the file names the user is asking for and populate the table + std::vector fileList = + FilePathGenerator::GenerateFileList(m_InputValues->InputFileListInfo.startIndex, m_InputValues->InputFileListInfo.endIndex, m_InputValues->InputFileListInfo.incrementIndex, + m_InputValues->InputFileListInfo.ordering, m_InputValues->InputPath.string(), m_InputValues->InputFileListInfo.filePrefix, + m_InputValues->InputFileListInfo.fileSuffix, m_InputValues->InputFileListInfo.fileExtension, m_InputValues->InputFileListInfo.paddingDigits); + + /* There is a frailness about the z index and the file list. The programmer + * using this code MUST ensure that the list of files that is sent into this + * class is in the appropriate order to match up with the z index (slice index) + * otherwise the import will have subtle errors. The programmer is urged NOT to + * simply gather a list from the file system as those lists are sorted in such + * a way that if the number of digits appearing in the filename are NOT the same + * then the list will be wrong, ie, this example: + * + * slice_1.ang + * slice_2.ang + * .... + * slice_10.ang + * + * Most, if not ALL C++ libraries when asked for that list will return the list + * sorted like the following: + * + * slice_1.ang + * slice_10.ang + * slice_2.ang + * + * which is going to cause problems because the data is going to be placed + * into the HDF5 file at the wrong index. YOU HAVE BEEN WARNED. + */ + // Loop on Each EBSD File + auto total = static_cast(m_InputValues->InputFileListInfo.endIndex - m_InputValues->InputFileListInfo.startIndex); + int32 progress; + int64 z = m_InputValues->InputFileListInfo.startIndex; + + auto result = Result<>{}; + ::Converter converter(getCancel(), m_InputValues->OutputPath, m_InputValues->OutputFilePrefix, m_InputValues->XYSpacing); + for(const auto& filepath : fileList) + { + m_MessageHandler(IFilter::Message::Type::Info, fmt::format("Now Processing: {}", filepath)); + + result = MergeResults(converter(fs::path(filepath)), result); + + { + z++; + progress = static_cast(z - m_InputValues->InputFileListInfo.startIndex - 1); + progress = static_cast(100.0f * static_cast(progress) / total); + std::string msg = "Converted File: " + filepath; + m_MessageHandler(IFilter::Message::Type::Progress, msg, progress); + } + + if(getCancel()) + { + result = MergeResults(MakeErrorResult(-00010, "Run Terminated Early"), result); + return result; + } + } + + return result; +} diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ConvertHexGridToSquareGrid.hpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ConvertHexGridToSquareGrid.hpp new file mode 100644 index 0000000000..fd6df1a825 --- /dev/null +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ConvertHexGridToSquareGrid.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include "OrientationAnalysis/OrientationAnalysis_export.hpp" + +#include "complex/DataStructure/DataPath.hpp" +#include "complex/DataStructure/DataStructure.hpp" +#include "complex/Filter/IFilter.hpp" +#include "complex/Parameters/ArrayCreationParameter.hpp" +#include "complex/Parameters/ArraySelectionParameter.hpp" +#include "complex/Parameters/BoolParameter.hpp" +#include "complex/Parameters/ChoicesParameter.hpp" +#include "complex/Parameters/FileSystemPathParameter.hpp" +#include "complex/Parameters/GeneratedFileListParameter.hpp" +#include "complex/Parameters/VectorParameter.hpp" + +namespace complex +{ +struct ORIENTATIONANALYSIS_EXPORT ConvertHexGridToSquareGridInputValues +{ + bool MultiFile; + VectorFloat32Parameter::ValueType XYSpacing; + FileSystemPathParameter::ValueType InputPath; + FileSystemPathParameter::ValueType OutputPath; + GeneratedFileListParameter::ValueType InputFileListInfo; + std::string OutputFilePrefix; +}; + +/** + * @class ConditionalSetValue + * @brief This filter replaces values in the target array with a user specified value + * where a bool mask array specifies. + */ + +class ORIENTATIONANALYSIS_EXPORT ConvertHexGridToSquareGrid +{ +public: + ConvertHexGridToSquareGrid(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, ConvertHexGridToSquareGridInputValues* inputValues); + ~ConvertHexGridToSquareGrid() noexcept; + + ConvertHexGridToSquareGrid(const ConvertHexGridToSquareGrid&) = delete; + ConvertHexGridToSquareGrid(ConvertHexGridToSquareGrid&&) noexcept = delete; + ConvertHexGridToSquareGrid& operator=(const ConvertHexGridToSquareGrid&) = delete; + ConvertHexGridToSquareGrid& operator=(ConvertHexGridToSquareGrid&&) noexcept = delete; + + Result<> operator()(); + + const std::atomic_bool& getCancel(); + +private: + DataStructure& m_DataStructure; + const ConvertHexGridToSquareGridInputValues* m_InputValues = nullptr; + const std::atomic_bool& m_ShouldCancel; + const IFilter::MessageHandler& m_MessageHandler; +}; + +} // namespace complex diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ConvertHexGridToSquareGridFilter.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ConvertHexGridToSquareGridFilter.cpp new file mode 100644 index 0000000000..a0159f040d --- /dev/null +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ConvertHexGridToSquareGridFilter.cpp @@ -0,0 +1,204 @@ +#include "ConvertHexGridToSquareGridFilter.hpp" + +#include "OrientationAnalysis/Filters/Algorithms/ConvertHexGridToSquareGrid.hpp" + +#include "complex/Parameters/BoolParameter.hpp" +#include "complex/Parameters/FileSystemPathParameter.hpp" +#include "complex/Parameters/GeneratedFileListParameter.hpp" +#include "complex/Parameters/StringParameter.hpp" +#include "complex/Parameters/VectorParameter.hpp" + +#include "EbsdLib/IO/HKL/CtfConstants.h" +#include "EbsdLib/IO/TSL/AngConstants.h" +#include "EbsdLib/IO/TSL/AngReader.h" + +#include +#include + +namespace fs = std::filesystem; +using namespace complex; + +namespace +{ +struct ConvertHexGridToSquareGridFilterCache +{ + fs::path workingPath; + std::string preflightReturnString; + fs::file_time_type lastWrite; +}; + +std::atomic_int32_t s_InstanceId = 0; +std::map s_HeaderCache; +} // namespace + +namespace complex +{ +//------------------------------------------------------------------------------ +ConvertHexGridToSquareGridFilter::ConvertHexGridToSquareGridFilter() +: m_InstanceId(s_InstanceId.fetch_add(1)) +{ + s_HeaderCache[m_InstanceId] = {}; +} + +//------------------------------------------------------------------------------ +ConvertHexGridToSquareGridFilter::~ConvertHexGridToSquareGridFilter() noexcept +{ + s_HeaderCache.erase(m_InstanceId); +} + +//------------------------------------------------------------------------------ +std::string ConvertHexGridToSquareGridFilter::name() const +{ + return FilterTraits::name.str(); +} + +//------------------------------------------------------------------------------ +std::string ConvertHexGridToSquareGridFilter::className() const +{ + return FilterTraits::className; +} + +//------------------------------------------------------------------------------ +Uuid ConvertHexGridToSquareGridFilter::uuid() const +{ + return FilterTraits::uuid; +} + +//------------------------------------------------------------------------------ +std::string ConvertHexGridToSquareGridFilter::humanName() const +{ + return "Convert EDAX Hex Grid to Square Grid (.ang)"; +} + +//------------------------------------------------------------------------------ +std::vector ConvertHexGridToSquareGridFilter::defaultTags() const +{ + return {className(), "Processing", "Conversion"}; +} + +//------------------------------------------------------------------------------ +Parameters ConvertHexGridToSquareGridFilter::parameters() const +{ + Parameters params; + + // Create the parameter descriptors that are needed for this filter + params.insertSeparator(Parameters::Separator{"Orientation Source Data"}); + params.insertLinkableParameter(std::make_unique(k_MultipleFiles_Key, "Convert Multiple Files", "", false)); + params.insert(std::make_unique(k_Spacing_Key, "Spacing", "Specifies the new spacing values", std::vector{1.0f, 1.0f}, std::vector{"X", "Y"})); + params.insert( + std::make_unique(k_InputPath_Key, "Input File", "", fs::path(""), FileSystemPathParameter::ExtensionsType{}, FileSystemPathParameter::PathType::InputFile, true)); + params.insert(std::make_unique(k_GeneratedFileList_Key, "Generated File List", "", GeneratedFileListParameter::ValueType{})); + + params.insertSeparator(Parameters::Separator{"Output Parameters"}); + params.insert( + std::make_unique(k_OutputPath_Key, "Output Directory", "", fs::path(""), FileSystemPathParameter::ExtensionsType{}, FileSystemPathParameter::PathType::OutputDir, true)); + params.insert(std::make_unique(k_OutputPrefix_Key, "Output Prefix", "", "Sqr_")); + + // Link Parameters + params.linkParameters(k_MultipleFiles_Key, k_GeneratedFileList_Key, true); + params.linkParameters(k_MultipleFiles_Key, k_InputPath_Key, false); + + return params; +} + +//------------------------------------------------------------------------------ +IFilter::UniquePointer ConvertHexGridToSquareGridFilter::clone() const +{ + return std::make_unique(); +} + +//------------------------------------------------------------------------------ +IFilter::PreflightResult ConvertHexGridToSquareGridFilter::preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel) const +{ + auto pUseMultipleFilesValue = filterArgs.value(k_MultipleFiles_Key); + auto pInputFileListInfoValue = filterArgs.value(k_GeneratedFileList_Key); + auto pInputSingleFile = filterArgs.value(k_InputPath_Key); + + complex::Result resultOutputActions; + std::vector preflightUpdatedValues; + + FileSystemPathParameter::ValueType inputPath = pInputSingleFile; + + if(pUseMultipleFilesValue) + { + std::vector files = pInputFileListInfoValue.generate(); + + if(files.empty()) + { + return MakePreflightErrorResult(-44600, "GeneratedFileList must not be empty"); + } + + inputPath = fs::path(files[0]); + } + + if(inputPath.extension() == ("." + EbsdLib::Ctf::FileExt)) + { + return MakePreflightErrorResult(-44601, "Ctf files are not on a hexagonal grid and do not need to be converted"); + } + else if(inputPath.extension() != ("." + EbsdLib::Ang::FileExt)) + { + return MakePreflightErrorResult(-44602, "The file extension was not detected correctly"); + } + + if(!fs::exists(inputPath)) + { + return MakePreflightErrorResult(-446003, "Please select a valid file path to run"); + } + + if(!fs::exists(s_HeaderCache[m_InstanceId].workingPath) || s_HeaderCache[m_InstanceId].workingPath != inputPath || + fs::last_write_time(s_HeaderCache[m_InstanceId].workingPath) > s_HeaderCache[m_InstanceId].lastWrite || s_HeaderCache[m_InstanceId].preflightReturnString.empty()) + { + s_HeaderCache[m_InstanceId].workingPath = inputPath; + s_HeaderCache[m_InstanceId].lastWrite = fs::last_write_time(inputPath); + AngReader reader; + reader.setFileName(inputPath.string()); + reader.setReadHexGrid(true); + int32 err = reader.readFile(); + if(err < 0 && err != -600) + { + return MakePreflightErrorResult(reader.getErrorCode(), reader.getErrorMessage()); + } + if(err == -600) + { + complex::Warning warning; + warning.code = reader.getErrorCode(); + warning.message = reader.getErrorMessage(); + resultOutputActions.m_Warnings.emplace_back(std::move(warning)); + } + + std::stringstream preflightString; + preflightString << "Hex Grid X Spacing: " << reader.getXStep() << "\n" + << "Hex Grid Y Spacing: " << reader.getYStep(); + s_HeaderCache[m_InstanceId].preflightReturnString = preflightString.str(); + } + + preflightUpdatedValues.emplace_back(PreflightValue{"Suggested Spacing", s_HeaderCache[m_InstanceId].preflightReturnString}); + + // Return both the resultOutputActions and the preflightUpdatedValues via std::move() + return {std::move(resultOutputActions), std::move(preflightUpdatedValues)}; +} + +//------------------------------------------------------------------------------ +Result<> ConvertHexGridToSquareGridFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel) const +{ + ConvertHexGridToSquareGridInputValues inputValues; + + inputValues.MultiFile = filterArgs.value(k_MultipleFiles_Key); + inputValues.XYSpacing = filterArgs.value(k_Spacing_Key); + inputValues.OutputPath = filterArgs.value(k_OutputPath_Key); + inputValues.OutputFilePrefix = filterArgs.value(k_OutputPrefix_Key); + inputValues.InputFileListInfo = filterArgs.value(k_GeneratedFileList_Key); + if(inputValues.MultiFile) + { + inputValues.InputPath = fs::path(inputValues.InputFileListInfo.inputPath); + } + else + { + inputValues.InputPath = filterArgs.value(k_InputPath_Key); + } + + return ConvertHexGridToSquareGrid(dataStructure, messageHandler, shouldCancel, &inputValues)(); +} +} // namespace complex diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ConvertHexGridToSquareGridFilter.hpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ConvertHexGridToSquareGridFilter.hpp new file mode 100644 index 0000000000..b00fb401f8 --- /dev/null +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ConvertHexGridToSquareGridFilter.hpp @@ -0,0 +1,104 @@ +#pragma once + +#include "OrientationAnalysis/OrientationAnalysis_export.hpp" + +#include "complex/Filter/FilterTraits.hpp" +#include "complex/Filter/IFilter.hpp" + +namespace complex +{ +/** + * @class ConvertHexGridToSquareGridFilter + * @brief This filter will... + */ +class ORIENTATIONANALYSIS_EXPORT ConvertHexGridToSquareGridFilter : public IFilter +{ +public: + ConvertHexGridToSquareGridFilter(); + ~ConvertHexGridToSquareGridFilter() noexcept override; + + ConvertHexGridToSquareGridFilter(const ConvertHexGridToSquareGridFilter&) = delete; + ConvertHexGridToSquareGridFilter(ConvertHexGridToSquareGridFilter&&) noexcept = delete; + + ConvertHexGridToSquareGridFilter& operator=(const ConvertHexGridToSquareGridFilter&) = delete; + ConvertHexGridToSquareGridFilter& operator=(ConvertHexGridToSquareGridFilter&&) noexcept = delete; + + // Parameter Keys + static inline constexpr StringLiteral k_MultipleFiles_Key = "multiple_files"; + static inline constexpr StringLiteral k_OutputPrefix_Key = "output_prefix"; + static inline constexpr StringLiteral k_OutputPath_Key = "output_path"; + static inline constexpr StringLiteral k_InputPath_Key = "input_path"; + static inline constexpr StringLiteral k_Spacing_Key = "spacing"; + static inline constexpr StringLiteral k_GeneratedFileList_Key = "generated_file_list"; + + /** + * @brief Returns the name of the filter. + * @return + */ + std::string name() const override; + + /** + * @brief Returns the C++ classname of this filter. + * @return + */ + std::string className() const override; + + /** + * @brief Returns the uuid of the filter. + * @return + */ + Uuid uuid() const override; + + /** + * @brief Returns the human readable name of the filter. + * @return + */ + std::string humanName() const override; + + /** + * @brief Returns the default tags for this filter. + * @return + */ + std::vector defaultTags() const override; + + /** + * @brief Returns the parameters of the filter (i.e. its inputs) + * @return + */ + Parameters parameters() const override; + + /** + * @brief Returns a copy of the filter. + * @return + */ + UniquePointer clone() const override; + +protected: + /** + * @brief Takes in a DataStructure and checks that the filter can be run on it with the given arguments. + * Returns any warnings/errors. Also returns the changes that would be applied to the DataStructure. + * Some parts of the actions may not be completely filled out if all the required information is not available at preflight time. + * @param dataStructure The input DataStructure instance + * @param filterArgs These are the input values for each parameter that is required for the filter + * @param messageHandler The MessageHandler object + * @return Returns a Result object with error or warning values if any of those occurred during execution of this function + */ + PreflightResult preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const override; + + /** + * @brief Applies the filter's algorithm to the DataStructure with the given arguments. Returns any warnings/errors. + * On failure, there is no guarantee that the DataStructure is in a correct state. + * @param dataStructure The input DataStructure instance + * @param filterArgs These are the input values for each parameter that is required for the filter + * @param messageHandler The MessageHandler object + * @return Returns a Result object with error or warning values if any of those occurred during execution of this function + */ + Result<> executeImpl(DataStructure& data, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const override; + +private: + int32 m_InstanceId; +}; +} // namespace complex + +COMPLEX_DEF_FILTER_TRAITS(complex, ConvertHexGridToSquareGridFilter, "960b0e35-de9f-496a-9423-0f55133b39c7"); +/* LEGACY UUID FOR THIS FILTER e1343abe-e5ad-5eb1-a89d-c209e620e4de */ diff --git a/src/Plugins/OrientationAnalysis/test/CMakeLists.txt b/src/Plugins/OrientationAnalysis/test/CMakeLists.txt index 3f74d0e01a..3d96ac3716 100644 --- a/src/Plugins/OrientationAnalysis/test/CMakeLists.txt +++ b/src/Plugins/OrientationAnalysis/test/CMakeLists.txt @@ -10,9 +10,9 @@ set(${PLUGIN_NAME}UnitTest_SRCS AlignSectionsMutualInformationTest.cpp BadDataNeighborOrientationCheckTest.cpp CAxisSegmentFeaturesTest.cpp + ConvertHexGridToSquareGridTest.cpp ConvertQuaternionTest.cpp ConvertOrientationsTest.cpp - ConvertQuaternionTest.cpp CreateEnsembleInfoTest.cpp EBSDSegmentFeaturesFilterTest.cpp EbsdToH5EbsdTest.cpp @@ -55,7 +55,6 @@ set(${PLUGIN_NAME}UnitTest_SRCS WriteStatsGenOdfAngleFileTest.cpp ) set(DISABLED_TESTS - # ConvertHexGridToSquareGridTest.cpp # MISSING 1 or more Parameter Implementations CreateLambertSphereTest.cpp EMsoftSO3SamplerTest.cpp FindDistsToCharactGBsTest.cpp @@ -139,6 +138,7 @@ if(EXISTS "${DREAM3D_DATA_DIR}" AND COMPLEX_DOWNLOAD_TEST_FILES) download_test_data(DREAM3D_DATA_DIR ${DREAM3D_DATA_DIR} ARCHIVE_NAME 6_6_read_ctf_data.tar.gz SHA512 e7ac4706d22574396aaa5d67b2a2b4e32db5005e841d3b6dafad65c74615441c028e4cba0ce0721c8929dace495afd6ef844585e2ce6d3b092582a258befd7c2) download_test_data(DREAM3D_DATA_DIR ${DREAM3D_DATA_DIR} ARCHIVE_NAME write_stats_gen_odf_angle_file.tar.gz SHA512 be3f663aae1f78e5b789200421534ed9fe293187ec3514796ac8177128b34ded18bb9a98b8e838bb283f9818ac30dc4b19ec379bdd581b1a98eb36d967cdd319) download_test_data(DREAM3D_DATA_DIR ${DREAM3D_DATA_DIR} ARCHIVE_NAME INL_writer.tar.gz SHA512 7d723351e51e84540abfbc38e69a6014852ba34808f9d216a27063a616bcfbd5eb708405305fd83334e48c9ca133d3d0be797c05040e4a115cc612e385d9ada6) + download_test_data(DREAM3D_DATA_DIR ${DREAM3D_DATA_DIR} ARCHIVE_NAME convert_hex_grid_to_square_grid_test.tar.gz SHA512 bb672ebbe2540ba493ad95bea95dac1f85b5634ac3311b5aa774ce3d2177103d1b45a13225221993dd40f0cbe02daf20ccd209d4ae0cab0bf034d97c5b234ba4) endif() diff --git a/src/Plugins/OrientationAnalysis/test/ConvertHexGridToSquareGridTest.cpp b/src/Plugins/OrientationAnalysis/test/ConvertHexGridToSquareGridTest.cpp new file mode 100644 index 0000000000..10a099cd86 --- /dev/null +++ b/src/Plugins/OrientationAnalysis/test/ConvertHexGridToSquareGridTest.cpp @@ -0,0 +1,148 @@ +#include "OrientationAnalysis/Filters/ConvertHexGridToSquareGridFilter.hpp" +#include "OrientationAnalysis/OrientationAnalysis_test_dirs.hpp" + +#include "complex/Parameters/GeneratedFileListParameter.hpp" +#include "complex/UnitTest/UnitTestCommon.hpp" + +#include + +#include +#include +#include + +namespace fs = std::filesystem; + +using namespace complex; + +namespace +{ +const std::string k_HexToSqrTestFilesDir = "convert_hex_grid_to_square_grid_test"; +const std::vector k_Spacing = {0.05f, 0.0403}; + +bool CompareFiles(const std::string& p1, const std::string& p2) +{ + fs::path path1(p1); + fs::path path2(p2); + + if(!fs::exists(path1)) + { + return false; + } + + if(!fs::exists(path2)) + { + return false; + } + + std::ifstream f1(path1, std::ifstream::binary | std::ifstream::ate); + std::ifstream f2(path2, std::ifstream::binary | std::ifstream::ate); + + if(!f1.is_open() || !f2.is_open()) + { + return false; // file problem + } + + if(f1.tellg() != f2.tellg()) + { + return false; // size mismatch + } + + // seek back to beginning and use std::equal to compare contents + f1.seekg(0, std::ifstream::beg); + f2.seekg(0, std::ifstream::beg); + return std::equal(std::istreambuf_iterator(f1.rdbuf()), std::istreambuf_iterator(), std::istreambuf_iterator(f2.rdbuf())); +} + +} // namespace + +TEST_CASE("OrientationAnalysis::ConvertHexGridToSquareGridFilter: Single File Valid Execution", "[OrientationAnalysis][ConvertHexGridToSquareGridFilter]") +{ + const complex::UnitTest::TestFileSentinel testDataSentinel(complex::unit_test::k_CMakeExecutable, complex::unit_test::k_TestFilesDir, "convert_hex_grid_to_square_grid_test.tar.gz", + k_HexToSqrTestFilesDir); + fs::path k_OutPath = fs::path(fmt::format("{}/single", complex::unit_test::k_BinaryTestOutputDir)); + + if(!exists(k_OutPath)) + { + fs::create_directories(k_OutPath); + } + + { + // Instantiate the filter, a DataStructure object and an Arguments Object + ConvertHexGridToSquareGridFilter filter; + DataStructure dataStructure; + Arguments args; + + fs::path k_InPath = fs::path(fmt::format("{}/{}/single/hex_grid.ang", complex::unit_test::k_TestFilesDir, ::k_HexToSqrTestFilesDir)); + + // Input Parameters + args.insertOrAssign(ConvertHexGridToSquareGridFilter::k_MultipleFiles_Key, std::make_any(false)); + args.insertOrAssign(ConvertHexGridToSquareGridFilter::k_InputPath_Key, std::make_any(k_InPath)); + args.insertOrAssign(ConvertHexGridToSquareGridFilter::k_Spacing_Key, std::make_any>(k_Spacing)); + + // Output Parameters + args.insertOrAssign(ConvertHexGridToSquareGridFilter::k_OutputPath_Key, std::make_any(k_OutPath)); + args.insertOrAssign(ConvertHexGridToSquareGridFilter::k_OutputPrefix_Key, std::make_any("Sqr_")); + + // Preflight the filter and check result + auto preflightResult = filter.preflight(dataStructure, args); + COMPLEX_RESULT_REQUIRE_VALID(preflightResult.outputActions) + + // Execute the filter and check the result + auto executeResult = filter.execute(dataStructure, args); + COMPLEX_RESULT_REQUIRE_VALID(executeResult.result) + } + + REQUIRE(::CompareFiles(fmt::format("{}/{}/single/exemplar/Sqr_SIMPL_hex_grid.ang", complex::unit_test::k_TestFilesDir, ::k_HexToSqrTestFilesDir), k_OutPath.string() + "/Sqr_hex_grid.ang")); +} + +TEST_CASE("OrientationAnalysis::ConvertHexGridToSquareGridFilter: Multiple File Valid Execution", "[OrientationAnalysis][ConvertHexGridToSquareGridFilter]") +{ + const complex::UnitTest::TestFileSentinel testDataSentinel(complex::unit_test::k_CMakeExecutable, complex::unit_test::k_TestFilesDir, "convert_hex_grid_to_square_grid_test.tar.gz", + k_HexToSqrTestFilesDir); + fs::path k_OutPath = fs::path(fmt::format("{}/multi", complex::unit_test::k_BinaryTestOutputDir)); + + if(!exists(k_OutPath)) + { + fs::create_directories(k_OutPath); + } + + { + // Instantiate the filter, a DataStructure object and an Arguments Object + ConvertHexGridToSquareGridFilter filter; + DataStructure dataStructure; + Arguments args; + + GeneratedFileListParameter::ValueType k_InPath; + k_InPath.startIndex = 1; + k_InPath.incrementIndex = 1; + k_InPath.endIndex = 2; + k_InPath.inputPath = fmt::format("{}/{}/multi", complex::unit_test::k_TestFilesDir, ::k_HexToSqrTestFilesDir); + k_InPath.filePrefix = "hex_grid"; + k_InPath.ordering = GeneratedFileListParameter::Ordering::LowToHigh; + k_InPath.paddingDigits = 0; + k_InPath.fileExtension = ".ang"; + k_InPath.fileSuffix = ""; + + // Input Parameters + args.insertOrAssign(ConvertHexGridToSquareGridFilter::k_MultipleFiles_Key, std::make_any(true)); + args.insertOrAssign(ConvertHexGridToSquareGridFilter::k_GeneratedFileList_Key, std::make_any(k_InPath)); + args.insertOrAssign(ConvertHexGridToSquareGridFilter::k_Spacing_Key, std::make_any>(k_Spacing)); + + // Output Parameters + args.insertOrAssign(ConvertHexGridToSquareGridFilter::k_OutputPath_Key, std::make_any(k_OutPath)); + args.insertOrAssign(ConvertHexGridToSquareGridFilter::k_OutputPrefix_Key, std::make_any("Sqr_")); + + // Preflight the filter and check result + auto preflightResult = filter.preflight(dataStructure, args); + COMPLEX_RESULT_REQUIRE_VALID(preflightResult.outputActions) + + // Execute the filter and check the result + auto executeResult = filter.execute(dataStructure, args); + COMPLEX_RESULT_REQUIRE_VALID(executeResult.result) + } + + REQUIRE((fs::exists(k_OutPath) && fs::is_directory(k_OutPath))); + + REQUIRE(::CompareFiles(fmt::format("{}/{}/multi/exemplars/Sqr_SIMPL_hex_grid1.ang", complex::unit_test::k_TestFilesDir, ::k_HexToSqrTestFilesDir), k_OutPath.string() + "/Sqr_hex_grid1.ang")); + REQUIRE(::CompareFiles(fmt::format("{}/{}/multi/exemplars/Sqr_SIMPL_hex_grid2.ang", complex::unit_test::k_TestFilesDir, ::k_HexToSqrTestFilesDir), k_OutPath.string() + "/Sqr_hex_grid2.ang")); +} diff --git a/src/complex/Utilities/FilePathGenerator.cpp b/src/complex/Utilities/FilePathGenerator.cpp index 51a759ac89..0b3a7193aa 100644 --- a/src/complex/Utilities/FilePathGenerator.cpp +++ b/src/complex/Utilities/FilePathGenerator.cpp @@ -12,7 +12,7 @@ namespace FilePathGenerator { // ----------------------------------------------------------------------------- std::pair, bool> GenerateAndValidateFileList(int32 start, int32 end, int32 increment, Ordering order, std::string_view inputPath, std::string_view filePrefix, - std::string_view fileSuffix, std::string_view fileExtension, int32 paddingDigits, bool failFast) + std::string_view fileSuffix, std::string_view fileExtension, uint32 paddingDigits, bool failFast) { std::vector fileList = GenerateFileList(start, end, increment, order, inputPath, filePrefix, fileSuffix, fileExtension, paddingDigits); bool missingFiles = false; @@ -32,7 +32,7 @@ std::pair, bool> GenerateAndValidateFileList(int32 star // ----------------------------------------------------------------------------- std::vector GenerateFileList(int32 start, int32 end, int32 increment, Ordering order, std::string_view inputPath, std::string_view filePrefix, std::string_view fileSuffix, - std::string_view fileExtension, int32 paddingDigits) + std::string_view fileExtension, uint32 paddingDigits) { std::vector fileList; if(!fs::exists(inputPath)) diff --git a/src/complex/Utilities/FilePathGenerator.hpp b/src/complex/Utilities/FilePathGenerator.hpp index 69916ec8c9..02146db807 100644 --- a/src/complex/Utilities/FilePathGenerator.hpp +++ b/src/complex/Utilities/FilePathGenerator.hpp @@ -32,7 +32,7 @@ enum class Ordering : uint8 * @return */ COMPLEX_EXPORT std::pair, bool> GenerateAndValidateFileList(int32 start, int32 end, int32 increment, Ordering order, std::string_view inputPath, std::string_view filePrefix, - std::string_view fileSuffix, std::string_view fileExtension, int32 paddingDigits, bool failFast = true); + std::string_view fileSuffix, std::string_view fileExtension, uint32 paddingDigits, bool failFast = true); /** * @brief GenerateFileList This method will generate a file list in the correct order of the files that should @@ -49,6 +49,6 @@ COMPLEX_EXPORT std::pair, bool> GenerateAndValidateFile * @return */ COMPLEX_EXPORT std::vector GenerateFileList(int32 start, int32 end, int32 increment, Ordering order, std::string_view inputPath, std::string_view filePrefix, std::string_view fileSuffix, - std::string_view fileExtension, int32 paddingDigits); + std::string_view fileExtension, uint32 paddingDigits); } // namespace FilePathGenerator } // namespace complex