update to MDAL 0.0.3

This commit is contained in:
Peter Petrik 2018-05-16 11:20:25 +02:00
parent ee7240f70d
commit bfbc64ce6c
13 changed files with 1329 additions and 75 deletions

View File

@ -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<double>: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<double>: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<double>: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

View File

@ -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 <stddef.h>
@ -22,14 +22,14 @@ MDAL::Loader2dm::Loader2dm( const std::string &meshFile ):
{
}
MDAL::Mesh *MDAL::Loader2dm::load( MDAL_Status *status )
std::unique_ptr<MDAL::Mesh> 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<Vertex> vertices( nodeCount );
std::vector<Face> faces( elemCount );
std::vector<Vertex> vertices( vertexCount );
std::vector<Face> faces( faceCount );
in.clear();
in.seekg( 0, std::ios::beg );
std::vector<std::string> chunks;
size_t elemIndex = 0;
size_t nodeIndex = 0;
std::map<size_t, size_t> elemIDtoIndex;
std::map<size_t, size_t> nodeIDtoIndex;
size_t faceIndex = 0;
size_t vertexIndex = 0;
std::map<size_t, size_t> faceIDtoIndex;
std::map<size_t, size_t> 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<size_t, size_t>::iterator search = elemIDtoIndex.find( elemID );
if ( search != elemIDtoIndex.end() )
std::map<size_t, size_t>::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<size_t, size_t>::iterator search = elemIDtoIndex.find( elemID );
if ( search != elemIDtoIndex.end() )
std::map<size_t, size_t>::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<size_t, size_t>::iterator search = elemIDtoIndex.find( elemID );
if ( search != elemIDtoIndex.end() )
std::map<size_t, size_t>::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<size_t, size_t>::iterator search = nodeIDtoIndex.find( nodeID );
if ( search != nodeIDtoIndex.end() )
std::map<size_t, size_t>::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<size_t, size_t>::iterator ni2i = nodeIDtoIndex.find( nodeID );
if ( ni2i != nodeIDtoIndex.end() )
std::map<size_t, size_t>::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;
}

View File

@ -7,6 +7,7 @@
#define MDAL_2DM_HPP
#include <string>
#include <memory>
#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;

305
external/mdal/frmts/mdal_ascii_dat.cpp vendored Normal file
View File

@ -0,0 +1,305 @@
/*
MDAL - Mesh Data Abstraction Library (MIT License)
Copyright (C) 2018 Lutra Consulting Ltd.
*/
#include <stddef.h>
#include <iosfwd>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <cassert>
#include <memory>
#include "mdal_ascii_dat.hpp"
#include "mdal.h"
#include "mdal_utils.hpp"
#include <math.h>
#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<std::shared_ptr<Dataset>> 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<std::string> 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<std::shared_ptr<Dataset>> &datOutputs ) const
{
for ( const std::shared_ptr<Dataset> &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<std::shared_ptr<MDAL::Dataset> > &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<MDAL::Dataset> 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<std::string> 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<std::shared_ptr<MDAL::Dataset> > &datOutputs, double t, bool isVector, std::ifstream &stream )
{
size_t faceCount = mesh->faces.size();
std::shared_ptr<MDAL::Dataset> 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<std::string> 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 ) );
}

52
external/mdal/frmts/mdal_ascii_dat.hpp vendored Normal file
View File

@ -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 <string>
#include <vector>
#include <memory>
#include <iosfwd>
#include <iostream>
#include <fstream>
#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<std::shared_ptr<Dataset>> &datOutputs,
double t,
bool isVector,
bool hasStatus,
std::ifstream &stream );
void readFaceTimestep(
const Mesh *mesh,
std::vector<std::shared_ptr<Dataset>> &datOutputs,
double t,
bool isVector,
std::ifstream &stream );
void addDatasets( MDAL::Mesh *mesh,
const std::string &name,
const std::vector<std::shared_ptr<Dataset>> &datOutputs ) const;
std::string mDatFile;
};
} // namespace MDAL
#endif //MDAL_ASCII_DAT_HPP

307
external/mdal/frmts/mdal_binary_dat.cpp vendored Normal file
View File

@ -0,0 +1,307 @@
/*
MDAL - Mesh Data Abstraction Library (MIT License)
Copyright (C) 2018 Lutra Consulting Ltd.
*/
#include <stddef.h>
#include <iosfwd>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <cassert>
#include <memory>
#include "mdal_binary_dat.hpp"
#include "mdal.h"
#include "mdal_utils.hpp"
#include <math.h>
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<std::shared_ptr<Dataset>> 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<std::shared_ptr<Dataset>> &datOutputs ) const
{
for ( const std::shared_ptr<Dataset> &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<std::shared_ptr<MDAL::Dataset> > &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<MDAL::Dataset> 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
}

46
external/mdal/frmts/mdal_binary_dat.hpp vendored Normal file
View File

@ -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 <string>
#include <vector>
#include <memory>
#include <iosfwd>
#include <iostream>
#include <fstream>
#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<std::shared_ptr<Dataset>> &datOutputs,
float time,
bool isVector,
bool hasStatus,
int sflg,
std::ifstream &in );
void addDatasets( MDAL::Mesh *mesh,
const std::string &name,
const std::vector<std::shared_ptr<Dataset>> &datOutputs ) const;
std::string mDatFile;
};
} // namespace MDAL
#endif //MDAL_BINARY_DAT_HPP

341
external/mdal/mdal.cpp vendored
View File

@ -1,16 +1,19 @@
#include <string>
#include <cassert>
#include <stddef.h>
#include <limits>
#include "mdal.h"
#include "mdal_loader.hpp"
#include "mdal_defines.hpp"
#define NODATA std::numeric_limits<double>::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<int>( 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<size_t>( 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<size_t>( 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<int>( 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<size_t>( index );
assert( m->faces.size() > i );
if ( m->faces.size() <= i )
{
sLastStatus = MDAL_Status::Err_IncompatibleMesh;
return 0;
}
int len = static_cast<int>( 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<size_t>( 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<size_t>( 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<int>( 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<int>( 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<int>( m->datasets.size() );
if ( len <= index )
{
sLastStatus = MDAL_Status::Err_IncompatibleMesh;
return nullptr;
}
size_t i = static_cast<size_t>( 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<int>( 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<int>( d->metadata.size() );
if ( len <= index )
{
sLastStatus = MDAL_Status::Err_IncompatibleDataset;
return nullptr;
}
size_t i = static_cast<size_t>( 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<int>( d->metadata.size() );
if ( len <= index )
{
sLastStatus = MDAL_Status::Err_IncompatibleDataset;
return nullptr;
}
size_t i = static_cast<size_t>( 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<int>( 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<int>( d->values.size() );
if ( len <= valueIndex )
{
sLastStatus = MDAL_Status::Err_IncompatibleDataset;
return NODATA;
}
size_t i = static_cast<size_t>( 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<int>( d->values.size() );
if ( len <= valueIndex )
{
sLastStatus = MDAL_Status::Err_IncompatibleDataset;
return NODATA;
}
size_t i = static_cast<size_t>( 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<size_t>( faceIndex );
return d->isActive( i );
}

View File

@ -8,6 +8,8 @@
#include <stddef.h>
#include <vector>
#include <memory>
#include <map>
namespace MDAL
{
@ -20,12 +22,105 @@ namespace MDAL
typedef std::vector<size_t> Face;
struct Mesh
typedef struct
{
std::vector<Vertex> vertices;
std::vector<Face> 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<Value> values; // size - vertex count if isOnVertices
// size - face count if !isOnVertices
std::vector<bool> 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<Vertex> vertices;
std::map<size_t, size_t> vertexIDtoIndex; // only for 2DM and DAT files
std::vector<Face> faces;
std::map<size_t, size_t> faceIDtoIndex; // only for 2DM and DAT files
std::vector<std::shared_ptr<Dataset>> datasets;
};
} // namespace MDAL
#endif //MDAL_DEFINES_HPP

View File

@ -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::Mesh> 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 );
}
}

View File

@ -7,6 +7,8 @@
#define MDAL_LOADER_HPP
#include <string>
#include <memory>
#include <vector>
#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

View File

@ -5,6 +5,7 @@
#include "mdal_utils.hpp"
#include <fstream>
#include <iostream>
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;
}

View File

@ -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<std::string> 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