diff --git a/.gitignore b/.gitignore index 547ec8f..2c0eafd 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,5 @@ CMakeLists.txt.* test_data/ CMakeUserPresets.json Workspace +cmake-build-debug-visual-studio +cmake-build-release-visual-studio diff --git a/CMakeLists.txt b/CMakeLists.txt index fa56f57..71e5bc2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,65 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) +set(BUILD_SHARED_LIBS ON) + +# ---------- Setup output Directories ------------------------- +if(NOT DEFINED CMAKE_LIBRARY_OUTPUT_DIRECTORY) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY + ${BCFTools_BINARY_DIR}/Bin + CACHE PATH + "Single Directory for all Libraries" + ) +endif() + +# --------- Setup the Executable output Directory ------------- +if(NOT DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY + ${BCFTools_BINARY_DIR}/Bin + CACHE PATH + "Single Directory for all Executables." + ) +endif() + +# --------- Setup the Executable output Directory ------------- +if(NOT DEFINED CMAKE_ARCHIVE_OUTPUT_DIRECTORY) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY + ${BCFTools_BINARY_DIR}/Bin + CACHE PATH + "Single Directory for all static libraries." + ) +endif() + + + +#------------------------------------------------------------------------------- +# PUGIXML Library +#------------------------------------------------------------------------------- +add_subdirectory(${BCFTools_SOURCE_DIR}/3rdparty/pugixml) + +#------------------------------------------------------------------------------- +# HDF5 Library +#------------------------------------------------------------------------------- +set(HDF5_BUILD_WITH_INSTALL_NAME ON CACHE BOOL "" FORCE) +set(HDF5_BUILD_CPP_LIB OFF CACHE BOOL "" FORCE) +set(HDF5_BUILD_HL_LIB OFF CACHE BOOL "" FORCE) +set(HDF5_BUILD_HL_TOOLS OFF CACHE BOOL "" FORCE) +set(HDF5_BUILD_TOOLS OFF CACHE BOOL "" FORCE) +set(HDF5_BUILD_UTILS OFF CACHE BOOL "" FORCE) +set(BUILD_TESTING OFF CACHE BOOL "" FORCE) +set(HDF_PACKAGE_NAMESPACE "hdf5::") +set(HDF5_ALLOW_EXTERNAL_SUPPORT ON CACHE BOOL "" FORCE) +set(HDF5_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) + +add_subdirectory(${BCFTools_SOURCE_DIR}/3rdparty/hdf5) + +#------------------------------------------------------------------------------- +# H5Support Library +#------------------------------------------------------------------------------- +#set(H5Support_INCLUDE_QT_API OFF) +#set(H5Support_INSTALL_HDF5 OFF) +#add_subdirectory(${BCFTools_SOURCE_DIR}/3rdparty/H5Support) + #------------------------------------------------------------------------------- # unbcf executable @@ -25,7 +84,43 @@ set(unbcf_sources ${BCFTools_SOURCE_DIR}/src/SFSNodeItem.cpp ${BCFTools_SOURCE_DIR}/src/SFSUtils.hpp - ${BCFTools_SOURCE_DIR}/src/unbcf.cpp + +) + +add_executable(unbcf ${unbcf_sources} ${BCFTools_SOURCE_DIR}/src/unbcf.cpp) + + +#------------------------------------------------------------------------------- +# bcftohdf5 executable +#------------------------------------------------------------------------------- +set(bcf2hdf5_sources + ${BCFTools_SOURCE_DIR}/src/bcf2hdf5.cpp + ${BCFTools_SOURCE_DIR}/src/BcfHdf5Convertor.h + ${BCFTools_SOURCE_DIR}/src/BcfHdf5Convertor.cpp + + ${BCFTools_SOURCE_DIR}/src/BrukerIntegration/BrukerIntegrationConstants.h + ${BCFTools_SOURCE_DIR}/src/BrukerIntegration/BrukerIntegrationStructs.h + + ${BCFTools_SOURCE_DIR}/src/BrukerIntegrationFilters/BrukerDataLoader.h + ${BCFTools_SOURCE_DIR}/src/BrukerIntegrationFilters/BrukerDataLoader.cpp + + ${BCFTools_SOURCE_DIR}/src/BrukerIntegrationFilters/EbsdPatterns.h + ${BCFTools_SOURCE_DIR}/src/BrukerIntegrationFilters/EbsdPatterns.cpp + + ${BCFTools_SOURCE_DIR}/src/EbsdLib/Core/EbsdDataArray.hpp + ${BCFTools_SOURCE_DIR}/src/EbsdLib/Core/EbsdDataArray.cpp + ${BCFTools_SOURCE_DIR}/src/EbsdLib/Core/EbsdLibConstants.h + ${BCFTools_SOURCE_DIR}/src/EbsdLib/Core/EbsdMacros.h ) -add_executable(unbcf ${unbcf_sources}) +#add_executable(bcf2hdf5 ${unbcf_sources} ${BCFTools_SOURCE_DIR}/src/unbcf.cpp) + +add_executable(bcf2hdf5 ${unbcf_sources} ${bcf2hdf5_sources}) +target_link_libraries(bcf2hdf5 hdf5-shared pugixml) +target_include_directories(bcf2hdf5 PUBLIC + ${BCFTools_SOURCE_DIR}/src + ${BCFTools_SOURCE_DIR}/3rdparty/H5Support/Source + ${BCFTools_SOURCE_DIR}/3rdparty/hdf5/src + ${BCFTools_BINARY_DIR}/3rdparty/hdf5/src + ${BCFTools_SOURCE_DIR}/3rdparty/pugixml/src + ) diff --git a/src/Base64.hpp b/src/Base64.hpp new file mode 100644 index 0000000..3fe0fbe --- /dev/null +++ b/src/Base64.hpp @@ -0,0 +1,124 @@ +#ifndef _MACARON_BASE64_H_ +#define _MACARON_BASE64_H_ + +/** + * The MIT License (MIT) + * Copyright (c) 2016 tomykaira + * + * 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. + */ + +#include + +namespace macaron { + +class Base64 { + public: + + static std::string Encode(const std::string data) { + static constexpr char sEncodingTable[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/' + }; + + size_t in_len = data.size(); + size_t out_len = 4 * ((in_len + 2) / 3); + std::string ret(out_len, '\0'); + size_t i; + char *p = const_cast(ret.c_str()); + + for (i = 0; i < in_len - 2; i += 3) { + *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; + *p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)]; + *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) | ((int) (data[i + 2] & 0xC0) >> 6)]; + *p++ = sEncodingTable[data[i + 2] & 0x3F]; + } + if (i < in_len) { + *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; + if (i == (in_len - 1)) { + *p++ = sEncodingTable[((data[i] & 0x3) << 4)]; + *p++ = '='; + } + else { + *p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)]; + *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2)]; + } + *p++ = '='; + } + + return ret; + } + + static std::string Decode(const std::string& input, std::string& out) { + static constexpr unsigned char kDecodingTable[] = { + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, + 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, + 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 + }; + + size_t in_len = input.size(); + if (in_len % 4 != 0) return "Input data size is not a multiple of 4"; + + size_t out_len = in_len / 4 * 3; + if (input[in_len - 1] == '=') out_len--; + if (input[in_len - 2] == '=') out_len--; + + out.resize(out_len); + + for (size_t i = 0, j = 0; i < in_len;) { + uint32_t a = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(input[i++])]; + uint32_t b = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(input[i++])]; + uint32_t c = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(input[i++])]; + uint32_t d = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(input[i++])]; + + uint32_t triple = (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6); + + if (j < out_len) out[j++] = (triple >> 2 * 8) & 0xFF; + if (j < out_len) out[j++] = (triple >> 1 * 8) & 0xFF; + if (j < out_len) out[j++] = (triple >> 0 * 8) & 0xFF; + } + + return ""; + } + +}; + +} + +#endif /* _MACARON_BASE64_H_ */ \ No newline at end of file diff --git a/src/BcfHdf5Convertor.cpp b/src/BcfHdf5Convertor.cpp index 105343e..266ffa6 100644 --- a/src/BcfHdf5Convertor.cpp +++ b/src/BcfHdf5Convertor.cpp @@ -4,8 +4,11 @@ #include "BrukerIntegration/BrukerIntegrationStructs.h" #include "BrukerIntegrationFilters/BrukerDataLoader.h" -#include "SIMPLib/DataArrays/DataArray.hpp" -#include "SIMPLib/Math/SIMPLibMath.h" +//#include "SIMPLib/DataArrays/DataArray.hpp" +//#include "SIMPLib/Math/SIMPLibMath.h" + +#include +#include #include "H5Support/H5Lite.h" #include "H5Support/H5ScopedErrorHandler.h" @@ -15,19 +18,38 @@ using namespace H5Support; #include "SFSNodeItem.h" #include "SFSReader.h" +#include "Base64.hpp" +#include "StringUtilities.hpp" -#include -#include -#include +//#include +//#include +//#include +//#include -#include +#include +#include #include #include #include #include #include #include +#include +#include +#include + +#ifdef SIMPL_USE_GHC_FILESYSTEM +#include +namespace fs = ghc::filesystem; +#else +#include +namespace fs = std::filesystem; +#endif + + + +using XmlDocumentType = std::shared_ptr; #if defined(__GNUC__) && !defined(__APPLE__) #define BDL_POS(var) var.__pos @@ -154,10 +176,29 @@ std::pair WriteGrayScaleImage(const std::string& filepath, return {0, "No Error"}; } + +class TempDirectory +{ +public: + TempDirectory(const std::string& path) + : m_Path({path}){} + + ~TempDirectory() + { + if(fs::exists(m_Path)) + { + fs::remove_all(m_Path); + } + } +private: + fs::path m_Path; +}; + + } // namespace // ----------------------------------------------------------------------------- -BcfHdf5Convertor::BcfHdf5Convertor(QString inputFile, QString outputFile) +BcfHdf5Convertor::BcfHdf5Convertor(std::string inputFile, std::string outputFile) : m_InputFile(std::move(inputFile)) , m_OutputFile(std::move(outputFile)) { @@ -177,27 +218,28 @@ void BcfHdf5Convertor::setFlipPatterns(bool flipPatterns) } // ----------------------------------------------------------------------------- -int32_t writeCameraConfiguration(hid_t semGrpId, hid_t ebsdGrpId, const QString& cameraConfiguration) +int32_t writeCameraConfiguration(hid_t semGrpId, hid_t ebsdGrpId, const std::string& cameraConfiguration) { - QString errorStr; + std::string errorStr; int errorLine = -1; int errorColumn = -1; - QFile device(cameraConfiguration); - - QDomDocument domDocument; - QDomElement root; - - if(!domDocument.setContent(&device, true, &errorStr, &errorLine, &errorColumn)) + // Reads and validates inputted xml data files + XmlDocumentType root = std::make_shared(); + pugi::xml_parse_result parseResult = root->load_file(cameraConfiguration.c_str()); + if(!parseResult) { - QString ss = QObject::tr("Parse error at line %1, column %2:\n%3").arg(errorLine).arg(errorColumn).arg(errorStr); - qDebug() << ss; + std::stringstream out; + out << "Error on parsing layer data:"; + out << "File name: " << cameraConfiguration << ", attr value: [" << root->child("node").attribute("attr").value() << "]\n"; + out << "Error description: " << parseResult.description() << "\n"; + out << cameraConfiguration << "[" << parseResult.offset << "]\n\n"; + std::cout << out.str() << std::endl; return -7080; } - root = domDocument.documentElement(); - QDomElement classInstance = root.firstChildElement("ClassInstance"); - if(classInstance.isNull()) + auto classInstance = root->first_element_by_path("TCameraConfiguration/ClassInstance"); + if(classInstance.empty()) { std::cout << "XML DOM entry ClassInstance was not found." << std::endl; return -7002; @@ -205,7 +247,7 @@ int32_t writeCameraConfiguration(hid_t semGrpId, hid_t ebsdGrpId, const QString& int32_t err = 0; // Start gathering the required information from the XML file - QString pixelFormat = classInstance.firstChildElement("PixelFormat").text(); + std::string pixelFormat = classInstance.first_element_by_path("PixelFormat").text().as_string(); int32_t pixelByteCount = 0; if(pixelFormat == "Gray8") { @@ -221,27 +263,28 @@ int32_t writeCameraConfiguration(hid_t semGrpId, hid_t ebsdGrpId, const QString& } // ----------------------------------------------------------------------------- -int32_t writeAuxIndexingOptions(hid_t semGrpId, hid_t ebsdGrpId, const QString& calibrationFile) +int32_t writeAuxIndexingOptions(hid_t semGrpId, hid_t ebsdGrpId, const std::string& calibrationFile) { - QString errorStr; + std::string errorStr; int errorLine = -1; int errorColumn = -1; - QFile device(calibrationFile); - - QDomDocument domDocument; - QDomElement root; - - if(!domDocument.setContent(&device, true, &errorStr, &errorLine, &errorColumn)) + // Reads and validates inputted xml data files + XmlDocumentType root = std::make_shared(); + pugi::xml_parse_result parseResult = root->load_file(calibrationFile.c_str()); + if(!parseResult) { - QString ss = QObject::tr("Parse error at line %1, column %2:\n%3").arg(errorLine).arg(errorColumn).arg(errorStr); - qDebug() << ss; + std::stringstream out; + out << "Error on parsing layer data:"; + out << "File name: " << calibrationFile << ", attr value: [" << root->child("node").attribute("attr").value() << "]\n"; + out << "Error description: " << parseResult.description() << "\n"; + out << calibrationFile << "[" << parseResult.offset << "]\n\n"; + std::cout << out.str() << std::endl; return -7080; } - root = domDocument.documentElement(); - QDomElement classInstance = root.firstChildElement("ClassInstance"); - if(classInstance.isNull()) + auto classInstance = root->first_element_by_path("TEBSDAuxIndexingOptions/ClassInstance"); + if(classInstance.empty()) { std::cout << "XML DOM entry ClassInstance was not found." << std::endl; return -7002; @@ -250,60 +293,62 @@ int32_t writeAuxIndexingOptions(hid_t semGrpId, hid_t ebsdGrpId, const QString& int32_t err = 0; // Start gathering the required information from the XML file - int32_t minIndexedBands = classInstance.firstChildElement("MinIndexedBandCount").text().toInt(&ok); + int32_t minIndexedBands = classInstance.first_element_by_path("MinIndexedBandCount").text().as_int(-1); err = H5Lite::writeScalarDataset(ebsdGrpId, "MinIndexedBands", minIndexedBands); // Start gathering the required information from the XML file - double madMax = classInstance.firstChildElement("MaxMAD").text().toDouble(&ok); + double madMax = classInstance.first_element_by_path("MaxMAD").text().as_double(0.0); err = H5Lite::writeScalarDataset(ebsdGrpId, "MADMax", madMax); return err; } // ----------------------------------------------------------------------------- -int32_t writeCalibrationData(hid_t semGrpId, hid_t ebsdGrpId, const QString& calibrationFile, float& pcx, float& pcy) +int32_t writeCalibrationData(hid_t semGrpId, hid_t ebsdGrpId, const std::string& calibrationFile, float& pcx, float& pcy) { - QString errorStr; + std::string errorStr; int errorLine = -1; int errorColumn = -1; - QFile device(calibrationFile); - - QDomDocument domDocument; - QDomElement root; - - if(!domDocument.setContent(&device, true, &errorStr, &errorLine, &errorColumn)) + // Reads and validates inputted xml data files + XmlDocumentType root = std::make_shared(); + pugi::xml_parse_result parseResult = root->load_file(calibrationFile.c_str()); + if(!parseResult) { - QString ss = QObject::tr("Parse error at line %1, column %2:\n%3").arg(errorLine).arg(errorColumn).arg(errorStr); - qDebug() << ss; + std::stringstream out; + out << "Error on parsing layer data:"; + out << "File name: " << calibrationFile << ", attr value: [" << root->child("node").attribute("attr").value() << "]\n"; + out << "Error description: " << parseResult.description() << "\n"; + out << calibrationFile << "[" << parseResult.offset << "]\n\n"; + std::cout << out.str() << std::endl; return -7080; } - root = domDocument.documentElement(); - QDomElement classInstance = root.firstChildElement("ClassInstance"); - if(classInstance.isNull()) + auto classInstance = root->first_element_by_path("TEBSDCalibration/ClassInstance"); + if(classInstance.empty()) { std::cout << "XML DOM entry ClassInstance was not found." << std::endl; return -7002; } + bool ok = false; int32_t err = 0; // Start gathering the required information from the XML file - double workingDistance = classInstance.firstChildElement("WorkingDistance").text().toDouble(&ok); + double workingDistance = classInstance.first_element_by_path("WorkingDistance").text().as_double(-1.0); err = H5Lite::writeScalarDataset(semGrpId, "SEM WD", workingDistance); err = H5Lite::writeScalarDataset(ebsdGrpId, "WD", workingDistance); - double topClip = classInstance.firstChildElement("TopClip").text().toDouble(&ok); + double topClip = classInstance.first_element_by_path("TopClip").text().as_double(-1.0); err = H5Lite::writeScalarDataset(ebsdGrpId, "TopClip", topClip); - pcx = classInstance.firstChildElement("PCX").text().toDouble(&ok); + pcx = classInstance.first_element_by_path("PCX").text().as_double(-1.0); err = H5Lite::writeScalarDataset(ebsdGrpId, "PCX", pcx); - pcy = classInstance.firstChildElement("PCY").text().toDouble(&ok); + pcy = classInstance.first_element_by_path("PCY").text().as_double(-1.0); err = H5Lite::writeScalarDataset(ebsdGrpId, "PCX", pcy); - float sampleTilt = classInstance.firstChildElement("ProbeTilt").text().toDouble(&ok); + float sampleTilt = classInstance.first_element_by_path("ProbeTilt").text().as_double(-1.0); err = H5Lite::writeScalarDataset(ebsdGrpId, "SampleTilt", sampleTilt); @@ -311,27 +356,28 @@ int32_t writeCalibrationData(hid_t semGrpId, hid_t ebsdGrpId, const QString& cal } // ----------------------------------------------------------------------------- -int32_t writeSEMData(hid_t semGrpId, hid_t ebsdGrpId, const QString& semFile) +int32_t writeSEMData(hid_t semGrpId, hid_t ebsdGrpId, const std::string& semFile) { - QString errorStr; + std::string errorStr; int errorLine; int errorColumn; - QFile device(semFile); - - QDomDocument domDocument; - QDomElement root; - - if(!domDocument.setContent(&device, true, &errorStr, &errorLine, &errorColumn)) + // Reads and validates inputted xml data files + XmlDocumentType root = std::make_shared(); + pugi::xml_parse_result parseResult = root->load_file(semFile.c_str()); + if(!parseResult) { - QString ss = QObject::tr("Parse error at line %1, column %2:\n%3").arg(errorLine).arg(errorColumn).arg(errorStr); - qDebug() << ss; + std::stringstream out; + out << "Error on parsing layer data:"; + out << "File name: " << semFile << ", attr value: [" << root->child("node").attribute("attr").value() << "]\n"; + out << "Error description: " << parseResult.description() << "\n"; + out << semFile << "[" << parseResult.offset << "]\n\n"; + std::cout << out.str() << std::endl; return -7080; } - root = domDocument.documentElement(); - QDomElement classInstance = root.firstChildElement("ClassInstance"); - if(classInstance.isNull()) + auto classInstance = root->first_element_by_path("TRTImageData/ClassInstance"); + if(classInstance.empty()) { std::cout << "XML DOM entry ClassInstance was not found." << std::endl; return -7002; @@ -339,47 +385,51 @@ int32_t writeSEMData(hid_t semGrpId, hid_t ebsdGrpId, const QString& semFile) bool ok = false; int32_t err = 0; - QString date = classInstance.firstChildElement("Date").text(); - err = H5Lite::writeStringDataset(ebsdGrpId, "Date", date.toStdString()); + std::string date = classInstance.first_element_by_path("Date").text().as_string("NOT FOUND"); + err = H5Lite::writeStringDataset(ebsdGrpId, "Date", date); err = H5Lite::writeStringAttribute(ebsdGrpId, "Date", "Format (ISO 8601)", "dd.mm.yyyy"); - QString time = classInstance.firstChildElement("Time").text(); - err = H5Lite::writeStringDataset(ebsdGrpId, "Time", time.toStdString()); + std::string time = classInstance.first_element_by_path("Time").text().as_string("NOT FOUND"); + err = H5Lite::writeStringDataset(ebsdGrpId, "Time", time); err = H5Lite::writeStringAttribute(ebsdGrpId, "Time", "Format (ISO 8601)", "hh:mm:ss"); - int32_t width = classInstance.firstChildElement("Width").text().toInt(&ok); + int32_t width = classInstance.first_element_by_path("Width").text().as_int(0xFFFFFFFF); err = H5Lite::writeScalarDataset(semGrpId, "SEM ImageWidth", width); - int32_t height = classInstance.firstChildElement("Height").text().toInt(&ok); + int32_t height = classInstance.first_element_by_path("Height").text().as_int(0xFFFFFFFF); err = H5Lite::writeScalarDataset(semGrpId, "SEM ImageHeight", height); std::vector tDims = {static_cast(height), static_cast(width)}; - float xRes = classInstance.firstChildElement("XCalibration").text().toFloat(&ok); + float xRes = classInstance.first_element_by_path("XCalibration").text().as_float(std::numeric_limits::max()); if(xRes == 0.0) { xRes = 1.0f;} err = H5Lite::writeScalarDataset(semGrpId, "SEM XResolution", xRes); err = H5Lite::writeScalarDataset(ebsdGrpId, "SEPixelSizeX", xRes); err = H5Lite::writeScalarDataset(ebsdGrpId, "XSTEP", xRes); - float yRes = classInstance.firstChildElement("YCalibration").text().toFloat(&ok); + float yRes = classInstance.first_element_by_path("YCalibration").text().as_float(std::numeric_limits::max()); if(yRes == 0.0) { yRes = 1.0f; } err = H5Lite::writeScalarDataset(semGrpId, "SEM YResolution", yRes); err = H5Lite::writeScalarDataset(ebsdGrpId, "SEPixelSizeY", yRes); err = H5Lite::writeScalarDataset(ebsdGrpId, "YSTEP", yRes); - int itemSize = classInstance.firstChildElement("ItemSize").text().toInt(&ok); + int itemSize = classInstance.first_element_by_path("ItemSize").text().as_int(0xFFFFFFFF); - int32_t planeCount = classInstance.firstChildElement("PlaneCount").text().toInt(&ok); + int32_t planeCount = classInstance.first_element_by_path("PlaneCount").text().as_int(0xFFFFFFFF); for(int32_t p = 0; p < planeCount; p++) { - QString tagName = "Plane" + QString::number(p); - QDomElement planeDomEle = classInstance.firstChildElement(tagName); - QByteArray b64str = planeDomEle.firstChildElement("Data").text().toLatin1(); - QByteArray decodedImage = QByteArray::fromBase64(b64str); - QString nameDomEle = planeDomEle.firstChildElement("Name").text(); - QString descDomEle = planeDomEle.firstChildElement("Description").text(); - - if(!nameDomEle.isEmpty() && !descDomEle.isEmpty()) + + std::string tagName = "Plane" + std::to_string(p); + + auto planeDomEle = classInstance.first_element_by_path(tagName.c_str()); + std::string b64str = planeDomEle.first_element_by_path("Data").text().as_string(""); + + std::string decodedImage; + macaron::Base64::Decode(b64str, decodedImage); + std::string nameDomEle = planeDomEle.first_element_by_path("Name").text().as_string("NOT FOUND"); + std::string descDomEle = planeDomEle.first_element_by_path("Description").text().as_string("NOT FOUND"); + + if(!nameDomEle.empty() && !descDomEle.empty()) { if(itemSize == 1) { @@ -406,15 +456,15 @@ int32_t writeSEMData(hid_t semGrpId, hid_t ebsdGrpId, const QString& semFile) err = H5Lite::writeStringAttribute(ebsdGrpId, "SEM Image", "IMAGE_SUBCLASS", "IMAGE_INDEXED"); err = H5Lite::writeStringAttribute(ebsdGrpId, "SEM Image", "IMAGE_VERSION", "1.2"); - if(!nameDomEle.isEmpty()) + if(!nameDomEle.empty()) { - err = H5Lite::writeStringAttribute(semGrpId, "SEM Image", "Name", nameDomEle.toStdString()); - err = H5Lite::writeStringAttribute(ebsdGrpId, "SEM Image", "Name", nameDomEle.toStdString()); + err = H5Lite::writeStringAttribute(semGrpId, "SEM Image", "Name", nameDomEle); + err = H5Lite::writeStringAttribute(ebsdGrpId, "SEM Image", "Name", nameDomEle); } - if(!descDomEle.isEmpty()) + if(!descDomEle.empty()) { - err = H5Lite::writeStringAttribute(semGrpId, "SEM Image", "Description", descDomEle.toStdString()); - err = H5Lite::writeStringAttribute(ebsdGrpId, "SEM Image", "Description", descDomEle.toStdString()); + err = H5Lite::writeStringAttribute(semGrpId, "SEM Image", "Description", descDomEle); + err = H5Lite::writeStringAttribute(ebsdGrpId, "SEM Image", "Description", descDomEle); } } } @@ -422,13 +472,13 @@ int32_t writeSEMData(hid_t semGrpId, hid_t ebsdGrpId, const QString& semFile) float semKV = 0.0f; float semMag = -1.0f; - QDomElement trtHeaderedClass = classInstance.firstChildElement("TRTHeaderedClass"); - QDomElement tRTREMHeader = trtHeaderedClass.firstChildElement("ClassInstance"); - if(!tRTREMHeader.isNull()) + auto trtHeaderedClass = classInstance.first_element_by_path("TRTHeaderedClass"); + auto tRTREMHeader = trtHeaderedClass.first_element_by_path("ClassInstance"); + if(!tRTREMHeader.empty()) { - semKV = tRTREMHeader.firstChildElement("Energy").text().toFloat(&ok); - semMag = tRTREMHeader.firstChildElement("Magnification").text().toFloat(&ok); - // float wd = tRTREMHeader.firstChildElement("WorkingDistance").text().toFloat(&ok); + semKV = tRTREMHeader.first_element_by_path("Energy").text().as_float(std::numeric_limits::max()); + semMag = tRTREMHeader.first_element_by_path("Magnification").text().as_float(std::numeric_limits::max()); + // float wd = tRTREMHeader.first_element_by_path("WorkingDistance").text().as_float(std::numeric_limits::max(); // err = H5Lite::writeScalarDataset(semGrpId, "SEM WD", wd); } err = H5Lite::writeScalarDataset(semGrpId, "SEM KV", semKV); @@ -440,135 +490,139 @@ int32_t writeSEMData(hid_t semGrpId, hid_t ebsdGrpId, const QString& semFile) } // ----------------------------------------------------------------------------- -int32_t writePhaseInformation(hid_t headerGrpId, const QString& phaseListFile) +int32_t writePhaseInformation(hid_t headerGrpId, const std::string& phaseListFile) { - hid_t phaseGrpId = H5Utilities::createGroup(headerGrpId, Bruker::Header::Phases.toStdString()); + hid_t phaseGrpId = H5Utilities::createGroup(headerGrpId, Bruker::Header::Phases); H5GroupAutoCloser phaseGrpAutoClose(phaseGrpId); - QString errorStr; + std::string errorStr; int errorLine; int errorColumn; - QFile device(phaseListFile); - - QDomDocument domDocument; - QDomElement root; - - if(!domDocument.setContent(&device, true, &errorStr, &errorLine, &errorColumn)) + // Reads and validates inputted xml data files + XmlDocumentType root = std::make_shared(); + pugi::xml_parse_result parseResult = root->load_file(phaseListFile.c_str()); + if(!parseResult) { - QString ss = QObject::tr("Parse error at line %1, column %2:\n%3").arg(errorLine).arg(errorColumn).arg(errorStr); - std::cout << ss.toStdString() << std::endl; - return -70000; + std::stringstream out; + out << "Error on parsing layer data:"; + out << "File name: " << phaseListFile << ", attr value: [" << root->child("node").attribute("attr").value() << "]\n"; + out << "Error description: " << parseResult.description() << "\n"; + out << phaseListFile << "[" << parseResult.offset << "]\n\n"; + std::cout << out.str() << std::endl; + return -7080; } - root = domDocument.documentElement(); - - QDomElement classInstance = root.firstChildElement("ClassInstance"); - if(classInstance.isNull()) + auto classInstance = root->first_element_by_path("TEBSDExtPhaseEntryList/ClassInstance"); + if(classInstance.empty()) { std::cout << "XML DOM entry ClassInstance was not found." << std::endl; return -7002; } - QDomElement childClassInstances = classInstance.firstChildElement("ChildClassInstances"); - if(childClassInstances.isNull()) + auto childClassInstances = classInstance.first_element_by_path("ChildClassInstances"); + if(childClassInstances.empty()) { std::cout << "XML DOM entry ChildClassInstances was not found." << std::endl; return -7003; } - QDomNodeList phaseInstaces = childClassInstances.childNodes(); - int32_t count = phaseInstaces.count(); - for(int32_t i = 0; i < count; i++) + auto phaseInstances = childClassInstances.children(); + int phaseIndex = 1; + for(const auto& phaseInstance : phaseInstances) { int32_t err = 0; bool ok = true; - hid_t grpId = H5Utilities::createGroup(phaseGrpId, QString::number(i + 1).toStdString()); + hid_t grpId = H5Utilities::createGroup(phaseGrpId, std::to_string(phaseIndex++)); H5GroupAutoCloser groupAutoCloser(grpId); - QDomNode phaseInstance = phaseInstaces.at(i); - QString name = phaseInstance.toElement().attribute("Name"); + //QDomNode phaseInstance = phaseInstances.at(i); + std::string name = phaseInstance.attribute("Name").as_string("NOT FOUND"); - err = H5Lite::writeStringDataset(grpId, "Name", name.toStdString()); + err = H5Lite::writeStringDataset(grpId, "Name", name); - QDomNode tEBSDPhaseEntry = phaseInstance.firstChildElement("TEBSDPhaseEntry"); + auto tEBSDPhaseEntry = phaseInstance.first_element_by_path("TEBSDPhaseEntry"); - // phaseInstance.firstChildElement("POS0").text() ); + // phaseInstance.first_element_by_path("POS0").text() ); - // phaseInstance.firstChildElement("REF").text() ); + // phaseInstance.first_element_by_path("REF").text() ); - // phaseInstance.firstChildElement("Complete").text() ); + // phaseInstance.first_element_by_path("Complete").text() ); - // phaseInstance.firstChildElement("BPS1").text() ); + // phaseInstance.first_element_by_path("BPS1").text() ); - // phaseInstance.firstChildElement("BPS2").text() ); - QString strValue = tEBSDPhaseEntry.firstChildElement("Chem").text(); - err = H5Lite::writeStringDataset(grpId, "Formula", strValue.toStdString()); + // phaseInstance.first_element_by_path("BPS2").text() ); + std::string strValue = tEBSDPhaseEntry.first_element_by_path("Chem").text().as_string("NOT FOUND"); + err = H5Lite::writeStringDataset(grpId, "Formula", strValue); - // phaseInstance.firstChildElement("DENSITY").text() ); + // phaseInstance.first_element_by_path("DENSITY").text() ); - // phaseInstance.firstChildElement("Elem").text() ); + // phaseInstance.first_element_by_path("Elem").text() ); /* Parse a DefaultGlideSystem subclass */ // m_DefaultGlideSystem = DefaultGlideSystem::Pointer(new DefaultGlideSystem(parent())); - // QDomElement ele_DefaultGlideSystem = phaseInstance.firstChildElement("DefaultGlideSystem"); + // QDomElement ele_DefaultGlideSystem = phaseInstance.first_element_by_path("DefaultGlideSystem"); // err = m_DefaultGlideSystem->parse(ele_DefaultGlideSystem); - // phaseInstance.firstChildElement("ISUSERDB").text() ); + // phaseInstance.first_element_by_path("ISUSERDB").text() ); - // phaseInstance.firstChildElement("PKEY").text() ); + // phaseInstance.first_element_by_path("PKEY").text() ); - // phaseInstance.firstChildElement("DBNAME").text() ); + // phaseInstance.first_element_by_path("DBNAME").text() ); /* Parse a Cell subclass */ // m_Cell = Cell::Pointer(new Cell(parent())); - QDomElement ele_Cell = tEBSDPhaseEntry.firstChildElement("Cell"); + auto ele_Cell = tEBSDPhaseEntry.first_element_by_path("Cell"); { std::vector latticeConstants(6); - QStringList values = ele_Cell.firstChildElement("Dim").text().split(","); - latticeConstants[0] = values[0].toFloat(&ok); - latticeConstants[1] = values[1].toFloat(&ok); - latticeConstants[2] = values[2].toFloat(&ok); - values = ele_Cell.firstChildElement("Angles").text().split(","); - latticeConstants[3] = values[0].toFloat(&ok); - latticeConstants[4] = values[1].toFloat(&ok); - latticeConstants[5] = values[2].toFloat(&ok); + std::string dataLine = ele_Cell.first_element_by_path("Dim").text().as_string("0.0,0.0,0.0"); + std::vector values = complex::StringUtilities::split_2(dataLine, ','); + latticeConstants[0] = std::stof(values[0]); + latticeConstants[1] = std::stof(values[1]); + latticeConstants[2] = std::stof(values[2]); + + dataLine = ele_Cell.first_element_by_path("Angles").text().as_string("0.0,0.0,0.0"); + values = complex::StringUtilities::split_2(dataLine, ','); + + latticeConstants[3] = std::stof(values[0]); + latticeConstants[4] = std::stof(values[1]); + latticeConstants[5] = std::stof(values[2]); std::vector dims = {6}; err = H5Lite::writeVectorDataset(grpId, "LatticeConstants", dims, latticeConstants); } // err = m_Cell->parse(ele_Cell); - // phaseInstance.firstChildElement("MU").text() ); + // phaseInstance.first_element_by_path("MU").text() ); - // phaseInstance.firstChildElement("USED").text() ); + // phaseInstance.first_element_by_path("USED").text() ); - // phaseInstance.firstChildElement("ENTRYID").text() ); + // phaseInstance.first_element_by_path("ENTRYID").text() ); - // phaseInstance.firstChildElement("Encrypted").text() ); + // phaseInstance.first_element_by_path("Encrypted").text() ); - int32_t se = tEBSDPhaseEntry.firstChildElement("SE").text().toInt(&ok); + int32_t se = tEBSDPhaseEntry.first_element_by_path("SE").text().as_int(0xFFFFFFFF); err = H5Lite::writeScalarDataset(grpId, "Setting", se); - // phaseInstance.firstChildElement("CC").text() ); + // phaseInstance.first_element_by_path("CC").text() ); - // phaseInstance.firstChildElement("REFLVERSION").text() ); + // phaseInstance.first_element_by_path("REFLVERSION").text() ); - strValue = tEBSDPhaseEntry.firstChildElement("SG").text(); - err = H5Lite::writeStringDataset(grpId, "SpaceGroup", strValue.toStdString()); + strValue = tEBSDPhaseEntry.first_element_by_path("SG").text().as_string("NOT FOUND"); + err = H5Lite::writeStringDataset(grpId, "SpaceGroup", strValue); - int32_t it = tEBSDPhaseEntry.firstChildElement("IT").text().toInt(&ok); + int32_t it = tEBSDPhaseEntry.first_element_by_path("IT").text().as_int(0xFFFFFFFF); err = H5Lite::writeScalarDataset(grpId, "IT", it); hid_t atGrpId = H5Utilities::createGroup(grpId, "AtomPositions"); H5GroupAutoCloser atGrpIdAutoCloser(atGrpId); // This tells us the number of atoms that we need to parse - it = tEBSDPhaseEntry.firstChildElement("AT").text().toInt(&ok); + it = tEBSDPhaseEntry.first_element_by_path("AT").text().as_int(0xFFFFFFFF); for(int32_t atom = 1; atom <= it; atom++) { - QString tagName = "POS" + QString::number(atom - 1); - strValue = tEBSDPhaseEntry.firstChildElement(tagName).text(); - err = H5Lite::writeStringDataset(atGrpId, QString::number(atom).toStdString(), strValue.toStdString()); + std::string tagName = "POS" + std::to_string(atom - 1); + strValue = tEBSDPhaseEntry.first_element_by_path(tagName.c_str()).text().as_string("NOT FOUND"); + err = H5Lite::writeStringDataset(atGrpId, std::to_string(atom), strValue); } } @@ -577,7 +631,7 @@ int32_t writePhaseInformation(hid_t headerGrpId, const QString& phaseListFile) // ----------------------------------------------------------------------------- template -int32_t writeDataArrayToHdf5(DataArray* data, hid_t grpId, size_t numElements) +int32_t writeDataArrayToHdf5(EbsdDataArray* data, hid_t grpId, size_t numElements) { std::vector cDims = data->getComponentDimensions(); if(cDims.size() == 1 && cDims[0] == 1) @@ -592,24 +646,24 @@ int32_t writeDataArrayToHdf5(DataArray* data, hid_t grpId, size_t numElements dims.push_back(dim); } - int32_t err = H5Lite::writePointerDataset(grpId, data->getName().toStdString(), static_cast(dims.size()), dims.data(), data->getPointer(0)); + int32_t err = H5Lite::writePointerDataset(grpId, data->getName(), static_cast(dims.size()), dims.data(), data->getPointer(0)); return err; } // ----------------------------------------------------------------------------- -int32_t analyzeFrameDescriptionFile(const QString& descFile) +int32_t analyzeFrameDescriptionFile(const std::string& descFile) { std::cout << "************** Frame Description File START ****************************" << std::endl; - QString filePath = descFile; - QFileInfo descFileInfo(filePath); - if(!descFileInfo.exists()) + if(!fs::exists(descFile)) { - std::cout << "The FrameDescription File does not exist: '" << filePath.toStdString() << "'" << std::endl; + std::cout << "The FrameDescription File does not exist: '" << descFile << "'" << std::endl; return -10; } // Open the FrameData File - FILE* f = fopen(descFileInfo.absoluteFilePath().toStdString().c_str(), "rb"); + fs::path inputPath(descFile); + std::string absolutPath = fs::absolute(inputPath).string(); + FILE* f = fopen(absolutPath.c_str(), "rb"); if(nullptr == f) { std::cout << "Could not open the FrameData File" << std::endl; @@ -652,27 +706,26 @@ int32_t analyzeFrameDescriptionFile(const QString& descFile) // ----------------------------------------------------------------------------- template int32_t writePatternData(const SFSReader& sfsFile, hid_t native_type, int32_t mapWidth, int32_t mapHeight, int32_t ebspWidth, - int32_t ebspHeight, bool flipPatterns, const QString& tempDir, const QString& dataFile, - const QString& descFile, hid_t dataGrpId) + int32_t ebspHeight, bool flipPatterns, const std::string& tempDir, const std::string& dataFile, + const std::string& descFile, hid_t dataGrpId) { int32_t err = 0; // =================================================== // Get the XBEAM and YBEAM data from the HDF5 file std::vector xbeam; - err = H5Lite::readVectorDataset(dataGrpId, Bruker::IndexingResults::XBEAM.toStdString(), xbeam); + err = H5Lite::readVectorDataset(dataGrpId, Bruker::IndexingResults::XBEAM, xbeam); std::vector ybeam; - err = H5Lite::readVectorDataset(dataGrpId, Bruker::IndexingResults::YBEAM.toStdString(), ybeam); + err = H5Lite::readVectorDataset(dataGrpId, Bruker::IndexingResults::YBEAM, ybeam); // =================================================== // Check the FrameDescription File exists - QString filePath = descFile; - QFileInfo descFileInfo(filePath); - if(!descFileInfo.exists()) + if(!fs::exists(descFile)) { - std::cout << "The FrameDescription File does not exist: '" << filePath.toStdString() << "'" << std::endl; + std::cout << "The FrameDescription File does not exist: '" << descFile << "'" << std::endl; return -10; } + err = analyzeFrameDescriptionFile(descFile); if(err < 0) { @@ -683,7 +736,9 @@ int32_t writePatternData(const SFSReader& sfsFile, hid_t native_type, int32_t ma // data starts in the FrameData file. std::vector frameDescription; { - FILE* f = fopen(descFileInfo.absoluteFilePath().toStdString().c_str(), "rb"); + fs::path inputPath(descFile); + std::string absolutPath = fs::absolute(inputPath).string(); + FILE* f = fopen(absolutPath.c_str(), "rb"); FrameDescriptionHeader_t descHeader; size_t nRead = fread(&descHeader, 12, 1, f); frameDescription.resize(descHeader.patternCount); @@ -693,24 +748,24 @@ int32_t writePatternData(const SFSReader& sfsFile, hid_t native_type, int32_t ma // =================================================== // Extract the FrameData file from the .bcf file. this can take a bit.... - err = sfsFile.extractFile(tempDir.toStdString(), dataFile.toStdString()); + err = sfsFile.extractFile(tempDir, dataFile); if(err != 0) { - std::cout << "Error extracting the " << dataFile.toStdString() << ". This data set will not be included in the resulting HDF5 file." << std::endl; + std::cout << "Error extracting the " << dataFile << ". This data set will not be included in the resulting HDF5 file." << std::endl; return err; } - filePath = tempDir + "/" + dataFile; - QFileInfo dataFileInfo(filePath); - if(!dataFileInfo.exists()) + fs::path filePath = tempDir + "/" + dataFile; + if(!fs::exists(filePath)) { - std::cout << "The FrameData File does not exist: '" << filePath.toStdString() << "'" << std::endl; + std::cout << "The FrameData File does not exist: '" << filePath << "'" << std::endl; return -11; } - qint64 filesize = dataFileInfo.size(); + auto filesize = fs::file_size(filePath); // Open the FrameData File - FILE* f = fopen(dataFileInfo.absoluteFilePath().toStdString().c_str(), "rb"); + std::string absolutPath = fs::absolute(filePath).string(); + FILE* f = fopen(absolutPath.c_str(), "rb"); if(nullptr == f) { std::cout << "Could not open the FrameData File" << std::endl; @@ -752,13 +807,13 @@ int32_t writePatternData(const SFSReader& sfsFile, hid_t native_type, int32_t ma status = H5Pset_fill_value(cparms, native_type, &fillvalue); // Create a new dataset within the file using cparms creation properties. - hid_t dataset = H5Dcreate2(dataGrpId, Bruker::IndexingResults::EBSP.toStdString().c_str(), native_type, dataspace, H5P_DEFAULT, cparms, H5P_DEFAULT); + hid_t dataset = H5Dcreate2(dataGrpId, Bruker::IndexingResults::EBSP.c_str(), native_type, dataspace, H5P_DEFAULT, cparms, H5P_DEFAULT); hid_t filespace = 0; size_t beamIdx = 0; for(int32_t y = 0; y < mapHeight; y++) { - std::cout << dataFileInfo.fileName().toStdString() << " Writing Row " << y << "/" << mapHeight << "\r"; + std::cout << filePath.filename() << " Writing Row " << y << "/" << mapHeight << "\r"; std::cout.flush(); for(int32_t x = 0; x < mapWidth; x++) @@ -883,32 +938,38 @@ void BcfHdf5Convertor::execute() // We are going to construct a QTemporaryDir _templatepath_ variable so we use a temp // location next to the input file. This *should* be ok for most situations. - // Qt will clean up the temp dir when it goes out of scope. - QFileInfo ifInfo(m_InputFile); - QString tmpPath = ifInfo.absolutePath() + "/" + ifInfo.baseName() + "_XXXXXX"; - QTemporaryDir tempDir(tmpPath); - if(!tempDir.isValid()) + // Qt will clean up the temp dir when it goes out of scope + + fs::path ifInfo(m_InputFile); + std::string tmpDir = ifInfo.parent_path().string() + "/" + ifInfo.stem().string() + "_XXXXXX"; + + std::error_code errorCode; + auto result = fs::create_directory({tmpDir}, errorCode); + if(!result && errorCode.value() != 0) { m_ErrorCode = -7000; - m_ErrorMessage = QString("Temp Directory could not be created."); + m_ErrorMessage = std::string("Temp Directory could not be created."); return; } + TempDirectory tempDirectory(tmpDir); + int32_t err = 0; - hid_t fid = H5Utilities::createFile(m_OutputFile.toStdString()); + hid_t fid = H5Utilities::createFile(m_OutputFile); H5ScopedFileSentinel fileSentinel(fid, k_ShowHdf5Errors); // *************************************************************************** // IF ANYTHING IN HERE CHANGES YOU NEED TO INCREMENT THE FILEVERSION NUMBER - // WHICH INDICATES THAT THE ORGANIZATION HAS BEED APPENDED/EDITED/REVISED. + // WHICH INDICATES THAT THE ORGANIZATION HAS BEEN APPENDED/EDITED/REVISED. // *************************************************************************** err = H5Lite::writeScalarAttribute(fid, "/", "FileVersion", ::k_FileVersion); - QFileInfo fi(m_InputFile); - QString baseInputFileName = fi.completeBaseName(); - hid_t topGrpId = H5Utilities::createGroup(fid, baseInputFileName.toStdString()); + fs::path fi(m_InputFile); + std::string baseInputFileName = fi.stem().string(); + + hid_t topGrpId = H5Utilities::createGroup(fid, baseInputFileName); fileSentinel.addGroupId(topGrpId); hid_t ebsdGrpId = H5Utilities::createGroup(topGrpId, k_EBSD); @@ -928,7 +989,7 @@ void BcfHdf5Convertor::execute() if(err < 0) { m_ErrorCode = err; - m_ErrorMessage = QString("Manufacturer Dataset was not written"); + m_ErrorMessage = std::string("Manufacturer Dataset was not written"); return; } @@ -937,56 +998,56 @@ void BcfHdf5Convertor::execute() if(err < 0) { m_ErrorCode = err; - m_ErrorMessage = QString("Version Dataset was not written"); + m_ErrorMessage = std::string("Version Dataset was not written"); return; } SFSReader sfsFile; - sfsFile.parseFile(m_InputFile.toStdString()); - QString outputFile; - QTextStream outFileStrm(&outputFile); + sfsFile.parseFile(m_InputFile); + + std::stringstream outFileStrm; - std::cout << "Using Temp Dir: " << tempDir.path().toStdString() << std::endl; + std::cout << "Using Temp Dir: " << tmpDir << std::endl; - outputFile.clear(); + outFileStrm.str(""); outFileStrm << Bruker::Files::EBSDData << "/" << Bruker::Files::FrameDescription; - QString descFile = outputFile; + std::string descFile = outFileStrm.str(); // std::cout << "Extracting FrameDescription"; - err = sfsFile.extractFile(tempDir.path().toStdString(), descFile.toStdString()); + err = sfsFile.extractFile(tmpDir, descFile); if(err < 0) { m_ErrorCode = -7020; - m_ErrorMessage = QString("Could not extract EBSDData/FrameDescription File."); + m_ErrorMessage = std::string("Could not extract EBSDData/FrameDescription File."); return; } - outputFile.clear(); + outFileStrm.str(""); outFileStrm << Bruker::Files::EBSDData << "/" << Bruker::Files::IndexingResults; - QString indexingResultsFile = outputFile; + std::string indexingResultsFile = outFileStrm.str(); // std::cout << "Extracting IndexingResults"; - err = sfsFile.extractFile(tempDir.path().toStdString(), indexingResultsFile.toStdString()); + err = sfsFile.extractFile(tmpDir, indexingResultsFile); if(err < 0) { m_ErrorCode = -7030; - m_ErrorMessage = QString("Could not extract EBSDData/IndexingResults File."); + m_ErrorMessage = std::string("Could not extract EBSDData/IndexingResults File."); return; } - outputFile.clear(); + outFileStrm.str(""); outFileStrm << Bruker::Files::EBSDData << "/" << Bruker::Files::Auxiliarien; - QString auxiliarienFile = outputFile; + std::string auxiliarienFile = outFileStrm.str(); // std::cout << "Extracting Auxiliarien"; - err = sfsFile.extractFile(tempDir.path().toStdString(), auxiliarienFile.toStdString()); + err = sfsFile.extractFile(tmpDir, auxiliarienFile); if(err < 0) { m_ErrorCode = -7040; - m_ErrorMessage = QString("Could not extract EBSDData/Auxiliarien File."); + m_ErrorMessage = std::string("Could not extract EBSDData/Auxiliarien File."); return; } - outputFile.clear(); - outFileStrm << tempDir.path() << "/" << Bruker::Files::EBSDData; - QString ebsdDataDir = outputFile; + outFileStrm.str(""); + outFileStrm << tmpDir << "/" << Bruker::Files::EBSDData; + std::string ebsdDataDir = outFileStrm.str(); // Read the Dimensions of the Map and EBSP int32_t mapHeight; @@ -1008,30 +1069,30 @@ void BcfHdf5Convertor::execute() // Scope this entire next part so that the arrays get cleaned up when we are done.... { - UInt16ArrayType::Pointer indices = UInt16ArrayType::CreateArray(numElements, cDims, "Positions", true); + UInt16Array::Pointer indices = UInt16Array::CreateArray(numElements, cDims, "Positions", true); cDims[0] = 3; - FloatArrayType::Pointer eulers = FloatArrayType::CreateArray(numElements, cDims, Bruker::IndexingResults::Eulers, true); + FloatArray::Pointer eulers = FloatArray::CreateArray(numElements, cDims, Bruker::IndexingResults::Eulers, true); cDims[0] = 1; - FloatArrayType::Pointer patQual = FloatArrayType::CreateArray(numElements, cDims, Bruker::IndexingResults::RadonQuality, true); - UInt16ArrayType::Pointer detectedBands = UInt16ArrayType::CreateArray(numElements, cDims, Bruker::IndexingResults::RadonBandCount, true); - Int16ArrayType::Pointer phases = Int16ArrayType::CreateArray(numElements, cDims, Bruker::IndexingResults::Phase, true); - UInt16ArrayType::Pointer indexedBands = UInt16ArrayType::CreateArray(numElements, cDims, Bruker::IndexingResults::NIndexedBands, true); - FloatArrayType::Pointer bmm = FloatArrayType::CreateArray(numElements, cDims, Bruker::IndexingResults::MAD, true); + FloatArray::Pointer patQual = FloatArray::CreateArray(numElements, cDims, Bruker::IndexingResults::RadonQuality, true); + UInt16Array::Pointer detectedBands = UInt16Array::CreateArray(numElements, cDims, Bruker::IndexingResults::RadonBandCount, true); + Int16Array::Pointer phases = Int16Array::CreateArray(numElements, cDims, Bruker::IndexingResults::Phase, true); + UInt16Array::Pointer indexedBands = UInt16Array::CreateArray(numElements, cDims, Bruker::IndexingResults::NIndexedBands, true); + FloatArray::Pointer bmm = FloatArray::CreateArray(numElements, cDims, Bruker::IndexingResults::MAD, true); - descFile = tempDir.path() + "/" + Bruker::Files::EBSDData + "/" + Bruker::Files::FrameDescription; - indexingResultsFile = tempDir.path() + "/" + Bruker::Files::EBSDData + "/" + Bruker::Files::IndexingResults; + descFile = tmpDir + "/" + Bruker::Files::EBSDData + "/" + Bruker::Files::FrameDescription; + indexingResultsFile = tmpDir + "/" + Bruker::Files::EBSDData + "/" + Bruker::Files::IndexingResults; err = BrukerDataLoader::LoadIndexingResults(descFile, indexingResultsFile, indices, eulers, patQual, detectedBands, phases, indexedBands, bmm, mapWidth, mapHeight, roi, m_Reorder); if(err < 0) { m_ErrorCode = -7050; - m_ErrorMessage = QString("Error Reading IndexingResults from extracted file: "); + m_ErrorMessage = std::string("Error Reading IndexingResults from extracted file: "); return; } // Write all the data to the HDF5 file with conversions - Int32ArrayType::Pointer i32Array = Int32ArrayType::CreateArray(numElements, Bruker::IndexingResults::XBEAM, true); + Int32Array::Pointer i32Array = Int32Array::CreateArray(numElements, Bruker::IndexingResults::XBEAM, true); for(size_t i = 0; i < numElements; i++) { auto value = static_cast(indices->getComponent(i, 0)); @@ -1052,15 +1113,15 @@ void BcfHdf5Convertor::execute() err = writeDataArrayToHdf5(i32Array.get(), semGrpId, numElements); // Convert from a single array of Eulers to 3 separate arrays and convert to degrees .. why? - std::vector names = {{Bruker::IndexingResults::phi1, Bruker::IndexingResults::PHI, Bruker::IndexingResults::phi2}}; + std::vector names = {{Bruker::IndexingResults::phi1, Bruker::IndexingResults::PHI, Bruker::IndexingResults::phi2}}; std::vector comp = {{0, 1, 2}}; - FloatArrayType::Pointer euler = FloatArrayType::CreateArray(numElements, Bruker::IndexingResults::phi1, true); + FloatArray::Pointer euler = FloatArray::CreateArray(numElements, Bruker::IndexingResults::phi1, true); for(size_t c = 0; c < 3; c++) { euler->setName(names.at(c)); for(size_t i = 0; i < numElements; i++) { - float value = eulers->getComponent(i, c) * SIMPLib::Constants::k_180OverPiD; + float value = eulers->getComponent(i, c) * 57.295779513082323; euler->setValue(i, value); } err = writeDataArrayToHdf5(euler.get(), dataGrpId, numElements); @@ -1102,59 +1163,59 @@ void BcfHdf5Convertor::execute() // Write all the Header information { - outputFile.clear(); + outFileStrm.str(""); outFileStrm << Bruker::Files::EBSDData << "/" << Bruker::Files::PhaseList; - QString phaseListFile = outputFile; + std::string phaseListFile = outFileStrm.str(); // std::cout << "Extracting PhaseList"; - err = sfsFile.extractFile(tempDir.path().toStdString(), phaseListFile.toStdString()); - phaseListFile = tempDir.path() + "/" + phaseListFile; + err = sfsFile.extractFile(tmpDir, phaseListFile); + phaseListFile = tmpDir + "/" + phaseListFile; if(err == 0) { - err = H5Lite::writeScalarDataset(headerGrpId, Bruker::Header::NCOLS.toStdString(), mapWidth); - err = H5Lite::writeScalarDataset(headerGrpId, Bruker::Header::NROWS.toStdString(), mapHeight); - err = H5Lite::writeScalarDataset(headerGrpId, Bruker::Header::NPoints.toStdString(), numElements); - err = H5Lite::writeStringDataset(headerGrpId, Bruker::Header::OriginalFile.toStdString(), m_InputFile.toStdString()); - err = H5Lite::writeScalarDataset(headerGrpId, Bruker::Header::PatternWidth.toStdString(), ebspWidth); - err = H5Lite::writeScalarDataset(headerGrpId, Bruker::Header::PatternHeight.toStdString(), ebspHeight); - err = H5Lite::writeStringDataset(headerGrpId, Bruker::Header::GridType.toStdString(), Bruker::Header::isometric.toStdString()); + err = H5Lite::writeScalarDataset(headerGrpId, Bruker::Header::NCOLS, mapWidth); + err = H5Lite::writeScalarDataset(headerGrpId, Bruker::Header::NROWS, mapHeight); + err = H5Lite::writeScalarDataset(headerGrpId, Bruker::Header::NPoints, numElements); + err = H5Lite::writeStringDataset(headerGrpId, Bruker::Header::OriginalFile, m_InputFile); + err = H5Lite::writeScalarDataset(headerGrpId, Bruker::Header::PatternWidth, ebspWidth); + err = H5Lite::writeScalarDataset(headerGrpId, Bruker::Header::PatternHeight, ebspHeight); + err = H5Lite::writeStringDataset(headerGrpId, Bruker::Header::GridType, Bruker::Header::isometric); double zOffset = 0.0; - err = H5Lite::writeScalarDataset(headerGrpId, Bruker::Header::ZOffset.toStdString(), zOffset); + err = H5Lite::writeScalarDataset(headerGrpId, Bruker::Header::ZOffset, zOffset); writePhaseInformation(headerGrpId, phaseListFile); } } // Write the SEM Data { - outputFile.clear(); + outFileStrm.str(""); outFileStrm << Bruker::Files::EBSDData << "/" << Bruker::Files::SEMImage; - QString semFile = outputFile; + std::string semFile = outFileStrm.str(); // std::cout << "Extracting SEIMImage"; - err = sfsFile.extractFile(tempDir.path().toStdString(), semFile.toStdString()); + err = sfsFile.extractFile(tmpDir, semFile); if(err < 0) { m_ErrorCode = -7060; - m_ErrorMessage = QString("Could not extract EBSDData/SEMImage File."); + m_ErrorMessage = std::string("Could not extract EBSDData/SEMImage File."); return; } - semFile = tempDir.path() + "/" + semFile; + semFile = tmpDir + "/" + semFile; writeSEMData(semGrpId, headerGrpId, semFile); } // Write the Calibration Data { - outputFile.clear(); + outFileStrm.str(""); outFileStrm << Bruker::Files::EBSDData << "/" << Bruker::Files::Calibration; - QString semFile = outputFile; + std::string semFile = outFileStrm.str(); // std::cout << "Extracting Calibration"; - err = sfsFile.extractFile(tempDir.path().toStdString(), semFile.toStdString()); + err = sfsFile.extractFile(tmpDir, semFile); if(err < 0) { m_ErrorCode = -7060; - m_ErrorMessage = QString("Could not extract EBSDData/Calibration File."); + m_ErrorMessage = std::string("Could not extract EBSDData/Calibration File."); return; } - semFile = tempDir.path() + "/" + semFile; + semFile = tmpDir + "/" + semFile; float pcx = 0.0f; float pcy = 0.0f; @@ -1174,18 +1235,18 @@ void BcfHdf5Convertor::execute() // Write the AuxIndexingOptions Data { - outputFile.clear(); + outFileStrm.str(""); outFileStrm << Bruker::Files::EBSDData << "/" << Bruker::Files::AuxIndexingOptions; - QString semFile = outputFile; + std::string semFile = outFileStrm.str(); // std::cout << "Extracting AuxIndexingOptions"; - err = sfsFile.extractFile(tempDir.path().toStdString(), semFile.toStdString()); + err = sfsFile.extractFile(tmpDir, semFile); if(err < 0) { m_ErrorCode = -7060; - m_ErrorMessage = QString("Could not extract EBSDData/AuxIndexingOptions File."); + m_ErrorMessage = std::string("Could not extract EBSDData/AuxIndexingOptions File."); return; } - semFile = tempDir.path() + "/" + semFile; + semFile = tmpDir + "/" + semFile; writeAuxIndexingOptions(semGrpId, headerGrpId, semFile); } @@ -1193,34 +1254,34 @@ void BcfHdf5Convertor::execute() int32_t pixelByteCount = 0; // Write the CameraConfiguration Data { - outputFile.clear(); + outFileStrm.str(""); outFileStrm << Bruker::Files::EBSDData << "/" << Bruker::Files::CameraConfiguration; - QString semFile = outputFile; + std::string semFile = outFileStrm.str(); // std::cout << "Extracting CameraConfiguration"; - err = sfsFile.extractFile(tempDir.path().toStdString(), semFile.toStdString()); + err = sfsFile.extractFile(tmpDir, semFile); if(err < 0) { m_ErrorCode = -7060; - m_ErrorMessage = QString("Could not extract EBSDData/CameraConfiguration File."); + m_ErrorMessage = std::string("Could not extract EBSDData/CameraConfiguration File."); return; } - semFile = tempDir.path() + "/" + semFile; + semFile = tmpDir + "/" + semFile; writeCameraConfiguration(semGrpId, headerGrpId, semFile); // Get the Pattern Pixel Byte Count err = H5Lite::readScalarDataset(headerGrpId, "PixelByteCount", pixelByteCount); } - outputFile.clear(); + outFileStrm.str(""); outFileStrm << Bruker::Files::EBSDData << "/" << Bruker::Files::FrameData; - QString dataFile = outputFile; + std::string dataFile = outFileStrm.str(); if(pixelByteCount == 1) { - writePatternData(sfsFile, H5T_NATIVE_UINT8, mapWidth, mapHeight, ebspWidth, ebspHeight, m_FlipPatterns, tempDir.path(), dataFile, descFile, dataGrpId); + writePatternData(sfsFile, H5T_NATIVE_UINT8, mapWidth, mapHeight, ebspWidth, ebspHeight, m_FlipPatterns, tmpDir, dataFile, descFile, dataGrpId); } else if(pixelByteCount == 2) { - writePatternData(sfsFile, H5T_NATIVE_UINT16, mapWidth, mapHeight, ebspWidth, ebspHeight, m_FlipPatterns, tempDir.path(), dataFile, descFile, dataGrpId); + writePatternData(sfsFile, H5T_NATIVE_UINT16, mapWidth, mapHeight, ebspWidth, ebspHeight, m_FlipPatterns, tmpDir, dataFile, descFile, dataGrpId); } } @@ -1231,7 +1292,7 @@ int32_t BcfHdf5Convertor::getErrorCode() const } // ----------------------------------------------------------------------------- -QString BcfHdf5Convertor::getErrorMessage() const +std::string BcfHdf5Convertor::getErrorMessage() const { return m_ErrorMessage; } diff --git a/src/BcfHdf5Convertor.h b/src/BcfHdf5Convertor.h index a341960..42fab3a 100644 --- a/src/BcfHdf5Convertor.h +++ b/src/BcfHdf5Convertor.h @@ -1,11 +1,11 @@ #pragma once -#include +#include class BcfHdf5Convertor { public: - BcfHdf5Convertor(QString inputFile, QString outputFile); + BcfHdf5Convertor(std::string inputFile, std::string outputFile); ~BcfHdf5Convertor(); BcfHdf5Convertor(const BcfHdf5Convertor&) = delete; // Copy Constructor Not Implemented @@ -18,13 +18,13 @@ class BcfHdf5Convertor void execute(); int32_t getErrorCode() const; - QString getErrorMessage() const; + std::string getErrorMessage() const; private: - QString m_InputFile; - QString m_OutputFile; + std::string m_InputFile; + std::string m_OutputFile; - QString m_ErrorMessage = QString("No Error"); + std::string m_ErrorMessage = std::string("No Error"); int32_t m_ErrorCode = 0; bool m_Reorder = false; bool m_FlipPatterns = false; diff --git a/src/BrukerIntegration/BrukerIntegrationConstants.h b/src/BrukerIntegration/BrukerIntegrationConstants.h new file mode 100644 index 0000000..27e01ea --- /dev/null +++ b/src/BrukerIntegration/BrukerIntegrationConstants.h @@ -0,0 +1,105 @@ +/* + * Your License should go here + */ +#pragma once + +#include + +/** +* @brief This namespace is used to define some Constants for the plugin itself. +*/ +namespace BrukerIntegrationConstants +{ + const std::string BrukerIntegrationPluginFile("BrukerIntegrationPlugin"); + const std::string BrukerIntegrationPluginDisplayName("BrukerIntegration"); + const std::string BrukerIntegrationBaseName("BrukerIntegration"); + + namespace FilterGroups + { + const std::string BrukerIntegrationFilters("Bruker Integration"); + } +} + +/** +* @brief Use this namespace to define any custom GUI widgets that collect FilterParameters +* for a filter. Do NOT define general reusable widgets here. +*/ +namespace FilterParameterWidgetType +{ + +/* const std::string SomeCustomWidget("SomeCustomWidget"); */ + +} + + + +namespace Bruker +{ + namespace Files + { + static const std::string EBSDData("EBSDData"); + static const std::string Auxiliarien("Auxiliarien"); + static const std::string AuxIndexingOptions("AuxIndexingOptions"); + static const std::string Calibration("Calibration"); + static const std::string CameraConfiguration("CameraConfiguration"); + static const std::string CameraLifeConfig("CameraLifeConfig"); + static const std::string FrameData("FrameData"); + static const std::string FrameDescription("FrameDescription"); + static const std::string ImgPreparation("ImgPreparation"); + static const std::string IndexingResults("IndexingResults"); + static const std::string Miszellaneen("Miszellaneen"); + static const std::string PhaseList("PhaseList"); + static const std::string RadonLines("RadonLines"); + static const std::string SEMImage("SEMImage"); + static const std::string ShownPhaseList("ShownPhaseList"); + static const std::string Version("Version"); + + } + + namespace IndexingResults + { + static const std::string XBEAM("X BEAM"); + static const std::string YBEAM("Y BEAM"); + static const std::string RadonQuality("RadonQuality"); + static const std::string RadonBandCount("RadonBandCount"); + static const std::string Eulers("EulerAngles"); + static const std::string Phase("Phase"); + static const std::string NIndexedBands("NIndexedBands"); + static const std::string MAD("MAD"); + static const std::string EBSP("RawPatterns"); + static const std::string phi1("phi1"); + static const std::string PHI("PHI"); + static const std::string phi2("phi2"); + } // namespace IndexingResults + + namespace Header + { + static const std::string NCOLS("NCOLS"); + static const std::string NPoints("NPoints"); + static const std::string NROWS("NROWS"); + static const std::string OriginalFile("OriginalFile"); + static const std::string PatternHeight("PatternHeight"); + static const std::string PatternWidth("PatternWidth"); + static const std::string GridType("Grid Type"); + static const std::string isometric("isometric"); + static const std::string Phases("Phases"); + static const std::string ZOffset("ZOffset"); + } // namespace Header + + namespace SEM { + static const std::string SEM("SEM"); + static const std::string SEMIX("SEM IX"); + static const std::string SEMIY("SEM IY"); + } +} + + +namespace BlueQuartz +{ + const std::string VendorName("BlueQuartz Software, LLC"); + const std::string URL("http://www.bluequartz.net"); + const std::string Copyright("(C) 2016-2019 BlueQuartz Software, LLC"); +} + + + diff --git a/src/BrukerIntegration/BrukerIntegrationStructs.h b/src/BrukerIntegration/BrukerIntegrationStructs.h new file mode 100644 index 0000000..9fe0d7a --- /dev/null +++ b/src/BrukerIntegration/BrukerIntegrationStructs.h @@ -0,0 +1,52 @@ +#pragma once + +#include +#include +#include + + +/* + * @brief These structs are ONLY validated against the Version 6 of the Indexing Results. This + * version information can be found in the fie "Version" that is extract from the .bcf file. + * Any updates to the IndexingResults format can change without notice from Bruker. + */ + +#pragma pack(push) /* push current alignment to stack */ +#pragma pack(1) /* set alignment to 1 byte boundary */ + +typedef struct { + int32_t width; + int32_t height; + int32_t patternCount; +} FrameDescriptionHeader_t; + + +typedef struct +{ + int xIndex; // The x index of this pattern + int yIndex; // The y index of this pattern + int dataSize; // The data size (Width* height * bytes per pixel + 17) + int width; // The Width in pixels of the pattern + int height; // The Height in pixels of the pattern + int bytesPerPixel; // Bytes per pixel + unsigned char pixelFormat; // Pixel Format. Can be ignored in this version. +} FrameDataHeader_t; + +typedef struct +{ + uint16_t xIndex; + uint16_t yIndex; + float radonQuality; + uint16_t detectedBands; + float euler1; // radians + float euler2; // radians + float euler3; // radians + int16_t phase; //Has byte value of 0xFFFF + uint16_t indexedBands; + float bmm; +} IndexResult_t; + +#pragma pack(pop) /* restore original alignment from stack */ + + + diff --git a/src/BrukerIntegrationFilters/BrukerDataLoader.cpp b/src/BrukerIntegrationFilters/BrukerDataLoader.cpp new file mode 100644 index 0000000..bb6cda6 --- /dev/null +++ b/src/BrukerIntegrationFilters/BrukerDataLoader.cpp @@ -0,0 +1,598 @@ +/* ============================================================================ + * Copyright (c) 2013 Michael A. Jackson (BlueQuartz Software) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * Neither the name of Michael A. Jackson, + * BlueQuartz Software nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This code was written under United States Air Force Contract number + * FA8650-07-D-5800 + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +#include "BrukerDataLoader.h" + +#include "EbsdLib/Core/EbsdLibConstants.h" + +#include "BrukerIntegration/BrukerIntegrationConstants.h" +#include "BrukerIntegration/BrukerIntegrationStructs.h" + +#include "StringUtilities.hpp" + +#include +#include +#include +#include +#include +#include + +#ifdef SIMPL_USE_GHC_FILESYSTEM +#include +namespace fs = ghc::filesystem; +#else +#include +namespace fs = std::filesystem; +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* pi */ +#endif + + +//using namespace BrukerEbsdXml; + +#if defined(__GNUC__) && !defined(__APPLE__) +#define BDL_POS(var) var.__pos +#else +#define BDL_POS(var) var +#endif + +// ----------------------------------------------------------------------------- +BrukerDataLoader::BrukerDataLoader() = default; + +// ----------------------------------------------------------------------------- +BrukerDataLoader::~BrukerDataLoader() = default; + +#if 0 +// ----------------------------------------------------------------------------- +EbsdPatterns::Pointer BrukerDataLoader::LoadPatternData(const std::string& descFile, const std::string& dataFile) +{ + QFileInfo descFileInfo(descFile); + if(!descFileInfo.exists()) + { + std::cout << "The FrameDescription File does not exist: '" << descFile << "'"; + return EbsdPatterns::NullPointer(); + } + + QFileInfo dataFileInfo(dataFile); + if(!dataFileInfo.exists()) + { + std::cout << "The FrameData File does not exist: '" << dataFile << "'"; + return EbsdPatterns::NullPointer(); + } + + FILE* desc = fopen(descFile.c_str(), "rb"); + if (nullptr == desc) + { + std::cout << "Could not open the FrameDescription File"; + return EbsdPatterns::NullPointer(); + } + + qint64 filesize = dataFileInfo.size(); + + // Get the total number of patterns from the FrameData file + FrameDescriptionHeader_t descHeader; + size_t nRead = fread(&descHeader, sizeof(int32_t), 3, desc); + if (nRead != 3) + { + std::cout << "Could not read the header values. Only " << nRead << " values were parsed"; + fclose(desc); + return EbsdPatterns::NullPointer(); + } + fclose(desc); + desc = nullptr; + + int32_t xStart = 0; + int32_t yStart = 0; + int32_t xEnd = descHeader.width; + int32_t yEnd = descHeader.height; + + // Open the Frame Data File + FILE* f = fopen(dataFile.c_str(), "rb"); + if (nullptr == f) + { + std::cout << "Could not open the FrameData File"; + return EbsdPatterns::NullPointer(); + } + + //Read the first pattern header which will give us the height & width of the actual pattern data. + FrameDataHeader_t patternHeader; + nRead = fread(&patternHeader, 1, 25, f); + if (nRead != 25) + { + std::cout << "Could not read the Frame Data Header values. Only " << nRead << " values were parsed"; + fclose(f); + return EbsdPatterns::NullPointer(); + } + + // Put the file pointer back to the start of the file + rewind(f); + + UInt8Array::Pointer patternDataPtr = UInt8ArrayType::NullPointer(); + + int32_t patternDataByteCount = patternHeader.width * patternHeader.height; + + // Loop through all the patterns loading them into memory. The Bruker Pattern data is NOT guaranteed to be in the + // correct order. So while we are looping over the number of patterns in the x and y directions we are going to + // read the pattern header to definitively get the proper XY index of the pattern, calculate the proper offset + // into the array and read the data into that position + QFileInfo fi(dataFile); + std::vector cDims(2); + cDims[1] = patternHeader.height; + cDims[0] = patternHeader.width; + patternDataPtr = UInt8ArrayType::CreateArray(descHeader.width * descHeader.height, cDims, "EBSPData", true); + patternDataPtr->initializeWithValue(0x00); + // size_t increment = patternHeader.width * patternHeader.height + 25; + // size_t offset = 0; + float progress = 0.0f; + float currentProgress = 0.0f; + size_t numPatterns = yEnd * xEnd; + size_t i = 0; + for(int32_t y = yStart; y < yEnd; y++) + { + for(int32_t x = xStart; x < xEnd; x++) + { + + currentProgress = static_cast(i) / static_cast(numPatterns); + if(currentProgress > progress) + { + progress = progress + 0.01f; + std::cout << fi.fileName().toStdString() << " [" << static_cast(currentProgress * 100.0f) << "%]\r"; + std::cout.flush(); + } + i++; + + fpos_t pos; + fgetpos(f, &pos); + + // Read the Header for the next pattern + nRead = fread(&patternHeader, 1, 25, f); + // We hit the end of the file, which is bad... + if(feof(f) != 0) + { + std::cout << "End of file hit early. Not all expected patterns were extracted." << std::endl; + y = yEnd; + x = xEnd; + break; + } + + size_t tupleIndex = (descHeader.width * patternHeader.yIndex) + patternHeader.xIndex; + // Read the Data associated with the header that was read. + fgetpos(f, &pos); + nRead = fread(patternDataPtr->getTuplePointer(tupleIndex), 1, patternDataByteCount, f); + + if(feof(f) != 0) + { + std::cout << "Unexpected End of File (EOF) was encountered. Details follow" << std::endl; + std::cout << "File Size: " << filesize << std::endl; + std::cout << "ferror(f) = " << ferror(f) << " feof(f) = " << feof(f) << std::endl; + //std::cout << "File Pos When Reading: " << static_cast(pos) << std::endl; + printf("File Pos When Reading: %llu\n", static_cast(BDL_POS(pos))); + fgetpos(f, &pos); + std::cout << "error reading data file: nRead=" << nRead << " but needed: " << patternDataByteCount << std::endl; + printf(" Current File Position: %llu\n", static_cast(BDL_POS(pos))); + std::cout << "X,Y Position from Pattern Header: " << patternHeader.xIndex << " , " << patternHeader.yIndex << std::endl; + y = yEnd; + x = xEnd; + break; + } + } + if(patternDataPtr.get() == nullptr) + { + break; + } + } + fclose(f); + + + EbsdPatterns::Pointer patterns = EbsdPatterns::New(); + patterns->setImageWidth(descHeader.width); + patterns->setImageHeight(descHeader.height); + patterns->setPatternWidth(patternHeader.width); + patterns->setPatternHeight(patternHeader.height); + patterns->setPatternData(patternDataPtr); + patterns->setIsValid(patternDataPtr.get() != nullptr); + + return patterns; +} + +#endif + +// ----------------------------------------------------------------------------- +int BrukerDataLoader::LoadIndexingResults(const std::string& descFile, const std::string& dataFile, const UInt16Array::Pointer& positions, const FloatArray::Pointer& eulers, + const FloatArray::Pointer& patQual, const UInt16Array::Pointer& detectedBands, const Int16Array::Pointer& phase, + const UInt16Array::Pointer& indexedBands, const FloatArray::Pointer& bmm, int32_t& mapWidth, int32_t& mapHeight, std::vector& roi, + bool reorder) +{ + + fs::path descFileInfo(descFile); + if(!fs::exists(descFileInfo)) + { + std::cout << "The FrameDescription File does not exist: '" << descFile << "'"; + return -1000; + } + + fs::path dataFileInfo(dataFile); + if(!fs::exists(dataFileInfo)) + { + std::cout << "The Indexing Result File does not exist: '" << dataFile << "'"; + return -1001; + } + + FILE* desc = fopen(descFile.c_str(), "rb"); + if (nullptr == desc) + { + std::cout << "Could not open the FrameDescription File"; + return -1003; + } + + // Get the total number of scan points from the FrameData file + FrameDescriptionHeader_t descHeader; + size_t nRead = fread(&descHeader, sizeof(int32_t), 3, desc); + if (nRead != 3) + { + std::cout << "Could not read the header values. Only " << nRead << " values were parsed"; + fclose(desc); + return -1004; + } + fclose(desc); + desc = nullptr; + + mapWidth = descHeader.width; + mapHeight = descHeader.height; + + // Now get all the array pointers. The arrays were pre-allocated already + uint16_t* posPtr = positions->getPointer(0); + positions->initializeWithZeros(); + + float* euPtr = eulers->getPointer(0); + eulers->initializeWithZeros(); + + float* pq = patQual->getPointer(0); + patQual->initializeWithZeros(); + + uint16_t* detBnds = detectedBands->getPointer(0); + detectedBands->initializeWithZeros(); + + int16_t* ph = phase->getPointer(0); + phase->initializeWithZeros(); + + uint16_t* idxBnds = indexedBands->getPointer(0); + indexedBands->initializeWithZeros(); + + float* bmmPtr = bmm->getPointer(0); + bmm->initializeWithZeros(); + + int64_t filesize = static_cast(fs::file_size(dataFileInfo)); + + FILE* f = fopen(dataFile.c_str(), "rb"); + if(nullptr == f) + { + std::cout << "Could not open Indexing Results file at " << dataFile; + return -1005; + } + + nRead = 0; + + uint8_t data[30]; + IndexResult_t* record = reinterpret_cast(data); + size_t index = 0; + uint16_t minX = std::numeric_limits::max(); + uint16_t maxX = std::numeric_limits::min(); + uint16_t minY = std::numeric_limits::max(); + uint16_t maxY = std::numeric_limits::min(); + size_t scannedPointCount = 0; + fpos_t pos; + fgetpos(f, &pos); +#if defined(Q_OS_LINUX) + while(pos.__pos < filesize) +#else + while(pos < filesize) +#endif + { + ::memset(data, 0, 30); // Splat zeros across the structure. + nRead = fread(&data, 1, 30, f); + if(feof(f) != 0) + { + std::cout << "BrukerDataLoader: " + << "Unexpected End of File (EOF) was encountered. Details follow" << std::endl; + std::cout << " ferror(f) = " << ferror(f) << " feof(f) = " << feof(f) << std::endl; + // std::cout << "File Pos When Reading: " << static_cast(pos) << std::endl; + printf(" File Pos When Reading: %llu\n", static_cast(BDL_POS(pos))); + fgetpos(f, &pos); + printf(" Current File Position: %llu\n", static_cast(BDL_POS(pos))); + break; + } + scannedPointCount++; + // Calculate the proper index to place the data as the data is out of order in the file, but only if requested. FALSE by default + if(reorder) + { + index = (mapWidth * record->yIndex) + record->xIndex; + } + + if(record->xIndex > maxX) + { + maxX = record->xIndex; + } + if(record->xIndex < minX) + { + minX = record->xIndex; + } + + if(record->yIndex > maxY) + { + maxY = record->yIndex; + } + if(record->yIndex < minY) + { + minY = record->yIndex; + } + + posPtr[index * 2] = record->xIndex; + posPtr[index * 2 + 1] = record->yIndex; + + euPtr[index * 3] = (M_PI - record->euler3); + euPtr[index * 3 + 1] = record->euler2; + euPtr[index * 3 + 2] = (M_PI - record->euler1); + + pq[index] = record->radonQuality; + detBnds[index] = record->detectedBands; + ph[index] = record->phase; + idxBnds[index] = record->indexedBands; + bmmPtr[index] = record->bmm; + index++; + fgetpos(f, &pos); + + // if((y != record->yIndex || x != record->xIndex) && debug) + // { + // debug = false; + // std::cout << "Index Value(s) Do(es) not match: " << x << "," << y << " vs " << record->xIndex << "," << record->yIndex << std::endl; + // std::cout << "Data: " << record->xIndex << "\t" << record->yIndex << "\t" << record->euler1 << "\t" << record->euler2 << "\t" << record->euler3 << "\t" << record->radonQuality << "\t" + // << record->detectedBands << "\t" << record->phase << "\t" << record->indexedBands << "\t" << record->bmm << std::endl; + // } + } + + roi.resize(4); + roi[0] = minX; + roi[1] = minY; + roi[2] = maxX; + roi[3] = maxY; + std::cout << "ROI: (" << minX << ", " << minY << ") -> (" << maxX << ", " << maxY << ")" << std::endl; + std::cout << "Total Measured Points: " << scannedPointCount << std::endl; + fclose(f); + return 0; +} + +// ----------------------------------------------------------------------------- +void parseIntValue(const std::string& line, int& value) +{ + auto tokens = complex::StringUtilities::split_2(line, '='); + value = stoi(tokens[1]); +} + + +// ----------------------------------------------------------------------------- +int BrukerDataLoader::ReadScanSizes(const std::string& path, int32_t& mapWidth, int32_t& mapHeight, + int32_t& ebspWidth, int32_t& ebspHeight) +{ + /* The file contents should be the following: + * AcquisitionStep=1 + SEMImgWidth=512 + SEMImgHeight=384 + MapWidth=512 + MapHeight=384 + EBSPWidth=80 + EBSPHeight=60 + ChannelNameCount=1 + ChannelName0=SE + MeasurementDuration=-1 + MaxRadonBandCount=12 + */ + + std::string filePath = path + "/" + Bruker::Files::Auxiliarien; + if(!fs::exists(filePath)) + { + return -1; + } + + std::string contents; + { + std::ifstream source(filePath); + + source.seekg(0, std::ios::end); + contents.reserve(source.tellg()); + source.seekg(0, std::ios::beg); + + contents.assign((std::istreambuf_iterator(source)), std::istreambuf_iterator()); + } + + auto list = complex::StringUtilities::split_2(contents, '\n'); + for(const auto& line : list) + { + if(complex::StringUtilities::contains(line, "MapWidth")) + { + parseIntValue(line, mapWidth); + } + else if(complex::StringUtilities::contains(line,"MapHeight")) + { + parseIntValue(line, mapHeight); + } + else if(complex::StringUtilities::contains(line,"EBSPWidth")) + { + parseIntValue(line, ebspWidth); + } + else if(complex::StringUtilities::contains(line,"EBSPHeight")) + { + parseIntValue(line, ebspHeight); + } + } + + return 1; +} + + + +#if 0 +// ----------------------------------------------------------------------------- +std::string BrukerDataLoader::VerifyRequiredFiles(const std::string& path) +{ + std::string errString; + + std::stringList files; + files << Bruker::Files::Auxiliarien << Bruker::Files::AuxIndexingOptions << Bruker::Files::Calibration + << Bruker::Files::CameraConfiguration << Bruker::Files::CameraLifeConfig << Bruker::Files::FrameData + << Bruker::Files::FrameDescription << Bruker::Files::ImgPreparation << Bruker::Files::IndexingResults + << Bruker::Files::Miszellaneen << Bruker::Files::PhaseList << Bruker::Files::RadonLines + << Bruker::Files::SEMImage << Bruker::Files::ShownPhaseList << Bruker::Files::Version; + + + std::stringListIterator iter(files); + while(iter.hasNext()) + { + std::string file = iter.next(); + QFileInfo fi(path + "/" + file); + if(!fi.exists()) + { + std::string str = std::string("File path does not exist: '%1'\n").arg(fi.absoluteFilePath()); + errString.append(str); + } + } + return errString; +} +#endif + +#if 0 +// ----------------------------------------------------------------------------- +int BrukerDataLoader::ReadCrystalSymmetries(const std::string& path, const UInt32Array::Pointer& xtal) +{ + + std::string filePath = path + "/" + Bruker::Files::PhaseList; + + + QFileInfo fi(filePath); + if(!fi.exists()) + { + std::cout << "BrukerDataLoader::ReadPhaseInformation Input file does not exist" << std::endl; + return -1000; + } + + QFile xmlFile(filePath); + + QIODevice* device = &xmlFile; + + QDomDocument domDocument; + std::string errorStr; + int errorLine; + int errorColumn; + if (!domDocument.setContent(device, true, &errorStr, &errorLine, &errorColumn)) + { + std::string errormessage("Parse error at line %1, column %2:\n%3"); + errormessage = errormessage.arg(errorLine).arg(errorColumn).arg(errorStr); + return 0; + } + QDomElement root = domDocument.documentElement(); + std::string nodeName = root.nodeName(); + QDomNodeList nodeList = root.elementsByTagName("ClassInstance"); + for(int i = 0; i < nodeList.size(); ++i) + { + QDomElement e = nodeList.at(i).toElement(); + std::string eType = e.attribute("Type"); + if (nodeName.compare(eType) == 0) + { + root = e; + break; + } + } + + TEBSDExtPhaseEntryList topLevel; + topLevel.parse(root); + + QVector phases = topLevel.getTEBSDExtPhaseEntry_vec(); + + xtal->resizeTuples(phases.size() + 1); + xtal->setValue(0, EbsdLib::CrystalStructure::UnknownCrystalStructure); + + for(size_t i = 0; i < phases.size(); i++) + { + TEBSDPhaseEntry::Pointer phase = phases[i]->getTEBSDPhaseEntry(); + // std::cout << "Phase List"; + // std::cout << phase->getCC(); + // std::cout << phase->getSG(); + // This could be put into the "Material Name" array + // std::cout << phase->getChem(); + Cell::Pointer cell = phase->getCell(); + // These could be put into the Lattice Constants Array + // std::cout << cell->getAngles(); + // std::cout << cell->getDim(); + + if(phase->getCC().compare("CUB") == 0) + { + xtal->setValue(i + 1, EbsdLib::CrystalStructure::Cubic_High); // This is a TOTAL GUESS!!!! + } + else + { + xtal->setValue(i + 1, EbsdLib::CrystalStructure::UnknownCrystalStructure); // This is a TOTAL GUESS!!!! + } + } + + return 0; +} +#endif + +// ----------------------------------------------------------------------------- +BrukerDataLoader::Pointer BrukerDataLoader::NullPointer() +{ + return Pointer(static_cast(nullptr)); +} + +// ----------------------------------------------------------------------------- +BrukerDataLoader::Pointer BrukerDataLoader::New() +{ + Pointer sharedPtr(new(BrukerDataLoader)); + return sharedPtr; +} + +// ----------------------------------------------------------------------------- +std::string BrukerDataLoader::getNameOfClass() const +{ + return std::string("BrukerDataLoader"); +} + +// ----------------------------------------------------------------------------- +std::string BrukerDataLoader::ClassName() +{ + return std::string("BrukerDataLoader"); +} diff --git a/src/BrukerIntegrationFilters/BrukerDataLoader.h b/src/BrukerIntegrationFilters/BrukerDataLoader.h new file mode 100644 index 0000000..955e0b8 --- /dev/null +++ b/src/BrukerIntegrationFilters/BrukerDataLoader.h @@ -0,0 +1,137 @@ +/* ============================================================================ + * Copyright (c) 2013 Michael A. Jackson (BlueQuartz Software) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * Neither the name of Michael A. Jackson, + * BlueQuartz Software nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This code was written under United States Air Force Contract number + * FA8650-07-D-5800 + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +#pragma once + + +#include "EbsdPatterns.h" +#include "EbsdLib/Core/EbsdDataArray.hpp" + +using namespace EbsdLib; + +#include +#include + + + +class BrukerDataLoader +{ + public: + using Self = BrukerDataLoader; + using Pointer = std::shared_ptr; + using ConstPointer = std::shared_ptr; + using WeakPointer = std::weak_ptr; + using ConstWeakPointer = std::weak_ptr; + static Pointer NullPointer(); + + static Pointer New(); + + /** + * @brief Returns the name of the class for BrukerDataLoader + */ + virtual std::string getNameOfClass() const; + /** + * @brief Returns the name of the class for BrukerDataLoader + */ + static std::string ClassName(); + + virtual ~BrukerDataLoader(); + + /** + * @brief loadDataFromFile + * @param descFileName + * @param dataFile + * @return + */ + static EbsdPatterns::Pointer LoadPatternData(const std::string& descFileName, const std::string& dataFile); + + /** + * @brief LoadIndexingResults + * @param descFile + * @param dataFile + * @param positions + * @param eulers + * @param patQual + * @param detBands + * @param phase + * @param indexedBands + * @param bmm + * @param mapWidth + * @param mapHeight + * @return + */ + static int LoadIndexingResults(const std::string& descFile, const std::string& dataFile, const UInt16Array::Pointer& positions, const FloatArray::Pointer& eulers, + const FloatArray::Pointer& patQual, const UInt16Array::Pointer& detectedBands, const Int16Array::Pointer& phase, + const UInt16Array::Pointer& indexedBands, const FloatArray::Pointer& bmm, int32_t& mapWidth, int32_t& mapHeight, std::vector& roi, + bool reorder = false); + + /** + * @brief ReadScanSizes + * @param mapWidth + * @param mapHeight + * @param ebspWidth + * @param ebspHeight + * @return + */ + static int ReadScanSizes(const std::string &path, int32_t &mapWidth, int32_t &mapHeight, int32_t &ebspWidth, int32_t &ebspHeight); + + /** + * @brief VerifyRequiredFiles + * @param path + * @return + */ + static std::string VerifyRequiredFiles(const std::string &path); + + /** + * @brief ReadPhaseInformation + * @param path + */ + static int ReadCrystalSymmetries(const std::string& path, const UInt32Array::Pointer& xtal); + + protected: + BrukerDataLoader(); + + public: + BrukerDataLoader(const BrukerDataLoader&) = delete; // Copy Constructor Not Implemented + BrukerDataLoader(BrukerDataLoader&&) = delete; // Move Constructor Not Implemented + BrukerDataLoader& operator=(const BrukerDataLoader&) = delete; // Copy Assignment Not Implemented + BrukerDataLoader& operator=(BrukerDataLoader&&) = delete; // Move Assignment Not Implemented + + private: +}; + + + + diff --git a/src/BrukerIntegrationFilters/EbsdPatterns.cpp b/src/BrukerIntegrationFilters/EbsdPatterns.cpp new file mode 100644 index 0000000..7807e08 --- /dev/null +++ b/src/BrukerIntegrationFilters/EbsdPatterns.cpp @@ -0,0 +1,425 @@ +/* ============================================================================ + * Copyright (c) 2013 Michael A. Jackson (BlueQuartz Software) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * Neither the name of Michael A. Jackson, + * BlueQuartz Software nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This code was written under United States Air Force Contract number + * FA8650-07-D-5800 + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +#include "EbsdPatterns.h" + +#ifdef SIMPL_USE_PARALLEL_ALGORITHMS +#include +#include +#include +#include +#endif + +#include "BrukerIntegration/BrukerIntegrationStructs.h" + +using namespace EbsdLib; + +//#include "SIMPLib/FilterParameters/AbstractFilterParametersReader.h" +//#include "BrukerIntegration/BrukerIntegrationConfig.h" + +#ifdef HAVE_SSE_EXTENSIONS +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +float dot_product_intrin(float* a, float* b, int size) +{ + //float arr[4]; + float total; + int i; + __m128 num1, num2, num3, num4; + num4 = _mm_setzero_ps(); //sets sum to zero + for(i = 0; i < size; i += 4) + { + num1 = _mm_loadu_ps(a + i); //loads unaligned array a into num1 num1= a[3] a[2] a[1] a[0] + num2 = _mm_loadu_ps(b + i); //loads unaligned array b into num2 num2= b[3] b[2] b[1] b[0] + num3 = _mm_mul_ps(num1, num2); //performs multiplication num3 = a[3]*b[3] a[2]*b[2] a[1]*b[1] a[0]*b[0] + num3 = _mm_hadd_ps(num3, num3); //performs horizontal addition + //num3= a[3]*b[3]+ a[2]*b[2] a[1]*b[1]+a[0]*b[0] a[3]*b[3]+ a[2]*b[2] a[1]*b[1]+a[0]*b[0] + num4 = _mm_add_ps(num4, num3); //performs vertical addition + } + num4 = _mm_hadd_ps(num4, num4); + _mm_store_ss(&total, num4); + return total; +} + +#endif + + +/** + * @brief + */ +class ComputeDotProductsImpl +{ + EbsdPatterns* m_Patterns; + UInt64Array* m_Dots; + + public: + ComputeDotProductsImpl(EbsdPatterns* patterns, UInt64Array* dots) : + m_Patterns(patterns), + m_Dots(dots) + { + } + + virtual ~ComputeDotProductsImpl() = default; + + // ----------------------------------------------------------------------------- + // + // ----------------------------------------------------------------------------- + void convert(int yStart, int yEnd, int xStart, int xEnd) const + { + + uint8_t* pattern = nullptr; + int32_t iWidth = m_Patterns->getImageWidth(); + uint64_t* dots = m_Dots->getPointer(0); + + size_t count = m_Patterns->getPatternWidth() * m_Patterns->getPatternHeight(); + uint64_t total = 0; + size_t dotsIdx = 0; + for(int y = yStart; y < yEnd; ++y) + { + for(int x = xStart; x < xEnd; ++x) + { + dotsIdx = (y * iWidth) + x; + total = 0; + // Get the pattern for the Image Pixel(x,y) + pattern = m_Patterns->getPatternPointer(x, y); + for(size_t i = 0; i < count; ++i) + { + total = total + *pattern * *pattern; + pattern = pattern + 1; // increment the pointer + } + dots[dotsIdx] = total; + } + } + } + +#ifdef SIMPL_USE_PARALLEL_ALGORITHMS + void operator()(const tbb::blocked_range2d& r) const + { + convert(r.rows().begin(), r.rows().end(), r.cols().begin(), r.cols().end()); + } +#endif + + private: + +}; + + +class SubtractMeanPatternImpl +{ + EbsdPatterns* m_Patterns; + FloatArray::Pointer m_MeanPattern; + FloatArray::Pointer m_Results; + + public: + SubtractMeanPatternImpl(EbsdPatterns* patterns, FloatArray::Pointer meanPattern, FloatArray::Pointer results) : + m_Patterns(patterns), + m_MeanPattern(meanPattern), + m_Results(results) + { } + virtual ~SubtractMeanPatternImpl() = default; + // ----------------------------------------------------------------------------- + // + // ----------------------------------------------------------------------------- + void convert(int yStart, int yEnd, int xStart, int xEnd) const + { + + uint8_t* pattern = nullptr; + int32_t iWidth = m_Patterns->getImageWidth(); + float* mean = m_MeanPattern->getPointer(0); + float* result = nullptr; + size_t count = m_Patterns->getPatternWidth() * m_Patterns->getPatternHeight(); + for(int y = yStart; y < yEnd; ++y) + { + for(int x = xStart; x < xEnd; ++x) + { + int index = (y * iWidth) + x; + // Get the pattern for the Image Pixel(x,y) + pattern = m_Patterns->getPatternPointer(x, y); + result = m_Results->getTuplePointer(index); + for(size_t i = 0; i < count; ++i) + { + result[i] = (static_cast(pattern[i]) - mean[i]); + } + } + } + } + +#ifdef SIMPL_USE_PARALLEL_ALGORITHMS + void operator()(const tbb::blocked_range2d& r) const + { + convert(r.rows().begin(), r.rows().end(), r.cols().begin(), r.cols().end()); + } +#endif + + private: +}; + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +EbsdPatterns::EbsdPatterns() = default; + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +EbsdPatterns::~EbsdPatterns() = default; + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +int EbsdPatterns::getPatternCount() +{ + return getImageHeight() * getImageWidth(); +} + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +int EbsdPatterns::getPerPatternElementCount() +{ + return getPatternHeight() * getPatternWidth(); +} + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +EbsdPatterns::Pointer EbsdPatterns::createSameSizePatterns() +{ + EbsdPatterns::Pointer ptr = EbsdPatterns::New(); + ptr->setImageHeight(m_ImageHeight); + ptr->setImageWidth(m_ImageWidth); + ptr->setPatternHeight(m_PatternHeight); + ptr->setPatternWidth(m_PatternWidth); + + std::vector cDims(2); + cDims[0] = m_PatternWidth; + cDims[1] = m_PatternHeight; + UInt8Array::Pointer data = UInt8Array::CreateArray(m_ImageHeight * m_ImageWidth, cDims, "EbsdPatterns", true); + data->initializeWithZeros(); + ptr->setPatternData(data); + return ptr; +} + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +uint8_t* EbsdPatterns::getPatternPointer(int32_t x, int32_t y) +{ + int64_t index = (y * m_ImageWidth) + x; + if (index < 0) { return nullptr; } + return m_PatternData->getTuplePointer(index); +} + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +uint8_t* EbsdPatterns::getPatternPointer(size_t index) +{ + if(!getIsValid()) + { + return nullptr; + } + return m_PatternData->getTuplePointer(index); +} + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +FloatArray::Pointer EbsdPatterns::computeMeanPattern() +{ + int32_t numPatterns = m_ImageWidth * m_ImageHeight; + int32_t patternDataByteCount = m_PatternWidth * m_PatternHeight; + uint8_t* buffer = nullptr; + + EbsdDataArray::Pointer meanPtr = EbsdDataArray::CreateArray((size_t)patternDataByteCount, std::string("MeanPattern"), true); + meanPtr->initializeWithZeros(); + float* mean = meanPtr->getPointer(0); + + for(int32_t i = 0; i < numPatterns; ++i) + { + // Get the pointer to the Pattern at index i + buffer = m_PatternData->getTuplePointer(i); + // Loop over each byte in the pattern and increment the total in the mean pattern + for(int i = 0; i < patternDataByteCount; ++i) + { + mean[i] = mean[i] + buffer[i]; + } + } + + // Loop over each pixel in the mean pattern and divide by the total number of patterns. + for(int i = 0; i < patternDataByteCount; ++i) + { + mean[i] = static_cast(mean[i] / numPatterns); + } + return meanPtr; +} + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +UInt64Array::Pointer EbsdPatterns::computeDotProducts() +{ + + UInt64Array::Pointer dots = UInt64Array::CreateArray(m_ImageWidth * m_ImageHeight, std::string("DotProducts"), true); + +#ifdef SIMPL_USE_PARALLEL_ALGORITHMS + tbb::parallel_for(tbb::blocked_range2d(0, m_ImageHeight, 0, m_ImageWidth), + ComputeDotProductsImpl(this, dots.get()), tbb::auto_partitioner()); + +#else + ComputeDotProductsImpl serial(this, dots.get()); + serial.convert(0, m_ImageHeight, 0, m_ImageWidth); +#endif + + + return dots; +} + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +void EbsdPatterns::subtractMeanPattern(FloatArray::Pointer meanPtr, FloatArray::Pointer results) +{ +#ifdef SIMPL_USE_PARALLEL_ALGORITHMS + tbb::parallel_for(tbb::blocked_range2d(0, m_ImageHeight, 0, m_ImageWidth), + SubtractMeanPatternImpl(this, meanPtr, results), tbb::auto_partitioner()); + +#else + SubtractMeanPatternImpl serial(this, meanPtr, results); + serial.convert(0, m_ImageHeight, 0, m_ImageWidth); +#endif + + +} + +// ----------------------------------------------------------------------------- +EbsdPatterns::Pointer EbsdPatterns::NullPointer() +{ + return Pointer(static_cast(nullptr)); +} + +// ----------------------------------------------------------------------------- +EbsdPatterns::Pointer EbsdPatterns::New() +{ + Pointer sharedPtr(new(EbsdPatterns)); + return sharedPtr; +} + +// ----------------------------------------------------------------------------- +std::string EbsdPatterns::getNameOfClass() const +{ + return std::string("EbsdPatterns"); +} + +// ----------------------------------------------------------------------------- +std::string EbsdPatterns::ClassName() +{ + return std::string("EbsdPatterns"); +} + +// ----------------------------------------------------------------------------- +void EbsdPatterns::setImageWidth(int32_t value) +{ + m_ImageWidth = value; +} + +// ----------------------------------------------------------------------------- +int32_t EbsdPatterns::getImageWidth() const +{ + return m_ImageWidth; +} + +// ----------------------------------------------------------------------------- +void EbsdPatterns::setImageHeight(int32_t value) +{ + m_ImageHeight = value; +} + +// ----------------------------------------------------------------------------- +int32_t EbsdPatterns::getImageHeight() const +{ + return m_ImageHeight; +} + +// ----------------------------------------------------------------------------- +void EbsdPatterns::setPatternWidth(int32_t value) +{ + m_PatternWidth = value; +} + +// ----------------------------------------------------------------------------- +int32_t EbsdPatterns::getPatternWidth() const +{ + return m_PatternWidth; +} + +// ----------------------------------------------------------------------------- +void EbsdPatterns::setPatternHeight(int32_t value) +{ + m_PatternHeight = value; +} + +// ----------------------------------------------------------------------------- +int32_t EbsdPatterns::getPatternHeight() const +{ + return m_PatternHeight; +} + +// ----------------------------------------------------------------------------- +void EbsdPatterns::setPatternData(const UInt8Array::Pointer& value) +{ + m_PatternData = value; +} + +// ----------------------------------------------------------------------------- +UInt8Array::Pointer EbsdPatterns::getPatternData() const +{ + return m_PatternData; +} + +// ----------------------------------------------------------------------------- +void EbsdPatterns::setIsValid(bool value) +{ + m_IsValid = value; +} + +// ----------------------------------------------------------------------------- +bool EbsdPatterns::getIsValid() const +{ + return m_IsValid; +} diff --git a/src/BrukerIntegrationFilters/EbsdPatterns.h b/src/BrukerIntegrationFilters/EbsdPatterns.h new file mode 100644 index 0000000..92288d7 --- /dev/null +++ b/src/BrukerIntegrationFilters/EbsdPatterns.h @@ -0,0 +1,170 @@ +/* ============================================================================ + * Copyright (c) 2013 Michael A. Jackson (BlueQuartz Software) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * Neither the name of Michael A. Jackson, + * BlueQuartz Software nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This code was written under United States Air Force Contract number + * FA8650-07-D-5800 + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#pragma once + +#include "BrukerIntegration/BrukerIntegrationStructs.h" + +#include "EbsdLib/Core/EbsdDataArray.hpp" + +#include +#include + +/** + * @brief The EbsdPatterns class + */ +class EbsdPatterns +{ + public: + using Self = EbsdPatterns; + using Pointer = std::shared_ptr; + using ConstPointer = std::shared_ptr; + using WeakPointer = std::weak_ptr; + using ConstWeakPointer = std::weak_ptr; + static Pointer NullPointer(); + + static Pointer New(); + + /** + * @brief Returns the name of the class for EbsdPatterns + */ + virtual std::string getNameOfClass() const; + /** + * @brief Returns the name of the class for EbsdPatterns + */ + static std::string ClassName(); + + virtual ~EbsdPatterns(); + + EbsdPatterns::Pointer createSameSizePatterns(); + + /** + * @brief Setter property for ImageWidth + */ + void setImageWidth(int32_t value); + /** + * @brief Getter property for ImageWidth + * @return Value of ImageWidth + */ + int32_t getImageWidth() const; + + /** + * @brief Setter property for ImageHeight + */ + void setImageHeight(int32_t value); + /** + * @brief Getter property for ImageHeight + * @return Value of ImageHeight + */ + int32_t getImageHeight() const; + + /** + * @brief Setter property for PatternWidth + */ + void setPatternWidth(int32_t value); + /** + * @brief Getter property for PatternWidth + * @return Value of PatternWidth + */ + int32_t getPatternWidth() const; + + /** + * @brief Setter property for PatternHeight + */ + void setPatternHeight(int32_t value); + /** + * @brief Getter property for PatternHeight + * @return Value of PatternHeight + */ + int32_t getPatternHeight() const; + + /** + * @brief Setter property for PatternData + */ + void setPatternData(const EbsdLib::UInt8Array::Pointer& value); + /** + * @brief Getter property for PatternData + * @return Value of PatternData + */ + EbsdLib::UInt8Array::Pointer getPatternData() const; + + /** + * @brief Setter property for IsValid + */ + void setIsValid(bool value); + /** + * @brief Getter property for IsValid + * @return Value of IsValid + */ + bool getIsValid() const; + + /** + * @brief getPatternCount Returns the number of patterns + * @return + */ + int getPatternCount(); + + /** + * @brief getPatternElementCount Returns the number of elements in each pattern + * @return + */ + int getPerPatternElementCount(); + + uint8_t* getPatternPointer(int32_t x, int32_t y); + uint8_t* getPatternPointer(size_t index); + + EbsdLib::FloatArray::Pointer computeMeanPattern(); + EbsdLib::UInt64Array::Pointer computeDotProducts(); + + void subtractMeanPattern(EbsdLib::FloatArray::Pointer meanPtr, EbsdLib::FloatArray::Pointer results); + + protected: + EbsdPatterns(); + + public: + EbsdPatterns(const EbsdPatterns&) = delete; // Copy Constructor Not Implemented + EbsdPatterns(EbsdPatterns&&) = delete; // Move Constructor Not Implemented + EbsdPatterns& operator=(const EbsdPatterns&) = delete; // Copy Assignment Not Implemented + EbsdPatterns& operator=(EbsdPatterns&&) = delete; // Move Assignment Not Implemented + + private: + int32_t m_ImageWidth = {-1}; + int32_t m_ImageHeight = {-1}; + int32_t m_PatternWidth = {-1}; + int32_t m_PatternHeight = {-1}; + EbsdLib::UInt8Array::Pointer m_PatternData = {}; + bool m_IsValid = {false}; +}; + + diff --git a/src/EbsdLib/Core/EbsdDataArray.cpp b/src/EbsdLib/Core/EbsdDataArray.cpp new file mode 100644 index 0000000..0a7fec1 --- /dev/null +++ b/src/EbsdLib/Core/EbsdDataArray.cpp @@ -0,0 +1,1560 @@ +/* ============================================================================ + * Copyright (c) 2009-2016 BlueQuartz Software, LLC + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * Neither the name of BlueQuartz Software, the US Air Force, nor the names of its + * contributors may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The code contained herein was partially funded by the following contracts: + * United States Air Force Prime Contract FA8650-07-D-5800 + * United States Air Force Prime Contract FA8650-10-D-5210 + * United States Prime Contract Navy N00173-07-C-2068 + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +#include "EbsdDataArray.hpp" + +#include +#include +#include +#include +#include +#include + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#if defined(_MSC_VER) +#include +#define EBSD_BYTE_SWAP_16(x) _byteswap_ushort(x) +#define EBSD_BYTE_SWAP_32(x) _byteswap_ulong(x) +#define EBSD_BYTE_SWAP_64(x) _byteswap_uint64(x) + +#elif(defined(__clang__) && __has_builtin(__builtin_bswap32) && __has_builtin(__builtin_bswap64)) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) +#if(defined(__clang__) && __has_builtin(__builtin_bswap16)) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) +#define EBSD_BYTE_SWAP_16(x) __builtin_bswap16(x) +#else +#define EBSD_BYTE_SWAP_16(x) __builtin_bswap32((x) << 16) +#endif +#define EBSD_BYTE_SWAP_32(x) __builtin_bswap32(x) +#define EBSD_BYTE_SWAP_64(x) __builtin_bswap64(x) +#elif defined(__linux__) +#include +#define EBSD_BYTE_SWAP_16(x) bswap_16(x) +#define EBSD_BYTE_SWAP_32(x) bswap_32(x) +#define EBSD_BYTE_SWAP_64(x) bswap_64(x) +#endif + +#include "EbsdLib/Core/EbsdMacros.h" + +namespace +{ +// Can be replaced with std::bit_cast in C++ 20 + +template ::value && std::is_trivial::value>> +To bit_cast(const From& src) noexcept +{ + To dst; + std::memcpy(&dst, &src, sizeof(To)); + return dst; +} + +template +T byteSwap(T value) +{ + static_assert(std::is_arithmetic_v, "byteSwap only works on arithmetic types"); + + if constexpr(sizeof(T) == sizeof(uint16_t)) + { + return EBSD_BYTE_SWAP_16(value); + } + else if constexpr(sizeof(T) == sizeof(uint32_t)) + { + if constexpr(std::is_floating_point_v) + { + return bit_cast(EBSD_BYTE_SWAP_32(bit_cast(value))); + } + else + { + return EBSD_BYTE_SWAP_32(value); + } + } + else if constexpr(sizeof(T) == sizeof(uint64_t)) + { + if constexpr(std::is_floating_point_v) + { + return bit_cast(EBSD_BYTE_SWAP_64(bit_cast(value))); + } + else + { + return EBSD_BYTE_SWAP_64(value); + } + } + + return value; +} + +} // namespace + +template +typename EbsdDataArray::Pointer EbsdDataArray::NullPointer() +{ + return nullptr; +} + +template +std::string EbsdDataArray::getNameOfClass() const +{ + return ClassName(); +} + +template +std::string EbsdDataArray::ClassName() +{ + return "EbsdDataArray"; +} + +template +int32_t EbsdDataArray::getClassVersion() const +{ + return 2; +} + +//========================================= Constructing EbsdDataArray Objects ================================= +template +EbsdDataArray::EbsdDataArray() = default; + +/** + * @brief Constructor + * @param numTuples The number of Tuples in the EbsdDataArray + * @param name The name of the EbsdDataArray + * @param initValue The value to use when initializing each element of the array + */ +template +EbsdDataArray::EbsdDataArray(size_t numTuples, const std::string& name, T initValue) +: m_Name(name) +, m_InitValue(initValue) +{ + resizeTuples(numTuples); +} + +/** + * @brief EbsdDataArray + * @param numTuples The number of Tuples in the EbsdDataArray + * @param name The name of the EbsdDataArray + * @param compDims The number of elements in each axis dimension. + * @param initValue The value to use when initializing each element of the array + * + * For example if you have a 2D image dimensions of 80(w) x 60(h) then the "cdims" would be [80][60] + */ +template +EbsdDataArray::EbsdDataArray(size_t numTuples, const std::string& name, const comp_dims_type& compDims, T initValue) +: m_Name(name) +, m_NumTuples(numTuples) +, m_InitValue(initValue) +, m_CompDims(compDims) +{ + m_NumComponents = std::accumulate(m_CompDims.cbegin(), m_CompDims.cend(), static_cast(1), std::multiplies<>()); + m_Array = resizeAndExtend(m_NumTuples * m_NumComponents); +} + +/** + * @brief Protected Constructor + * @param numTuples The number of Tuples in the EbsdDataArray + * @param name The name of the EbsdDataArray + * @param compDims The number of elements in each axis dimension. + * @param initValue The value to use when initializing each element of the array + * @param allocate Will all the memory be allocated at time of construction + */ +template +EbsdDataArray::EbsdDataArray(size_t numTuples, const std::string& name, const comp_dims_type& compDims, T initValue, bool allocate) +: m_Name(name) +, m_NumTuples(numTuples) +, m_InitValue(initValue) +, m_CompDims(std::move(compDims)) +{ + m_NumComponents = std::accumulate(m_CompDims.cbegin(), m_CompDims.cend(), static_cast(1), std::multiplies<>()); + if(allocate) + { + resizeTuples(numTuples); + } + else + { + m_Size = m_NumTuples * m_NumComponents; + m_MaxId = (m_Size > 0) ? m_Size - 1 : m_Size; + } +#if 0 + MUD_FLAP_0 = MUD_FLAP_1 = MUD_FLAP_2 = MUD_FLAP_3 = MUD_FLAP_4 = MUD_FLAP_5 = 0xABABABABABABABABul; +#endif +} + +template +EbsdDataArray::~EbsdDataArray() +{ + clear(); +} + +template +typename EbsdDataArray::Pointer EbsdDataArray::CreateArray(size_t numTuples, const std::string& name, bool allocate) +{ + if(name.empty()) + { + return nullptr; + } + comp_dims_type cDims = {1}; + auto d = std::make_shared>(numTuples, name, cDims, static_cast(0), allocate); + if(allocate) + { + if(d->allocate() < 0) + { + // Could not allocate enough memory, reset the pointer to null and return + return nullptr; + } + } + return d; +} + +// ----------------------------------------------------------------------------- +template +typename EbsdDataArray::Pointer EbsdDataArray::CreateArray(size_t numTuples, int32_t rank, const size_t* dims, const std::string& name, bool allocate) +{ + if(name.empty()) + { + return nullptr; + } + comp_dims_type cDims(static_cast(rank)); + std::copy(dims, dims + rank, cDims.begin()); + auto d = std::make_shared>(numTuples, name, cDims, static_cast(0), allocate); + if(allocate) + { + if(d->allocate() < 0) + { + // Could not allocate enough memory, reset the pointer to null and return + return nullptr; + } + } + return d; +} + +// ----------------------------------------------------------------------------- +template +typename EbsdDataArray::Pointer EbsdDataArray::CreateArray(size_t numTuples, const comp_dims_type& compDims, const std::string& name, bool allocate) +{ + if(name.empty()) + { + return nullptr; + } + auto d = std::make_shared>(numTuples, name, compDims, static_cast(0), allocate); + if(allocate) + { + if(d->allocate() < 0) + { + // Could not allocate enough memory, reset the pointer to null and return + return nullptr; + } + } + return d; +} + +// ----------------------------------------------------------------------------- +template +typename EbsdDataArray::Pointer EbsdDataArray::CreateArray(const comp_dims_type& tupleDims, const comp_dims_type& compDims, const std::string& name, bool allocate) +{ + if(name.empty()) + { + return nullptr; + } + + size_t numTuples = std::accumulate(tupleDims.cbegin(), tupleDims.cend(), static_cast(1), std::multiplies<>()); + + auto d = std::make_shared>(numTuples, name, compDims, static_cast(0), allocate); + if(allocate) + { + if(d->allocate() < 0) + { + // Could not allocate enough memory, reset the pointer to null and return + return nullptr; + } + } + return d; +} + +template +typename EbsdDataArray::Pointer EbsdDataArray::createNewArray(size_t numTuples, int rank, const size_t* compDims, const std::string& name, bool allocate) const +{ + return EbsdDataArray::CreateArray(numTuples, rank, compDims, name, allocate); +} + +template +typename EbsdDataArray::Pointer EbsdDataArray::createNewArray(size_t numTuples, const comp_dims_type& compDims, const std::string& name, bool allocate) const +{ + return EbsdDataArray::CreateArray(numTuples, compDims, name, allocate); +} + +// ----------------------------------------------------------------------------- +template +typename EbsdDataArray::Pointer EbsdDataArray::FromQVector(const std::vector& vec, const std::string& name) +{ + Pointer p = CreateArray(static_cast(vec.size()), name, true); + if(nullptr != p) + { + std::copy(vec.cbegin(), vec.cend(), p->begin()); + } + return p; +} + +// ----------------------------------------------------------------------------- +template +typename EbsdDataArray::Pointer EbsdDataArray::FromStdVector(const std::vector& vec, const std::string& name) +{ + comp_dims_type cDims = {1}; + Pointer p = CreateArray(vec.size(), cDims, name, true); + if(nullptr != p) + { + std::copy(vec.cbegin(), vec.cend(), p->begin()); + } + return p; +} + +// ----------------------------------------------------------------------------- +template +typename EbsdDataArray::Pointer EbsdDataArray::CopyFromPointer(const T* data, size_t size, const std::string& name) +{ + Pointer p = CreateArray(size, name, true); + if(nullptr != p) + { + std::copy(data, data + size, p->begin()); + } + return p; +} + +/** + * @brief WrapPointer Creates a EbsdDataArray object that references the pointer. The original caller can + * set if the memory should be "free()'ed" when the object goes away. The original memory MUST have been + * "alloc()'ed" and NOT new 'ed. + * @param data + * @param numTuples + * @param cDims + * @param name + * @param ownsData + * @return + */ +template +typename EbsdDataArray::Pointer EbsdDataArray::WrapPointer(T* data, size_t numTuples, const comp_dims_type& compDims, const std::string& name, bool ownsData) +{ + // Allocate on the heap + auto d = std::make_shared>(numTuples, name, compDims, static_cast(0), false); + + // Now set the internal array to the raw pointer + d->m_Array = data; + // Set who owns the data, i.e., who is going to "free" the memory + d->m_OwnsData = ownsData; + if(nullptr != data) + { + d->m_IsAllocated = true; + } + + return d; +} + +//========================================= Begin API ================================= + +template +void EbsdDataArray::setName(const std::string& name) +{ + m_Name = name; +} + +template +std::string EbsdDataArray::getName() const +{ + return m_Name; +} + +template +typename EbsdDataArray::Pointer EbsdDataArray::deepCopy(bool forceNoAllocate) const +{ + bool allocate = m_IsAllocated; + if(forceNoAllocate) + { + allocate = false; + } + auto daCopy = CreateArray(getNumberOfTuples(), getComponentDimensions(), getName(), allocate); + if(m_IsAllocated && !forceNoAllocate) + { + std::copy(begin(), end(), daCopy->begin()); + } + return daCopy; +} + +/** + * @brief GetTypeName Returns a string representation of the type of data that is stored by this class. This + * can be a primitive like char, float, int or the name of a class. + * @return + */ +template +EbsdLib::NumericTypes::Type EbsdDataArray::getType() const +{ + if constexpr(std::is_same_v) + { + return EbsdLib::NumericTypes::Type::Int8; + } + else if constexpr(std::is_same_v) + { + return EbsdLib::NumericTypes::Type::UInt8; + } + else if constexpr(std::is_same_v) + { + return EbsdLib::NumericTypes::Type::Int16; + } + else if constexpr(std::is_same_v) + { + return EbsdLib::NumericTypes::Type::UInt16; + } + else if constexpr(std::is_same_v) + { + return EbsdLib::NumericTypes::Type::Int32; + } + else if constexpr(std::is_same_v) + { + return EbsdLib::NumericTypes::Type::UInt32; + } + else if constexpr(std::is_same_v) + { + return EbsdLib::NumericTypes::Type::Int64; + } + else if constexpr(std::is_same_v) + { + return EbsdLib::NumericTypes::Type::UInt64; + } + else if constexpr(std::is_same_v) + { + return EbsdLib::NumericTypes::Type::Float; + } + else if constexpr(std::is_same_v) + { + return EbsdLib::NumericTypes::Type::Double; + } + else if constexpr(std::is_same_v) + { + return EbsdLib::NumericTypes::Type::Bool; + } + + return EbsdLib::NumericTypes::Type::UnknownNumType; +} + +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::getXdmfTypeAndSize(std::string& xdmfTypeName, int& precision) const +{ + xdmfTypeName = "UNKNOWN"; + precision = 0; + + if constexpr(std::is_same_v) + { + xdmfTypeName = "Char"; + precision = 1; + } + else if constexpr(std::is_same_v) + { + xdmfTypeName = "UChar"; + precision = 1; + } + else if constexpr(std::is_same_v) + { + xdmfTypeName = "Int"; + precision = 2; + } + else if constexpr(std::is_same_v) + { + xdmfTypeName = "UInt"; + precision = 2; + } + else if constexpr(std::is_same_v) + { + xdmfTypeName = "Int"; + precision = 4; + } + else if constexpr(std::is_same_v) + { + xdmfTypeName = "UInt"; + precision = 4; + } + else if constexpr(std::is_same_v) + { + xdmfTypeName = "Int"; + precision = 8; + } + else if constexpr(std::is_same_v) + { + xdmfTypeName = "UInt"; + precision = 8; + } + else if constexpr(std::is_same_v) + { + xdmfTypeName = "Float"; + precision = 4; + } + else if constexpr(std::is_same_v) + { + xdmfTypeName = "Float"; + precision = 8; + } + else if constexpr(std::is_same_v) + { + xdmfTypeName = "UChar"; + precision = 1; + } +} + +// ----------------------------------------------------------------------------- +template +bool EbsdDataArray::copyFromArray(size_t destTupleOffset, EbsdDataArray::ConstPointer sourceArray, size_t srcTupleOffset, size_t totalSrcTuples) +{ + if(!m_IsAllocated) + { + return false; + } + if(nullptr == m_Array) + { + return false; + } + if(destTupleOffset > m_MaxId) + { + return false; + } + if(!sourceArray->isAllocated()) + { + return false; + } + const Self* source = dynamic_cast(sourceArray.get()); + if(source == nullptr) + { + return false; + } + if(nullptr == source->getPointer(0)) + { + return false; + } + + if(sourceArray->getNumberOfComponents() != getNumberOfComponents()) + { + return false; + } + + if(srcTupleOffset + totalSrcTuples > sourceArray->getNumberOfTuples()) + { + return false; + } + + if(totalSrcTuples * static_cast(sourceArray->getNumberOfComponents()) + destTupleOffset * static_cast(getNumberOfComponents()) > m_Size) + { + return false; + } + + auto srcBegin = source->cbegin() + (srcTupleOffset * source->m_NumComponents); + auto srcEnd = srcBegin + (totalSrcTuples * source->m_NumComponents); + auto dstBegin = begin() + (destTupleOffset * m_NumComponents); + std::copy(srcBegin, srcEnd, dstBegin); + return true; +} + +// ----------------------------------------------------------------------------- +template +bool EbsdDataArray::copyIntoArray(Pointer dest) const +{ + if(m_IsAllocated && dest->isAllocated() && m_Array && dest->getPointer(0)) + { + std::copy(cbegin(), cend(), dest->begin()); + return true; + } + return false; +} + +// ----------------------------------------------------------------------------- +template +bool EbsdDataArray::isAllocated() const +{ + return m_IsAllocated; +} + +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::setInitValue(T initValue) +{ + m_InitValue = initValue; +} + +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::takeOwnership() +{ + m_OwnsData = true; +} + +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::releaseOwnership() +{ + m_OwnsData = false; +} + +// ----------------------------------------------------------------------------- +template +int32_t EbsdDataArray::allocate() +{ + if((nullptr != m_Array) && m_OwnsData) + { + deallocate(); + } + m_Array = nullptr; + m_OwnsData = true; + m_IsAllocated = false; + if(m_Size == 0) + { + clear(); + return 1; + } + + size_t newSize = m_Size; + m_Array = new(std::nothrow) T[newSize](); + if(!m_Array) + { + std::cout << "Unable to allocate " << newSize << " elements of size " << sizeof(T) << " bytes. "; + return -1; + } + m_Size = newSize; + m_IsAllocated = true; + + return 1; +} + +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::initializeWithZeros() +{ + if(!m_IsAllocated || nullptr == m_Array) + { + return; + } + std::fill_n(m_Array, m_Size, static_cast(0)); +} + +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::initializeWithValue(T initValue, size_t offset) +{ + if(!m_IsAllocated || nullptr == m_Array) + { + return; + } + std::fill(begin() + offset, end(), initValue); +} + +// ----------------------------------------------------------------------------- +template +int32_t EbsdDataArray::eraseTuples(const comp_dims_type& idxs) +{ + int32_t err = 0; + + // If nothing is to be erased just return + if(idxs.empty()) + { + return 0; + } + auto idxs_size = static_cast(idxs.size()); + if(idxs_size >= getNumberOfTuples()) + { + resizeTuples(0); + return 0; + } + + // Sanity Check the Indices in the vector to make sure we are not trying to remove any indices that are + // off the end of the array and return an error code. + for(const size_t& idx : idxs) + { + if(idx * m_NumComponents > m_MaxId) + { + return -100; + } + } + + // Calculate the new size of the array to copy into + size_t newSize = (getNumberOfTuples() - idxs.size()) * m_NumComponents; + + // Create a new m_Array to copy into + T* newArray = new T[newSize](); + +#ifndef NDEBUG + // Splat AB across the array so we know if we are copying the values or not + std::memset(newArray, 0xAB, newSize * sizeof(T)); +#endif + + size_t j = 0; + size_t k = 0; + // Find the first chunk to copy by walking the idxs array until we get an + // index that is NOT a continuous increment from the start + for(k = 0; k < idxs.size(); ++k) + { + if(j == idxs[k]) + { + ++j; + } + else + { + break; + } + } + + // Only front elements are being dropped + if(k == idxs.size()) + { + auto srcBegin = begin() + (j * m_NumComponents); + auto srcEnd = srcBegin + (getNumberOfTuples() - idxs.size()) * m_NumComponents; + std::copy(srcBegin, srcEnd, newArray); + // We are done copying - delete the current m_Array + deallocate(); + m_Size = newSize; + m_Array = newArray; + m_OwnsData = true; + m_MaxId = newSize - 1; + m_IsAllocated = true; + return 0; + } + + comp_dims_type srcIdx(idxs.size() + 1); + comp_dims_type destIdx(idxs.size() + 1); + comp_dims_type copyElements(idxs.size() + 1); + srcIdx[0] = 0; + destIdx[0] = 0; + copyElements[0] = (idxs[0] - 0) * m_NumComponents; + + for(size_t i = 1; i < srcIdx.size(); ++i) + { + srcIdx[i] = (idxs[i - 1] + 1) * m_NumComponents; + + if(i < srcIdx.size() - 1) + { + copyElements[i] = (idxs[i] - idxs[i - 1] - 1) * m_NumComponents; + } + else + { + copyElements[i] = (getNumberOfTuples() - idxs[i - 1] - 1) * m_NumComponents; + } + destIdx[i] = copyElements[i - 1] + destIdx[i - 1]; + } + + // Copy the data + for(size_t i = 0; i < srcIdx.size(); ++i) + { + auto srcBegin = begin() + srcIdx[i]; + auto srcEnd = srcBegin + copyElements[i]; + auto dstBegin = newArray + destIdx[i]; + std::copy(srcBegin, srcEnd, dstBegin); + } + + // We are done copying - delete the current m_Array + deallocate(); + + // Allocation was successful. Save it. + m_Size = newSize; + m_Array = newArray; + // This object has now allocated its memory and owns it. + m_OwnsData = true; + m_IsAllocated = true; + m_MaxId = newSize - 1; + + return err; +} + +// ----------------------------------------------------------------------------- +template +int EbsdDataArray::copyTuple(size_t currentPos, size_t newPos) +{ + size_t max = ((m_MaxId + 1) / m_NumComponents); + if(currentPos >= max || newPos >= max) + { + return -1; + } + auto srcBegin = begin() + (currentPos * m_NumComponents); + auto srcEnd = srcBegin + m_NumComponents; + auto dstBegin = begin() + (newPos * m_NumComponents); + std::copy(srcBegin, srcEnd, dstBegin); + return 0; +} + +// ----------------------------------------------------------------------------- +template +size_t EbsdDataArray::getTypeSize() const +{ + return sizeof(T); +} + +// ----------------------------------------------------------------------------- +template +size_t EbsdDataArray::getNumberOfTuples() const +{ + return m_NumTuples; +} + +// ----------------------------------------------------------------------------- +template +size_t EbsdDataArray::getSize() const +{ + return m_Size; +} + +// ----------------------------------------------------------------------------- +template +typename EbsdDataArray::comp_dims_type EbsdDataArray::getComponentDimensions() const +{ + return m_CompDims; +} + +// ----------------------------------------------------------------------------- +template +int32_t EbsdDataArray::getNumberOfComponents() const +{ + return static_cast(m_NumComponents); +} + +// ----------------------------------------------------------------------------- +template +void* EbsdDataArray::getVoidPointer(size_t i) +{ + if(i >= m_Size) + { + return nullptr; + } + + return reinterpret_cast(&(m_Array[i])); +} + +// ----------------------------------------------------------------------------- +template +T* EbsdDataArray::getPointer(size_t i) const +{ +#ifndef NDEBUG + if(m_Size > 0) + { + EBSD_INDEX_OUT_OF_RANGE(i < m_Size); + } +#endif + return m_Array + i; +} + +// ----------------------------------------------------------------------------- +template +T EbsdDataArray::getValue(size_t i) const +{ +#ifndef NDEBUG + if(m_Size > 0) + { + EBSD_INDEX_OUT_OF_RANGE(i < m_Size); + } +#endif + return m_Array[i]; +} + +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::setValue(size_t i, T value) +{ +#ifndef NDEBUG + if(m_Size > 0) + { + EBSD_INDEX_OUT_OF_RANGE(i < m_Size); + } +#endif + m_Array[i] = value; +} + +// ----------------------------------------------------------------------------- +template +T EbsdDataArray::getComponent(size_t i, int32_t j) const +{ +#ifndef NDEBUG + if(m_Size > 0) + { + EBSD_INDEX_OUT_OF_RANGE(i * m_NumComponents + static_cast(j) < m_Size); + } +#endif + return m_Array[i * m_NumComponents + static_cast(j)]; +} + +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::setComponent(size_t i, int32_t j, T c) +{ +#ifndef NDEBUG + if(m_Size > 0) + { + EBSD_INDEX_OUT_OF_RANGE(i * m_NumComponents + static_cast(j) < m_Size); + } +#endif + m_Array[i * m_NumComponents + static_cast(j)] = c; +} + +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::setTuple(size_t tupleIndex, const T* data) +{ +#ifndef NDEBUG + if(m_Size > 0) + { + EBSD_INDEX_OUT_OF_RANGE(tupleIndex * m_NumComponents + (m_NumComponents - 1) < m_Size); + } +#endif + std::copy(data, data + m_NumComponents, begin() + (tupleIndex * m_NumComponents)); +} + +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::setTuple(size_t tupleIndex, const std::vector& data) +{ +#ifndef NDEBUG + if(m_Size > 0) + { + EBSD_INDEX_OUT_OF_RANGE(tupleIndex * m_NumComponents + (m_NumComponents - 1) < m_Size); + } +#endif + auto srcBegin = data.cbegin(); + auto srcEnd = srcBegin + m_NumComponents; + std::copy(srcBegin, srcEnd, begin() + (tupleIndex * m_NumComponents)); +} + +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::initializeTuple(size_t i, const void* p) +{ + if(!m_IsAllocated) + { + return; + } +#ifndef NDEBUG + if(m_Size > 0) + { + EBSD_INDEX_OUT_OF_RANGE(i * m_NumComponents < m_Size); + } +#endif + if(nullptr == p) + { + return; + } + const T* c = reinterpret_cast(p); + std::fill_n(begin() + (i * m_NumComponents), m_NumComponents, *c); +} + +// ----------------------------------------------------------------------------- +template +T* EbsdDataArray::getTuplePointer(size_t tupleIndex) const +{ +#ifndef NDEBUG + if(m_Size > 0) + { + EBSD_INDEX_OUT_OF_RANGE(tupleIndex * m_NumComponents < m_Size); + } +#endif + return m_Array + (tupleIndex * m_NumComponents); +} + +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::resizeTuples(size_t numTuples) +{ + T* ptr = resizeAndExtend(numTuples * m_NumComponents); + if(nullptr != ptr) + { + m_NumTuples = numTuples; + } +} + +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::printTuple(std::ostream& out, size_t i, char delimiter) const +{ + int32_t precision = 8; + if constexpr(std::is_same_v) + { + precision = 8; + } + else if constexpr(std::is_same_v) + { + precision = 16; + } + + for(size_t j = 0; j < m_NumComponents; ++j) + { + if(j != 0) + { + out << delimiter; + } + out << std::setw(precision) << m_Array[i * m_NumComponents + j]; + } +} + +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::printComponent(std::stringstream& out, size_t i, int32_t j) const +{ + out << m_Array[i * m_NumComponents + static_cast(j)]; +} + +// ----------------------------------------------------------------------------- +template +std::string EbsdDataArray::getFullNameOfClass() const +{ + std::string theType = getTypeAsString(); + theType = "EbsdDataArray<" + theType + ">"; + return theType; +} + +// ----------------------------------------------------------------------------- +template +std::string EbsdDataArray::getTypeAsString() const +{ + if constexpr(std::is_same_v) + { + return "int8_t"; + } + else if constexpr(std::is_same_v) + { + return "uint8_t"; + } + else if constexpr(std::is_same_v) + { + return "int16_t"; + } + else if constexpr(std::is_same_v) + { + return "uint16_t"; + } + else if constexpr(std::is_same_v) + { + return "int32_t"; + } + else if constexpr(std::is_same_v) + { + return "uint32_t"; + } + else if constexpr(std::is_same_v) + { + return "int64_t"; + } + else if constexpr(std::is_same_v) + { + return "uint64_t"; + } + else if constexpr(std::is_same_v) + { + return "float"; + } + else if constexpr(std::is_same_v) + { + return "double"; + } + else if constexpr(std::is_same_v) + { + return "bool"; + } + + return "UnknownType"; +} + +// ----------------------------------------------------------------------------- +template +int EbsdDataArray::writeXdmfAttribute(std::stringstream& out, const int64_t* volDims, const std::string& hdfFileName, const std::string& groupPath, const std::string& label) const +{ + if(m_Array == nullptr) + { + return -85648; + } + std::stringstream dimStr; + int32_t precision = 0; + std::string xdmfTypeName; + getXdmfTypeAndSize(xdmfTypeName, precision); + if(0 == precision) + { + out << "" + << "\n"; + return -100; + } + + int numComp = getNumberOfComponents(); + out << " \n"; + // Open the Tag + out << R"( \n"; + + out << " " << hdfFileName << groupPath << "/" << getName() << "\n"; + out << " " + << "\n"; + out << " " + << "\n"; + return 1; +} + +// ----------------------------------------------------------------------------- +template +std::string EbsdDataArray::getInfoString(EbsdLib::InfoStringFormat format) const +{ + std::string info; + std::stringstream ss; + if(format == EbsdLib::HtmlFormat) + { + ss << "\n"; + ss << "\n"; + ss << "\n"; + ss << "\n"; + ss << ""; + + ss << R"("; + + ss << R"("; + + ss << R"("; + + std::stringstream compDimStr; + compDimStr << "("; + for(size_t i = 0; i < m_CompDims.size(); i++) + { + compDimStr << m_CompDims[i]; + if(i < m_CompDims.size() - 1) + { + compDimStr << ", "; + } + } + compDimStr << ")"; + ss << R"("; + + ss << R"("; + + ss << R"("; + ss << "
Attribute Array Info
Name:)" << getName() << "
Type: EbsdDataArray<)" << getTypeAsString() << ">
Number of Tuples:)" << getNumberOfTuples() << "
Component Dimensions:)" << compDimStr.str() << "
Total Elements:)" << m_Size << "
Total Memory Required:)" << m_Size * sizeof(T) << "
\n"; + ss << ""; + } + else if(format == EbsdLib::MarkDown) + { + ss << "+ Name: " << getName() << "\n"; + ss << "+ Type: " << getTypeAsString() << "\n"; + ss << "+ Num. Tuple: " << getNumberOfTuples() << "\n"; + std::stringstream compDimStr; + compDimStr << "("; + for(size_t i = 0; i < m_CompDims.size(); i++) + { + compDimStr << m_CompDims[i]; + if(i < m_CompDims.size() - 1) + { + compDimStr << ", "; + } + } + compDimStr << +")"; + ss << "+ Comp. Dims: " << compDimStr.str() << "\n"; + ss << "+ Total Elements: " << m_Size << "\n"; + ss << "+ Total Memory: " << (m_Size * sizeof(T)) << "\n"; + } + return info; +} + +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::byteSwapElements() +{ + for(auto& value : *this) + { + value = byteSwap(value); + } +} + +template +typename EbsdDataArray::iterator EbsdDataArray::begin() +{ + return iterator(m_Array); +} + +template +typename EbsdDataArray::iterator EbsdDataArray::end() +{ + return iterator(m_Array + m_Size); +} + +template +typename EbsdDataArray::const_iterator EbsdDataArray::begin() const +{ + return const_iterator(m_Array); +} +template +typename EbsdDataArray::const_iterator EbsdDataArray::end() const +{ + return const_iterator(m_Array + m_Size); +} + +template +typename EbsdDataArray::const_iterator EbsdDataArray::cbegin() const +{ + return begin(); +} + +template +typename EbsdDataArray::const_iterator EbsdDataArray::cend() const +{ + return end(); +} + +template +typename EbsdDataArray::reverse_iterator EbsdDataArray::rbegin() +{ + return std::make_reverse_iterator(end()); +} + +template +typename EbsdDataArray::reverse_iterator EbsdDataArray::rend() +{ + return std::make_reverse_iterator(begin()); +} + +template +typename EbsdDataArray::const_reverse_iterator EbsdDataArray::rbegin() const +{ + return std::make_reverse_iterator(end()); +} + +template +typename EbsdDataArray::const_reverse_iterator EbsdDataArray::rend() const +{ + return std::make_reverse_iterator(begin()); +} + +template +typename EbsdDataArray::const_reverse_iterator EbsdDataArray::crbegin() const +{ + return rbegin(); +} + +template +typename EbsdDataArray::const_reverse_iterator EbsdDataArray::crend() const +{ + return rend(); +} + +template +typename EbsdDataArray::tuple_iterator EbsdDataArray::tupleBegin() +{ + return tuple_iterator(m_Array, m_NumComponents); +} + +template +typename EbsdDataArray::tuple_iterator EbsdDataArray::tupleEnd() +{ + return tuple_iterator(m_Array + m_Size, m_NumComponents); +} + +template +typename EbsdDataArray::const_tuple_iterator EbsdDataArray::tupleBegin() const +{ + return const_tuple_iterator(m_Array, m_NumComponents); +} + +template +typename EbsdDataArray::const_tuple_iterator EbsdDataArray::tupleEnd() const +{ + return const_tuple_iterator(m_Array + m_Size, m_NumComponents); +} + +template +typename EbsdDataArray::const_tuple_iterator EbsdDataArray::constTupleBegin() const +{ + return tupleBegin(); +} + +template +typename EbsdDataArray::const_tuple_iterator EbsdDataArray::constTupleEnd() const +{ + return tupleEnd(); +} + +// ######### Capacity ######### +template +typename EbsdDataArray::size_type EbsdDataArray::size() const +{ + return m_Size; +} + +template +typename EbsdDataArray::size_type EbsdDataArray::capacity() const noexcept +{ + return m_Size; +} + +template +bool EbsdDataArray::empty() const noexcept +{ + return (m_Size == 0); +} + +// ######### Element Access ######### + +// ######### Modifiers ######### + +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::assign(size_type n, const value_type& val) // fill (2) +{ + resizeAndExtend(n); + std::fill(begin(), end(), val); +} + +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::assign(std::initializer_list il) // initializer list (3) +{ + assign(il.begin(), il.end()); +} + +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::push_back(const value_type& val) +{ + resizeAndExtend(m_Size + 1); + m_Array[m_MaxId] = val; +} +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::push_back(value_type&& val) +{ + resizeAndExtend(m_Size + 1); + m_Array[m_MaxId] = val; +} + +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::pop_back() +{ + resizeAndExtend(m_Size - 1); +} + +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::clear() +{ + if(nullptr != m_Array && m_OwnsData) + { + deallocate(); + } + m_Array = nullptr; + m_Size = 0; + m_OwnsData = true; + m_MaxId = 0; + m_IsAllocated = false; + m_NumTuples = 0; +} + +// =================================== END STL COMPATIBLE INTERFACe =================================================== + +// ----------------------------------------------------------------------------- +template +void EbsdDataArray::deallocate() +{ +#ifndef NDEBUG + // We are going to splat 0xABABAB across the first value of the array as a debugging aid + auto cptr = reinterpret_cast(m_Array); + if(nullptr != cptr) + { + if(m_Size > 0) + { + if(sizeof(T) >= 1) + { + cptr[0] = 0xAB; + } + if(sizeof(T) >= 2) + { + cptr[1] = 0xAB; + } + if(sizeof(T) >= 4) + { + cptr[2] = 0xAB; + cptr[3] = 0xAB; + } + if(sizeof(T) >= 8) + { + cptr[4] = 0xAB; + cptr[5] = 0xAB; + cptr[6] = 0xAB; + cptr[7] = 0xAB; + } + } + } +#endif +#if 0 + if (MUD_FLAP_0 != 0xABABABABABABABABul + || MUD_FLAP_1 != 0xABABABABABABABABul + || MUD_FLAP_2 != 0xABABABABABABABABul + || MUD_FLAP_3 != 0xABABABABABABABABul + || MUD_FLAP_4 != 0xABABABABABABABABul + || MUD_FLAP_5 != 0xABABABABABABABABul) + { + EBSD_INDEX_OUT_OF_RANGE(false); + } +#endif + + delete[](m_Array); + + m_Array = nullptr; + m_IsAllocated = false; +} + +// ----------------------------------------------------------------------------- +template +int32_t EbsdDataArray::resizeTotalElements(size_t size) +{ + // std::cout << "EbsdDataArray::resizeTotalElements(" << size << ")" << std::endl; + if(size == 0) + { + clear(); + return 1; + } + T* ptr = resizeAndExtend(size); + if(nullptr != ptr) + { + return 1; + } + return 0; +} + +// ----------------------------------------------------------------------------- +template +T* EbsdDataArray::resizeAndExtend(size_t size) +{ + T* newArray = nullptr; + size_t newSize = 0; + size_t oldSize = 0; + + // Requested size is equal to current size. Do nothing. + if(size == m_Size) + { + return m_Array; + } + newSize = size; + oldSize = m_Size; + + // Wipe out the array completely if new size is zero. + if(newSize == 0) + { + clear(); + return m_Array; + } + + newArray = new(std::nothrow) T[newSize](); + if(!newArray) + { + std::cout << "Unable to allocate " << newSize << " elements of size " << sizeof(T) << " bytes. "; + return nullptr; + } + + // Copy the data from the old array. + if(m_Array != nullptr) + { + auto srcBegin = begin(); + auto srcEnd = srcBegin + (newSize < m_Size ? newSize : m_Size); + std::copy(srcBegin, srcEnd, newArray); + } + + // Allocate a new array if we DO NOT own the current array + if((nullptr != m_Array) && m_OwnsData) + { + // Free the old array + deallocate(); + } + + // Allocation was successful. Save it. + m_Size = newSize; + m_Array = newArray; + + // This object has now allocated its memory and owns it. + m_OwnsData = true; + + m_MaxId = newSize - 1; + m_IsAllocated = true; + + // Initialize the new tuples if newSize is larger than old size + if(newSize > oldSize) + { + initializeWithValue(m_InitValue, oldSize); + } + + return m_Array; +} + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- + +#define EbsdLib_EXPORT + +template class EbsdLib_EXPORT EbsdDataArray; + +template class EbsdLib_EXPORT EbsdDataArray; + +template class EbsdLib_EXPORT EbsdDataArray; +template class EbsdLib_EXPORT EbsdDataArray; + +template class EbsdLib_EXPORT EbsdDataArray; +template class EbsdLib_EXPORT EbsdDataArray; + +template class EbsdLib_EXPORT EbsdDataArray; +template class EbsdLib_EXPORT EbsdDataArray; + +template class EbsdLib_EXPORT EbsdDataArray; +template class EbsdLib_EXPORT EbsdDataArray; + +template class EbsdLib_EXPORT EbsdDataArray; +template class EbsdLib_EXPORT EbsdDataArray; + +#if defined(__APPLE__) || defined(_MSC_VER) +template class EbsdLib_EXPORT EbsdDataArray; +#endif diff --git a/src/EbsdLib/Core/EbsdDataArray.hpp b/src/EbsdLib/Core/EbsdDataArray.hpp new file mode 100644 index 0000000..c7dd117 --- /dev/null +++ b/src/EbsdLib/Core/EbsdDataArray.hpp @@ -0,0 +1,1253 @@ +/* ============================================================================ + * Copyright (c) 2009-2016 BlueQuartz Software, LLC + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * Neither the name of BlueQuartz Software, the US Air Force, nor the names of its + * contributors may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The code contained herein was partially funded by the following contracts: + * United States Air Force Prime Contract FA8650-07-D-5800 + * United States Air Force Prime Contract FA8650-10-D-5210 + * United States Prime Contract Navy N00173-07-C-2068 + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#pragma once + +// STL Includes +#include +#include +#include +#include +#include +#include + +#include "EbsdLib/Core/EbsdLibConstants.h" + + +/** + * @class EbsdDataArray + * @brief Template class for wrapping raw arrays of data and is the basis for storing data within the SIMPL data structure. + */ +template +class EbsdDataArray +{ + +public: + using Self = EbsdDataArray; + using Pointer = std::shared_ptr; + using ConstPointer = std::shared_ptr; + using WeakPointer = std::weak_ptr; + using ConstWeakPointer = std::weak_ptr; + + static Pointer NullPointer(); + + /** + * @brief Returns the name of the class for AbstractMessage + */ + std::string getNameOfClass() const; + /** + * @brief Returns the name of the class for AbstractMessage + */ + static std::string ClassName(); + + /** + * @brief Returns the version of this class. + * @return + */ + int32_t getClassVersion() const; + + EbsdDataArray(const EbsdDataArray&) = default; // Copy Constructor default Implemented + EbsdDataArray(EbsdDataArray&&) = delete; // Move Constructor Not Implemented + EbsdDataArray& operator=(const EbsdDataArray&) = delete; // Copy Assignment Not Implemented + EbsdDataArray& operator=(EbsdDataArray&&) = delete; // Move Assignment Not Implemented + + //========================================= STL INTERFACE COMPATIBILITY ================================= + using comp_dims_type = std::vector; + using size_type = size_t; + using value_type = T; + using reference = T&; + using pointer = T*; + using difference_type = ptrdiff_t; + + //========================================= SIMPL INTERFACE COMPATIBILITY ================================= + using ContainterType = std::vector; + + //========================================= Constructing EbsdDataArray Objects ================================= + EbsdDataArray(); + + /** + * @brief Constructor + * @param numTuples The number of Tuples in the EbsdDataArray + * @param name The name of the EbsdDataArray + * @param initValue The value to use when initializing each element of the array + */ + EbsdDataArray(size_t numTuples, const std::string& name, T initValue); + /** + * @brief EbsdDataArray + * @param numTuples The number of Tuples in the EbsdDataArray + * @param name The name of the EbsdDataArray + * @param compDims The number of elements in each axis dimension. + * @param initValue The value to use when initializing each element of the array + * + * For example if you have a 2D image dimensions of 80(w) x 60(h) then the "cdims" would be [80][60] + */ + EbsdDataArray(size_t numTuples, const std::string& name, const comp_dims_type& compDims, T initValue); + + /** + * @brief Protected Constructor + * @param numTuples The number of Tuples in the EbsdDataArray + * @param name The name of the EbsdDataArray + * @param compDims The number of elements in each axis dimension. + * @param initValue The value to use when initializing each element of the array + * @param allocate Will all the memory be allocated at time of construction + */ + EbsdDataArray(size_t numTuples, const std::string& name, const comp_dims_type& compDims, T initValue, bool allocate); + + ~EbsdDataArray(); + + //========================================= Static Constructing EbsdDataArray Objects ================================= + /** + * @brief Static constructor + * @param numElements The number of elements in the internal array. + * @param name The name of the array + * @param allocate Will all the memory be allocated at time of construction + * @return Std::Shared_Ptr wrapping an instance of EbsdDataArrayTemplate + */ + static Pointer CreateArray(size_t numTuples, const std::string& name, bool allocate); + + /** + * @brief Static constructor + * @param numTuples The number of tuples in the array. + * @param rank The number of dimensions of the attribute on each Tuple + * @param dims The actual dimensions of the attribute on each Tuple + * @param name The name of the array + * @param allocate Will all the memory be allocated at time of construction + * @return Std::Shared_Ptr wrapping an instance of EbsdDataArrayTemplate + */ + static Pointer CreateArray(size_t numTuples, int32_t rank, const size_t* dims, const std::string& name, bool allocate); + + /** + * @brief Static constructor + * @param numTuples The number of tuples in the array. + * @param compDims The actual dimensions of the attribute on each Tuple + * @param name The name of the array + * @param allocate Will all the memory be allocated at time of construction + * @return Std::Shared_Ptr wrapping an instance of EbsdDataArrayTemplate + */ + static Pointer CreateArray(size_t numTuples, const comp_dims_type& compDims, const std::string& name, bool allocate); + + /** + * @brief Static constructor + * @param numTuples The number of tuples in the array. + * @param tDims The actual dimensions of the Tuples + * @param compDims The number of elements in each axis dimension. + * @param name The name of the array + * @param allocate Will all the memory be allocated at time of construction + * @return Std::Shared_Ptr wrapping an instance of EbsdDataArrayTemplate + */ + static Pointer CreateArray(const comp_dims_type& tupleDims, const comp_dims_type& compDims, const std::string& name, bool allocate); + + //========================================= Instance Constructing EbsdDataArray Objects ================================= + /** + * @brief createNewArray Creates a new EbsdDataArray object using the same POD type as the existing instance + * @param numTuples The number of tuples in the array. + * @param rank The number of dimensions of the attribute on each Tuple + * @param dims The actual dimensions of the attribute on each Tuple + * @param name The name of the array + * @param allocate Will all the memory be allocated at time of construction + * @return + */ + Pointer createNewArray(size_t numTuples, int32_t rank, const size_t* compDims, const std::string& name, bool allocate) const; + + /** + * @brief createNewArray + * @param numTuples The number of tuples in the array. + * @param compDims The number of elements in each axis dimension. + * @param name The name of the array + * @param allocate Will all the memory be allocated at time of construction + * @return Std::Shared_Ptr wrapping an instance of EbsdDataArrayTemplate + */ + Pointer createNewArray(size_t numTuples, const comp_dims_type& compDims, const std::string& name, bool allocate) const; + + /** + * @brief Static Method to create a EbsdDataArray from a std::vector through a deep copy of the data + * contained in the vector. The number of components will be set to 1. + * @param vec The vector to copy the data from + * @param name The name of the array + * @return Std::Shared_Ptr wrapping an instance of EbsdDataArrayTemplate + */ + static Pointer FromQVector(const std::vector& vec, const std::string& name); + + /** + * @brief Static Method to create a EbsdDataArray from a std::vector through a deep copy of the data + * contained in the vector. The number of components will be set to 1. + * @param vec The vector to copy the data from + * @param name The name of the array + * @return Std::Shared_Ptr wrapping an instance of EbsdDataArrayTemplate + */ + static Pointer FromStdVector(const std::vector& vec, const std::string& name); + + /** + * @brief FromPointer Creates a EbsdDataArray object with a DEEP COPY of the data + * @param data + * @param size + * @param name + * @return + */ + static Pointer CopyFromPointer(const T* data, size_t size, const std::string& name); + + /** + * @brief WrapPointer Creates a EbsdDataArray object that references the pointer. The original caller can + * set if the memory should be "free()'ed" when the object goes away. The original memory MUST have been + * "alloc()'ed" and NOT new 'ed. + * @param data + * @param numTuples + * @param cDims + * @param name + * @param ownsData + * @return + */ + static Pointer WrapPointer(T* data, size_t numTuples, const comp_dims_type& compDims, const std::string& name, bool ownsData); + + /** + * @brief Use this method to move the pointer ownership from this class to another similar class, such as SIMPLib::DataArray + */ + template + std::shared_ptr moveToDataArrayType() + { + std::shared_ptr output = DataArrayType::WrapPointer(data(), getNumberOfTuples(), getComponentDimensions(), getName().c_str(), true); + releaseOwnership(); + return output; + } + + //========================================= Begin API ================================= + + /** + * @brief setName + * @param name + */ + void setName(const std::string& name); + + /** + * @brief getName + * @return + */ + std::string getName() const; + + /** + * @brief deepCopy + * @param forceNoAllocate + * @return + */ + Pointer deepCopy(bool forceNoAllocate = false) const; + + /** + * @brief GetTypeName Returns a string representation of the type of data that is stored by this class. This + * can be a primitive like char, float, int or the name of a class. + * @return + */ + + EbsdLib::NumericTypes::Type getType() const; + + /** + * @brief GetTypeName Returns a string representation of the type of data that is stored by this class. This + * can be a primitive like char, float, int or the name of a class. + * @return + */ + void getXdmfTypeAndSize(std::string& xdmfTypeName, int32_t& precision) const; + + /** + * @brief copyData This method copies the number of tuples specified by the + * totalSrcTuples value starting from the source tuple offset value in sourceArray + * into the current array starting at the target destination tuple offset value. + * + * For example if the EbsdDataArray has 10 tuples, the source EbsdDataArray has 10 tuples, + * the destTupleOffset = 5, the srcTupleOffset = 5, and the totalSrcTuples = 3, + * then tuples 5, 6, and 7 will be copied from the source into tuples 5, 6, and 7 + * of the destination array. In psuedo code it would be the following: + * @code + * destArray[5] = sourceArray[5]; + * destArray[6] = sourceArray[6]; + * destArray[7] = sourceArray[7]; + * ..... + * @endcode + * @param destTupleOffset + * @param sourceArray + * @return + */ + bool copyFromArray(size_t destTupleOffset, ConstPointer sourceArray, size_t srcTupleOffset, size_t totalSrcTuples); + + /** + * @brief copyIntoArray + * @param dest + */ + bool copyIntoArray(Pointer dest) const; + + /** + * @brief isAllocated + * @return + */ + bool isAllocated() const; + /** + * @brief Gives this array a human readable name + * @param name The name of this array + */ + void setInitValue(T initValue); + + /** + * @brief Returns the initial value for the array. + * @return + */ + T getInitValue() const + { + return m_InitValue; + } + + /** + * @brief Makes this class responsible for freeing the memory + */ + void takeOwnership(); + + /** + * @brief This class will NOT free the memory associated with the internal pointer. + * This can be useful if the user wishes to keep the data around after this + * class goes out of scope. + */ + void releaseOwnership(); + + /** + * @brief Allocates the memory needed for this class + * @return 1 on success, -1 on failure + */ + int32_t allocate(); + + /** + * @brief Sets all the values to zero. + */ + void initializeWithZeros(); + + /** + * @brief Sets all the values to value. + */ + void initializeWithValue(T initValue, size_t offset = 0); + + /** + * @brief Removes Tuples from the m_Array. If the size of the vector is Zero nothing is done. If the size of the + * vector is greater than or Equal to the number of Tuples then the m_Array is Resized to Zero. If there are + * indices that are larger than the size of the original (before erasing operations) then an error code (-100) is + * returned from the program. + * @param idxs The indices to remove + * @return error code. + */ + int32_t eraseTuples(const comp_dims_type& idxs); + + /** + * @brief + * @param currentPos + * @param newPos + * @return + */ + int32_t copyTuple(size_t currentPos, size_t newPos); + + /** + * @brief Returns the number of bytes that make up the data type. + * 1 = char + * 2 = 16 bit integer + * 4 = 32 bit integer/Float + * 8 = 64 bit integer/Double + */ + size_t getTypeSize() const; + + /** + * @brief Returns the number of elements in the internal array. + */ + size_t getNumberOfTuples() const; + + /** + * @brief Returns the total number of elements that make up this array. Equal to NumTuples * NumComponents + */ + size_t getSize() const; + + /** + * @brief Returns the dimensions for the data residing at each Tuple. For example if you have a simple Scalar value + * at each tuple then this will return a single element std::vector. If you have a 1x3 array (like EUler Angles) then + * this will return a 3 Element std::vector. + */ + comp_dims_type getComponentDimensions() const; + + /** + * @brief Returns the number component values at each Tuple location. For example if you have a + * 3 element component (vector) then this will be 3. If you are storing a small image of size 80x60 + * at each Tuple (like EBSD Kikuchi patterns) then the result would be 4800. + */ + int32_t getNumberOfComponents() const; + + /** + * @brief Returns a void pointer pointing to the index of the array. nullptr + * pointers are entirely possible. No checks are performed to make sure + * the index is with in the range of the internal data array. + * @param i The index to have the returned pointer pointing to. + * @return Void Pointer. Possibly nullptr. + */ + void* getVoidPointer(size_t i); + + /** + * @brief Returns the pointer to a specific index into the array. No checks are made + * as to the correctness of the index being passed in. If you ask for an index off + * then end of the array they you will likely cause your program to abort. + * @param i The index to return the pointer to. + * @return The pointer to the index + */ + T* getPointer(size_t i) const; + + /** + * @brief Returns the value for a given index + * @param i The index to return the value at + * @return The value at index i + */ + T getValue(size_t i) const; + + /** + * @brief Sets a specific value in the array + * @param i The index of the value to set + * @param value The new value to be set at the specified index + */ + void setValue(size_t i, T value); + + //---------------------------------------------------------------------------- + // These can be overridden for more efficiency + T getComponent(size_t i, int32_t j) const; + + /** + * @brief Sets a specific component of the Tuple located at i + * @param i The index of the Tuple + * @param j The Component index into the Tuple + * @param c The value to set + */ + void setComponent(size_t i, int32_t j, T c); + + /** + * @brief setTuple + * @param tupleIndex + * @param data + */ + void setTuple(size_t tupleIndex, const T* data); + + /** + * @brief setTuple + * @param tupleIndex + * @param data + */ + void setTuple(size_t tupleIndex, const std::vector& data); + + /** + * @brief Splats the same value c across all values in the Tuple + * @param i The index of the Tuple + * @param c The value to splat across all components in the tuple + */ + void initializeTuple(size_t i, const void* p); + + /** + * @brief getTuplePointer Returns the pointer to a specific tuple + * @param tupleIndex The index of tuple + */ + T* getTuplePointer(size_t tupleIndex) const; + + /** + * @brief resize + * @param numTuples + * @return + */ + void resizeTuples(size_t numTuples); + + /** + * @brief printTuple + * @param out + * @param i + * @param delimiter + */ + void printTuple(std::ostream& out, size_t i, char delimiter = ',') const; + + /** + * @brief printComponent + * @param out + * @param i + * @param j + */ + void printComponent(std::stringstream& out, size_t i, int32_t j) const; + + /** + * @brief Returns the HDF Type for a given primitive value. + * @param value A value to use. Can be anything. Just used to get the type info + * from + * @return The HDF5 native type for the value + */ + std::string getFullNameOfClass() const; + + /** + * @brief getTypeAsString + * @return + */ + std::string getTypeAsString() const; + + /** + * @brief writeXdmfAttribute + * @param out + * @param volDims + * @return + */ + int writeXdmfAttribute(std::stringstream& out, const int64_t* volDims, const std::string& hdfFileName, const std::string& groupPath, const std::string& label) const; + + /** + * @brief getInfoString + * @return Returns a formatted string that contains general infomation about + * the instance of the object. + */ + std::string getInfoString(EbsdLib::InfoStringFormat format) const; + + /** + * @brief + */ + void byteSwapElements(); + + //========================================= STL INTERFACE COMPATIBILITY ================================= + + class tuple_iterator + { + public: + using self_type = tuple_iterator; + using value_type = T; + using reference = T&; + using pointer = T*; + using difference_type = ptrdiff_t; + using iterator_category = std::random_access_iterator_tag; + + tuple_iterator() = delete; + + self_type& operator++() + { + ptr_ += num_comps_; + return *this; + } // PREFIX + self_type operator++([[maybe_unused]] int32_t unused) + { + self_type i = *this; + ptr_ += num_comps_; + return i; + } // POSTFIX + self_type& operator--() + { + ptr_ -= num_comps_; + return *this; + } // PREFIX + self_type operator--([[maybe_unused]] int32_t unused) + { + self_type i = *this; + ptr_ -= num_comps_; + return i; + } // POSTFIX + self_type& operator+=(difference_type amt) + { + ptr_ += amt * num_comps_; + return *this; + } + self_type operator+(difference_type amt) const + { + return self_type(ptr_ + amt * num_comps_, num_comps_); + } + self_type& operator-=(difference_type amt) + { + ptr_ -= amt * num_comps_; + return *this; + } + self_type operator-(difference_type amt) const + { + return self_type(ptr_ - amt * num_comps_, num_comps_); + } + difference_type operator-(const self_type& rhs) const + { + return (ptr_ - rhs.ptr_) / static_cast(num_comps_); + } + friend self_type operator+(difference_type lhs, const self_type& rhs) + { + return self_type(lhs * rhs.num_comps_ + rhs.ptr_, rhs.num_comps_); + } + reference operator[](difference_type amt) const + { + return ptr_[amt * num_comps_]; + } + reference operator*() const + { + return *ptr_; + } + pointer operator->() const + { + return ptr_; + } + bool operator==(const self_type& rhs) const + { + return ptr_ == rhs.ptr_; + } + bool operator!=(const self_type& rhs) const + { + return ptr_ != rhs.ptr_; + } + bool operator>(const self_type& rhs) const + { + return ptr_ > rhs.ptr_; + } + bool operator<(const self_type& rhs) const + { + return ptr_ < rhs.ptr_; + } + bool operator>=(const self_type& rhs) const + { + return ptr_ >= rhs.ptr_; + } + bool operator<=(const self_type& rhs) const + { + return ptr_ <= rhs.ptr_; + } + + reference comp_value(size_type comp) + { + return *(ptr_ + comp); + } + + protected: + tuple_iterator(pointer ptr, size_type numComps) + : ptr_(ptr) + , num_comps_(numComps) + { + } + + friend class EbsdDataArray; + + private: + pointer ptr_; + size_t num_comps_; + }; + + class const_tuple_iterator + { + public: + using self_type = const_tuple_iterator; + using value_type = T; + using reference = const T&; + using pointer = const T*; + using difference_type = ptrdiff_t; + using iterator_category = std::random_access_iterator_tag; + + const_tuple_iterator() = delete; + + self_type& operator++() + { + ptr_ += num_comps_; + return *this; + } // PREFIX + self_type operator++([[maybe_unused]] int32_t unused) + { + self_type i = *this; + ptr_ += num_comps_; + return i; + } // POSTFIX + self_type& operator--() + { + ptr_ -= num_comps_; + return *this; + } // PREFIX + self_type operator--([[maybe_unused]] int32_t unused) + { + self_type i = *this; + ptr_ -= num_comps_; + return i; + } // POSTFIX + self_type& operator+=(difference_type amt) + { + ptr_ += amt * num_comps_; + return *this; + } + self_type operator+(difference_type amt) const + { + return self_type(ptr_ + amt * num_comps_, num_comps_); + } + self_type& operator-=(difference_type amt) + { + ptr_ -= amt * num_comps_; + return *this; + } + self_type operator-(difference_type amt) const + { + return self_type(ptr_ - amt * num_comps_, num_comps_); + } + difference_type operator-(const self_type& rhs) const + { + return (ptr_ - rhs.ptr_) / static_cast(num_comps_); + } + friend self_type operator+(difference_type lhs, const self_type& rhs) + { + return self_type(lhs * rhs.num_comps_ + rhs.ptr_, rhs.num_comps_); + } + reference operator[](difference_type amt) const + { + return ptr_[amt * num_comps_]; + } + reference operator*() const + { + return *ptr_; + } + pointer operator->() const + { + return ptr_; + } + bool operator==(const self_type& rhs) const + { + return ptr_ == rhs.ptr_; + } + bool operator!=(const self_type& rhs) const + { + return ptr_ != rhs.ptr_; + } + bool operator>(const self_type& rhs) const + { + return ptr_ > rhs.ptr_; + } + bool operator<(const self_type& rhs) const + { + return ptr_ < rhs.ptr_; + } + bool operator>=(const self_type& rhs) const + { + return ptr_ >= rhs.ptr_; + } + bool operator<=(const self_type& rhs) const + { + return ptr_ <= rhs.ptr_; + } + + reference comp_value(size_type comp) const + { + return *(ptr_ + comp); + } + + protected: + const_tuple_iterator(pointer ptr, size_type numComps) + : ptr_(ptr) + , num_comps_(numComps) + { + } + + friend class EbsdDataArray; + + private: + pointer ptr_; + size_t num_comps_; + }; + + class iterator + { + public: + using self_type = iterator; + using value_type = T; + using reference = T&; + using pointer = T*; + using difference_type = ptrdiff_t; + using iterator_category = std::random_access_iterator_tag; + + iterator() = delete; + + iterator(const self_type& iter) + : ptr_(iter.ptr_) + { + } + + self_type& operator++() + { + ptr_++; + return *this; + } // PREFIX + self_type operator++([[maybe_unused]] int32_t unused) + { + self_type i = *this; + ptr_++; + return i; + } // POSTFIX + self_type& operator--() + { + ptr_--; + return *this; + } // PREFIX + self_type operator--([[maybe_unused]] int32_t unused) + { + self_type i = *this; + ptr_--; + return i; + } // POSTFIX + self_type& operator+=(difference_type amt) + { + ptr_ += amt; + return *this; + } + self_type operator+(difference_type amt) const + { + return self_type(ptr_ + amt); + } + self_type& operator-=(difference_type amt) + { + ptr_ -= amt; + return *this; + } + self_type operator-(difference_type amt) const + { + return self_type(ptr_ - amt); + } + difference_type operator-(const self_type& rhs) const + { + return ptr_ - rhs.ptr_; + } + friend self_type operator+(difference_type lhs, const self_type& rhs) + { + return self_type(lhs + rhs.ptr_); + } + reference operator[](difference_type amt) const + { + return ptr_[amt]; + } + reference operator*() const + { + return *ptr_; + } + pointer operator->() const + { + return ptr_; + } + bool operator==(const self_type& rhs) const + { + return ptr_ == rhs.ptr_; + } + bool operator!=(const self_type& rhs) const + { + return ptr_ != rhs.ptr_; + } + bool operator>(const self_type& rhs) const + { + return ptr_ > rhs.ptr_; + } + bool operator<(const self_type& rhs) const + { + return ptr_ < rhs.ptr_; + } + bool operator>=(const self_type& rhs) const + { + return ptr_ >= rhs.ptr_; + } + bool operator<=(const self_type& rhs) const + { + return ptr_ <= rhs.ptr_; + } + + protected: + iterator(pointer ptr) + : ptr_(ptr) + { + } + + friend class EbsdDataArray; + + private: + pointer ptr_; + }; + + using reverse_iterator = std::reverse_iterator; + + class const_iterator + { + public: + using self_type = const_iterator; + using value_type = T; + using reference = const T&; + using pointer = const T*; + using difference_type = ptrdiff_t; + using iterator_category = std::random_access_iterator_tag; + + const_iterator() = delete; + + const_iterator(const self_type& iter) + : ptr_(iter.ptr_) + { + } + + self_type& operator++() + { + ptr_++; + return *this; + } // PREFIX + self_type operator++([[maybe_unused]] int32_t unused) + { + self_type i = *this; + ptr_++; + return i; + } // POSTFIX + self_type& operator--() + { + ptr_--; + return *this; + } // PREFIX + self_type operator--([[maybe_unused]] int32_t unused) + { + self_type i = *this; + ptr_--; + return i; + } // POSTFIX + self_type& operator+=(difference_type amt) + { + ptr_ += amt; + return *this; + } + self_type operator+(difference_type amt) const + { + return self_type(ptr_ + amt); + } + self_type& operator-=(difference_type amt) + { + ptr_ -= amt; + return *this; + } + self_type operator-(difference_type amt) const + { + return self_type(ptr_ - amt); + } + difference_type operator-(const self_type& rhs) const + { + return ptr_ - rhs.ptr_; + } + friend self_type operator+(difference_type lhs, const self_type& rhs) + { + return self_type(lhs + rhs.ptr_); + } + reference operator[](difference_type amt) const + { + return ptr_[amt]; + } + reference operator*() const + { + return *ptr_; + } + pointer operator->() const + { + return ptr_; + } + bool operator==(const self_type& rhs) const + { + return ptr_ == rhs.ptr_; + } + bool operator!=(const self_type& rhs) const + { + return ptr_ != rhs.ptr_; + } + bool operator>(const self_type& rhs) const + { + return ptr_ > rhs.ptr_; + } + bool operator<(const self_type& rhs) const + { + return ptr_ < rhs.ptr_; + } + bool operator>=(const self_type& rhs) const + { + return ptr_ >= rhs.ptr_; + } + bool operator<=(const self_type& rhs) const + { + return ptr_ <= rhs.ptr_; + } + + protected: + const_iterator(pointer ptr) + : ptr_(ptr) + { + } + + friend class EbsdDataArray; + + private: + pointer ptr_; + }; + + using const_reverse_iterator = std::reverse_iterator; + + // ######### Iterators ######### + + tuple_iterator tupleBegin(); + + tuple_iterator tupleEnd(); + + const_tuple_iterator tupleBegin() const; + + const_tuple_iterator tupleEnd() const; + + const_tuple_iterator constTupleBegin() const; + + const_tuple_iterator constTupleEnd() const; + + iterator begin(); + + iterator end(); + + const_iterator begin() const; + + const_iterator end() const; + + const_iterator cbegin() const; + + const_iterator cend() const; + + reverse_iterator rbegin(); + + reverse_iterator rend(); + + const_reverse_iterator rbegin() const; + + const_reverse_iterator rend() const; + + const_reverse_iterator crbegin() const; + + const_reverse_iterator crend() const; + + // ######### Capacity ######### + + size_type size() const; + + size_type capacity() const noexcept; + bool empty() const noexcept; + + // ######### Element Access ######### + + inline reference operator[](size_type index) + { + return m_Array[index]; + } + + inline const T& operator[](size_type index) const + { + return m_Array[index]; + } + + inline reference at(size_type index) + { + if(index >= m_Size) + { + throw std::out_of_range("EbsdDataArray subscript out of range"); + } + return m_Array[index]; + } + + inline const T& at(size_type index) const + { + if(index >= m_Size) + { + throw std::out_of_range("EbsdDataArray subscript out of range"); + } + return m_Array[index]; + } + + inline reference front() + { + return m_Array[0]; + } + inline const T& front() const + { + return m_Array[0]; + } + + inline reference back() + { + return m_Array[m_MaxId]; + } + inline const T& back() const + { + return m_Array[m_MaxId]; + } + + inline T* data() noexcept + { + return m_Array; + } + inline const T* data() const noexcept + { + return m_Array; + } + + // ######### Modifiers ######### + + /** + * @brief In the range version (1), the new contents are elements constructed from each of the elements in the range + * between first and last, in the same order. + */ + template + void assign(InputIterator first, InputIterator last) // range (1) + { + size_type size = last - first; + resizeAndExtend(size); + size_type idx = 0; + while(first != last) + { + m_Array[idx] = *first; + first++; + } + } + + /** + * @brief In the fill version (2), the new contents are n elements, each initialized to a copy of val. + * @param n + * @param val + */ + void assign(size_type n, const value_type& val); + + /** + * @brief In the initializer list version (3), the new contents are copies of the values passed as initializer list, in the same order. + * @param il + */ + void assign(std::initializer_list il); + + /** + * @brief push_back + * @param val + */ + void push_back(const value_type& val); + /** + * @brief push_back + * @param val + */ + void push_back(value_type&& val); + + /** + * @brief pop_back + */ + void pop_back(); + + /** + * @brief Removes all elements from the array (which are destroyed), leaving the container with a size of 0. + */ + void clear(); + + /** + * @brief equal + * @param range1 + * @param range2 + * @return + */ + template + bool equal(Range1 const& range1, Range2 const& range2) + { + if(range1.size() != range2.size()) + { + return false; + } + + return std::equal(begin(range1), end(range1), begin(range2)); + } + + // =================================== END STL COMPATIBLE INTERFACe =================================================== + +protected: + /** + * @brief deallocates the memory block + */ + void deallocate(); + + /** + * @brief Resizes the internal array + * @param size The new size of the internal array + * @return 1 on success, 0 on failure + */ + int32_t resizeTotalElements(size_t size); + + /** + * @brief resizes the internal array to be 'size' elements in length + * @param size + * @return Pointer to the internal array + */ + T* resizeAndExtend(size_t size); + +private: + std::string m_Name = {}; + T* m_Array = nullptr; + size_t m_Size = 0; + size_t m_MaxId = 0; + size_t m_NumTuples = 0; + size_t m_NumComponents = 1; + T m_InitValue = static_cast(0); + comp_dims_type m_CompDims = {1}; + bool m_IsAllocated = false; + bool m_OwnsData = true; +}; + +// ----------------------------------------------------------------------------- +// Declare our extern templates +extern template class EbsdDataArray; + +extern template class EbsdDataArray; +extern template class EbsdDataArray; + +extern template class EbsdDataArray; +extern template class EbsdDataArray; +extern template class EbsdDataArray; +extern template class EbsdDataArray; +extern template class EbsdDataArray; +extern template class EbsdDataArray; +extern template class EbsdDataArray; +extern template class EbsdDataArray; + +extern template class EbsdDataArray; +extern template class EbsdDataArray; + +extern template class EbsdDataArray; + +// ----------------------------------------------------------------------------- +// Declare our aliases +namespace EbsdLib +{ +// using BoolArrayType = EbsdDataArray; + +// using CharArrayType = EbsdDataArray; +// using UCharArrayType = EbsdDataArray; + +// using Int8ArrayType = EbsdDataArray; +using UInt8Array = EbsdDataArray; + +using Int16Array = EbsdDataArray; +using UInt16Array = EbsdDataArray; + +using Int32Array = EbsdDataArray; +using UInt32Array = EbsdDataArray; + +using Int64Array = EbsdDataArray; +using UInt64Array = EbsdDataArray; + +using FloatArray = EbsdDataArray; +using DoubleArray = EbsdDataArray; + +// using SizeTArrayType = EbsdDataArray; +} // namespace EbsdLib diff --git a/src/EbsdLib/Core/EbsdLibConstants.h b/src/EbsdLib/Core/EbsdLibConstants.h new file mode 100644 index 0000000..b09519c --- /dev/null +++ b/src/EbsdLib/Core/EbsdLibConstants.h @@ -0,0 +1,293 @@ +/* ============================================================================ + * Copyright (c) 2009-2016 BlueQuartz Software, LLC + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * Neither the name of BlueQuartz Software, the US Air Force, nor the names of its + * contributors may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The code contained herein was partially funded by the following contracts: + * United States Air Force Prime Contract FA8650-07-D-5800 + * United States Air Force Prime Contract FA8650-10-D-5210 + * United States Prime Contract Navy N00173-07-C-2068 + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +#pragma once + +#include + +/** + * @file EbsdConstants.h + * @brief This file contains many constants that are generic to the EBSD library + */ +namespace EbsdLib +{ + +using Rgb = uint32_t; +inline constexpr Rgb RGB_MASK = 0x00ffffff; // masks RGB values +inline const std::string PathSep("|"); +inline constexpr uint8_t Unchecked = 0; +inline constexpr uint8_t PartiallyChecked = 1; +inline constexpr uint8_t Checked = 2; + +enum InfoStringFormat +{ + HtmlFormat = 0, + MarkDown = 1, + // JsonFormat, + // TextFormat, + // XmlFormat, + UnknownFormat +}; + +namespace StringConstants +{ +inline const std::string Statistics("Statistics"); +inline const std::string StatsData("StatsData"); +inline const std::string StatsType("StatsType"); +inline const std::string GBCD("GBCD"); +} // namespace StringConstants + +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 +{ + Int8 = 0, + UInt8, + Int16, + UInt16, + Int32, + UInt32, + Int64, + UInt64, + Float, + Double, + Bool, + SizeT, + 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 */ +namespace RefFrameZDir +{ +inline constexpr uint32_t LowtoHigh = 0; +inline constexpr uint32_t HightoLow = 1; +inline constexpr uint32_t UnknownRefFrameZDirection = 2; +} // namespace RefFrameZDir + +namespace H5Ebsd +{ +inline const std::string Manufacturer("Manufacturer"); +inline const std::string Header("Header"); +inline const std::string Phases("Phases"); +inline const std::string Phase("Phase"); +inline const std::string Data("Data"); +inline const std::string Index("Index"); + +inline const std::string ZStartIndex("ZStartIndex"); +inline const std::string ZEndIndex("ZEndIndex"); +inline const std::string ZResolution("Z Resolution"); +inline const std::string StackingOrder("Stacking Order"); +inline const std::string SampleTransformationAngle("SampleTransformationAngle"); +inline const std::string SampleTransformationAxis("SampleTransformationAxis"); +inline const std::string EulerTransformationAngle("EulerTransformationAngle"); +inline const std::string EulerTransformationAxis("EulerTransformationAxis"); + +// Each Manufacturer has their own naming scheme for these variables but for +// DREAM.3D we are going to settle on using these names for consistency +inline const std::string XResolution("X Resolution"); +inline const std::string YResolution("Y Resolution"); + +// We store the Maximum number of X and Y Points for the given volume. This +// allows us to store slices that have different XY voxel dimensions. +inline const std::string XPoints("Max X Points"); +inline const std::string YPoints("Max Y Points"); + +inline const std::string FileVersionStr("FileVersion"); +inline constexpr uint32_t FileVersion = 5; +inline const std::string EbsdLibVersionStr("EbsdLibVersion"); +} // namespace H5Ebsd + +using EnumType = int32_t; +enum class OEM : EnumType +{ + EDAX = 0, + Oxford = 1, + Bruker = 2, + HEDM = 3, + Zeiss = 4, + Phillips = 5, + ThermoFisher = 6, + DREAM3D = 7, + Unknown = 8 +}; + +namespace CellData +{ +inline const std::string EulerAngles("EulerAngles"); +inline const std::string Phases("Phases"); +} // namespace CellData + +enum EbsdToSampleCoordinateMapping +{ + TSLdefault = 0, + HKLdefault = 1, + HEDMdefault = 2, + UnknownCoordinateMapping = 3 +}; + +namespace StackingOrder +{ +inline const std::string LowToHigh("Low To High"); +inline const std::string HighToLow("High To Low"); +inline const std::string UnknownStackingOrder("Unknown Stacking Order"); + +namespace Utils +{ +inline std::string getStringForEnum(uint32_t v) +{ + if(EbsdLib::RefFrameZDir::LowtoHigh == v) + { + return EbsdLib::StackingOrder::LowToHigh; + } + if(EbsdLib::RefFrameZDir::HightoLow == v) + { + return EbsdLib::StackingOrder::HighToLow; + } + return EbsdLib::StackingOrder::UnknownStackingOrder; +} + +inline int32_t getEnumForString(const std::string& v) +{ + if(EbsdLib::StackingOrder::LowToHigh == v) + { + return EbsdLib::RefFrameZDir::LowtoHigh; + } + if(EbsdLib::StackingOrder::HighToLow == v) + { + return EbsdLib::RefFrameZDir::HightoLow; + } + return EbsdLib::RefFrameZDir::UnknownRefFrameZDirection; +} +} // namespace Utils +} // namespace StackingOrder + +/** + * @brief IF YOU CHANGE THE VALUES THERE ARE DEEP RAMIFICATIONS IN THE CODE BUT + * MOSTLY IN THE HDF5 FILES WHICH ARE WRITTEN USING THE ENUMERATIONS. + */ +namespace CrystalStructure +{ + +inline constexpr uint32_t Triclinic = 4; //!< Triclinic -1 +inline constexpr uint32_t Monoclinic = 5; //!< Monoclinic 2/m +inline constexpr uint32_t OrthoRhombic = 6; //!< Orthorhombic mmm +inline constexpr uint32_t Tetragonal_Low = 7; //!< Tetragonal-Low 4/m +inline constexpr uint32_t Tetragonal_High = 8; //!< Tetragonal-High 4/mmm +inline constexpr uint32_t Trigonal_Low = 9; //!< Trigonal-Low -3 +inline constexpr uint32_t Trigonal_High = 10; //!< Trigonal-High -3m + +inline constexpr uint32_t Hexagonal_Low = 2; //!< Hexagonal-Low 6/m +inline constexpr uint32_t Hexagonal_High = 0; //!< Hexagonal-High 6/mmm +inline constexpr uint32_t Cubic_Low = 3; //!< Cubic Cubic-Low m3 (Tetrahedral) +inline constexpr uint32_t Cubic_High = 1; //!< Cubic Cubic-High m3m + +inline constexpr uint32_t LaueGroupEnd = 11; //!< The end of the Laue groups +inline constexpr uint32_t UnknownCrystalStructure = 999; //!< UnknownCrystalStructure +} // namespace CrystalStructure + +namespace BravaisLattice +{ +inline const std::string Unknown("Unknown"); +inline const std::string Cubic("Cubic"); +inline const std::string Hexagonal("Hexagonal"); +} // namespace BravaisLattice + +namespace AngleRepresentation +{ +inline constexpr int32_t Radians = 0; +inline constexpr int32_t Degrees = 1; +inline constexpr int32_t Invalid = 2; +}; // namespace AngleRepresentation + +namespace LambertParametersType +{ +inline constexpr double iPi = 0.3183098861837910; // 1/pi +inline constexpr double sPi = 1.7724538509055160; // sqrt(pi) +inline constexpr double sPio2 = 1.2533141373155000; // sqrt(pi/2) +inline constexpr double sPi2 = 0.8862269254527580; // sqrt(pi)/2 +inline constexpr double srt = 0.8660254037844390; // sqrt(3)/2 +inline constexpr double isrt = 0.5773502691896260; // 1/sqrt(3) +inline constexpr double alpha = 1.3467736870885980; // sqrt(pi)/3^(1/4) +inline constexpr double rtt = 1.7320508075688770; // sqrt(3) +inline constexpr double prea = 0.5250375679043320; // 3^(1/4)/sqrt(2pi) +inline constexpr double preb = 1.0500751358086640; // 3^(1/4)sqrt(2/pi) +inline constexpr double prec = 0.9068996821171090; // pi/2sqrt(3) +inline constexpr double pred = 2.0943951023931950; // 2pi/3 +inline constexpr double pree = 0.7598356856515930; // 3^(-1/4) +inline constexpr double pref = 1.3819765978853420; // sqrt(6/pi) +// ! the following constants are used for the cube to quaternion hemisphere mapping +inline constexpr double a = 1.9257490199582530; // pi^(5/6)/6^(1/6) +inline constexpr double ap = 2.1450293971110250; // pi^(2/3) +inline constexpr double sc = 0.8977727869612860; // a/ap +inline constexpr double beta = 0.9628745099791260; // pi^(5/6)/6^(1/6)/2 +inline constexpr double R1 = 1.3306700394914690; //(3pi/4)^(1/3) +inline constexpr double r2 = 1.4142135623730950; // sqrt(2) +inline constexpr double r22 = 0.7071067811865470; // 1/sqrt(2) +inline constexpr double pi12 = 0.2617993877991490; // pi/12 +inline constexpr double pi8 = 0.3926990816987240; // pi/8 +inline constexpr double prek = 1.6434564029725040; // R1 2^(1/4)/beta +inline constexpr double r24 = 4.8989794855663560; // sqrt(24) +inline constexpr double tfit[16] = {1.00000000000188520, -0.50000000021948470, -0.0249999921275931260, -0.0039287015447813740, -0.00081527015354504380, -0.00020095004261197120, + -0.000023979867760717560, -0.000082028689266058410, +0.000124487150420900920, -0.00017491142148225770, +0.00017034819341400540, -0.000120620650041168280, + +0.0000597197058686608260, -0.000019807567239656470, +0.0000039537146842128740, -0.000000365550014397195440}; +inline constexpr double BP[6] = {0.0, 1.0, 0.5773502691896260, 0.4142135623730950, 0.0, 0.2679491924311230}; // used for Fundamental Zone determination in so3 module +} // namespace LambertParametersType + +// Add some shortened namespace alias +// Condense some of the namespaces to same some typing later on. +namespace LPs = LambertParametersType; + +} // namespace EbsdLib diff --git a/src/EbsdLib/Core/EbsdMacros.h b/src/EbsdLib/Core/EbsdMacros.h new file mode 100644 index 0000000..71924e0 --- /dev/null +++ b/src/EbsdLib/Core/EbsdMacros.h @@ -0,0 +1,285 @@ +/* ============================================================================ + * Copyright (c) 2009-2016 BlueQuartz Software, LLC + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * Neither the name of BlueQuartz Software, the US Air Force, nor the names of its + * contributors may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The code contained herein was partially funded by the following contracts: + * United States Air Force Prime Contract FA8650-07-D-5800 + * United States Air Force Prime Contract FA8650-10-D-5210 + * United States Prime Contract Navy N00173-07-C-2068 + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +#pragma once + +#include +#include +#include +#include + +namespace EbsdLib +{ +class method_not_implemented : public std::exception +{ +public: + /** + * @brief This class is used when a method is not implemented in a subclass and you want to throw an exception. + * @param what + */ + method_not_implemented(const std::string& what) + : m_Message(what) + { + updateWhat(); + } + + /** + * @brief Copy Constructor + */ + method_not_implemented(const method_not_implemented& te) + { + m_Message = (&te)->m_Message; + updateWhat(); + } + + virtual ~method_not_implemented() throw() = default; + + /** + * @brief Over ride from base class + */ + virtual const char* what() const throw() + { + return m_What; + } + +protected: + method_not_implemented() + { + updateWhat(); + } + + void updateWhat() + { + std::stringstream ss; + ss << " Reason: " << m_Message << std::endl; + + ::memset(m_What, 0, 2048); + ::memcpy(m_What, ss.str().c_str(), ss.str().size()); + m_What[2047] = 0; // Make sure we nullptr terminate no matter what. + } + +private: + std::string m_Message; + char m_What[2048]; + void operator=(const method_not_implemented&) = delete; // Move assignment Not Implemented +}; + +} // namespace EbsdLib + +/** @brief This macro is used to shorten the code needed to go from std::string to QString. Helpful in other codes that use + * QString instead of std::string + */ +#define S2Q(var) QString::fromStdString((var)) + +/** + * @brief If a method is not implemented then it should use this macro to throw an exception. + */ +#define EBSD_METHOD_NOT_IMPLEMENTED() \ + { \ + std::stringstream assert_message; \ + assert_message << __FILE__ << "(" << __LINE__ << ")" << getNameOfClass() << ": Method is not implemented."; \ + throw EbsdLib::method_not_implemented(assert_message.str()); \ + } + +/** + * @brief If an index is out of range this is a convenient macro to throw a std::out_of_range exception + */ +#define EBSD_INDEX_OUT_OF_RANGE(CONDITION) \ + if(!(CONDITION)) \ + { \ + std::stringstream assert_message; \ + assert_message << __FILE__ << "(" << __LINE__ << ")" << getNameOfClass() << ": Index out of Range."; \ + throw std::out_of_range(assert_message.str()); \ + } + +/** + * @brief If a there is an unknown type argument this is a convenient macro to throw an std::invalid_argument exception + */ +#define EBSD_UNKNOWN_TYPE(CONDITION) \ + if(!(CONDITION)) \ + { \ + std::stringstream assert_message; \ + assert_message << __FILE__ << "(" << __LINE__ << ")" << getNameOfClass() << ": invalid_argument"; \ + throw std::invalid_argument(assert_message.str()); \ + } + +/** + * @brief These macros are used to read header values from an HDF5 file, NOT From a .ang or .ctf file + */ + +#define READ_EBSD_HEADER_DATA(cname, class, Type, getName, key, gid) \ + { \ + auto t = static_cast(0); \ + err = H5Lite::readScalarDataset(gid, key, t); \ + if(err < 0) \ + { \ + std::stringstream ss##getName; \ + ss##getName << cname << ": The header value for '" << key << "' was not found in the H5EBSD file. Was this header originally found in the files that were imported into this H5EBSD File?"; \ + setErrorCode(-90002); \ + setErrorMessage(ss##getName.str()); \ + err = H5Gclose(gid); \ + return -1; \ + } \ + EbsdHeaderEntry::Pointer p = m_HeaderMap[key]; \ + auto c = dynamic_cast(p.get()); \ + c->setValue(t); \ + } + +#define READ_EBSD_HEADER_STRING_DATA(cname, class, Type, getName, key, gid) \ + { \ + std::string t; \ + err = H5Lite::readStringDataset(gid, key, t); \ + if(err < 0) \ + { \ + std::stringstream getName##ss; \ + getName##ss << cname << ": The header value for '" << key << "' was not found in the H5EBSD file. Was this header originally found in the files that were imported into this H5EBSD File?"; \ + setErrorCode(-90002); \ + setErrorMessage(getName##ss.str()); \ + err = H5Gclose(gid); \ + return -1; \ + } \ + EbsdHeaderEntry::Pointer p = m_HeaderMap[key]; \ + auto c = dynamic_cast(p.get()); \ + c->setValue(t); \ + } + +#define READ_PHASE_STRING_DATA(cname, pid, fqKey, key, phase) \ + { \ + std::string t; \ + err = H5Lite::readStringDataset(pid, fqKey, t); \ + if(err < 0) \ + { \ + std::stringstream ss##getName; \ + ss##getName << cname << ": The header value for '" << fqKey << "' was not found in the H5EBSD file. Was this header originally found in the files that were imported into this H5EBSD File?"; \ + setErrorCode(-90003); \ + setErrorMessage(ss##getName.str()); \ + err = H5Gclose(pid); \ + H5Gclose(phasesGid); \ + H5Gclose(gid); \ + return -1; \ + } \ + phase->set##key(t); \ + } + +#define READ_PHASE_HEADER_DATA(cname, pid, Type, fqKey, key, phase) \ + { \ + Type t; \ + err = H5Lite::readScalarDataset(pid, fqKey, t); \ + if(err < 0) \ + { \ + std::stringstream ss##getName; \ + ss##getName << cname << ": The header value for '" << fqKey << "' was not found in the H5EBSD file. Was this header originally found in the files that were imported into this H5EBSD File?"; \ + setErrorCode(-90004); \ + setErrorMessage(ss##getName.str()); \ + err = H5Gclose(pid); \ + H5Gclose(phasesGid); \ + H5Gclose(gid); \ + return -1; \ + } \ + phase->set##key(t); \ + } + +#define READ_PHASE_HEADER_DATA_CAST(cname, pid, cast, Type, fqKey, key, phase) \ + { \ + Type t; \ + err = H5Lite::readScalarDataset(pid, fqKey, t); \ + if(err < 0) \ + { \ + std::stringstream ss##key; \ + ss##key << cname << ": The header value for '" << fqKey << "' was not found in the H5EBSD file. Was this header originally found in the files that were imported into this H5EBSD File?"; \ + setErrorCode(-90005); \ + setErrorMessage(ss##key.str()); \ + err = H5Gclose(pid); \ + H5Gclose(phasesGid); \ + H5Gclose(gid); \ + return -1; \ + } \ + phase->set##key(static_cast(t)); \ + } + +#define READ_PHASE_HEADER_ARRAY(cname, pid, Type, fqKey, key, phase) \ + { \ + std::vector t; \ + err = H5Lite::readVectorDataset(pid, fqKey, t); \ + if(err < 0) \ + { \ + std::stringstream ss##key; \ + ss##key << cname << ": The header value for '" << fqKey << "' was not found in the H5EBSD file. Was this header originally found in the files that were imported into this H5EBSD File?"; \ + setErrorCode(-90006); \ + setErrorMessage(ss##key.str()); \ + err = H5Gclose(pid); \ + H5Gclose(phasesGid); \ + H5Gclose(gid); \ + return -1; \ + } \ + /*QVECTOR_FROM_STD_VECTOR(std::vector, qvec, t)*/ \ + phase->set##key(t); \ + } + +#define SHUFFLE_ARRAY(name, var, Type) \ + { \ + Type* f = allocateArray(totalDataRows); \ + for(size_t i = 0; i < totalDataRows; ++i) \ + { \ + size_t nIdx = shuffleTable[i]; \ + f[nIdx] = var[i]; \ + } \ + set##name##Pointer(f); \ + } + +#define ANG_READER_ALLOCATE_AND_READ(name, h5name, type) \ + free##name##Pointer(); /* Always free the current data before reading new data */ \ + if(m_ReadAllArrays == true || m_ArrayNames.find(h5name) != m_ArrayNames.end()) \ + { \ + auto _##name = allocateArray(totalDataRows); \ + if(nullptr != _##name) \ + { \ + ::memset(_##name, 0, numBytes); \ + std::string dataName = h5name; \ + err = H5Lite::readPointerDataset(gid, dataName, _##name); \ + if(err < 0) \ + { \ + deallocateArrayData(_##name); /*deallocate the array*/ \ + setErrorCode(-90020); \ + ss << "Error reading dataset '" << #name \ + << "' from the HDF5 file. This data set is required to be in the file because either " \ + "the program is set to read ALL the Data arrays or the program was instructed to read this array."; \ + setErrorMessage(sBuf); \ + err = H5Gclose(gid); \ + return -90020; \ + } \ + } \ + set##name##Pointer(_##name); \ + } diff --git a/src/StringUtilities.hpp b/src/StringUtilities.hpp new file mode 100644 index 0000000..303875b --- /dev/null +++ b/src/StringUtilities.hpp @@ -0,0 +1,291 @@ +/* ============================================================================ + * Copyright (c) 2020 BlueQuartz Software, LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * Neither the names of any of the BlueQuartz Software contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#pragma once + + +#include +#include +#include + +/*' '(0x20)space(SPC) + * '\t'(0x09)horizontal tab(TAB) + * '\n'(0x0a)newline(LF) + * '\v'(0x0b)vertical tab(VT) + * '\f'(0x0c)feed(FF) + * '\r'(0x0d)carriage return (CR) + */ + +namespace complex +{ +namespace StringUtilities +{ + +inline std::string k_Whitespaces = " \t\f\v\n\r"; + +template +void for_each_token(InputIt first, InputIt last, ForwardIt s_first, ForwardIt s_last, BinOp binary_op) +{ + while(true) + { + const auto pos = std::find_first_of(first, last, s_first, s_last); + binary_op(first, pos); + if(pos == last) + { + break; + } + first = std::next(pos); + } +} + +inline std::string replace(std::string str, std::string_view from, std::string_view to) +{ + size_t startPos = 0; + while((startPos = str.find(from, startPos)) != std::string::npos) + { + str.replace(startPos, from.length(), to); + startPos += to.length(); + } + return str; +} + +inline std::string ltrim(std::string_view str) +{ + if(str.empty()) + { + return ""; + } + + std::string::size_type front = str.find_first_not_of(k_Whitespaces); + if(front == std::string::npos) + { + return ""; + } + + return std::string(str.substr(front)); +} + +inline std::string rtrim(std::string_view str) +{ + if(str.empty()) + { + return ""; + } + + std::string::size_type back = str.find_last_not_of(k_Whitespaces); + if(back == std::string::npos) + { + return ""; + } + + return std::string(str.substr(0, back + 1)); +} + +inline std::string trimmed(std::string_view str) +{ + if(str.empty()) + { + return ""; + } + + std::string::size_type back = str.find_last_not_of(k_Whitespaces); + if(back == std::string::npos) + { + return ""; + } + + std::string::size_type front = str.find_first_not_of(k_Whitespaces); + + return std::string(str.substr(front, back - front + 1)); +} + +// inline std::vector split(std::string_view str, nonstd::span delimiters, bool consecutiveDelimiters) +// { +// std::vector tokens; +// auto endPos = str.end(); +// for_each_token(str.begin(), endPos, delimiters.cbegin(), delimiters.cend(), [&tokens, &consecutiveDelimiters](auto first, auto second) { +// if(first != second) +// { +// std::string substr = {first, second}; +// substr = trimmed(substr); +// if(!substr.empty() || !consecutiveDelimiters) +// { +// tokens.push_back(substr); +// } +// } +// }); +// return tokens; +// } + +// inline std::vector split(std::string_view str, char delim) +// { +// std::array delims = {delim}; +// return split(str, delims, false); +// } + +inline std::vector split_2(const std::string& line, char delimiter) +{ + std::stringstream ss(line); + + std::vector tokens; + std::string tempStr; + + while(std::getline(ss, tempStr, delimiter)) + { + tokens.push_back(tempStr); + } + return tokens; +} + +// inline std::string join(nonstd::span vec, std::string_view delim) +// { +// return fmt::format("{}", fmt::join(vec, delim)); +// } + +inline bool contains(std::string_view str, std::string_view val) +{ + return str.find(val) != std::string::npos; +} + +inline bool contains(std::string_view str, char val) +{ + return str.find(val) != std::string::npos; +} + +inline std::string chop(std::string_view str, size_t numElements) +{ + return std::string(str.substr(0, str.size() - numElements)); +} +inline std::string chop(std::string_view str, std::string_view chopFrom) +{ + if(str.empty()) + { + return ""; + } + + std::string::size_type back = str.find_last_not_of(chopFrom); + if(back == std::string::npos) + { + return ""; + } + + return std::string(str.substr(0, back + 1)); +} + +inline std::string chopr(std::string_view str, size_t numElements) +{ + return std::string(str.substr(numElements, str.size() - numElements)); +} + +template +inline std::string number(T arg) +{ + std::stringstream ss; + ss << arg; + return ss.str(); +} + +inline std::string simplified(std::string_view text) +{ + if(text.empty()) + { + return ""; + } + std::string out = trimmed(text); + std::string finalString; + for(char c : out) + { + if(std::isspace(static_cast(c)) == 0) + { + finalString += c; + } + else + { + finalString += ' '; + } + } + return finalString; +} + +/** + * @brief Converts a char to its uppercase version according to the current locale. + * Uses std::toupper internally. + * @param c + * @return char + */ +inline char toUpper(char c) +{ + return static_cast(std::toupper(static_cast(c))); +} + +/** + * @brief Converts a char to its lowercase version according to the current locale. + * Uses std::tolower internally. + * @param c + * @return char + */ +inline char toLower(char c) +{ + return static_cast(std::tolower(static_cast(c))); +} + +/** + * @brief Converts the given string to uppercase. + * Assumes that the string is ASCII. + * @param input + * @return std::string + */ +inline std::string toUpper(std::string input) +{ + for(char& c : input) + { + c = toUpper(c); + } + return input; +} + +/** + * @brief Converts the given string to lowercase. + * Assumes that the string is ASCII. + * @param input + * @return std::string + */ +inline std::string toLower(std::string input) +{ + for(char& c : input) + { + c = toLower(c); + } + return input; +} + +} // namespace StringUtilities +} // namespace complex diff --git a/src/bcf2hdf5.cpp b/src/bcf2hdf5.cpp index 94b4fc8..4b66a1a 100644 --- a/src/bcf2hdf5.cpp +++ b/src/bcf2hdf5.cpp @@ -1,53 +1,66 @@ -// Qt Includes -#include -#include -#include -#include - #include "BcfHdf5Convertor.h" #include +#include +#include +#include int main(int argc, char* argv[]) { - QString version("1.0.0"); - // Instantiate the QCoreApplication that we need to get the current path and load plugins. - QCoreApplication* app = new QCoreApplication(argc, argv); - QCoreApplication::setOrganizationName("BlueQuartz Software"); - QCoreApplication::setOrganizationDomain("bluequartz.net"); - QCoreApplication::setApplicationName("bcf2hdf5"); - QCoreApplication::setApplicationVersion(version); + std::string version("1.0.0"); + const size_t k_InputFileIndex = 0; + const size_t k_OutputFileIndex = 1; + const size_t k_FlipPatter = 2; + const size_t k_Reorder = 3; + const size_t k_HelpIndex = 4; + + using ArgEntry = std::vector; + using ArgEntries = std::vector; - QCommandLineParser parser; - QString str; - QTextStream ss(&str); - ss << "bcf2hdf5 (" << version << "): This application will convert a Bruker Nano .bcf file into a somewhat compatible HDF5 file."; - parser.setApplicationDescription(str); - parser.addHelpOption(); - parser.addVersionOption(); + ArgEntries args; - QCommandLineOption bcfFileArg(QStringList() << "b" - << "bcf", - "Input BCF ", "file"); - parser.addOption(bcfFileArg); + args.push_back({"-b", "--bcf", "The input file to process"}); + args.push_back({"-o", "--output", "The output file to write"}); + args.push_back({"-r", "--reorder", "Reorder Data inside of HDF5 file. This can increase final file size significantly. true or false."}); + args.push_back({"-f", "--flip", "Flip the patterns across the X Axis (Vertical Flip). true or false."}); + args.push_back({"-h", "--help", "Show help for this program"}); - QCommandLineOption hdf5FileArg(QStringList() << "o" - << "output", - "Output HDF5 ", "file"); - parser.addOption(hdf5FileArg); + std::string inputFile; + std::string outputFile; + std::string reorder; + std::string flipPatterns; + bool header = false; - QCommandLineOption reorderArg(QStringList() << "r" - << "reorder", - "Reorder Data inside of HDF5 file. This can increase final file size significantly. true or false.", "file"); - parser.addOption(reorderArg); + for(int32_t i = 0; i < argc; i++) + { + if(argv[i] == args[k_InputFileIndex][0] || argv[i] == args[k_InputFileIndex][1]) + { + inputFile = argv[++i]; + } + if(argv[i] == args[k_OutputFileIndex][0] || argv[i] == args[k_OutputFileIndex][1]) + { + outputFile = argv[++i]; + } + if(argv[i] == args[k_FlipPatter][0] || argv[i] == args[k_FlipPatter][1]) + { + flipPatterns = argv[++i]; + } + if(argv[i] == args[k_Reorder][0] || argv[i] == args[k_Reorder][1]) + { + reorder = argv[++i]; + } - QCommandLineOption flipPatternArg(QStringList() << "f" - << "flip", - "Flip the patterns across the X Axis (Vertical Flip). true or false.", "file"); - parser.addOption(flipPatternArg); + if(argv[i] == args[k_HelpIndex][0] || argv[i] == args[k_HelpIndex][1]) + { + std::cout << "This program has the following arguments:" << std::endl; + for(const auto& input : args) + { + std::cout << input[0] << ", " << input[1] << ": " << input[2] << std::endl; + } + return 0; + } + } - // Process the actual command line arguments given by the user - parser.process(*app); if(argc != 9) { @@ -55,21 +68,6 @@ int main(int argc, char* argv[]) return EXIT_FAILURE; } - QString inputFile = parser.value(bcfFileArg); - if(inputFile.isEmpty()) - { - std::cout << "Input file was empty. Use --help for more information." << std::endl; - return EXIT_FAILURE; - } - QString outputFile = parser.value(hdf5FileArg); - if(outputFile.isEmpty()) - { - std::cout << "Output file was empty. Use --help for more information." << std::endl; - return EXIT_FAILURE; - } - - QString reorder = parser.value(reorderArg); - QString flipPatterns = parser.value(flipPatternArg); BcfHdf5Convertor convertor(inputFile, outputFile); convertor.setReorder(reorder == "true"); @@ -78,11 +76,10 @@ int main(int argc, char* argv[]) int32_t err = convertor.getErrorCode(); if(err < 0) { - std::cout << convertor.getErrorMessage().toStdString() << ": " << convertor.getErrorCode() << std::endl; + std::cout << convertor.getErrorMessage() << ": " << convertor.getErrorCode() << std::endl; } std::cout << "Complete" << std::endl; - /* code */ return err; }