From 1c5bfc8f9aba668edbdf87d7a06183e999ff0cb0 Mon Sep 17 00:00:00 2001 From: Michael Jackson Date: Mon, 4 Nov 2024 16:52:47 -0500 Subject: [PATCH] BUG: Fix crashing issue with string constants. Add CPR/CRC Binary EBSD Reader (#28) * VERSION: Update to 1.0.35 * BUG: Fix crashing due to use of std::string as a constant in headers. (#26) * COMP: Add missing #include directive for tbb task_group * READER: Implement Aztec .cpr/.crc reader for EBSD data. (#27) * Fix Xcode 16 crash on start up. Signed-off-by: Michael Jackson --------- Signed-off-by: Michael Jackson --- CMakeLists.txt | 2 +- CMakePresets.json | 4 + Source/Apps/ParseAztecProject.cpp | 112 +++ Source/Apps/SourceList.cmake | 4 + Source/Apps/make_ipf.cpp | 2 +- Source/EbsdLib/Core/EbsdLibConstants.h | 18 - Source/EbsdLib/Core/StringLiteral.hpp | 249 ++++++ Source/EbsdLib/IO/AngleFileLoader.h | 3 +- Source/EbsdLib/IO/BrukerNano/EspritPhase.cpp | 2 +- Source/EbsdLib/IO/BrukerNano/EspritPhase.h | 2 +- Source/EbsdLib/IO/BrukerNano/H5EspritReader.h | 2 +- Source/EbsdLib/IO/EbsdReader.h | 2 +- Source/EbsdLib/IO/HKL/CprReader.cpp | 728 ++++++++++++++++++ Source/EbsdLib/IO/HKL/CprReader.h | 177 +++++ Source/EbsdLib/IO/HKL/CtfConstants.h | 15 + Source/EbsdLib/IO/HKL/CtfPhase.cpp | 5 +- Source/EbsdLib/IO/HKL/CtfPhase.h | 4 +- Source/EbsdLib/IO/HKL/CtfReader.h | 3 +- Source/EbsdLib/IO/HKL/DataParser.hpp | 17 + Source/EbsdLib/IO/HKL/H5CtfReader.h | 2 +- Source/EbsdLib/IO/HKL/H5OINAReader.h | 2 +- Source/EbsdLib/IO/HKL/SourceList.cmake | 2 + Source/EbsdLib/IO/TSL/AngPhase.cpp | 2 +- Source/EbsdLib/IO/TSL/AngPhase.h | 2 +- Source/EbsdLib/IO/TSL/H5AngReader.h | 2 +- Source/EbsdLib/IO/TSL/H5OIMReader.h | 2 +- Source/EbsdLib/LaueOps/CubicLowOps.cpp | 1 + Source/EbsdLib/LaueOps/CubicOps.cpp | 1 + Source/EbsdLib/LaueOps/HexagonalLowOps.cpp | 1 + Source/EbsdLib/LaueOps/HexagonalOps.cpp | 1 + Source/EbsdLib/LaueOps/MonoclinicOps.cpp | 1 + Source/EbsdLib/LaueOps/OrthoRhombicOps.cpp | 1 + Source/EbsdLib/LaueOps/TetragonalLowOps.cpp | 1 + Source/EbsdLib/LaueOps/TetragonalOps.cpp | 1 + Source/EbsdLib/LaueOps/TrigonalLowOps.cpp | 1 + Source/EbsdLib/LaueOps/TrigonalOps.cpp | 1 + Source/EbsdLib/Utilities/SourceList.cmake | 1 + Source/EbsdLib/Utilities/inipp.h | 332 ++++++++ 38 files changed, 1671 insertions(+), 37 deletions(-) create mode 100644 Source/Apps/ParseAztecProject.cpp create mode 100644 Source/EbsdLib/Core/StringLiteral.hpp create mode 100644 Source/EbsdLib/IO/HKL/CprReader.cpp create mode 100644 Source/EbsdLib/IO/HKL/CprReader.h create mode 100644 Source/EbsdLib/Utilities/inipp.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fac92d9..f9309c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # set project's name -project(EbsdLibProj VERSION 1.0.33) +project(EbsdLibProj VERSION 1.0.35) # ---------- Setup output Directories ------------------------- set(CMAKE_LIBRARY_OUTPUT_DIRECTORY diff --git a/CMakePresets.json b/CMakePresets.json index a4d9085..37d9160 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -128,6 +128,10 @@ "VCPKG_HOST_TRIPLET": { "type": "STRING", "value": "arm64-osx-dynamic" + }, + "CMAKE_BUILD_TYPE": { + "type": "STRING", + "value": "Debug" } }, "environment": { diff --git a/Source/Apps/ParseAztecProject.cpp b/Source/Apps/ParseAztecProject.cpp new file mode 100644 index 0000000..2ff61bc --- /dev/null +++ b/Source/Apps/ParseAztecProject.cpp @@ -0,0 +1,112 @@ + +#include "EbsdLib/IO/HKL/CprReader.h" +#include "EbsdLib/LaueOps/LaueOps.h" + +#include + +namespace detail +{ +// const std::string k_CprPath = "/Volumes/OWC_Express_1M2/DREAM3D_Troubleshoot_Data/Benjamin_Layer1/Layer1.cpr"; +const std::string k_CprPath = "/Users/Shared/Data/CPR_CRC_Test_Data/dg7kv5mcv3-1/dg7kv5mcv3-1/17NZ41B_untwinnedquartzsample.cpr"; + +} // namespace detail + +std::string ConvertLaueGroupToString(int idx) +{ + switch(idx) + { + case 0: + return "Hexagonal_High"; + case 1: + return "Cubic_High"; + case 2: + return "Hexagonal_Low"; + case 3: + return "Cubic_Low"; + case 4: + return "Triclinic"; + case 5: + return "Monoclinic"; + case 6: + return "OrthoRhombic"; + case 7: + return "Tetragonal_Low"; + case 8: + return "Tetragonal_High"; + case 9: + return "Trigonal_Low"; + case 10: + return "Trigonal_High"; + case 11: + return "UnknownCrystalStructure"; + } + return "Undefined"; +} + +// ----------------------------------------------------------------------------- +int main(int argc, char* argv[]) +{ + + // if(argc != 3) + // { + // std::cout << "Program .cpr and .crc files as input." << std::endl; + // return 1; + // } + + CprReader reader; + reader.setFileName(detail::k_CprPath); + int error = reader.readHeaderOnly(); + if(error < 0) + { + std::cout << "Reading Header Failed: " << error << "\n"; + return 1; + } + // reader.printHeader(std::cout); + // Write out a compatible DREAM3D "Ensemble" File + auto phases = reader.getPhaseVector(); + std::cout << "[EnsembleInfo]\n" + << "Number_Phases=" << phases.size() << std::endl; + size_t idx = 0; + for(const auto& phase : phases) + { + std::cout << std::endl; + std::cout << "[" << ++idx << "]\n" + << "CrystalStructure=" << ConvertLaueGroupToString(phase->determineOrientationOpsIndex()) << "\n" + << "PhaseType=PrimaryPhase\n"; + } + + std::cout << "\n\nField Names\n"; + auto fieldParsers = reader.createFieldParsers(detail::k_CprPath); + for(const auto& parser : fieldParsers) + { + std::cout << parser.FieldDefinition.FieldName << "\n"; + } + + error = reader.readFile(); + if(error < 0) + { + std::cout << reader.getErrorMessage() << error << "\n"; + return 2; + } + + // Dump all the data to the command line + // std::cout << "Phase,Bands,Error,Euler1,Euler2,Euler3,MAD,BC,BS\n"; + // uint8_t* phasePtr = reader.getPhasePointer(); + // uint8_t* bandsPtr = reader.getBandCountPointer(); + // uint8_t* errorPtr = reader.getErrorPointer(); + // float* phi1Ptr = reader.getEuler1Pointer(); + // float* phiPtr = reader.getEuler2Pointer(); + // float* phi2Ptr = reader.getEuler3Pointer(); + // float* madPtr = reader.getMeanAngularDeviationPointer(); + // uint8_t* bcPtr = reader.getBandContrastPointer(); + // uint8_t* bsPtr = reader.getBandSlopePointer(); + // + // size_t numScanPoints = reader.getNumberOfElements(); + // for(size_t i = 0; i < numScanPoints; i++) + // { + // std::cout << static_cast(phasePtr[i]) << "," << static_cast(bandsPtr[i]) << "," << static_cast(errorPtr[i]) << "," << phi1Ptr[i] << "," << phiPtr[i] << "," << phi2Ptr[i] << "," + // << madPtr[i] << "," << static_cast(bcPtr[i]) << "," << static_cast(bsPtr[i]) << std::endl; + // } + + return 0; +} diff --git a/Source/Apps/SourceList.cmake b/Source/Apps/SourceList.cmake index ea96746..d47c6ed 100644 --- a/Source/Apps/SourceList.cmake +++ b/Source/Apps/SourceList.cmake @@ -26,6 +26,10 @@ target_include_directories(generate_ipf_legends PRIVATE "${EbsdLibProj_SOURCE_DIR}/3rdParty/canvas_ity/src") +add_executable(ParseAztecProject ${EbsdLibProj_SOURCE_DIR}/Source/Apps/ParseAztecProject.cpp) +target_link_libraries(ParseAztecProject PUBLIC EbsdLib) +target_include_directories(ParseAztecProject PUBLIC ${EbsdLibProj_SOURCE_DIR}/Source) + if(EbsdLib_INSTALL_FILES) install(FILES diff --git a/Source/Apps/make_ipf.cpp b/Source/Apps/make_ipf.cpp index d2d9c64..748cf63 100644 --- a/Source/Apps/make_ipf.cpp +++ b/Source/Apps/make_ipf.cpp @@ -49,7 +49,7 @@ class GenerateIPFColorsImpl std::vector laueOpsIndex(m_PhaseInfos.size()); for(size_t i = 0; i < laueOpsIndex.size(); i++) { - laueOpsIndex[i] = m_PhaseInfos[i]->determineLaueGroup(); + laueOpsIndex[i] = m_PhaseInfos[i]->determineOrientationOpsIndex(); } size_t totalPoints = m_CellEulerAngles.size() / 3; diff --git a/Source/EbsdLib/Core/EbsdLibConstants.h b/Source/EbsdLib/Core/EbsdLibConstants.h index 76ceb1e..e90acd5 100644 --- a/Source/EbsdLib/Core/EbsdLibConstants.h +++ b/Source/EbsdLib/Core/EbsdLibConstants.h @@ -72,21 +72,6 @@ inline const std::string GBCD("GBCD"); namespace NumericTypes { -namespace Names -{ -inline const std::string Int8("signed int 8 bit"); -inline const std::string UInt8("unsigned int 8 bit"); -inline const std::string Int16("signed int 16 bit"); -inline const std::string UInt16("unsigned int 16 bit"); -inline const std::string Int32("signed int 32 bit"); -inline const std::string UInt32("unsigned int 32 bit"); -inline const std::string Int64("signed int 64 bit"); -inline const std::string UInt64("unsigned int 64 bit"); -inline const std::string Float("Float 32 bit"); -inline const std::string Double("Double 64 bit"); -inline const std::string Bool("Bool"); -inline const std::string SizeT("size_t"); -} // namespace Names enum class Type : int32_t { @@ -105,9 +90,6 @@ enum class Type : int32_t UnknownNumType }; -inline const std::string SupportedTypeList(NumericTypes::Names::Int8 + ", " + NumericTypes::Names::UInt8 + ", " + NumericTypes::Names::Int16 + ", " + NumericTypes::Names::UInt16 + ", " + - NumericTypes::Names::Int32 + ", " + NumericTypes::Names::UInt32 + ", " + NumericTypes::Names::Int64 + ", " + NumericTypes::Names::UInt64 + ", " + - NumericTypes::Names::Float + ", " + NumericTypes::Names::Double + ", " + NumericTypes::Names::Bool + ", " + NumericTypes::Names::SizeT); } // namespace NumericTypes /** @brief RefFrameZDir defined for the Stacking order of images into a 3D Volume */ diff --git a/Source/EbsdLib/Core/StringLiteral.hpp b/Source/EbsdLib/Core/StringLiteral.hpp new file mode 100644 index 0000000..8de8508 --- /dev/null +++ b/Source/EbsdLib/Core/StringLiteral.hpp @@ -0,0 +1,249 @@ +#pragma once + +#include +#include +#include + +// #include +// #include + +namespace EbsdLib +{ +namespace detail +{ +/** + * @brief Returns true if the given character array is null-terminated. + * @tparam T + * @param string + * @return + */ +template +constexpr bool HasNullTerminator(const T (&string)[Size]) noexcept +{ + return string[Size - 1] == static_cast('\0'); +} +} // namespace detail + +/** + * @brief BasicStringLiteral is meant to be a safe container for a string literal allowing for easy access to its size/length. + * This class should always contain a pointer to a static compile time null-terminated string literal. + * Typical usage will be for static string constants. At this time the constructors allow non string literals to be passed in. + * This is undesired behavior, but there is no way to overcome this in C++17 without using character parameter packs which come with their own issues. + * Example: + * @code + * static constexpr StringLiteral k_Foo = "foo"; + * @endcode + * @tparam T Character type + */ +template +class BasicStringLiteral +{ +public: + BasicStringLiteral() = delete; + + /** + * @brief Constructor that accepts a string literal of fixed size. Should be made consteval in C++20. + * Requires string to be null-terminated. + * @param string + * @return + */ + template + constexpr BasicStringLiteral(const T (&string)[Size]) + : m_String(string) + , m_Size(Size) + { + if(!detail::HasNullTerminator(string)) + { + throw std::runtime_error("BasicStringLiteral must be null-terminated"); + } + } + + ~BasicStringLiteral() noexcept = default; + + BasicStringLiteral(const BasicStringLiteral&) noexcept = default; + BasicStringLiteral(BasicStringLiteral&&) noexcept = default; + + BasicStringLiteral& operator=(const BasicStringLiteral&) noexcept = default; + BasicStringLiteral& operator=(BasicStringLiteral&&) noexcept = default; + + /** + * @brief Returns the c-string pointer. + * @return const T* + */ + constexpr const T* c_str() const noexcept + { + return m_String; + } + + /** + * @brief Returns the size of the string literal not including the null terminator. + * @return size_t + */ + constexpr size_t size() const noexcept + { + return m_Size - 1; + } + + /** + * @brief Returns a view of string literal not including the null terminator. + * @return std::basic_string_view + */ + constexpr std::basic_string_view view() const + { + return std::basic_string_view(m_String, size()); + } + + /** + * @brief Returns a view of string literal including the null terminator. + * @return std::basic_string_view + */ + constexpr std::basic_string_view c_view() const + { + return std::basic_string_view(m_String, m_Size); + } + + /** + * @brief Returns a null-terminated heap allocated string. + * @return std::basic_string + */ + std::basic_string str() const + { + return std::basic_string(m_String, size()); + } + + /** + * @brief Implicit conversion to std::basic_string + */ + operator std::basic_string() const + { + return str(); + } + + /** + * @brief Implicit conversion to std::basic_string_view + */ + operator std::basic_string_view() const + { + return view(); + } + +private: + const T* m_String; + size_t m_Size; +}; + +template +bool operator==(const std::basic_string& lhs, BasicStringLiteral rhs) +{ + return lhs == rhs.view(); +} + +template +bool operator==(BasicStringLiteral lhs, const std::basic_string& rhs) +{ + return rhs == lhs; +} + +template +bool operator!=(const std::basic_string& lhs, BasicStringLiteral rhs) +{ + return lhs != rhs.view(); +} + +template +bool operator!=(BasicStringLiteral lhs, const std::basic_string& rhs) +{ + return rhs != lhs; +} + +template +bool operator<(const std::basic_string& lhs, BasicStringLiteral rhs) +{ + return lhs < rhs.view(); +} + +template +bool operator<(BasicStringLiteral lhs, const std::basic_string& rhs) +{ + return lhs.view() < rhs; +} + +template +bool operator>(const std::basic_string& lhs, BasicStringLiteral rhs) +{ + return lhs > rhs.view(); +} + +template +bool operator>(BasicStringLiteral lhs, const std::basic_string& rhs) +{ + return lhs.view() > rhs; +} + +template +bool operator<=(const std::basic_string& lhs, BasicStringLiteral rhs) +{ + return lhs <= rhs.view(); +} + +template +bool operator<=(BasicStringLiteral lhs, const std::basic_string& rhs) +{ + return lhs.view() <= rhs; +} + +template +bool operator>=(const std::basic_string& lhs, BasicStringLiteral rhs) +{ + return lhs >= rhs.view(); +} + +template +bool operator>=(BasicStringLiteral lhs, const std::basic_string& rhs) +{ + return lhs.view() >= rhs; +} + +using StringLiteral = BasicStringLiteral; +using WStringLiteral = BasicStringLiteral; +using String16Literal = BasicStringLiteral; +using String32Literal = BasicStringLiteral; +} // namespace EbsdLib + +#if 0 +template +struct fmt::formatter> +{ + static constexpr const CharT* GetFormatString() + { + if constexpr(std::is_same_v) + { + return "{}"; + } + if constexpr(std::is_same_v) + { + return L"{}"; + } + if constexpr(std::is_same_v) + { + return u"{}"; + } + if constexpr(std::is_same_v) + { + return U"{}"; + } + } + + constexpr typename basic_format_parse_context::iterator parse(basic_format_parse_context& ctx) + { + return ctx.begin(); + } + + typename buffer_context::iterator format(const nx::core::BasicStringLiteral& p, buffer_context& ctx) const + { + static constexpr const CharT* formatStr = GetFormatString(); + + return fmt::format_to(ctx.out(), formatStr, p.view()); + } +}; +#endif diff --git a/Source/EbsdLib/IO/AngleFileLoader.h b/Source/EbsdLib/IO/AngleFileLoader.h index c7dae8a..879711c 100644 --- a/Source/EbsdLib/IO/AngleFileLoader.h +++ b/Source/EbsdLib/IO/AngleFileLoader.h @@ -36,9 +36,8 @@ #pragma once #include -#include - #include +#include #include "EbsdLib/Core/EbsdDataArray.hpp" #include "EbsdLib/EbsdLib.h" diff --git a/Source/EbsdLib/IO/BrukerNano/EspritPhase.cpp b/Source/EbsdLib/IO/BrukerNano/EspritPhase.cpp index fda6c85..87ebcd9 100644 --- a/Source/EbsdLib/IO/BrukerNano/EspritPhase.cpp +++ b/Source/EbsdLib/IO/BrukerNano/EspritPhase.cpp @@ -58,7 +58,7 @@ std::string EspritPhase::getMaterialName() // ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- -unsigned int EspritPhase::determineLaueGroup() +unsigned int EspritPhase::determineOrientationOpsIndex() { int sg = getIT(); diff --git a/Source/EbsdLib/IO/BrukerNano/EspritPhase.h b/Source/EbsdLib/IO/BrukerNano/EspritPhase.h index 384cda9..29b78d1 100644 --- a/Source/EbsdLib/IO/BrukerNano/EspritPhase.h +++ b/Source/EbsdLib/IO/BrukerNano/EspritPhase.h @@ -109,7 +109,7 @@ class EbsdLib_EXPORT EspritPhase /** * @brief Returns the type of crystal structure for this phase. */ - unsigned int determineLaueGroup(); + unsigned int determineOrientationOpsIndex(); protected: EspritPhase(); diff --git a/Source/EbsdLib/IO/BrukerNano/H5EspritReader.h b/Source/EbsdLib/IO/BrukerNano/H5EspritReader.h index 0e1854a..96cdd54 100644 --- a/Source/EbsdLib/IO/BrukerNano/H5EspritReader.h +++ b/Source/EbsdLib/IO/BrukerNano/H5EspritReader.h @@ -65,7 +65,7 @@ class EbsdLib_EXPORT H5EspritReader : public EbsdReader /** * @brief Returns the name of the class for H5EspritReader */ - std::string getNameOfClass() const; + std::string getNameOfClass() const override; /** * @brief Returns the name of the class for H5EspritReader */ diff --git a/Source/EbsdLib/IO/EbsdReader.h b/Source/EbsdLib/IO/EbsdReader.h index b8a3d28..c93368c 100644 --- a/Source/EbsdLib/IO/EbsdReader.h +++ b/Source/EbsdLib/IO/EbsdReader.h @@ -66,7 +66,7 @@ class EbsdLib_EXPORT EbsdReader /** * @brief Returns the name of the class for EbsdReader */ - std::string getNameOfClass() const; + virtual std::string getNameOfClass() const; /** * @brief Returns the name of the class for EbsdReader */ diff --git a/Source/EbsdLib/IO/HKL/CprReader.cpp b/Source/EbsdLib/IO/HKL/CprReader.cpp new file mode 100644 index 0000000..fa9f5d8 --- /dev/null +++ b/Source/EbsdLib/IO/HKL/CprReader.cpp @@ -0,0 +1,728 @@ +// +// Created by Michael Jackson on 10/22/24. +// + +#include "CprReader.h" + +#include "CtfPhase.h" +#include "EbsdLib/Core/EbsdLibConstants.h" +#include "EbsdLib/Math/EbsdLibMath.h" +#include "EbsdLib/Utilities/inipp.h" + +#include +#include +#include +#include +#include + +using namespace EbsdLib; + +namespace +{ + +/* +enum ColumnNames { + 'X' % 1 4 bytes + 'Y' % 2 " + 'phi1' % 3 " + 'Phi' % 4 " + 'phi2' % 5 " + 'MAD' % 6 " + 'BC' % 7 1 byte + 'BS' % 8 " + 'Unknown' % 9 " + 'Bands' % 10 " + 'Error' % 11 " + 'ReliabilityIndex' % 12 " +}; +*/ + +// std::array k_FieldByteSize = {0, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1}; +// std::array k_FieldNames = {"", "X", "Y", "phi1", "Phi", "phi2", "MAD", "BC", "BS", "Unknown", "Bands", "Error", "ReliabilityIndex"}; +// std::array k_FieldNumericTypes = {EbsdLib::NumericTypes::Type::UnknownNumType, +// EbsdLib::NumericTypes::Type::Float, EbsdLib::NumericTypes::Type::Float, EbsdLib::NumericTypes::Type::Float, +// EbsdLib::NumericTypes::Type::Float, EbsdLib::NumericTypes::Type::Float, EbsdLib::NumericTypes::Type::Float, +// EbsdLib::NumericTypes::Type::UInt8, EbsdLib::NumericTypes::Type::UInt8, EbsdLib::NumericTypes::Type::UInt8, +// EbsdLib::NumericTypes::Type::UInt8, EbsdLib::NumericTypes::Type::UInt8, EbsdLib::NumericTypes::Type::UInt8}; +// + +// clang-format off +std::array k_FieldDefinitions{CrcFieldDefinition{1, "Phase", EbsdLib::NumericTypes::Type::UInt8}, + CrcFieldDefinition{4, "X", EbsdLib::NumericTypes::Type::Float}, + CrcFieldDefinition{4, "Y", EbsdLib::NumericTypes::Type::Float}, + CrcFieldDefinition{4, "phi1", EbsdLib::NumericTypes::Type::Float}, + CrcFieldDefinition{4, "Phi", EbsdLib::NumericTypes::Type::Float}, + CrcFieldDefinition{4, "phi2", EbsdLib::NumericTypes::Type::Float}, + CrcFieldDefinition{4, "MAD", EbsdLib::NumericTypes::Type::Float}, + CrcFieldDefinition{1, "BC", EbsdLib::NumericTypes::Type::UInt8}, + CrcFieldDefinition{1, "BS", EbsdLib::NumericTypes::Type::UInt8}, + CrcFieldDefinition{1, "Unknown", EbsdLib::NumericTypes::Type::UInt8}, + CrcFieldDefinition{1, "Bands", EbsdLib::NumericTypes::Type::UInt8}, + CrcFieldDefinition{1, "Error", EbsdLib::NumericTypes::Type::UInt8}, + CrcFieldDefinition{4, "ReliabilityIndex", EbsdLib::NumericTypes::Type::Int32}}; +// clang-format on + +// Read a complete Scan Point +// loop over parserDefinitions->parse(buffer, currentIndex); + +template +T getFieldValue(inipp::Ini& iniParser, const std::string& section, const std::string& key) +{ + T value; + inipp::get_value(iniParser.sections[section], key, value); + return value; +} + +std::vector getLatticeConstants(inipp::Ini& iniParser, const std::string& section) +{ + float a; + float b; + float c; + float alpha; + float beta; + float gamma; + + inipp::get_value(iniParser.sections[section], "a", a); + inipp::get_value(iniParser.sections[section], "b", b); + inipp::get_value(iniParser.sections[section], "c", c); + inipp::get_value(iniParser.sections[section], "alpha", alpha); + inipp::get_value(iniParser.sections[section], "beta", beta); + inipp::get_value(iniParser.sections[section], "gamma", gamma); + + return {a, b, c, alpha, beta, gamma}; +} + +void ParseAndStoreHeaderEntry(inipp::Ini& iniParser, const std::string& section, const std::string& key, std::map& m_HeaderMap) +{ + EbsdHeaderEntry::Pointer p1 = m_HeaderMap[key]; + auto value = getFieldValue(iniParser, section, key); + p1->parseValue(value); +} + +} // namespace + +// ----------------------------------------------------------------------------- +CprReader::CprReader() +{ + + // Initialize the map of header key to header value + m_HeaderMap[EbsdLib::Ctf::ChannelTextFile] = CtfStringHeaderEntry::NewEbsdHeaderEntry(EbsdLib::Ctf::ChannelTextFile); + m_HeaderMap[EbsdLib::Ctf::Prj] = CtfStringHeaderEntry::NewEbsdHeaderEntry(EbsdLib::Ctf::Prj); + m_HeaderMap[EbsdLib::Ctf::Author] = CtfStringHeaderEntry::NewEbsdHeaderEntry(EbsdLib::Ctf::Author); + m_HeaderMap[EbsdLib::Ctf::JobMode] = CtfStringHeaderEntry::NewEbsdHeaderEntry(EbsdLib::Ctf::JobMode); + + m_HeaderMap[EbsdLib::Ctf::xCells] = CtfHeaderEntry::NewEbsdHeaderEntry(EbsdLib::Ctf::XCells); + m_HeaderMap[EbsdLib::Ctf::yCells] = CtfHeaderEntry::NewEbsdHeaderEntry(EbsdLib::Ctf::YCells); + // m_HeaderMap[EbsdLib::Ctf::ZCells] = CtfHeaderEntry::NewEbsdHeaderEntry(EbsdLib::Ctf::ZCells); + m_HeaderMap[EbsdLib::Ctf::GridDistX] = CtfHeaderEntry::NewEbsdHeaderEntry(EbsdLib::Ctf::XStep); + m_HeaderMap[EbsdLib::Ctf::GridDistY] = CtfHeaderEntry::NewEbsdHeaderEntry(EbsdLib::Ctf::YStep); + // m_HeaderMap[EbsdLib::Ctf::ZStep] = CtfHeaderEntry::NewEbsdHeaderEntry(EbsdLib::Ctf::ZStep); + // m_HeaderMap[EbsdLib::Ctf::AcqE1] = CtfHeaderEntry::NewEbsdHeaderEntry(EbsdLib::Ctf::AcqE1); + // m_HeaderMap[EbsdLib::Ctf::AcqE2] = CtfHeaderEntry::NewEbsdHeaderEntry(EbsdLib::Ctf::AcqE2); + // m_HeaderMap[EbsdLib::Ctf::AcqE3] = CtfHeaderEntry::NewEbsdHeaderEntry(EbsdLib::Ctf::AcqE3); + // m_HeaderMap[EbsdLib::Ctf::Euler] = CtfStringHeaderEntry::NewEbsdHeaderEntry(EbsdLib::Ctf::Euler); + + m_HeaderMap[EbsdLib::Ctf::Magnification] = CtfHeaderEntry::NewEbsdHeaderEntry(EbsdLib::Ctf::Mag); + m_HeaderMap[EbsdLib::Ctf::Coverage] = CtfHeaderEntry::NewEbsdHeaderEntry(EbsdLib::Ctf::Coverage); + m_HeaderMap[EbsdLib::Ctf::Device] = CtfHeaderEntry::NewEbsdHeaderEntry(EbsdLib::Ctf::Device); + m_HeaderMap[EbsdLib::Ctf::kV] = CtfHeaderEntry::NewEbsdHeaderEntry(EbsdLib::Ctf::kV); + m_HeaderMap[EbsdLib::Ctf::TiltAngle] = CtfHeaderEntry::NewEbsdHeaderEntry(EbsdLib::Ctf::TiltAngle); + m_HeaderMap[EbsdLib::Ctf::TiltAxis] = CtfHeaderEntry::NewEbsdHeaderEntry(EbsdLib::Ctf::TiltAxis); + m_HeaderMap[EbsdLib::Ctf::NumPhases] = CtfHeaderEntry::NewEbsdHeaderEntry(EbsdLib::Ctf::NumPhases); + + setXCells(0); + setYCells(0); + // setZCells(1); +} + +// ----------------------------------------------------------------------------- +CprReader::~CprReader() = default; + +// ----------------------------------------------------------------------------- +void* CprReader::getPointerByName(const std::string& featureName) +{ + void* ptr = nullptr; + if(m_NamePointerMap.find(featureName) != m_NamePointerMap.end()) + { + ptr = m_NamePointerMap[featureName]->getVoidPointer(); + } + return ptr; +} + +std::vector CprReader::getPointerNames() const +{ + std::vector names; + for(const auto& entry : m_NamePointerMap) + { + names.push_back(entry.first); + } + return names; +} + +std::map CprReader::getPointerTypes() const +{ + std::map types; + for(const auto& entry : m_NamePointerMap) + { + types[entry.first] = entry.second->getNumericType(); + } + return types; +} + +// ----------------------------------------------------------------------------- +EbsdLib::NumericTypes::Type CprReader::getPointerType(const std::string& featureName) +{ + // std::cout << "featureName: " << featureName << std::endl; + if(featureName == EbsdLib::Ctf::ReliabilityIndex) + { + return EbsdLib::NumericTypes::Type::Int32; + } + if(featureName == EbsdLib::Ctf::Phase) + { + return EbsdLib::NumericTypes::Type::UInt8; + } + if(featureName == EbsdLib::Ctf::X) + { + return EbsdLib::NumericTypes::Type::Float; + } + if(featureName == EbsdLib::Ctf::Y) + { + return EbsdLib::NumericTypes::Type::Float; + } + if(featureName == EbsdLib::Ctf::Z) + { + return EbsdLib::NumericTypes::Type::Float; + } + if(featureName == EbsdLib::Ctf::Bands) + { + return EbsdLib::NumericTypes::Type::UInt8; + } + if(featureName == EbsdLib::Ctf::Error) + { + return EbsdLib::NumericTypes::Type::UInt8; + } + if(featureName == EbsdLib::Ctf::phi1) + { + return EbsdLib::NumericTypes::Type::Float; + } + if(featureName == EbsdLib::Ctf::Phi) + { + return EbsdLib::NumericTypes::Type::Float; + } + if(featureName == EbsdLib::Ctf::phi2) + { + return EbsdLib::NumericTypes::Type::Float; + } + if(featureName == EbsdLib::Ctf::MAD) + { + return EbsdLib::NumericTypes::Type::Float; + } + if(featureName == EbsdLib::Ctf::BC) + { + return EbsdLib::NumericTypes::Type::UInt8; + } + if(featureName == EbsdLib::Ctf::BS) + { + return EbsdLib::NumericTypes::Type::UInt8; + } + if(featureName == EbsdLib::Ctf::GrainIndex) + { + return EbsdLib::NumericTypes::Type::Int32; + } + if(featureName == EbsdLib::Ctf::GrainRandomColourR) + { + return EbsdLib::NumericTypes::Type::Int32; + } + if(featureName == EbsdLib::Ctf::GrainRandomColourG) + { + return EbsdLib::NumericTypes::Type::Int32; + } + if(featureName == EbsdLib::Ctf::GrainRandomColourB) + { + return EbsdLib::NumericTypes::Type::Int32; + } + // std::cout << "THIS IS NOT GOOD. Feature name: " << featureName << " was not found in the list" << std::endl; + return EbsdLib::NumericTypes::Type::UnknownNumType; +} + +// +// ----------------------------------------------------------------------------- +int CprReader::getTypeSize(const std::string& featureName) +{ + if(featureName == EbsdLib::Ctf::ReliabilityIndex) + { + return 4; + } + if(featureName == EbsdLib::Ctf::Phase) + { + return 1; + } + if(featureName == EbsdLib::Ctf::X) + { + return 4; + } + if(featureName == EbsdLib::Ctf::Y) + { + return 4; + } + if(featureName == EbsdLib::Ctf::Z) + { + return 4; + } + if(featureName == EbsdLib::Ctf::Bands) + { + return 1; + } + if(featureName == EbsdLib::Ctf::Error) + { + return 1; + } + if(featureName == EbsdLib::Ctf::phi1) + { + return 4; + } + if(featureName == EbsdLib::Ctf::Phi) + { + return 4; + } + if(featureName == EbsdLib::Ctf::phi2) + { + return 4; + } + if(featureName == EbsdLib::Ctf::MAD) + { + return 4; + } + if(featureName == EbsdLib::Ctf::BC) + { + return 1; + } + if(featureName == EbsdLib::Ctf::BS) + { + return 1; + } + if(featureName == EbsdLib::Ctf::GrainIndex) + { + return 4; + } + if(featureName == EbsdLib::Ctf::GrainRandomColourR) + { + return 4; + } + if(featureName == EbsdLib::Ctf::GrainRandomColourG) + { + return 4; + } + if(featureName == EbsdLib::Ctf::GrainRandomColourB) + { + return 4; + } + return 0; +} + +// ----------------------------------------------------------------------------- +int CprReader::readHeaderOnly() +{ + int err = 0; + + try + { + if(!std::filesystem::exists(getFileName())) + { + setErrorMessage(".cpr file does not exist"); + setErrorCode(-11); + return getErrorCode(); + } + } catch(std::exception& e) + { + setErrorMessage(".cpr std::file_system threw an exception trying to determine if the .cpr file exists."); + setErrorCode(-10); + return getErrorCode(); + } + // Open the file + std::ifstream is(getFileName()); + + // Create an INI parser object and parse the file + inipp::Ini ini; + ini.parse(is); + + // Extract out the Phases + { + const std::string sectionName("Phases"); + int phaseCount = -1; + inipp::get_value(ini.sections[sectionName], "Count", phaseCount); + EbsdHeaderEntry::Pointer p1 = m_HeaderMap[EbsdLib::Ctf::NumPhases]; + auto value = getFieldValue(ini, sectionName, EbsdLib::Ctf::Count); + p1->parseValue(value); + // std::cout << "Phase Count: " << phaseCount << std::endl; + for(int phaseIndex = 1; phaseIndex <= phaseCount; phaseIndex++) + { + std::stringstream sectionNameStrm; + sectionNameStrm << "Phase" << phaseIndex; + + CtfPhase::Pointer phase = CtfPhase::New(); + phase->setPhaseIndex(phaseIndex); + + // Phase Name + phase->setPhaseName(getFieldValue(ini, sectionNameStrm.str(), "StructureName")); + + // Lattice Constants + phase->setLatticeConstants(getLatticeConstants(ini, sectionNameStrm.str())); + + // Laue Group + phase->setLaueGroup(static_cast(getFieldValue(ini, sectionNameStrm.str(), "LaueGroup"))); + + // Comment + phase->setComment(getFieldValue(ini, sectionNameStrm.str(), "Reference")); + + // Space Group + phase->setSpaceGroup(getFieldValue(ini, sectionNameStrm.str(), "SpaceGroup")); + + // internal 1 + phase->setInternal1(getFieldValue(ini, sectionNameStrm.str(), "ID1")); + + // Internal 2 + phase->setInternal2(getFieldValue(ini, sectionNameStrm.str(), "ID2")); + + m_PhaseVector.push_back(phase); + } + } + + { + const std::string sectionName("Job"); + ParseAndStoreHeaderEntry(ini, sectionName, EbsdLib::Ctf::Magnification, m_HeaderMap); + ParseAndStoreHeaderEntry(ini, sectionName, EbsdLib::Ctf::Coverage, m_HeaderMap); + ParseAndStoreHeaderEntry(ini, sectionName, EbsdLib::Ctf::Device, m_HeaderMap); + ParseAndStoreHeaderEntry(ini, sectionName, EbsdLib::Ctf::kV, m_HeaderMap); + ParseAndStoreHeaderEntry(ini, sectionName, EbsdLib::Ctf::TiltAngle, m_HeaderMap); + ParseAndStoreHeaderEntry(ini, sectionName, EbsdLib::Ctf::TiltAxis, m_HeaderMap); + + ParseAndStoreHeaderEntry(ini, sectionName, EbsdLib::Ctf::GridDistX, m_HeaderMap); + ParseAndStoreHeaderEntry(ini, sectionName, EbsdLib::Ctf::GridDistY, m_HeaderMap); + ParseAndStoreHeaderEntry(ini, sectionName, EbsdLib::Ctf::xCells, m_HeaderMap); + ParseAndStoreHeaderEntry(ini, sectionName, EbsdLib::Ctf::yCells, m_HeaderMap); + + setNumberOfElements(getXCells() * getYCells()); + } + + { + const std::string sectionName("General"); + ParseAndStoreHeaderEntry(ini, sectionName, EbsdLib::Ctf::Author, m_HeaderMap); + ParseAndStoreHeaderEntry(ini, sectionName, EbsdLib::Ctf::JobMode, m_HeaderMap); + } + + { + const std::string sectionName("General"); + ParseAndStoreHeaderEntry(ini, sectionName, EbsdLib::Ctf::Author, m_HeaderMap); + ParseAndStoreHeaderEntry(ini, sectionName, EbsdLib::Ctf::JobMode, m_HeaderMap); + } + + return err; +} + +// ----------------------------------------------------------------------------- +int CprReader::readFile() +{ + + int error = readHeaderOnly(); + + if(error < 0) + { + return error; + } + setErrorCode(0); + + if(getXStep() == 0.0 || getYStep() == 0.0f) + { + setErrorMessage("Either the X Step or Y Step was Zero (0.0) which is NOT allowed. Please update the CTF file header with appropriate values."); + setErrorCode(-102); + return getErrorCode(); + } + + if(getXCells() == 0 || getYCells() == 0) + { + setErrorMessage("Either the X Cells or Y Cells was Zero (0) which is NOT allowed. Please update the CTF file header with appropriate values."); + setErrorCode(-103); + return getErrorCode(); + } + + std::vector scanPointParsers = createFieldParsers(getFileName()); + if(scanPointParsers.empty()) + { + setErrorMessage("The .cpr file did not contain any [Fields] data to parse"); + setErrorCode(-100); + return getErrorCode(); + } + + size_t bufferSize = 0; + // Allocate all memory + size_t totalScanPoints = getNumberOfElements(); + bool didAllocate = false; + int index = 0; + for(auto& parser : scanPointParsers) + { + bufferSize += parser.FieldDefinition.ByteSize; + if(m_NamePointerMap.find(parser.FieldDefinition.FieldName) != m_NamePointerMap.end()) + { + std::stringstream ss; + ss << "Column Header '" << parser.FieldDefinition.FieldName << "' has been found multiple times in the Header Row. Please check the CTF file for mistakes."; + setErrorMessage(ss.str()); + setErrorCode(-110); + return getErrorCode(); + } + if(EbsdLib::NumericTypes::Type::UInt8 == parser.FieldDefinition.numericType) + { + UInt8Parser::Pointer dparser = UInt8Parser::New(nullptr, totalScanPoints, parser.FieldDefinition.FieldName, index); + didAllocate = dparser->allocateArray(totalScanPoints); + // Q_ASSERT_X(dparser->getVoidPointer() != nullptr, __FILE__, "Could not allocate memory for Integer data in CTF File."); + if(didAllocate) + { + ::memset(dparser->getVoidPointer(), 0xAB, sizeof(uint8_t) * totalScanPoints); + m_NamePointerMap[parser.FieldDefinition.FieldName] = dparser; + parser.destinationPtr = reinterpret_cast(dparser->getVoidPointer()); + } + } + else if(EbsdLib::NumericTypes::Type::Float == parser.FieldDefinition.numericType) + { + FloatParser::Pointer dparser = FloatParser::New(nullptr, totalScanPoints, parser.FieldDefinition.FieldName, index); + didAllocate = dparser->allocateArray(totalScanPoints); + // Q_ASSERT_X(dparser->getVoidPointer() != nullptr, __FILE__, "Could not allocate memory for Integer data in CTF File."); + if(didAllocate) + { + ::memset(dparser->getVoidPointer(), 0xAB, sizeof(float) * totalScanPoints); + m_NamePointerMap[parser.FieldDefinition.FieldName] = dparser; + parser.destinationPtr = reinterpret_cast(dparser->getVoidPointer()); + } + } + else if(EbsdLib::NumericTypes::Type::Int32 == parser.FieldDefinition.numericType) + { + Int32Parser::Pointer dparser = Int32Parser::New(nullptr, totalScanPoints, parser.FieldDefinition.FieldName, index); + didAllocate = dparser->allocateArray(totalScanPoints); + // Q_ASSERT_X(dparser->getVoidPointer() != nullptr, __FILE__, "Could not allocate memory for Integer data in CTF File."); + if(didAllocate) + { + ::memset(dparser->getVoidPointer(), 0xAB, sizeof(int32_t) * totalScanPoints); + m_NamePointerMap[parser.FieldDefinition.FieldName] = dparser; + parser.destinationPtr = reinterpret_cast(dparser->getVoidPointer()); + } + } + else + { + std::stringstream ss; + ss << "Column Header '" << parser.FieldDefinition.FieldName << "' is not a recognized column for this CRC Files. Please recheck your .cpr file and report this error to the DREAM3D developers."; + setErrorMessage(ss.str()); + setErrorCode(-107); + return getErrorCode(); + } + + if(!didAllocate) + { + std::stringstream ss; + ss << "The CTF reader could not allocate memory for the data. Check the header for the number of X, Y and Z Cells."; + ss << "\n X Cells: " << getXCells(); + ss << "\n Y Cells: " << getYCells(); + // ss << "\n Z Cells: " << getzCells(); + ss << "\n Total Scan Points: " << totalScanPoints; + setErrorMessage(ss.str()); + setErrorCode(-106); // Could not allocate the memory + return getErrorCode(); + } + index++; + } + + // Make a buffer + std::vector buffer(bufferSize, 0); + + fs::path filePath(getFileName()); + // Replace the extension with ".crc" + fs::path crcPath = filePath.replace_extension(".crc"); + // Open the file for reading + FILE* inputFilePtr = std::fopen(crcPath.string().c_str(), "rb"); + if(inputFilePtr == nullptr) + { + std::stringstream ss; + ss << "The input file '" << crcPath.string() << "' probably does not exist. Nullptr returns when opening the file"; + setErrorMessage(ss.str()); + setErrorCode(-108); + return getErrorCode(); + } + + // Read through the file + for(size_t idx = 0; idx < totalScanPoints; idx++) + { + size_t elementsRead = std::fread(buffer.data(), 1, bufferSize, inputFilePtr); + if(elementsRead != buffer.size()) + { + fclose(inputFilePtr); + std::stringstream ss; + ss << "Error when reading the .crc file at file offset " << (idx * bufferSize) << ". We should have read " << bufferSize << " bytes but we only read " << elementsRead << " bytes."; + setErrorMessage(ss.str()); + setErrorCode(-1666); + return getErrorCode(); + } + for(const auto& parser : scanPointParsers) + { + parser.parse(buffer.data(), idx); + } + } + fclose(inputFilePtr); + + return getErrorCode(); +} + +// ----------------------------------------------------------------------------- +std::vector CprReader::createFieldParsers(const std::string& filename) +{ + try + { + if(!std::filesystem::exists(filename)) + { + return {}; + } + } catch(std::exception& e) + { + return {}; + } + // Open the file + std::ifstream is(filename); + + // Create an INI parser object and parse the file + inipp::Ini ini; + ini.parse(is); + + size_t fieldCount = getFieldValue(ini, "Fields", "Count"); + // std::cout << "Field Count: " << fieldCount << std::endl; + std::vector fieldOrder(fieldCount + 1); + + // Insert the Phase as the first field. I guess? + fieldOrder[0] = {k_FieldDefinitions[0], nullptr, 0}; + size_t currentOffset = 1; + size_t edxCurrentOffset = 1; + + for(int i = 1; i <= fieldCount; i++) + { + std::stringstream fieldNameStrm; + fieldNameStrm << "Field" << i; + auto fieldIndex = getFieldValue(ini, "Fields", fieldNameStrm.str()); + if(fieldIndex < 13) + { + CrcFieldDefinition fieldDefinition = k_FieldDefinitions[fieldIndex]; + fieldOrder[i] = {fieldDefinition, nullptr, currentOffset}; + currentOffset += fieldDefinition.ByteSize; + } + // Handle EDX (XRay EDS) data which seems to have field index values > 100. + if(fieldIndex > 100) + { + fieldNameStrm.str(""); // Clear the stringstream buffer + fieldNameStrm << "Window" << edxCurrentOffset; + auto elementName = getFieldValue(ini, "EDX Windows", fieldNameStrm.str()); + if(elementName.empty()) + { + fieldNameStrm.str(""); // Clear the stringstream buffer + fieldNameStrm << "Field" << i; + elementName = fieldNameStrm.str(); + } + fieldOrder[i].FieldDefinition = {4, elementName, EbsdLib::NumericTypes::Type::Float}; + fieldOrder[i].destinationPtr = nullptr; + fieldOrder[i].readOffset = currentOffset; + currentOffset += 4; + edxCurrentOffset++; + } + } + + return fieldOrder; +} + +#if 0 +#define PRINT_HTML_TABLE_ROW(p) \ + std::cout << "\n " << p->getKey() << "\n " << p->getHDFType() << "\n"; \ + std::cout << " Contains value for the header entry " << p->getKey() << "\n" << std::endl; +#else +#define PRINT_HTML_TABLE_ROW(p) +#endif + +// ----------------------------------------------------------------------------- +int CprReader::getXDimension() +{ + return getXCells(); +} + +// ----------------------------------------------------------------------------- +void CprReader::setXDimension(int xdim) +{ + setXCells(xdim); +} + +// ----------------------------------------------------------------------------- +int CprReader::getYDimension() +{ + return getYCells(); +} + +// ----------------------------------------------------------------------------- +void CprReader::setYDimension(int ydim) +{ + setYCells(ydim); +} + +// ----------------------------------------------------------------------------- +std::vector CprReader::getColumnNames() +{ + std::vector keys; + keys.reserve(m_NamePointerMap.size()); + for(const auto& entry : m_NamePointerMap) + { + keys.push_back(entry.first); + } + + return keys; +} + +#define CTF_PRINT_QSTRING(var, out) out << #var << ": " << get##var() << std::endl; + +#define CTF_PRINT_HEADER_VALUE(var, out) out << #var << ": " << get##var() << std::endl; + +// ----------------------------------------------------------------------------- +void CprReader::printHeader(std::ostream& out) +{ + std::cout << "-------------------- CprReader Header Values --------------------" << std::endl; + CTF_PRINT_QSTRING(Channel, out) + CTF_PRINT_QSTRING(Prj, out) + CTF_PRINT_QSTRING(Author, out) + CTF_PRINT_QSTRING(JobMode, out) + CTF_PRINT_HEADER_VALUE(XCells, out) + CTF_PRINT_HEADER_VALUE(YCells, out) + CTF_PRINT_HEADER_VALUE(XStep, out) + CTF_PRINT_HEADER_VALUE(YStep, out) + // CTF_PRINT_HEADER_VALUE(AcqE1, out); + // CTF_PRINT_HEADER_VALUE(AcqE2, out); + // CTF_PRINT_HEADER_VALUE(AcqE3, out); + // CTF_PRINT_QSTRING(Euler, out); + CTF_PRINT_HEADER_VALUE(Mag, out) + CTF_PRINT_HEADER_VALUE(Coverage, out) + CTF_PRINT_HEADER_VALUE(Device, out) + CTF_PRINT_HEADER_VALUE(KV, out) + CTF_PRINT_HEADER_VALUE(TiltAngle, out) + CTF_PRINT_HEADER_VALUE(TiltAxis, out) + CTF_PRINT_HEADER_VALUE(NumPhases, out) + int nPhases = getNumPhases(); + for(int p = 0; p < nPhases; ++p) + { + out << "### Phase " << p << std::endl; + m_PhaseVector[p]->printSelf(out); + } + + std::cout << "----------------------------------------" << std::endl; +} + +// ----------------------------------------------------------------------------- +std::string CprReader::getNameOfClass() const +{ + return {"CprReader"}; +} + +// ----------------------------------------------------------------------------- +std::string CprReader::ClassName() +{ + return {"CprReader"}; +} diff --git a/Source/EbsdLib/IO/HKL/CprReader.h b/Source/EbsdLib/IO/HKL/CprReader.h new file mode 100644 index 0000000..88f5606 --- /dev/null +++ b/Source/EbsdLib/IO/HKL/CprReader.h @@ -0,0 +1,177 @@ +// +// Created by Michael Jackson on 10/22/24. +// +#pragma once + +#include +#include +#include +#include +#include + +#include "CtfConstants.h" +#include "CtfHeaderEntry.h" +#include "CtfPhase.h" +#include "DataParser.hpp" +#include "EbsdLib/Core/EbsdLibConstants.h" +#include "EbsdLib/Core/EbsdSetGetMacros.h" +#include "EbsdLib/EbsdLib.h" +#include "EbsdLib/IO/EbsdReader.h" + +#define CPR_READER_PTR_PROP(name, var, type) \ + type* get##name##Pointer() \ + { \ + return static_cast(getPointerByName(#var)); \ + } +namespace EbsdLib +{ + +struct CrcFieldDefinition +{ + size_t ByteSize = 0; + std::string FieldName; + EbsdLib::NumericTypes::Type numericType = EbsdLib::NumericTypes::Type::UnknownNumType; +}; + +struct CrcDataParser +{ + CrcFieldDefinition FieldDefinition = {}; + uint8_t* destinationPtr = nullptr; + size_t readOffset = 0; + + void parse(uint8_t* buffer, size_t destinationIndex) const + { + // calculate the proper pointer offset + uint8_t* finalPtr = destinationPtr + (destinationIndex * FieldDefinition.ByteSize); + // Copy the bytes from the buffer into the final destination + std::memcpy(finalPtr, buffer + readOffset, FieldDefinition.ByteSize); + } +}; + +} // namespace EbsdLib +/** + * @brief This class can parse an Oxford Instruments .cpr/.crc file combination. + * + * This class should successfully be able to read files even all phase types and including EDX data. + */ +class EbsdLib_EXPORT CprReader : public EbsdReader +{ +public: + CprReader(); + ~CprReader() override; + + /** + * @brief Returns the name of the class for CtfReader + */ + std::string getNameOfClass() const override; + + /** + * @brief Returns the name of the class for CtfReader + */ + static std::string ClassName(); + + using CtfIntHeaderType = CtfHeaderEntry; + using CtfFloatHeaderType = CtfHeaderEntry; + EBSDHEADER_INSTANCE_PROPERTY(CtfStringHeaderEntry, std::string, Channel, EbsdLib::Ctf::ChannelTextFile) + EBSDHEADER_INSTANCE_PROPERTY(CtfStringHeaderEntry, std::string, Prj, EbsdLib::Ctf::Prj) + EBSDHEADER_INSTANCE_PROPERTY(CtfStringHeaderEntry, std::string, Author, EbsdLib::Ctf::Author) + EBSDHEADER_INSTANCE_PROPERTY(CtfStringHeaderEntry, std::string, JobMode, EbsdLib::Ctf::JobMode) + + EBSDHEADER_INSTANCE_PROPERTY(CtfIntHeaderType, int, XCells, EbsdLib::Ctf::xCells) + EBSDHEADER_INSTANCE_PROPERTY(CtfIntHeaderType, int, YCells, EbsdLib::Ctf::yCells) + // EBSDHEADER_INSTANCE_PROPERTY(CtfIntHeaderType, int, ZCells, EbsdLib::Ctf::ZCells) + EBSDHEADER_INSTANCE_PROPERTY(CtfFloatHeaderType, float, XStep, EbsdLib::Ctf::GridDistX) + EBSDHEADER_INSTANCE_PROPERTY(CtfFloatHeaderType, float, YStep, EbsdLib::Ctf::GridDistY) + // EBSDHEADER_INSTANCE_PROPERTY(CtfFloatHeaderType, float, ZStep, EbsdLib::Ctf::ZStep) + // EBSDHEADER_INSTANCE_PROPERTY(CtfFloatHeaderType, float, AcqE1, EbsdLib::Ctf::AcqE1) + // EBSDHEADER_INSTANCE_PROPERTY(CtfFloatHeaderType, float, AcqE2, EbsdLib::Ctf::AcqE2) + // EBSDHEADER_INSTANCE_PROPERTY(CtfFloatHeaderType, float, AcqE3, EbsdLib::Ctf::AcqE3) + // EBSDHEADER_INSTANCE_PROPERTY(CtfStringHeaderEntry, std::string, Euler, EbsdLib::Ctf::Euler) + EBSDHEADER_INSTANCE_PROPERTY(CtfIntHeaderType, int, Mag, EbsdLib::Ctf::Magnification) + EBSDHEADER_INSTANCE_PROPERTY(CtfIntHeaderType, int, Coverage, EbsdLib::Ctf::Coverage) + EBSDHEADER_INSTANCE_PROPERTY(CtfIntHeaderType, int, Device, EbsdLib::Ctf::Device) + EBSDHEADER_INSTANCE_PROPERTY(CtfIntHeaderType, int, KV, EbsdLib::Ctf::kV) + EBSDHEADER_INSTANCE_PROPERTY(CtfFloatHeaderType, float, TiltAngle, EbsdLib::Ctf::TiltAngle) + EBSDHEADER_INSTANCE_PROPERTY(CtfFloatHeaderType, float, TiltAxis, EbsdLib::Ctf::TiltAxis) + EBSDHEADER_INSTANCE_PROPERTY(CtfIntHeaderType, int, NumPhases, EbsdLib::Ctf::NumPhases) + EBSD_INSTANCE_PROPERTY(std::vector, PhaseVector) + + CPR_READER_PTR_PROP(Phase, Phase, uint8_t) + CPR_READER_PTR_PROP(X, X, float) + CPR_READER_PTR_PROP(Y, Y, float) + // CPR_READER_PTR_PROP(Z, Z, float) + CPR_READER_PTR_PROP(BandCount, Bands, uint8_t) + CPR_READER_PTR_PROP(Error, Error, uint8_t) + CPR_READER_PTR_PROP(Euler1, phi1, float) + CPR_READER_PTR_PROP(Euler2, Phi, float) + CPR_READER_PTR_PROP(Euler3, phi2, float) + CPR_READER_PTR_PROP(MeanAngularDeviation, MAD, float) + CPR_READER_PTR_PROP(BandContrast, BC, uint8_t) + CPR_READER_PTR_PROP(BandSlope, BS, uint8_t) + CPR_READER_PTR_PROP(ReliabilityIndex, ReliabilityIndex, int32_t) + + /** + * @brief Returns the pointer to the data for a given feature + * @param featureName The name of the feature to return the pointer to. + */ + void* getPointerByName(const std::string& featureName) override; + + /** + * @brief Returns the string names of all the arrays that were allocated during the reading of the file + * @return + */ + std::vector getPointerNames() const; + + /** + * @brief Returns the types of data that each array holds. + * @return + */ + std::map getPointerTypes() const; + + /** + * @brief Returns an enumeration value that depicts the numerical + * primitive type that the data is stored as (Int, Float, etc). + * @param featureName The name of the feature. + */ + EbsdLib::NumericTypes::Type getPointerType(const std::string& featureName) override; + + int getTypeSize(const std::string& featureName); + + // DataParser::Pointer getParser(const std::string& featureName, void* ptr, size_t size); + + std::vector getColumnNames(); + + /** + * @brief Reads the complete HKL .ctf file. + * @return 1 on success + */ + int readFile() override; + + /** + * @brief Reads ONLY the header portion of the HKL .ctf file + * @return 1 on success + */ + int readHeaderOnly() override; + + // void readOnlySliceIndex(int slice); + + int getXDimension() override; + void setXDimension(int xdim) override; + int getYDimension() override; + void setYDimension(int ydim) override; + + void printHeader(std::ostream& out); + + std::vector createFieldParsers(const std::string& filename); + +private: + int m_SingleSliceRead = -1; + + std::map m_NamePointerMap; + +public: + CprReader(const CprReader&) = delete; // Copy Constructor Not Implemented + CprReader(CprReader&&) = delete; // Move Constructor Not Implemented + CprReader& operator=(const CprReader&) = delete; // Copy Assignment Not Implemented + CprReader& operator=(CprReader&&) = delete; // Move Assignment Not Implemented +}; diff --git a/Source/EbsdLib/IO/HKL/CtfConstants.h b/Source/EbsdLib/IO/HKL/CtfConstants.h index be33bbf..bf09021 100644 --- a/Source/EbsdLib/IO/HKL/CtfConstants.h +++ b/Source/EbsdLib/IO/HKL/CtfConstants.h @@ -132,6 +132,13 @@ DECLARE_STRING_CONST(Author) DECLARE_STRING_CONST(JobMode) DECLARE_STRING_CONST(XCells) DECLARE_STRING_CONST(YCells) + +DECLARE_STRING_CONST(GridDistX) +DECLARE_STRING_CONST(GridDistY) +DECLARE_STRING_CONST(xCells) +DECLARE_STRING_CONST(yCells) +DECLARE_STRING_CONST(Count) + DECLARE_STRING_CONST(ZCells) DECLARE_STRING_CONST(XStep) DECLARE_STRING_CONST(YStep) @@ -141,9 +148,11 @@ DECLARE_STRING_CONST(AcqE2) DECLARE_STRING_CONST(AcqE3) DECLARE_STRING_CONST(Euler) DECLARE_STRING_CONST(Mag) +DECLARE_STRING_CONST(Magnification) DECLARE_STRING_CONST(Coverage) DECLARE_STRING_CONST(Device) DECLARE_STRING_CONST(KV) +DECLARE_STRING_CONST(kV) DECLARE_STRING_CONST(TiltAngle) DECLARE_STRING_CONST(TiltAxis) const std::string NumPhases("Phases"); @@ -161,6 +170,7 @@ DECLARE_STRING_CONST(Comment) /* ******************************************************************************************************** */ // These are the names of the Data Columns // DO NOT CHANGE ANY OF THESE CONSTANTS, IT WILL MESS UP THE CTF Parser +DECLARE_STRING_CONST(ReliabilityIndex) DECLARE_STRING_CONST(Phase) DECLARE_STRING_CONST(X) DECLARE_STRING_CONST(Y) @@ -170,6 +180,11 @@ DECLARE_STRING_CONST(Error) DECLARE_STRING_CONST(Euler1) DECLARE_STRING_CONST(Euler2) DECLARE_STRING_CONST(Euler3) + +DECLARE_STRING_CONST(phi1) +DECLARE_STRING_CONST(Phi) +DECLARE_STRING_CONST(phi2) + DECLARE_STRING_CONST(MAD) DECLARE_STRING_CONST(BC) // BC DECLARE_STRING_CONST(BS) // BS diff --git a/Source/EbsdLib/IO/HKL/CtfPhase.cpp b/Source/EbsdLib/IO/HKL/CtfPhase.cpp index 1758a5b..666cf5e 100644 --- a/Source/EbsdLib/IO/HKL/CtfPhase.cpp +++ b/Source/EbsdLib/IO/HKL/CtfPhase.cpp @@ -35,6 +35,7 @@ #include "CtfPhase.h" +#include "EbsdLib/LaueOps/LaueOps.h" #include "EbsdLib/Utilities/EbsdStringUtils.hpp" // ----------------------------------------------------------------------------- @@ -119,7 +120,7 @@ void CtfPhase::printSelf(std::ostream& stream) << m_LatticeConstants[4] << ", " << m_LatticeConstants[5] << std::endl; stream << EbsdLib::Ctf::PhaseName << " " << m_PhaseName << std::endl; stream << EbsdLib::Ctf::LaueGroup << " " << m_LaueGroup << std::endl; - stream << EbsdLib::Ctf::SpaceGroup << " " << m_SpaceGroup << std::endl; + stream << EbsdLib::Ctf::SpaceGroup << " " << m_SpaceGroup << " " << LaueOps::GetOrientationOpsFromSpaceGroupNumber(m_SpaceGroup)->getSymmetryName() << std::endl; stream << EbsdLib::Ctf::Internal1 << " " << m_Internal1 << std::endl; stream << EbsdLib::Ctf::Internal2 << " " << m_Internal2 << std::endl; stream << EbsdLib::Ctf::Comment << " " << m_Comment << std::endl; @@ -128,7 +129,7 @@ void CtfPhase::printSelf(std::ostream& stream) // ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- -unsigned int CtfPhase::determineLaueGroup() +unsigned int CtfPhase::determineOrientationOpsIndex() { EbsdLib::Ctf::LaueGroupTable symmetry = getLaueGroup(); diff --git a/Source/EbsdLib/IO/HKL/CtfPhase.h b/Source/EbsdLib/IO/HKL/CtfPhase.h index b759716..6b52d0f 100644 --- a/Source/EbsdLib/IO/HKL/CtfPhase.h +++ b/Source/EbsdLib/IO/HKL/CtfPhase.h @@ -132,9 +132,9 @@ class EbsdLib_EXPORT CtfPhase void printSelf(std::ostream& stream); /** - * @brief Returns the type of crystal structure for this phase. + * @brief Returns the index of the appropriate LaueOps class */ - unsigned int determineLaueGroup(); + unsigned int determineOrientationOpsIndex(); std::string getMaterialName(); diff --git a/Source/EbsdLib/IO/HKL/CtfReader.h b/Source/EbsdLib/IO/HKL/CtfReader.h index 3a4ce7a..248564e 100644 --- a/Source/EbsdLib/IO/HKL/CtfReader.h +++ b/Source/EbsdLib/IO/HKL/CtfReader.h @@ -73,7 +73,8 @@ class EbsdLib_EXPORT CtfReader : public EbsdReader /** * @brief Returns the name of the class for CtfReader */ - std::string getNameOfClass() const; + std::string getNameOfClass() const override; + /** * @brief Returns the name of the class for CtfReader */ diff --git a/Source/EbsdLib/IO/HKL/DataParser.hpp b/Source/EbsdLib/IO/HKL/DataParser.hpp index aa72c2b..e89e04c 100644 --- a/Source/EbsdLib/IO/HKL/DataParser.hpp +++ b/Source/EbsdLib/IO/HKL/DataParser.hpp @@ -101,6 +101,8 @@ class DataParser { } + virtual EbsdLib::NumericTypes::Type getNumericType() const = 0; + protected: DataParser() : m_ManageMemory(false) @@ -147,6 +149,11 @@ class UInt8Parser : public DataParser return std::string("UInt8Parser"); } + EbsdLib::NumericTypes::Type getNumericType() const override + { + return EbsdLib::NumericTypes::Type::UInt8; + } + int32_t IsA() const override { return 1; @@ -253,6 +260,11 @@ class Int32Parser : public DataParser return std::string("Int32Parser"); } + EbsdLib::NumericTypes::Type getNumericType() const override + { + return EbsdLib::NumericTypes::Type::Int32; + } + int32_t IsA() const override { return 1; @@ -357,6 +369,11 @@ class FloatParser : public DataParser return std::string("FloatParser"); } + EbsdLib::NumericTypes::Type getNumericType() const override + { + return EbsdLib::NumericTypes::Type::Float; + } + int32_t IsA() const override { return 2; diff --git a/Source/EbsdLib/IO/HKL/H5CtfReader.h b/Source/EbsdLib/IO/HKL/H5CtfReader.h index 0c654c3..54e8d71 100644 --- a/Source/EbsdLib/IO/HKL/H5CtfReader.h +++ b/Source/EbsdLib/IO/HKL/H5CtfReader.h @@ -86,7 +86,7 @@ class EbsdLib_EXPORT H5CtfReader : public CtfReader /** * @brief Returns the name of the class for H5CtfReader */ - std::string getNameOfClass() const; + std::string getNameOfClass() const override; /** * @brief Returns the name of the class for H5CtfReader */ diff --git a/Source/EbsdLib/IO/HKL/H5OINAReader.h b/Source/EbsdLib/IO/HKL/H5OINAReader.h index 8d1b368..c6ef77d 100644 --- a/Source/EbsdLib/IO/HKL/H5OINAReader.h +++ b/Source/EbsdLib/IO/HKL/H5OINAReader.h @@ -141,7 +141,7 @@ class EbsdLib_EXPORT H5OINAReader : public EbsdReader /** * @brief Returns the name of the class for H5OINAReader */ - std::string getNameOfClass() const; + std::string getNameOfClass() const override; /** * @brief Returns the name of the class for H5OINAReader diff --git a/Source/EbsdLib/IO/HKL/SourceList.cmake b/Source/EbsdLib/IO/HKL/SourceList.cmake index a971a64..7199766 100644 --- a/Source/EbsdLib/IO/HKL/SourceList.cmake +++ b/Source/EbsdLib/IO/HKL/SourceList.cmake @@ -3,6 +3,7 @@ set(HKL_SRCS ${EbsdLibProj_SOURCE_DIR}/Source/EbsdLib/IO/HKL/CtfReader.cpp ${EbsdLibProj_SOURCE_DIR}/Source/EbsdLib/IO/HKL/CtfPhase.cpp ${EbsdLibProj_SOURCE_DIR}/Source/EbsdLib/IO/HKL/CtfFields.cpp + ${EbsdLibProj_SOURCE_DIR}/Source/EbsdLib/IO/HKL/CprReader.cpp ) set(HKL_HDRS @@ -26,6 +27,7 @@ if(EbsdLib_ENABLE_HDF5) ${EbsdLibProj_SOURCE_DIR}/Source/EbsdLib/IO/HKL/H5CtfReader.h ${EbsdLibProj_SOURCE_DIR}/Source/EbsdLib/IO/HKL/H5CtfVolumeReader.h ${EbsdLibProj_SOURCE_DIR}/Source/EbsdLib/IO/HKL/H5OINAReader.h + ${EbsdLibProj_SOURCE_DIR}/Source/EbsdLib/IO/HKL/CprReader.h ) endif() diff --git a/Source/EbsdLib/IO/TSL/AngPhase.cpp b/Source/EbsdLib/IO/TSL/AngPhase.cpp index 1074cfa..446df27 100644 --- a/Source/EbsdLib/IO/TSL/AngPhase.cpp +++ b/Source/EbsdLib/IO/TSL/AngPhase.cpp @@ -288,7 +288,7 @@ void AngPhase::printSelf(std::stringstream& stream) // ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- -unsigned int AngPhase::determineLaueGroup() +unsigned int AngPhase::determineOrientationOpsIndex() { uint32_t symmetry = getSymmetry(); unsigned int crystal_structure = EbsdLib::CrystalStructure::UnknownCrystalStructure; diff --git a/Source/EbsdLib/IO/TSL/AngPhase.h b/Source/EbsdLib/IO/TSL/AngPhase.h index 352501b..6584e58 100644 --- a/Source/EbsdLib/IO/TSL/AngPhase.h +++ b/Source/EbsdLib/IO/TSL/AngPhase.h @@ -215,7 +215,7 @@ class EbsdLib_EXPORT AngPhase /** * @brief Returns the type of crystal structure for this phase. */ - unsigned int determineLaueGroup(); + unsigned int determineOrientationOpsIndex(); private: std::string m_MaterialName = {}; diff --git a/Source/EbsdLib/IO/TSL/H5AngReader.h b/Source/EbsdLib/IO/TSL/H5AngReader.h index 96a6b18..7d6916c 100644 --- a/Source/EbsdLib/IO/TSL/H5AngReader.h +++ b/Source/EbsdLib/IO/TSL/H5AngReader.h @@ -111,7 +111,7 @@ class EbsdLib_EXPORT H5AngReader : public AngReader /** * @brief Returns the name of the class for H5AngReader */ - std::string getNameOfClass() const; + std::string getNameOfClass() const override; /** * @brief Returns the name of the class for H5AngReader */ diff --git a/Source/EbsdLib/IO/TSL/H5OIMReader.h b/Source/EbsdLib/IO/TSL/H5OIMReader.h index 3d31334..55b9c24 100644 --- a/Source/EbsdLib/IO/TSL/H5OIMReader.h +++ b/Source/EbsdLib/IO/TSL/H5OIMReader.h @@ -99,7 +99,7 @@ class EbsdLib_EXPORT H5OIMReader : public AngReader /** * @brief Returns the name of the class for H5OIMReader */ - std::string getNameOfClass() const; + std::string getNameOfClass() const override; /** * @brief Returns the name of the class for H5OIMReader */ diff --git a/Source/EbsdLib/LaueOps/CubicLowOps.cpp b/Source/EbsdLib/LaueOps/CubicLowOps.cpp index 42589de..a128bf8 100644 --- a/Source/EbsdLib/LaueOps/CubicLowOps.cpp +++ b/Source/EbsdLib/LaueOps/CubicLowOps.cpp @@ -50,6 +50,7 @@ #ifdef EbsdLib_USE_PARALLEL_ALGORITHMS #include #include +#include #endif namespace CubicLow diff --git a/Source/EbsdLib/LaueOps/CubicOps.cpp b/Source/EbsdLib/LaueOps/CubicOps.cpp index 0de82ab..a7e36bd 100644 --- a/Source/EbsdLib/LaueOps/CubicOps.cpp +++ b/Source/EbsdLib/LaueOps/CubicOps.cpp @@ -50,6 +50,7 @@ #ifdef EbsdLib_USE_PARALLEL_ALGORITHMS #include #include +#include #endif namespace CubicHigh diff --git a/Source/EbsdLib/LaueOps/HexagonalLowOps.cpp b/Source/EbsdLib/LaueOps/HexagonalLowOps.cpp index a25a961..cb037a6 100644 --- a/Source/EbsdLib/LaueOps/HexagonalLowOps.cpp +++ b/Source/EbsdLib/LaueOps/HexagonalLowOps.cpp @@ -50,6 +50,7 @@ #ifdef EbsdLib_USE_PARALLEL_ALGORITHMS #include #include +#include #endif namespace HexagonalLow diff --git a/Source/EbsdLib/LaueOps/HexagonalOps.cpp b/Source/EbsdLib/LaueOps/HexagonalOps.cpp index 7af4604..90b69db 100644 --- a/Source/EbsdLib/LaueOps/HexagonalOps.cpp +++ b/Source/EbsdLib/LaueOps/HexagonalOps.cpp @@ -52,6 +52,7 @@ #ifdef EbsdLib_USE_PARALLEL_ALGORITHMS #include #include +#include #endif namespace HexagonalHigh diff --git a/Source/EbsdLib/LaueOps/MonoclinicOps.cpp b/Source/EbsdLib/LaueOps/MonoclinicOps.cpp index bdc452d..b1b4a08 100644 --- a/Source/EbsdLib/LaueOps/MonoclinicOps.cpp +++ b/Source/EbsdLib/LaueOps/MonoclinicOps.cpp @@ -49,6 +49,7 @@ #ifdef EbsdLib_USE_PARALLEL_ALGORITHMS #include #include +#include #endif namespace Monoclinic diff --git a/Source/EbsdLib/LaueOps/OrthoRhombicOps.cpp b/Source/EbsdLib/LaueOps/OrthoRhombicOps.cpp index 7d78fad..4973a84 100644 --- a/Source/EbsdLib/LaueOps/OrthoRhombicOps.cpp +++ b/Source/EbsdLib/LaueOps/OrthoRhombicOps.cpp @@ -49,6 +49,7 @@ #ifdef EbsdLib_USE_PARALLEL_ALGORITHMS #include #include +#include #endif #define EBSD_LIB_GENERATE_ENTIRE_CIRCLE diff --git a/Source/EbsdLib/LaueOps/TetragonalLowOps.cpp b/Source/EbsdLib/LaueOps/TetragonalLowOps.cpp index 66ddb8f..c6471c8 100644 --- a/Source/EbsdLib/LaueOps/TetragonalLowOps.cpp +++ b/Source/EbsdLib/LaueOps/TetragonalLowOps.cpp @@ -49,6 +49,7 @@ #ifdef EbsdLib_USE_PARALLEL_ALGORITHMS #include #include +#include #endif namespace TetragonalLow diff --git a/Source/EbsdLib/LaueOps/TetragonalOps.cpp b/Source/EbsdLib/LaueOps/TetragonalOps.cpp index 2c36495..cdae564 100644 --- a/Source/EbsdLib/LaueOps/TetragonalOps.cpp +++ b/Source/EbsdLib/LaueOps/TetragonalOps.cpp @@ -50,6 +50,7 @@ #ifdef EbsdLib_USE_PARALLEL_ALGORITHMS #include #include +#include #endif namespace TetragonalHigh diff --git a/Source/EbsdLib/LaueOps/TrigonalLowOps.cpp b/Source/EbsdLib/LaueOps/TrigonalLowOps.cpp index 1feaa70..1ac0c11 100644 --- a/Source/EbsdLib/LaueOps/TrigonalLowOps.cpp +++ b/Source/EbsdLib/LaueOps/TrigonalLowOps.cpp @@ -49,6 +49,7 @@ #ifdef EbsdLib_USE_PARALLEL_ALGORITHMS #include #include +#include #endif #include diff --git a/Source/EbsdLib/LaueOps/TrigonalOps.cpp b/Source/EbsdLib/LaueOps/TrigonalOps.cpp index 1c71a35..38598fb 100644 --- a/Source/EbsdLib/LaueOps/TrigonalOps.cpp +++ b/Source/EbsdLib/LaueOps/TrigonalOps.cpp @@ -50,6 +50,7 @@ #ifdef EbsdLib_USE_PARALLEL_ALGORITHMS #include #include +#include #endif namespace TrigonalHigh diff --git a/Source/EbsdLib/Utilities/SourceList.cmake b/Source/EbsdLib/Utilities/SourceList.cmake index d9fbd72..8c520a4 100644 --- a/Source/EbsdLib/Utilities/SourceList.cmake +++ b/Source/EbsdLib/Utilities/SourceList.cmake @@ -21,6 +21,7 @@ set(EbsdLib_${DIR_NAME}_HDRS ${EbsdLibProj_SOURCE_DIR}/Source/EbsdLib/${DIR_NAME}/LatoBold.hpp ${EbsdLibProj_SOURCE_DIR}/Source/EbsdLib/${DIR_NAME}/LatoRegular.hpp ${EbsdLibProj_SOURCE_DIR}/Source/EbsdLib/${DIR_NAME}/CanvasUtilities.hpp + ${EbsdLibProj_SOURCE_DIR}/Source/EbsdLib/${DIR_NAME}/inipp.h ) set(EbsdLib_${DIR_NAME}_SRCS diff --git a/Source/EbsdLib/Utilities/inipp.h b/Source/EbsdLib/Utilities/inipp.h new file mode 100644 index 0000000..313a77a --- /dev/null +++ b/Source/EbsdLib/Utilities/inipp.h @@ -0,0 +1,332 @@ +/* +MIT License + +Copyright (c) 2017-2020 Matthias C. M. Troffaes + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace inipp +{ + +namespace detail +{ + +// trim functions based on http://stackoverflow.com/a/217605 + +template +inline void ltrim(std::basic_string& s, const std::locale& loc) +{ + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [&loc](CharT ch) { return !std::isspace(ch, loc); })); +} + +template +inline void rtrim(std::basic_string& s, const std::locale& loc) +{ + s.erase(std::find_if(s.rbegin(), s.rend(), [&loc](CharT ch) { return !std::isspace(ch, loc); }).base(), s.end()); +} + +template +inline void rtrim2(std::basic_string& s, UnaryPredicate pred) +{ + s.erase(std::find_if(s.begin(), s.end(), pred), s.end()); +} + +// string replacement function based on http://stackoverflow.com/a/3418285 + +template +inline bool replace(std::basic_string& str, const std::basic_string& from, const std::basic_string& to) +{ + auto changed = false; + size_t start_pos = 0; + while((start_pos = str.find(from, start_pos)) != std::basic_string::npos) + { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); + changed = true; + } + return changed; +} + +} // namespace detail + +template +inline bool extract(const std::basic_string& value, T& dst) +{ + CharT c; + std::basic_istringstream is{value}; + T result; + if((is >> std::boolalpha >> result) && !(is >> c)) + { + dst = result; + return true; + } + else + { + return false; + } +} + +template +inline bool extract(const std::basic_string& value, std::basic_string& dst) +{ + dst = value; + return true; +} + +template +inline bool get_value(const std::map, std::basic_string>& sec, const std::basic_string& key, T& dst) +{ + const auto it = sec.find(key); + if(it == sec.end()) + return false; + return extract(it->second, dst); +} + +template +inline bool get_value(const std::map, std::basic_string>& sec, const CharT* key, T& dst) +{ + return get_value(sec, std::basic_string(key), dst); +} + +template +class Format +{ +public: + // used for generating + const CharT char_section_start; + const CharT char_section_end; + const CharT char_assign; + const CharT char_comment; + + // used for parsing + virtual bool is_section_start(CharT ch) const + { + return ch == char_section_start; + } + virtual bool is_section_end(CharT ch) const + { + return ch == char_section_end; + } + virtual bool is_assign(CharT ch) const + { + return ch == char_assign; + } + virtual bool is_comment(CharT ch) const + { + return ch == char_comment; + } + + // used for interpolation + const CharT char_interpol; + const CharT char_interpol_start; + const CharT char_interpol_sep; + const CharT char_interpol_end; + + Format(CharT section_start, CharT section_end, CharT assign, CharT comment, CharT interpol, CharT interpol_start, CharT interpol_sep, CharT interpol_end) + : char_section_start(section_start) + , char_section_end(section_end) + , char_assign(assign) + , char_comment(comment) + , char_interpol(interpol) + , char_interpol_start(interpol_start) + , char_interpol_sep(interpol_sep) + , char_interpol_end(interpol_end) + { + } + + Format() + : Format('[', ']', '=', ';', '$', '{', ':', '}') + { + } + + const std::basic_string local_symbol(const std::basic_string& name) const + { + return char_interpol + (char_interpol_start + name + char_interpol_end); + } + + const std::basic_string global_symbol(const std::basic_string& sec_name, const std::basic_string& name) const + { + return local_symbol(sec_name + char_interpol_sep + name); + } +}; + +template +class Ini +{ +public: + using String = std::basic_string; + using Section = std::map; + using Sections = std::map; + + Sections sections; + std::list errors; + std::shared_ptr> format; + + static const int max_interpolation_depth = 10; + + Ini() + : format(std::make_shared>()){}; + Ini(std::shared_ptr> fmt) + : format(fmt){}; + + void generate(std::basic_ostream& os) const + { + for(auto const& sec : sections) + { + os << format->char_section_start << sec.first << format->char_section_end << std::endl; + for(auto const& val : sec.second) + { + os << val.first << format->char_assign << val.second << std::endl; + } + os << std::endl; + } + } + + void parse(std::basic_istream& is) + { + String line; + String section; + const std::locale loc{"C"}; + while(std::getline(is, line)) + { + detail::ltrim(line, loc); + detail::rtrim(line, loc); + const auto length = line.length(); + if(length > 0) + { + const auto pos = std::find_if(line.begin(), line.end(), [this](CharT ch) { return format->is_assign(ch); }); + const auto& front = line.front(); + if(format->is_comment(front)) + { + } + else if(format->is_section_start(front)) + { + if(format->is_section_end(line.back())) + section = line.substr(1, length - 2); + else + errors.push_back(line); + } + else if(pos != line.begin() && pos != line.end()) + { + String variable(line.begin(), pos); + String value(pos + 1, line.end()); + detail::rtrim(variable, loc); + detail::ltrim(value, loc); + auto& sec = sections[section]; + if(sec.find(variable) == sec.end()) + sec.emplace(variable, value); + else + errors.push_back(line); + } + else + { + errors.push_back(line); + } + } + } + } + + void interpolate() + { + int global_iteration = 0; + auto changed = false; + // replace each "${variable}" by "${section:variable}" + for(auto& sec : sections) + replace_symbols(local_symbols(sec.first, sec.second), sec.second); + // replace each "${section:variable}" by its value + do + { + changed = false; + const auto syms = global_symbols(); + for(auto& sec : sections) + changed |= replace_symbols(syms, sec.second); + } while(changed && (max_interpolation_depth > global_iteration++)); + } + + void default_section(const Section& sec) + { + for(auto& sec2 : sections) + for(const auto& val : sec) + sec2.second.insert(val); + } + + void strip_trailing_comments() + { + const std::locale loc{"C"}; + for(auto& sec : sections) + for(auto& val : sec.second) + { + detail::rtrim2(val.second, [this](CharT ch) { return format->is_comment(ch); }); + detail::rtrim(val.second, loc); + } + } + + void clear() + { + sections.clear(); + errors.clear(); + } + +private: + using Symbols = std::vector>; + + const Symbols local_symbols(const String& sec_name, const Section& sec) const + { + Symbols result; + for(const auto& val : sec) + result.emplace_back(format->local_symbol(val.first), format->global_symbol(sec_name, val.first)); + return result; + } + + const Symbols global_symbols() const + { + Symbols result; + for(const auto& sec : sections) + for(const auto& val : sec.second) + result.emplace_back(format->global_symbol(sec.first, val.first), val.second); + return result; + } + + bool replace_symbols(const Symbols& syms, Section& sec) const + { + auto changed = false; + for(auto& sym : syms) + for(auto& val : sec) + changed |= detail::replace(val.second, sym.first, sym.second); + return changed; + } +}; + +} // namespace inipp