diff --git a/.github/workflows/osx_tests.yml b/.github/workflows/osx_tests.yml index c3181705..bfb2e8c6 100644 --- a/.github/workflows/osx_tests.yml +++ b/.github/workflows/osx_tests.yml @@ -4,7 +4,7 @@ env: QGIS_DEPS_VERSION: 0.4.0 jobs: osx_tests: - runs-on: macos-latest + runs-on: macos-12 steps: - name: Checkout MDAL uses: actions/checkout@v2 diff --git a/docs/source/drivers/index.rst b/docs/source/drivers/index.rst index 71661c39..59d32027 100644 --- a/docs/source/drivers/index.rst +++ b/docs/source/drivers/index.rst @@ -40,3 +40,4 @@ MDAL drivers dfsu dfs2 h2i + mike21 diff --git a/mdal/frmts/mdal_mike21.cpp b/mdal/frmts/mdal_mike21.cpp index 1f63758d..16252160 100644 --- a/mdal/frmts/mdal_mike21.cpp +++ b/mdal/frmts/mdal_mike21.cpp @@ -133,14 +133,18 @@ bool MDAL::DriverMike21::canReadMesh( const std::string &uri ) return true; } -size_t MDAL::DriverMike21::getVertexCount( const std::string &line ) +void MDAL::DriverMike21::parseHeader( const std::string &line ) { auto matchResults = std::smatch{}; if ( std::regex_search( line, matchResults, mRegexHeader2012 ) ) { if ( matchResults.size() > 4 ) { - return std::stoi( matchResults[3].str() ); + mDataType = matchResults[1].str(); + mDataUnit = matchResults[2].str(); + mVertexCount = std::stoi( matchResults[3].str() ); + mCrs = matchResults[4].str(); + return; } } @@ -148,33 +152,11 @@ size_t MDAL::DriverMike21::getVertexCount( const std::string &line ) { if ( matchResults.size() > 2 ) { - return std::stoi( matchResults[1].str() ); + mVertexCount = std::stoi( matchResults[1].str() ); + mCrs = matchResults[2].str(); + return; } } - - return 0; -} - -std::string MDAL::DriverMike21::getCrs( const std::string &line ) -{ - auto matchResults = std::smatch{}; - if ( std::regex_search( line, matchResults, mRegexHeader2012 ) ) - { - if ( matchResults.size() > 5 ) - { - return matchResults[4].str(); - } - } - - if ( std::regex_search( line, matchResults, mRegexHeader2011 ) ) - { - if ( matchResults.size() > 3 ) - { - return matchResults[2].str(); - } - } - - return ""; } std::unique_ptr MDAL::DriverMike21::load( const std::string &meshFile, const std::string & ) @@ -192,9 +174,8 @@ std::unique_ptr MDAL::DriverMike21::load( const std::string &meshFil return nullptr; } - std::string crs = getCrs( line ); + parseHeader( line ); - size_t vertexCount = getVertexCount( line ); size_t faceCount = 0; size_t maxVerticesPerFace = 2; @@ -202,7 +183,7 @@ std::unique_ptr MDAL::DriverMike21::load( const std::string &meshFil while ( std::getline( in, line ) ) { - if ( lineNumber == vertexCount + 1 ) + if ( lineNumber == mVertexCount + 1 ) { auto matchResults = std::smatch{}; if ( std::regex_search( line, matchResults, mRegexElementHeader ) ) @@ -236,7 +217,7 @@ std::unique_ptr MDAL::DriverMike21::load( const std::string &meshFil } // number of lines in file does not match number of vertices and faces specifed in first and element line - if ( lineNumber > 2 + vertexCount + faceCount ) + if ( lineNumber > 2 + mVertexCount + faceCount ) { MDAL::Log::error( MDAL_Status::Err_InvalidData, name(), "Number of lines in file does not fit with number of vertexes and faces specified." ); return nullptr; @@ -245,11 +226,11 @@ std::unique_ptr MDAL::DriverMike21::load( const std::string &meshFil in.clear(); in.seekg( 0, std::ios::beg ); - Vertices vertices( vertexCount ); + Vertices vertices( mVertexCount ); Faces faces( faceCount ); std::map vertexIDtoIndex; - std::vector vertexType( vertexCount ); + std::vector vertexType( mVertexCount ); std::vector nativeVertexIds; std::vector nativeFaceIds; @@ -263,7 +244,7 @@ std::unique_ptr MDAL::DriverMike21::load( const std::string &meshFil while ( std::getline( in, line ) ) { - if ( 0 < lineNumber && lineNumber < vertexCount + 1 ) + if ( 0 < lineNumber && lineNumber < mVertexCount + 1 ) { chunks = regex_split( MDAL::trim( line ) ); if ( chunks.size() != 5 ) @@ -288,10 +269,10 @@ std::unique_ptr MDAL::DriverMike21::load( const std::string &meshFil } // in case we have gaps/reorders in native indexes, store it - persist_native_index( nativeVertexIds, nodeID, vertexIndex, vertexCount ); + persist_native_index( nativeVertexIds, nodeID, vertexIndex, mVertexCount ); parse_vertex_id_gaps( vertexIDtoIndex, vertexIndex, nodeID - 1 ); - assert( vertexIndex < vertexCount ); + assert( vertexIndex < mVertexCount ); Vertex &vertex = vertices[vertexIndex]; vertex.x = toDouble( chunks[1] ); vertex.y = toDouble( chunks[2] ); @@ -300,7 +281,7 @@ std::unique_ptr MDAL::DriverMike21::load( const std::string &meshFil vertexIndex++; } - if ( vertexCount + 1 < lineNumber ) + if ( mVertexCount + 1 < lineNumber ) { chunks = regex_split( MDAL::trim( line ) ); assert( faceIndex < faceCount ); @@ -375,7 +356,13 @@ std::unique_ptr MDAL::DriverMike21::load( const std::string &meshFil if ( !nativeVertexIds.empty() ) MDAL::addVertexScalarDatasetGroup( mesh.get(), nativeVertexIds, "NativeVertexIds" ); - mesh->setSourceCrs( crs ); + mesh->setSourceCrs( mCrs ); + mesh->setMetadata( "crs", mCrs ); + if ( !mDataType.empty() ) + mesh->setMetadata( "data_type", mDataType ); + + if ( !mDataUnit.empty() ) + mesh->setMetadata( "data_unit", mDataUnit ); return std::unique_ptr( mesh.release() ); } @@ -391,7 +378,15 @@ void MDAL::DriverMike21::save( const std::string &fileName, const std::string &, MDAL::Log::error( MDAL_Status::Err_FailToWriteToDisk, name(), "Could not open file " + fileName ); } - std::string line = std::to_string( mesh->verticesCount() ) + " " + mesh->crs(); + std::string line; + + const std::string dataType = mesh->getMetadata( "data_type" ); + const std::string dataUnit = mesh->getMetadata( "data_unit" ); + if ( !dataType.empty() && !dataUnit.empty() ) + line.append( dataType + " " + dataUnit + " " ); + + line.append( std::to_string( mesh->verticesCount() ) + " " + mesh->getMetadata( "crs" ) ); + file << line << std::endl; std::vector vertexTypes; diff --git a/mdal/frmts/mdal_mike21.hpp b/mdal/frmts/mdal_mike21.hpp index 60c36256..b7d78e92 100644 --- a/mdal/frmts/mdal_mike21.hpp +++ b/mdal/frmts/mdal_mike21.hpp @@ -88,6 +88,10 @@ namespace MDAL private: std::string mMeshFile; + std::string mCrs; + std::string mDataType; + std::string mDataUnit; + size_t mVertexCount = 0; // regex for header line in form of - integer string const std::regex mRegexHeader2011 = std::regex( "(\\d+)\\s+(.+)(\\s+)?" ); // regex for header line in form of - integer integer integer string @@ -96,8 +100,7 @@ namespace MDAL const std::regex mRegexElementHeader = std::regex( "(\\d+)\\s+(\\d)\\s+(\\d{2})(\\s+)?" ); bool canReadHeader( const std::string &line ); - size_t getVertexCount( const std::string &line ); - std::string getCrs( const std::string &line ); + void parseHeader( const std::string &line ); }; } // namespace MDAL diff --git a/tests/mdal_testutils.cpp b/tests/mdal_testutils.cpp index 49bab897..1be85a37 100644 --- a/tests/mdal_testutils.cpp +++ b/tests/mdal_testutils.cpp @@ -255,6 +255,31 @@ void compareMeshFrames( MDAL_MeshH meshA, MDAL_MeshH meshB ) EXPECT_TRUE( compareVectors( verticesA, verticesB ) ); } +void compareMeshMetadata( MDAL_MeshH meshA, MDAL_MeshH meshB ) +{ + // Metadata count + const int orignal_m_count = MDAL_M_metadataCount( meshA ); + const int saved_m_count = MDAL_M_metadataCount( meshB ); + EXPECT_EQ( orignal_m_count, saved_m_count ); + + // Metadata values + for ( int i = 0; i < orignal_m_count; ++i ) + { + const std::string keyA( MDAL_M_metadataKey( meshA, i ) ); + const std::string valA( MDAL_M_metadataValue( meshA, i ) ); + for ( int j = 0; j < saved_m_count; ++j ) + { + const std::string keyB( MDAL_M_metadataKey( meshB, j ) ); + const std::string valB( MDAL_M_metadataValue( meshB, j ) ); + + if ( keyA == keyB && valA == valB ) + break; + else if ( j == saved_m_count - 1 ) + FAIL() << "Mesh metadata do not match: " << keyA << ": " << valA; + } + } +} + std::vector getCoordinates( MDAL_MeshH mesh, int verticesCount ) { MDAL_MeshVertexIteratorH iterator = MDAL_M_vertexIterator( mesh ); @@ -399,7 +424,7 @@ bool compareReferenceTime( MDAL_DatasetGroupH group, const char *referenceTime ) return std::strcmp( MDAL_G_referenceTime( group ), referenceTime ) == 0; } -void saveAndCompareMesh( const std::string &filename, const std::string &savedFile, const std::string &driver, const std::string &meshName ) +void saveAndCompareMesh( const std::string &filename, const std::string &savedFile, const std::string &driver, const std::string &meshName, bool compareMetadata ) { //test driver capability EXPECT_TRUE( MDAL_DR_saveMeshCapability( MDAL_driverFromName( driver.c_str() ) ) ); @@ -433,6 +458,8 @@ void saveAndCompareMesh( const std::string &filename, const std::string &savedFi // Compare saved with the original mesh compareMeshFrames( meshToSave, savedMesh ); + if ( compareMetadata ) + compareMeshMetadata( meshToSave, savedMesh ); MDAL_CloseMesh( savedMesh ); diff --git a/tests/mdal_testutils.hpp b/tests/mdal_testutils.hpp index bf8913df..bd4f16e6 100644 --- a/tests/mdal_testutils.hpp +++ b/tests/mdal_testutils.hpp @@ -62,7 +62,8 @@ bool compareVectors( const std::vector &a, const std::vector &b ); //! Same vertices (coords), faces, edges and connectivity between them void compareMeshFrames( MDAL_MeshH meshA, MDAL_MeshH meshB ); -void saveAndCompareMesh( const std::string &filename, const std::string &savedFile, const std::string &driver, const std::string &meshName = "" ); +void compareMeshMetadata( MDAL_MeshH meshA, MDAL_MeshH meshB ); +void saveAndCompareMesh( const std::string &filename, const std::string &savedFile, const std::string &driver, const std::string &meshName = "", bool compareMetadata = false ); //! Compare duration with millisecond precision bool compareDurationInHours( double h1, double h2 ); diff --git a/tests/test_mike21.cpp b/tests/test_mike21.cpp index a3727faa..5c4a03ed 100644 --- a/tests/test_mike21.cpp +++ b/tests/test_mike21.cpp @@ -190,16 +190,28 @@ TEST( MeshMike21Test, ReadOdenseRough ) TEST( MeshMike21Test, SaveMike21MeshToFile ) { + saveAndCompareMesh( + test_file( "/mike21/small.mesh" ), + tmp_file( "/small_saved.mesh" ), + "Mike21", + "", + true + ); + saveAndCompareMesh( test_file( "/mike21/odense_rough_comparison.mesh" ), tmp_file( "/odense_rough_saved.mesh" ), - "Mike21" + "Mike21", + "", + true ); saveAndCompareMesh( test_file( "/mike21/odense_rough_quads_comparion.mesh" ), tmp_file( "/odense_rough_quads_saved.mesh" ), - "Mike21" + "Mike21", + "", + true ); }