From bfbc64ce6ceb78de6d82715cf5d59c8996677bb8 Mon Sep 17 00:00:00 2001 From: Peter Petrik Date: Wed, 16 May 2018 11:20:25 +0200 Subject: [PATCH] update to MDAL 0.0.3 --- external/mdal/api/mdal.h | 71 ++++- external/mdal/frmts/mdal_2dm.cpp | 85 +++--- external/mdal/frmts/mdal_2dm.hpp | 3 +- external/mdal/frmts/mdal_ascii_dat.cpp | 305 +++++++++++++++++++++ external/mdal/frmts/mdal_ascii_dat.hpp | 52 ++++ external/mdal/frmts/mdal_binary_dat.cpp | 307 +++++++++++++++++++++ external/mdal/frmts/mdal_binary_dat.hpp | 46 ++++ external/mdal/mdal.cpp | 341 ++++++++++++++++++++++-- external/mdal/mdal_defines.hpp | 101 ++++++- external/mdal/mdal_loader.cpp | 16 +- external/mdal/mdal_loader.hpp | 5 +- external/mdal/mdal_utils.cpp | 42 ++- external/mdal/mdal_utils.hpp | 30 +++ 13 files changed, 1329 insertions(+), 75 deletions(-) create mode 100644 external/mdal/frmts/mdal_ascii_dat.cpp create mode 100644 external/mdal/frmts/mdal_ascii_dat.hpp create mode 100644 external/mdal/frmts/mdal_binary_dat.cpp create mode 100644 external/mdal/frmts/mdal_binary_dat.hpp diff --git a/external/mdal/api/mdal.h b/external/mdal/api/mdal.h index c049b41d76d..c856077c14e 100644 --- a/external/mdal/api/mdal.h +++ b/external/mdal/api/mdal.h @@ -6,6 +6,12 @@ #ifndef MDAL_H #define MDAL_H +/**********************************************************************/ +/**********************************************************************/ +/* API is considered EXPERIMENTAL and can be changed without a notice */ +/**********************************************************************/ +/**********************************************************************/ + #ifdef MDAL_STATIC # define MDAL_EXPORT #else @@ -46,6 +52,7 @@ enum MDAL_Status Err_UnknownFormat, Err_IncompatibleMesh, Err_InvalidData, + Err_IncompatibleDataset, Err_MissingDriver, // Warnings Warn_UnsupportedElement, @@ -57,6 +64,7 @@ enum MDAL_Status //! Mesh typedef void *MeshH; +typedef void *DatasetH; //! Return MDAL version MDAL_EXPORT const char *MDAL_Version(); @@ -68,7 +76,6 @@ MDAL_EXPORT MDAL_Status MDAL_LastStatus(); MDAL_EXPORT MeshH MDAL_LoadMesh( const char *meshFile ); //! Close mesh, free the memory MDAL_EXPORT void MDAL_CloseMesh( MeshH mesh ); - //! Return vertex count for the mesh MDAL_EXPORT int MDAL_M_vertexCount( MeshH mesh ); //! Return vertex X coord for the mesh @@ -82,6 +89,68 @@ MDAL_EXPORT int MDAL_M_faceVerticesCountAt( MeshH mesh, int index ); //! Return vertex index for face MDAL_EXPORT int MDAL_M_faceVerticesIndexAt( MeshH mesh, int face_index, int vertex_index ); +/** + * Load dataset file. On error see MDAL_LastStatus for error type. + * This may effectively load whole dataset in-memory for some providers + * Datasets will be closed automatically on mesh destruction or memory + * can be freed manually with MDAL_CloseDataset if needed + */ +MDAL_EXPORT void MDAL_M_LoadDatasets( MeshH mesh, const char *datasetFile ); + +//! Free the memory used to get dataset values +MDAL_EXPORT void MDAL_M_CloseDataset( DatasetH dataset ); + +//! Return dataset count +MDAL_EXPORT int MDAL_M_datasetCount( MeshH mesh ); + +//! Return dataset handle +MDAL_EXPORT DatasetH MDAL_M_dataset( MeshH mesh, int index ); + +//! Whether dataset has scalar data associated +MDAL_EXPORT bool MDAL_D_hasScalarData( DatasetH dataset ); + +//! Whether dataset is on vertices +MDAL_EXPORT bool MDAL_D_isOnVertices( DatasetH dataset ); + +//! Return number of metadata values +MDAL_EXPORT int MDAL_D_metadataCount( DatasetH dataset ); + +//! Return dataset metadata key +MDAL_EXPORT const char *MDAL_D_metadataKey( DatasetH dataset, int index ); + +//! Return dataset metadata value +MDAL_EXPORT const char *MDAL_D_metadataValue( DatasetH dataset, int index ); + +//! Return number of values +MDAL_EXPORT int MDAL_D_valueCount( DatasetH dataset ); + +/** + * Return scalar value associated with the index from the dataset + * for nodata return numeric_limits:quiet_NaN + */ +MDAL_EXPORT double MDAL_D_value( DatasetH dataset, int valueIndex ); + +/** + * Return X value associated with the index from the vector dataset + * for nodata return numeric_limits:quiet_NaN + */ +MDAL_EXPORT double MDAL_D_valueX( DatasetH dataset, int valueIndex ); + +/** + * Return Y value associated with the index from the vector dataset + * for nodata return numeric_limits:quiet_NaN + */ +MDAL_EXPORT double MDAL_D_valueY( DatasetH dataset, int valueIndex ); + +/** + * Whether element is active - should be taken into account + * Some formats support switching off the element for particular timestep + */ +MDAL_EXPORT bool MDAL_D_active( DatasetH dataset, int faceIndex ); + +//! Return whether dataset is valid +MDAL_EXPORT bool MDAL_D_isValid( DatasetH dataset ); + #ifdef __cplusplus } #endif diff --git a/external/mdal/frmts/mdal_2dm.cpp b/external/mdal/frmts/mdal_2dm.cpp index 5ee1d308a38..839b87a15ad 100644 --- a/external/mdal/frmts/mdal_2dm.cpp +++ b/external/mdal/frmts/mdal_2dm.cpp @@ -1,6 +1,6 @@ /* MDAL - Mesh Data Abstraction Library (MIT License) - Copyright (C) 2018 Peter Petrik (zilolv at gmail dot com) + Copyright (C) 2018 Lutra Consulting Ltd. */ #include @@ -22,14 +22,14 @@ MDAL::Loader2dm::Loader2dm( const std::string &meshFile ): { } -MDAL::Mesh *MDAL::Loader2dm::load( MDAL_Status *status ) +std::unique_ptr MDAL::Loader2dm::load( MDAL_Status *status ) { if ( status ) *status = MDAL_Status::None; if ( !MDAL::fileExists( mMeshFile ) ) { if ( status ) *status = MDAL_Status::Err_FileNotFound; - return 0; + return nullptr; } std::ifstream in( mMeshFile, std::ifstream::in ); @@ -37,11 +37,11 @@ MDAL::Mesh *MDAL::Loader2dm::load( MDAL_Status *status ) if ( !std::getline( in, line ) || !startsWith( line, "MESH2D" ) ) { if ( status ) *status = MDAL_Status::Err_UnknownFormat; - return 0; + return nullptr; } - size_t elemCount = 0; - size_t nodeCount = 0; + size_t faceCount = 0; + size_t vertexCount = 0; // Find out how many nodes and elements are contained in the .2dm mesh file while ( std::getline( in, line ) ) @@ -49,11 +49,11 @@ MDAL::Mesh *MDAL::Loader2dm::load( MDAL_Status *status ) if ( startsWith( line, "E4Q" ) || startsWith( line, "E3T" ) ) { - elemCount++; + faceCount++; } else if ( startsWith( line, "ND" ) ) { - nodeCount++; + vertexCount++; } else if ( startsWith( line, "E2L" ) || startsWith( line, "E3L" ) || @@ -62,63 +62,63 @@ MDAL::Mesh *MDAL::Loader2dm::load( MDAL_Status *status ) startsWith( line, "E9Q" ) ) { if ( status ) *status = MDAL_Status::Warn_UnsupportedElement; - elemCount += 1; // We still count them as elements + faceCount += 1; // We still count them as elements } } // Allocate memory - std::vector vertices( nodeCount ); - std::vector faces( elemCount ); + std::vector vertices( vertexCount ); + std::vector faces( faceCount ); in.clear(); in.seekg( 0, std::ios::beg ); std::vector chunks; - size_t elemIndex = 0; - size_t nodeIndex = 0; - std::map elemIDtoIndex; - std::map nodeIDtoIndex; + size_t faceIndex = 0; + size_t vertexIndex = 0; + std::map faceIDtoIndex; + std::map vertexIDtoIndex; while ( std::getline( in, line ) ) { if ( startsWith( line, "E4Q" ) ) { chunks = split( line, " ", SplitBehaviour::SkipEmptyParts ); - assert( elemIndex < elemCount ); + assert( faceIndex < faceCount ); size_t elemID = toSizeT( chunks[1] ); - std::map::iterator search = elemIDtoIndex.find( elemID ); - if ( search != elemIDtoIndex.end() ) + std::map::iterator search = faceIDtoIndex.find( elemID ); + if ( search != faceIDtoIndex.end() ) { if ( status ) *status = MDAL_Status::Warn_ElementNotUnique; continue; } - elemIDtoIndex[elemID] = elemIndex; - Face &face = faces[elemIndex]; + faceIDtoIndex[elemID] = faceIndex; + Face &face = faces[faceIndex]; face.resize( 4 ); // Right now we just store node IDs here - we will convert them to node indices afterwards for ( size_t i = 0; i < 4; ++i ) face[i] = toSizeT( chunks[i + 2] ); - elemIndex++; + faceIndex++; } else if ( startsWith( line, "E3T" ) ) { chunks = split( line, " ", SplitBehaviour::SkipEmptyParts ); - assert( elemIndex < elemCount ); + assert( faceIndex < faceCount ); size_t elemID = toSizeT( chunks[1] ); - std::map::iterator search = elemIDtoIndex.find( elemID ); - if ( search != elemIDtoIndex.end() ) + std::map::iterator search = faceIDtoIndex.find( elemID ); + if ( search != faceIDtoIndex.end() ) { if ( status ) *status = MDAL_Status::Warn_ElementNotUnique; continue; } - elemIDtoIndex[elemID] = elemIndex; - Face &face = faces[elemIndex]; + faceIDtoIndex[elemID] = faceIndex; + Face &face = faces[faceIndex]; face.resize( 3 ); // Right now we just store node IDs here - we will convert them to node indices afterwards for ( size_t i = 0; i < 3; ++i ) @@ -126,7 +126,7 @@ MDAL::Mesh *MDAL::Loader2dm::load( MDAL_Status *status ) face[i] = toSizeT( chunks[i + 2] ); } - elemIndex++; + faceIndex++; } else if ( startsWith( line, "E2L" ) || startsWith( line, "E3L" ) || @@ -136,39 +136,39 @@ MDAL::Mesh *MDAL::Loader2dm::load( MDAL_Status *status ) { // We do not yet support these elements chunks = split( line, " ", SplitBehaviour::SkipEmptyParts ); - assert( elemIndex < elemCount ); + assert( faceIndex < faceCount ); size_t elemID = toSizeT( chunks[1] ); - std::map::iterator search = elemIDtoIndex.find( elemID ); - if ( search != elemIDtoIndex.end() ) + std::map::iterator search = faceIDtoIndex.find( elemID ); + if ( search != faceIDtoIndex.end() ) { if ( status ) *status = MDAL_Status::Warn_ElementNotUnique; continue; } - elemIDtoIndex[elemID] = elemIndex; + faceIDtoIndex[elemID] = faceIndex; assert( false ); //TODO mark element as unusable - elemIndex++; + faceIndex++; } else if ( startsWith( line, "ND" ) ) { chunks = split( line, " ", SplitBehaviour::SkipEmptyParts ); size_t nodeID = toSizeT( chunks[1] ); - std::map::iterator search = nodeIDtoIndex.find( nodeID ); - if ( search != nodeIDtoIndex.end() ) + std::map::iterator search = vertexIDtoIndex.find( nodeID ); + if ( search != vertexIDtoIndex.end() ) { if ( status ) *status = MDAL_Status::Warn_NodeNotUnique; continue; } - nodeIDtoIndex[nodeID] = nodeIndex; - assert( nodeIndex < nodeCount ); - Vertex &vertex = vertices[nodeIndex]; + vertexIDtoIndex[nodeID] = vertexIndex; + assert( vertexIndex < vertexCount ); + Vertex &vertex = vertices[vertexIndex]; vertex.x = toDouble( chunks[2] ); vertex.y = toDouble( chunks[3] ); - nodeIndex++; + vertexIndex++; } } @@ -179,8 +179,8 @@ MDAL::Mesh *MDAL::Loader2dm::load( MDAL_Status *status ) { size_t nodeID = face[nd]; - std::map::iterator ni2i = nodeIDtoIndex.find( nodeID ); - if ( ni2i != nodeIDtoIndex.end() ) + std::map::iterator ni2i = vertexIDtoIndex.find( nodeID ); + if ( ni2i != vertexIDtoIndex.end() ) { face[nd] = ni2i->second; // convert from ID to index } @@ -196,9 +196,12 @@ MDAL::Mesh *MDAL::Loader2dm::load( MDAL_Status *status ) //check that we have distinct nodes } - Mesh *mesh = new Mesh; + std::unique_ptr< Mesh > mesh( new Mesh ); + mesh->uri = mMeshFile; mesh->faces = faces; mesh->vertices = vertices; + mesh->faceIDtoIndex = faceIDtoIndex; + mesh->vertexIDtoIndex = vertexIDtoIndex; return mesh; } diff --git a/external/mdal/frmts/mdal_2dm.hpp b/external/mdal/frmts/mdal_2dm.hpp index e1bdf9936a3..3abd1f8555c 100644 --- a/external/mdal/frmts/mdal_2dm.hpp +++ b/external/mdal/frmts/mdal_2dm.hpp @@ -7,6 +7,7 @@ #define MDAL_2DM_HPP #include +#include #include "mdal_defines.hpp" #include "mdal.h" @@ -18,7 +19,7 @@ namespace MDAL { public: Loader2dm( const std::string &meshFile ); - Mesh *load( MDAL_Status *status ); + std::unique_ptr< Mesh > load( MDAL_Status *status ); private: std::string mMeshFile; diff --git a/external/mdal/frmts/mdal_ascii_dat.cpp b/external/mdal/frmts/mdal_ascii_dat.cpp new file mode 100644 index 00000000000..d80afa5e0e5 --- /dev/null +++ b/external/mdal/frmts/mdal_ascii_dat.cpp @@ -0,0 +1,305 @@ +/* + MDAL - Mesh Data Abstraction Library (MIT License) + Copyright (C) 2018 Lutra Consulting Ltd. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mdal_ascii_dat.hpp" +#include "mdal.h" +#include "mdal_utils.hpp" + +#include + +#define EXIT_WITH_ERROR(error) { if (status) *status = (error); return; } + +MDAL::LoaderAsciiDat::LoaderAsciiDat( const std::string &datFile ): + mDatFile( datFile ) +{ +} + +/** + * The DAT format contains "datasets" and each dataset has N-outputs. One output + * represents data for all vertices/faces for one timestep + * + * In MDAL we convert one output to one MDAL dataset; + * + */ +void MDAL::LoaderAsciiDat::load( MDAL::Mesh *mesh, MDAL_Status *status ) +{ + if ( status ) *status = MDAL_Status::None; + + if ( !MDAL::fileExists( mDatFile ) ) + { + if ( status ) *status = MDAL_Status::Err_FileNotFound; + return; + } + + std::ifstream in( mDatFile, std::ifstream::in ); + std::string line; + if ( !std::getline( in, line ) ) + { + if ( status ) *status = MDAL_Status::Err_UnknownFormat; + return; + } + line = trim( line ); + std::string basename = baseName( mDatFile ); + + // http://www.xmswiki.com/xms/SMS:ASCII_Dataset_Files_*.dat + // Apart from the format specified above, there is an older supported format used in BASEMENT (and SMS?) + // which is simpler (has only one dataset in one file, no status flags etc) + bool oldFormat; + bool isVector = false; + bool readingDataset = false; // whether we are in process of reading the dataset + + std::string baseDatasetName( basename ); + std::vector> datOutputs; // DAT outputs data + + if ( line == "DATASET" ) + oldFormat = false; + else if ( line == "SCALAR" || line == "VECTOR" ) + { + oldFormat = true; + isVector = ( line == "VECTOR" ); + baseDatasetName = basename; + readingDataset = true; + } + else + EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat ); + + // see if it contains element-centered results - supported by BASEMENT + bool elementCentered = false; + if ( !oldFormat && contains( basename, "_els_" ) ) + elementCentered = true; + + while ( std::getline( in, line ) ) + { + std::vector items = split( line, " ", SplitBehaviour::SkipEmptyParts ); + if ( items.size() < 1 ) + continue; // empty line?? let's skip it + + std::string cardType = items[0]; + if ( cardType == "ND" && items.size() >= 2 ) + { + size_t fileNodeCount = toSizeT( items[1] ); + if ( mesh->vertexIDtoIndex.size() != fileNodeCount ) + EXIT_WITH_ERROR( MDAL_Status::Err_IncompatibleMesh ); + } + else if ( !oldFormat && cardType == "NC" && items.size() >= 2 ) + { + size_t fileElemCount = toSizeT( items[1] ); + if ( mesh->faceIDtoIndex.size() != fileElemCount ) + EXIT_WITH_ERROR( MDAL_Status::Err_IncompatibleMesh ); + } + else if ( !oldFormat && cardType == "OBJTYPE" ) + { + if ( items[1] != "mesh2d" && items[1] != "\"mesh2d\"" ) + EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat ); + } + else if ( !oldFormat && ( cardType == "BEGSCL" || cardType == "BEGVEC" ) ) + { + if ( readingDataset ) + { + debug( "New dataset while previous one is still active!" ); + EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat ); + } + isVector = cardType == "BEGVEC"; + baseDatasetName = basename; + readingDataset = true; + } + else if ( !oldFormat && cardType == "ENDDS" ) + { + if ( !readingDataset ) + { + debug( "ENDDS card for no active dataset!" ); + EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat ); + } + + addDatasets( mesh, baseDatasetName, datOutputs ); + } + else if ( !oldFormat && cardType == "NAME" && items.size() >= 2 ) + { + if ( !readingDataset ) + { + debug( "NAME card for no active dataset!" ); + EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat ); + } + + size_t quoteIdx1 = line.find( '\"' ); + size_t quoteIdx2 = line.find( '\"', quoteIdx1 + 1 ); + if ( quoteIdx1 != std::string::npos && quoteIdx2 != std::string::npos ) + baseDatasetName = line.substr( quoteIdx1 + 1, quoteIdx2 - quoteIdx1 - 1 ); + } + else if ( oldFormat && ( cardType == "SCALAR" || cardType == "VECTOR" ) ) + { + // just ignore - we know the type from earlier... + } + else if ( cardType == "TS" && items.size() >= ( oldFormat ? 2 : 3 ) ) + { + double t = toDouble( items[oldFormat ? 1 : 2] ); + + if ( elementCentered ) + { + readFaceTimestep( mesh, datOutputs, t, isVector, in ); + } + else + { + bool hasStatus = ( oldFormat ? false : toBool( items[1] ) ); + readVertexTimestep( mesh, datOutputs, t, isVector, hasStatus, in ); + } + + } + else + { + std::stringstream str; + str << " Unknown card:" << line; + debug( str.str() ); + } + } + + if ( oldFormat ) + { + if ( datOutputs.size() == 0 ) + EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat ); + + addDatasets( mesh, baseDatasetName, datOutputs ); + } +} + +void MDAL::LoaderAsciiDat::addDatasets( MDAL::Mesh *mesh, + const std::string &name, + const std::vector> &datOutputs ) const +{ + for ( const std::shared_ptr &ds : datOutputs ) + { + ds->uri = mDatFile; + ds->setName( name ); + ds->isValid = true; + } + + //https://stackoverflow.com/a/2551785/2838364 + mesh->datasets.insert( + mesh->datasets.end(), + datOutputs.begin(), + datOutputs.end() + ); +} + +void MDAL::LoaderAsciiDat::readVertexTimestep( const MDAL::Mesh *mesh, std::vector > &datOutputs, double t, bool isVector, bool hasStatus, std::ifstream &stream ) +{ + size_t vertexCount = mesh->vertices.size(); + size_t faceCount = mesh->faces.size(); + + std::shared_ptr dataset( new MDAL::Dataset ); + dataset->isScalar = !isVector; //everything else to be set in addDatasets + dataset->setMetadata( "time", std::to_string( t / 3600. ) ); + dataset->values.resize( vertexCount ); + dataset->active.resize( faceCount ); + dataset->isOnVertices = true; + + // only for new format + for ( size_t i = 0; i < faceCount; ++i ) + { + if ( hasStatus ) + { + std::string line; + std::getline( stream, line ); + dataset->active[i] = toBool( line ); + } + else + dataset->active[i] = true; + } + + for ( size_t i = 0; i < mesh->vertexIDtoIndex.size(); ++i ) + { + std::string line; + std::getline( stream, line ); + std::vector tsItems = split( line, " ", SplitBehaviour::SkipEmptyParts ); + + auto idx = mesh->vertexIDtoIndex.find( i + 1 ); // ID in 2dm are numbered from 1 + if ( idx == mesh->vertexIDtoIndex.end() ) + continue; // node ID that does not exist in the mesh + + size_t index = idx->second; + + if ( isVector ) + { + if ( tsItems.size() >= 2 ) // BASEMENT files with vectors have 3 columns + { + dataset->values[index].x = toDouble( tsItems[0] ); + dataset->values[index].y = toDouble( tsItems[1] ); + } + else + { + debug( "invalid timestep line" ); + dataset->values[index].noData = true; + } + } + else + { + if ( tsItems.size() >= 1 ) + dataset->values[index].x = toDouble( tsItems[0] ); + else + { + debug( "invalid timestep line" ); + dataset->values[index].noData = true; + } + } + } + + datOutputs.push_back( std::move( dataset ) ); +} + +void MDAL::LoaderAsciiDat::readFaceTimestep( const MDAL::Mesh *mesh, std::vector > &datOutputs, double t, bool isVector, std::ifstream &stream ) +{ + size_t faceCount = mesh->faces.size(); + + std::shared_ptr dataset( new MDAL::Dataset ); + dataset->isScalar = !isVector; //everything else to be set in addDatasets + dataset->setMetadata( "time", std::to_string( t / 3600. ) ); + dataset->values.resize( faceCount ); + dataset->isOnVertices = false; + + // TODO: hasStatus + for ( size_t index = 0; index < faceCount; ++index ) + { + std::string line; + std::getline( stream, line ); + std::vector tsItems = split( line, " ", SplitBehaviour::SkipEmptyParts ); + + if ( isVector ) + { + if ( tsItems.size() >= 2 ) // BASEMENT files with vectors have 3 columns + { + dataset->values[index].x = toDouble( tsItems[0] ); + dataset->values[index].y = toDouble( tsItems[1] ); + } + else + { + debug( "invalid timestep line" ); + dataset->values[index].noData = true; + } + } + else + { + if ( tsItems.size() >= 1 ) + dataset->values[index].x = toDouble( tsItems[0] ); + else + { + debug( "invalid timestep line" ); + dataset->values[index].noData = true; + } + } + } + + datOutputs.push_back( std::move( dataset ) ); +} diff --git a/external/mdal/frmts/mdal_ascii_dat.hpp b/external/mdal/frmts/mdal_ascii_dat.hpp new file mode 100644 index 00000000000..bd1bcdc3122 --- /dev/null +++ b/external/mdal/frmts/mdal_ascii_dat.hpp @@ -0,0 +1,52 @@ +/* + MDAL - Mesh Data Abstraction Library (MIT License) + Copyright (C) 2018 Peter Petrik (zilolv at gmail dot com) +*/ + +#ifndef MDAL_ASCII_DAT_HPP +#define MDAL_ASCII_DAT_HPP + +#include +#include +#include +#include +#include +#include + +#include "mdal_defines.hpp" +#include "mdal.h" + +namespace MDAL +{ + + class LoaderAsciiDat + { + public: + LoaderAsciiDat( const std::string &datFile ); + void load( Mesh *mesh, MDAL_Status *status ); + + private: + void readVertexTimestep( + const Mesh *mesh, + std::vector> &datOutputs, + double t, + bool isVector, + bool hasStatus, + std::ifstream &stream ); + + void readFaceTimestep( + const Mesh *mesh, + std::vector> &datOutputs, + double t, + bool isVector, + std::ifstream &stream ); + + void addDatasets( MDAL::Mesh *mesh, + const std::string &name, + const std::vector> &datOutputs ) const; + + std::string mDatFile; + }; + +} // namespace MDAL +#endif //MDAL_ASCII_DAT_HPP diff --git a/external/mdal/frmts/mdal_binary_dat.cpp b/external/mdal/frmts/mdal_binary_dat.cpp new file mode 100644 index 00000000000..6166b2ab37c --- /dev/null +++ b/external/mdal/frmts/mdal_binary_dat.cpp @@ -0,0 +1,307 @@ +/* + MDAL - Mesh Data Abstraction Library (MIT License) + Copyright (C) 2018 Lutra Consulting Ltd. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mdal_binary_dat.hpp" +#include "mdal.h" +#include "mdal_utils.hpp" + +#include + +static const int CT_VERSION = 3000; +static const int CT_OBJTYPE = 100; +static const int CT_SFLT = 110; +static const int CT_SFLG = 120; +static const int CT_BEGSCL = 130; +static const int CT_BEGVEC = 140; +static const int CT_VECTYPE = 150; +static const int CT_OBJID = 160; +static const int CT_NUMDATA = 170; +static const int CT_NUMCELLS = 180; +static const int CT_NAME = 190; +static const int CT_TS = 200; +static const int CT_ENDDS = 210; +static const int CT_RT_JULIAN = 240; +static const int CT_TIMEUNITS = 250; + +static const int CT_2D_MESHES = 3; +static const int CT_FLOAT_SIZE = 4; +static const int CF_FLAG_SIZE = 1; +static const int CF_FLAG_INT_SIZE = 4; + +#define EXIT_WITH_ERROR(error) { if (status) *status = (error); return; } + +static bool read( std::ifstream &in, char *s, int n ) +{ + in.read( s, n ); + if ( !in ) + return true; //error + else + return false; //OK +} + +static bool readIStat( std::ifstream &in, int sflg, char *flag ) +{ + if ( sflg == CF_FLAG_SIZE ) + { + in.read( flag, sflg ); + if ( !in ) + return true; // error + } + else + { + int istat; + in.read( ( char * )&istat, sflg ); + if ( !in ) + return true; // error + else + *flag = ( istat == 1 ); + } + return false; +} + +MDAL::LoaderBinaryDat::LoaderBinaryDat( const std::string &datFile ): + mDatFile( datFile ) +{ +} + +/** + * The DAT format contains "datasets" and each dataset has N-outputs. One output + * represents data for all vertices/faces for one timestep + * + * in TUFLOW results there could be also a special timestep (99999) with maximums + * we will put it into a separate dataset with name suffixed with "/Maximums" + * + * In MDAL we convert one output to one MDAL dataset; + * + */ +void MDAL::LoaderBinaryDat::load( MDAL::Mesh *mesh, MDAL_Status *status ) +{ + if ( status ) *status = MDAL_Status::None; + + if ( !MDAL::fileExists( mDatFile ) ) + { + if ( status ) *status = MDAL_Status::Err_FileNotFound; + return; + } + + std::ifstream in( mDatFile, std::ifstream::in | std::ifstream::binary ); + + // implementation based on information from: + // http://www.xmswiki.com/wiki/SMS:Binary_Dataset_Files_*.dat + if ( !in ) + EXIT_WITH_ERROR( MDAL_Status::Err_FileNotFound ); // Couldn't open the file + + size_t vertexCount = mesh->vertices.size(); + size_t elemCount = mesh->faces.size(); + + int card = 0; + int version; + int objecttype; + int sflt; + int sflg; + int vectype; + int objid; + int numdata; + int numcells; + char name[40]; + char istat; + float time; + + if ( read( in, ( char * )&version, 4 ) ) + EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat ); + + if ( version != CT_VERSION ) // Version should be 3000 + EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat ); + + bool isVector = false; + std::string baseDatasetName; + std::vector> datOutputs; // DAT outputs data + + while ( card != CT_ENDDS ) + { + if ( read( in, ( char * )&card, 4 ) ) + { + // We've reached the end of the file and there was no ends card + break; + } + + switch ( card ) + { + + case CT_OBJTYPE: + // Object type + if ( read( in, ( char * )&objecttype, 4 ) || objecttype != CT_2D_MESHES ) + EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat ); + break; + + case CT_SFLT: + // Float size + if ( read( in, ( char * )&sflt, 4 ) || sflt != CT_FLOAT_SIZE ) + EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat ); + break; + + case CT_SFLG: + // Flag size + if ( read( in, ( char * )&sflg, 4 ) ) + if ( sflg != CF_FLAG_SIZE && sflg != CF_FLAG_INT_SIZE ) + EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat ); + break; + + case CT_BEGSCL: + isVector = false; + break; + + case CT_BEGVEC: + isVector = true; + break; + + case CT_VECTYPE: + // Vector type + if ( read( in, ( char * )&vectype, 4 ) || vectype != 0 ) + EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat ); + break; + + case CT_OBJID: + // Object id + if ( read( in, ( char * )&objid, 4 ) ) + EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat ); + break; + + case CT_NUMDATA: + // Num data + if ( read( in, ( char * )&numdata, 4 ) ) + EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat ); + if ( numdata != ( int ) vertexCount ) + EXIT_WITH_ERROR( MDAL_Status::Err_IncompatibleMesh ); + break; + + case CT_NUMCELLS: + // Num data + if ( read( in, ( char * )&numcells, 4 ) ) + EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat ); + if ( numcells != ( int ) elemCount ) + EXIT_WITH_ERROR( MDAL_Status::Err_IncompatibleMesh ); + break; + + case CT_NAME: + // Name + if ( read( in, ( char * )&name, 40 ) ) + EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat ); + if ( name[39] != 0 ) + name[39] = 0; + baseDatasetName = trim( std::string( name ) ); + break; + + case CT_TS: + // Time step! + if ( readIStat( in, sflg, &istat ) ) + EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat ); + + if ( read( in, ( char * )&time, 4 ) ) + EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat ); + + if ( readVertexTimestep( mesh, datOutputs, time, isVector, istat, sflg, in ) ) + EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat ); + + break; + } + } + + if ( datOutputs.size() == 0 ) + EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat ); + + addDatasets( mesh, baseDatasetName, datOutputs ); +} + + +void MDAL::LoaderBinaryDat::addDatasets( MDAL::Mesh *mesh, + const std::string &name, + const std::vector> &datOutputs ) const +{ + for ( const std::shared_ptr &ds : datOutputs ) + { + ds->uri = mDatFile; + std::string suffix = ds->name(); + ds->setName( name + suffix ); + ds->isValid = true; + } + + //https://stackoverflow.com/a/2551785/2838364 + mesh->datasets.insert( + mesh->datasets.end(), + datOutputs.begin(), + datOutputs.end() + ); +} + +bool MDAL::LoaderBinaryDat::readVertexTimestep( const MDAL::Mesh *mesh, std::vector > &datOutputs, float time, + bool isVector, bool hasStatus, int sflg, std::ifstream &in ) +{ + size_t vertexCount = mesh->vertices.size(); + size_t faceCount = mesh->faces.size(); + + std::shared_ptr dataset( new MDAL::Dataset ); + dataset->isScalar = !isVector; //everything else to be set in addDatasets + dataset->setMetadata( "time", std::to_string( time / 3600.0f ) ); + dataset->values.resize( vertexCount ); + dataset->active.resize( faceCount ); + dataset->isOnVertices = true; + + // name will be set properly in the addDatasets at the end. + if ( time == 99999 ) // Special TUFLOW dataset with maximus + dataset->setName( "/Maximums" ); + + bool active = true; + for ( size_t i = 0; i < faceCount; ++i ) + { + if ( hasStatus ) + { + if ( readIStat( in, sflg, ( char * )&active ) ) + return true; //error + + } + dataset->active[i] = active; + } + + for ( size_t i = 0; i < vertexCount; ++i ) + { + if ( isVector ) + { + float x, y; + + if ( read( in, ( char * )&x, 4 ) ) + return true; //error + if ( read( in, ( char * )&y, 4 ) ) + return true; //error + + dataset->values[i].x = x; + dataset->values[i].y = y; + } + else + { + float scalar; + + if ( read( in, ( char * )&scalar, 4 ) ) + return true; //error + + dataset->values[i].x = scalar; + } + } + + datOutputs.push_back( std::move( dataset ) ); + + return false; //OK +} diff --git a/external/mdal/frmts/mdal_binary_dat.hpp b/external/mdal/frmts/mdal_binary_dat.hpp new file mode 100644 index 00000000000..1a790b32651 --- /dev/null +++ b/external/mdal/frmts/mdal_binary_dat.hpp @@ -0,0 +1,46 @@ +/* + MDAL - Mesh Data Abstraction Library (MIT License) + Copyright (C) 2018 Peter Petrik (zilolv at gmail dot com) +*/ + +#ifndef MDAL_BINARY_DAT_HPP +#define MDAL_BINARY_DAT_HPP + +#include +#include +#include +#include +#include +#include + +#include "mdal_defines.hpp" +#include "mdal.h" + +namespace MDAL +{ + + class LoaderBinaryDat + { + public: + LoaderBinaryDat( const std::string &datFile ); + void load( Mesh *mesh, MDAL_Status *status ); + + private: + bool readVertexTimestep( + const Mesh *mesh, + std::vector> &datOutputs, + float time, + bool isVector, + bool hasStatus, + int sflg, + std::ifstream &in ); + + void addDatasets( MDAL::Mesh *mesh, + const std::string &name, + const std::vector> &datOutputs ) const; + + std::string mDatFile; + }; + +} // namespace MDAL +#endif //MDAL_BINARY_DAT_HPP diff --git a/external/mdal/mdal.cpp b/external/mdal/mdal.cpp index c5db6db755f..cf989155f1d 100644 --- a/external/mdal/mdal.cpp +++ b/external/mdal/mdal.cpp @@ -1,16 +1,19 @@ #include -#include #include +#include #include "mdal.h" #include "mdal_loader.hpp" #include "mdal_defines.hpp" +#define NODATA std::numeric_limits::quiet_NaN() +static const char *EMPTY_STR = ""; + static MDAL_Status sLastStatus; const char *MDAL_Version() { - return "0.0.2"; + return "0.0.3"; } MDAL_Status MDAL_LastStatus() @@ -21,10 +24,13 @@ MDAL_Status MDAL_LastStatus() MeshH MDAL_LoadMesh( const char *meshFile ) { if ( !meshFile ) + { + sLastStatus = MDAL_Status::Err_FileNotFound; return nullptr; + } std::string filename( meshFile ); - return ( MeshH ) MDAL::Loader::load( filename, &sLastStatus ); + return static_cast< MeshH >( MDAL::Loader::load( filename, &sLastStatus ).release() ); } @@ -32,7 +38,7 @@ void MDAL_CloseMesh( MeshH mesh ) { if ( mesh ) { - MDAL::Mesh *m = ( MDAL::Mesh * ) mesh; + MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); delete m; } } @@ -40,61 +46,344 @@ void MDAL_CloseMesh( MeshH mesh ) int MDAL_M_vertexCount( MeshH mesh ) { - assert( mesh ); - MDAL::Mesh *m = ( MDAL::Mesh * ) mesh; + if ( !mesh ) + { + sLastStatus = MDAL_Status::Err_IncompatibleMesh; + return 0; + } + + MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); int len = static_cast( m->vertices.size() ); return len; } double MDAL_M_vertexXCoordinatesAt( MeshH mesh, int index ) { - assert( mesh ); - MDAL::Mesh *m = ( MDAL::Mesh * ) mesh; - assert( index > -1 ); + if ( !mesh ) + { + sLastStatus = MDAL_Status::Err_IncompatibleMesh; + return NODATA; + } + MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); + if ( index < 0 ) + { + sLastStatus = MDAL_Status::Err_IncompatibleMesh; + return NODATA; + } size_t i = static_cast( index ); - assert( m->vertices.size() > i ); + if ( m->vertices.size() <= i ) + { + sLastStatus = MDAL_Status::Err_IncompatibleMesh; + return NODATA; + } return m->vertices[i].x; } double MDAL_M_vertexYCoordinatesAt( MeshH mesh, int index ) { - assert( mesh ); - MDAL::Mesh *m = ( MDAL::Mesh * ) mesh; - assert( index > -1 ); + if ( !mesh ) + { + sLastStatus = MDAL_Status::Err_IncompatibleMesh; + return NODATA; + } + MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); + if ( index < 0 ) + { + sLastStatus = MDAL_Status::Err_IncompatibleMesh; + return NODATA; + } size_t i = static_cast( index ); - assert( m->vertices.size() > i ); + if ( m->vertices.size() <= i ) + { + sLastStatus = MDAL_Status::Err_IncompatibleMesh; + return NODATA; + } return m->vertices[i].y; } int MDAL_M_faceCount( MeshH mesh ) { - assert( mesh ); - MDAL::Mesh *m = ( MDAL::Mesh * ) mesh; + if ( !mesh ) + { + sLastStatus = MDAL_Status::Err_IncompatibleMesh; + return 0; + } + MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); int len = static_cast( m->faces.size() ); return len; } int MDAL_M_faceVerticesCountAt( MeshH mesh, int index ) { - assert( mesh ); - MDAL::Mesh *m = ( MDAL::Mesh * ) mesh; - assert( index > -1 ); + if ( !mesh ) + { + sLastStatus = MDAL_Status::Err_IncompatibleMesh; + return 0; + } + MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); + if ( index < 0 ) + { + sLastStatus = MDAL_Status::Err_IncompatibleMesh; + return 0; + } size_t i = static_cast( index ); - assert( m->faces.size() > i ); + if ( m->faces.size() <= i ) + { + sLastStatus = MDAL_Status::Err_IncompatibleMesh; + return 0; + } int len = static_cast( m->faces[i].size() ); return len; } int MDAL_M_faceVerticesIndexAt( MeshH mesh, int face_index, int vertex_index ) { - assert( mesh ); - MDAL::Mesh *m = ( MDAL::Mesh * ) mesh; - assert( face_index > -1 ); + if ( !mesh ) + { + sLastStatus = MDAL_Status::Err_IncompatibleMesh; + return 0; + } + MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); + if ( face_index < 0 ) + { + sLastStatus = MDAL_Status::Err_IncompatibleMesh; + return 0; + } size_t fi = static_cast( face_index ); - assert( m->faces.size() > fi ); - assert( vertex_index > -1 ); + if ( m->faces.size() <= fi ) + { + sLastStatus = MDAL_Status::Err_IncompatibleMesh; + return 0; + } + if ( vertex_index < 0 ) + { + sLastStatus = MDAL_Status::Err_IncompatibleMesh; + return 0; + } size_t vi = static_cast( vertex_index ); - assert( m->faces[fi].size() > vi ); + if ( m->faces[fi].size() <= vi ) + { + sLastStatus = MDAL_Status::Err_IncompatibleMesh; + return 0; + } int len = static_cast( m->faces[fi][vi] ); return len; } + +void MDAL_M_LoadDatasets( MeshH mesh, const char *datasetFile ) +{ + if ( !datasetFile ) + { + sLastStatus = MDAL_Status::Err_FileNotFound; + return; + } + + if ( !mesh ) + { + sLastStatus = MDAL_Status::Err_IncompatibleMesh; + return; + } + + MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); + + std::string filename( datasetFile ); + MDAL::Loader::loadDatasets( m, datasetFile, &sLastStatus ); +} + +void MDAL_M_CloseDataset( DatasetH dataset ) +{ + if ( !dataset ) + { + return; + } + + MDAL::Dataset *d = static_cast< MDAL::Dataset * >( dataset ); + d->free(); +} + +int MDAL_M_datasetCount( MeshH mesh ) +{ + if ( !mesh ) + { + sLastStatus = MDAL_Status::Err_IncompatibleMesh; + return 0; + } + MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); + int len = static_cast( m->datasets.size() ); + return len; +} + +DatasetH MDAL_M_dataset( MeshH mesh, int index ) +{ + if ( !mesh ) + { + sLastStatus = MDAL_Status::Err_IncompatibleMesh; + return nullptr; + } + MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); + int len = static_cast( m->datasets.size() ); + if ( len <= index ) + { + sLastStatus = MDAL_Status::Err_IncompatibleMesh; + return nullptr; + } + size_t i = static_cast( index ); + return static_cast< DatasetH >( m->datasets[i].get() ); +} + +bool MDAL_D_hasScalarData( DatasetH dataset ) +{ + if ( !dataset ) + { + sLastStatus = MDAL_Status::Err_IncompatibleDataset; + return true; + } + MDAL::Dataset *d = static_cast< MDAL::Dataset * >( dataset ); + return d->isScalar; +} + +bool MDAL_D_isOnVertices( DatasetH dataset ) +{ + if ( !dataset ) + { + sLastStatus = MDAL_Status::Err_IncompatibleDataset; + return true; + } + MDAL::Dataset *d = static_cast< MDAL::Dataset * >( dataset ); + return d->isOnVertices; +} + +int MDAL_D_metadataCount( DatasetH dataset ) +{ + if ( !dataset ) + { + sLastStatus = MDAL_Status::Err_IncompatibleDataset; + return 0; + } + MDAL::Dataset *d = static_cast< MDAL::Dataset * >( dataset ); + int len = static_cast( d->metadata.size() ); + return len; +} + +const char *MDAL_D_metadataKey( DatasetH dataset, int index ) +{ + if ( !dataset ) + { + sLastStatus = MDAL_Status::Err_IncompatibleDataset; + return EMPTY_STR; + } + + MDAL::Dataset *d = static_cast< MDAL::Dataset * >( dataset ); + int len = static_cast( d->metadata.size() ); + if ( len <= index ) + { + sLastStatus = MDAL_Status::Err_IncompatibleDataset; + return nullptr; + } + size_t i = static_cast( index ); + return d->metadata[i].first.c_str(); +} + +const char *MDAL_D_metadataValue( DatasetH dataset, int index ) +{ + if ( !dataset ) + { + sLastStatus = MDAL_Status::Err_IncompatibleDataset; + return EMPTY_STR; + } + MDAL::Dataset *d = static_cast< MDAL::Dataset * >( dataset ); + int len = static_cast( d->metadata.size() ); + if ( len <= index ) + { + sLastStatus = MDAL_Status::Err_IncompatibleDataset; + return nullptr; + } + size_t i = static_cast( index ); + return d->metadata[i].second.c_str(); +} + +int MDAL_D_valueCount( DatasetH dataset ) +{ + if ( !dataset ) + { + sLastStatus = MDAL_Status::Err_IncompatibleDataset; + return 0; + } + MDAL::Dataset *d = static_cast< MDAL::Dataset * >( dataset ); + int len = static_cast( d->values.size() ); + return len; +} + +double MDAL_D_value( DatasetH dataset, int valueIndex ) +{ + return MDAL_D_valueX( dataset, valueIndex ); +} + +double MDAL_D_valueX( DatasetH dataset, int valueIndex ) +{ + if ( !dataset ) + { + sLastStatus = MDAL_Status::Err_IncompatibleDataset; + return NODATA; + } + MDAL::Dataset *d = static_cast< MDAL::Dataset * >( dataset ); + int len = static_cast( d->values.size() ); + if ( len <= valueIndex ) + { + sLastStatus = MDAL_Status::Err_IncompatibleDataset; + return NODATA; + } + size_t i = static_cast( valueIndex ); + if ( d->values[i].noData ) + { + return NODATA; + } + else + return d->values[i].x; +} + +double MDAL_D_valueY( DatasetH dataset, int valueIndex ) +{ + if ( !dataset ) + { + sLastStatus = MDAL_Status::Err_IncompatibleDataset; + return NODATA; + } + MDAL::Dataset *d = static_cast< MDAL::Dataset * >( dataset ); + int len = static_cast( d->values.size() ); + if ( len <= valueIndex ) + { + sLastStatus = MDAL_Status::Err_IncompatibleDataset; + return NODATA; + } + size_t i = static_cast( valueIndex ); + if ( d->values[i].noData ) + { + return NODATA; + } + else + return d->values[i].y; +} + +bool MDAL_D_isValid( DatasetH dataset ) +{ + if ( !dataset ) + { + sLastStatus = MDAL_Status::Err_IncompatibleDataset; + return false; + } + MDAL::Dataset *d = static_cast< MDAL::Dataset * >( dataset ); + return d->isValid; +} + +bool MDAL_D_active( DatasetH dataset, int faceIndex ) +{ + if ( !dataset ) + { + sLastStatus = MDAL_Status::Err_IncompatibleDataset; + return false; + } + MDAL::Dataset *d = static_cast< MDAL::Dataset * >( dataset ); + size_t i = static_cast( faceIndex ); + return d->isActive( i ); +} diff --git a/external/mdal/mdal_defines.hpp b/external/mdal/mdal_defines.hpp index f1259b6c653..305a59773f2 100644 --- a/external/mdal/mdal_defines.hpp +++ b/external/mdal/mdal_defines.hpp @@ -8,6 +8,8 @@ #include #include +#include +#include namespace MDAL { @@ -20,12 +22,105 @@ namespace MDAL typedef std::vector Face; - struct Mesh + + + + typedef struct { - std::vector vertices; - std::vector faces; + double x; + double y; + + bool noData = false; + } Value; //Dataset Value + + class Dataset + { + public: + + std::string getMetadata( const std::string &key ) + { + for ( auto pair : metadata ) + { + if ( pair.first == key ) + { + return pair.second; + } + } + return std::string(); + } + + void setMetadata( const std::string &key, const std::string &val ) + { + bool found = false; + for ( auto pair : metadata ) + { + if ( pair.first == key ) + { + found = true; + pair.second = val; + } + } + if ( !found ) + metadata.push_back( std::make_pair( key, val ) ); + } + + std::string name() + { + return getMetadata( "name" ); + } + + void setName( const std::string &name ) + { + setMetadata( "name", name ); + } + + std::vector< std::pair< std::string, std::string > > metadata; + std::vector values; // size - vertex count if isOnVertices + // size - face count if !isOnVertices + std::vector active; // size - face count. Whether the output for this is active... + + bool isScalar = true; + bool isOnVertices = true; + bool isValid = true; + + std::string uri; // file/uri from where it came + + + void free() + { + values.clear(); + metadata.clear(); + isValid = false; + } + + bool isActive( size_t faceIndex ) + { + if ( isOnVertices ) + { + if ( active.size() > faceIndex ) + return active[faceIndex]; + else + return false; + } + else + { + return true; + } + } }; + struct Mesh + { + std::string uri; // file/uri from where it came + + std::vector vertices; + std::map vertexIDtoIndex; // only for 2DM and DAT files + + std::vector faces; + std::map faceIDtoIndex; // only for 2DM and DAT files + + std::vector> datasets; + }; } // namespace MDAL #endif //MDAL_DEFINES_HPP diff --git a/external/mdal/mdal_loader.cpp b/external/mdal/mdal_loader.cpp index cde668b04ce..b6b82f0e5f2 100644 --- a/external/mdal/mdal_loader.cpp +++ b/external/mdal/mdal_loader.cpp @@ -5,9 +5,23 @@ #include "mdal_loader.hpp" #include "frmts/mdal_2dm.hpp" +#include "frmts/mdal_ascii_dat.hpp" +#include "frmts/mdal_binary_dat.hpp" -MDAL::Mesh *MDAL::Loader::load( const std::string &meshFile, MDAL_Status *status ) +std::unique_ptr MDAL::Loader::load( const std::string &meshFile, MDAL_Status *status ) { MDAL::Loader2dm loader( meshFile ); return loader.load( status ); } + +void MDAL::Loader::loadDatasets( Mesh *mesh, const std::string &datasetFile, MDAL_Status *status ) +{ + MDAL::LoaderAsciiDat loader( datasetFile ); + loader.load( mesh, status ); + + if ( status && *status == MDAL_Status::Err_UnknownFormat ) + { + MDAL::LoaderBinaryDat loader( datasetFile ); + loader.load( mesh, status ); + } +} diff --git a/external/mdal/mdal_loader.hpp b/external/mdal/mdal_loader.hpp index 2e412c99d35..3317cc35297 100644 --- a/external/mdal/mdal_loader.hpp +++ b/external/mdal/mdal_loader.hpp @@ -7,6 +7,8 @@ #define MDAL_LOADER_HPP #include +#include +#include #include "mdal.h" #include "mdal_defines.hpp" @@ -17,7 +19,8 @@ namespace MDAL class Loader { public: - static Mesh *load( const std::string &meshFile, MDAL_Status *status ); + static std::unique_ptr< Mesh > load( const std::string &meshFile, MDAL_Status *status ); + static void loadDatasets( Mesh *mesh, const std::string &datasetFile, MDAL_Status *status ); }; } // namespace MDAL diff --git a/external/mdal/mdal_utils.cpp b/external/mdal/mdal_utils.cpp index 57a94e1ec5a..b238a3d22d9 100644 --- a/external/mdal/mdal_utils.cpp +++ b/external/mdal/mdal_utils.cpp @@ -5,6 +5,7 @@ #include "mdal_utils.hpp" #include +#include bool MDAL::fileExists( const std::string &filename ) { @@ -47,10 +48,49 @@ size_t MDAL::toSizeT( const std::string &str ) int i = atoi( str.c_str() ); if ( i < 0 ) // consistent with atoi return i = 0; - return i; + return static_cast< size_t >( i ); } double MDAL::toDouble( const std::string &str ) { return atof( str.c_str() ); } + +std::string MDAL::baseName( const std::string &filename ) +{ + // https://stackoverflow.com/a/8520815/2838364 + std::string fname( filename ); + + // Remove directory if present. + // Do this before extension removal incase directory has a period character. + const size_t last_slash_idx = fname.find_last_of( "\\/" ); + if ( std::string::npos != last_slash_idx ) + { + fname.erase( 0, last_slash_idx + 1 ); + } + + // Remove extension if present. + const size_t period_idx = fname.rfind( '.' ); + if ( std::string::npos != period_idx ) + { + fname.erase( period_idx ); + } + return fname; +} + +bool MDAL::contains( const std::string &str, const std::string &substr ) +{ + return str.find( substr ) != std::string::npos; +} + +void MDAL::debug( const std::string &message ) +{ + //TODO something smarter + std::cout << message << std::endl; +} + +bool MDAL::toBool( const std::string &str ) +{ + int i = atoi( str.c_str() ); + return i != 0; +} diff --git a/external/mdal/mdal_utils.hpp b/external/mdal/mdal_utils.hpp index b50d6caaff6..942035884e9 100644 --- a/external/mdal/mdal_utils.hpp +++ b/external/mdal/mdal_utils.hpp @@ -13,15 +13,21 @@ namespace MDAL { + // debugging + void debug( const std::string &message ); + /** Return whether file exists */ bool fileExists( const std::string &filename ); + std::string baseName( const std::string &filename ); // strings bool startsWith( const std::string &str, const std::string &substr ); + bool contains( const std::string &str, const std::string &substr ); /** Return 0 if not possible to convert */ size_t toSizeT( const std::string &str ); double toDouble( const std::string &str ); + bool toBool( const std::string &str ); enum SplitBehaviour { @@ -30,5 +36,29 @@ namespace MDAL }; std::vector split( const std::string &str, const std::string &delimiter, SplitBehaviour behaviour ); + // http://www.cplusplus.com/faq/sequences/strings/trim/ + inline std::string rtrim( + const std::string &s, + const std::string &delimiters = " \f\n\r\t\v" ) + { + return s.substr( 0, s.find_last_not_of( delimiters ) + 1 ); + } + + // http://www.cplusplus.com/faq/sequences/strings/trim/ + inline std::string ltrim( + const std::string &s, + const std::string &delimiters = " \f\n\r\t\v" ) + { + return s.substr( s.find_first_not_of( delimiters ) ); + } + + // http://www.cplusplus.com/faq/sequences/strings/trim/ + inline std::string trim( + const std::string &s, + const std::string &delimiters = " \f\n\r\t\v" ) + { + return ltrim( rtrim( s, delimiters ), delimiters ); + } + } // namespace MDAL #endif //MDAL_UTILS_HPP