update MDAL 0.7.91 (beta release for QGIS 3.18)

This commit is contained in:
Peter Petrik 2020-12-17 09:03:08 +01:00 committed by Nyall Dawson
parent fe6cf6090b
commit 8f5583eb51
22 changed files with 1226 additions and 171 deletions

View File

@ -34,7 +34,7 @@ MDAL::Mesh2dm::Mesh2dm( size_t faceVerticesMaximumCount,
MDAL::Mesh2dm::~Mesh2dm() = default;
bool _parse_vertex_id_gaps( std::map<size_t, size_t> &vertexIDtoIndex, size_t vertexIndex, size_t vertexID )
static bool _parse_vertex_id_gaps( std::map<size_t, size_t> &vertexIDtoIndex, size_t vertexIndex, size_t vertexID )
{
if ( vertexIndex == vertexID )
return false;
@ -50,6 +50,21 @@ bool _parse_vertex_id_gaps( std::map<size_t, size_t> &vertexIDtoIndex, size_t ve
return false;
}
static void _persist_native_index( std::vector<double> &arr, size_t nativeID, size_t ourId, size_t maxOurId )
{
if ( !arr.empty() || ( nativeID != ourId + 1 ) )
{
// we have gaps in face indexing
if ( arr.empty() )
{
arr.resize( maxOurId );
for ( size_t i = 0; i < ourId; ++i )
arr[i] = static_cast<double>( i + 1 );
}
arr[ourId] = static_cast<double>( nativeID );
}
}
size_t MDAL::Mesh2dm::vertexIndex( size_t vertexID ) const
{
auto ni2i = mVertexIDtoIndex.find( vertexID );
@ -120,11 +135,16 @@ std::unique_ptr<MDAL::Mesh> MDAL::Driver2dm::load( const std::string &meshFile,
size_t materialCount = 0;
bool hasMaterialsDefinitionsForElements = false;
std::vector<double> nativeVertexIds;
std::vector<double> nativeFaceIds;
std::vector<double> nativeEdgeIds;
// Find out how many nodes and elements are contained in the .2dm mesh file
while ( std::getline( in, line ) )
{
if ( startsWith( line, "E4Q" ) ||
startsWith( line, "E3T" ) )
startsWith( line, "E3T" ) ||
startsWith( line, "E6T" ) )
{
faceCount++;
}
@ -137,7 +157,6 @@ std::unique_ptr<MDAL::Mesh> MDAL::Driver2dm::load( const std::string &meshFile,
edgesCount++;
}
else if ( startsWith( line, "E3L" ) ||
startsWith( line, "E6T" ) ||
startsWith( line, "E8Q" ) ||
startsWith( line, "E9Q" ) )
{
@ -156,6 +175,7 @@ std::unique_ptr<MDAL::Mesh> MDAL::Driver2dm::load( const std::string &meshFile,
Vertices vertices( vertexCount );
Edges edges( edgesCount );
Faces faces( faceCount );
size_t maxVerticesPerFace = 2;
// .2dm mesh files may have any number of material ID columns
std::vector<std::vector<double>> faceMaterials;
@ -174,24 +194,31 @@ std::unique_ptr<MDAL::Mesh> MDAL::Driver2dm::load( const std::string &meshFile,
while ( std::getline( in, line ) )
{
if ( startsWith( line, "E4Q" ) ||
startsWith( line, "E3T" )
startsWith( line, "E3T" ) ||
startsWith( line, "E6T" )
)
{
chunks = split( line, ' ' );
assert( faceIndex < faceCount );
const size_t faceVertexCount = MDAL::toSizeT( line[1] );
assert( ( faceVertexCount == 3 ) || ( faceVertexCount == 4 ) );
assert( ( faceVertexCount == 3 ) || ( faceVertexCount == 4 ) || ( faceVertexCount == 6 ) );
if ( maxVerticesPerFace < faceVertexCount )
maxVerticesPerFace = faceVertexCount;
Face &face = faces[faceIndex];
face.resize( faceVertexCount );
// chunks format here
// E** id vertex_id1, vertex_id2, vertex_id3, material_id [, aux_column_1, aux_column_2, ...]
// E** id vertex_id1, vertex_id2, vertex_id3, ..., material_id [, aux_column_1, aux_column_2, ...]
// vertex ids are numbered from 1
// Right now we just store node IDs here - we will convert them to node indices afterwards
assert( chunks.size() > faceVertexCount + 1 );
// in case we have gaps/reorders in native indexes, store it
size_t nativeID = MDAL::toSizeT( chunks[1] );
_persist_native_index( nativeFaceIds, nativeID, faceIndex, faceCount );
for ( size_t i = 0; i < faceVertexCount; ++i )
face[i] = MDAL::toSizeT( chunks[i + 2] ) - 1; // 2dm is numbered from 1
@ -237,6 +264,10 @@ std::unique_ptr<MDAL::Mesh> MDAL::Driver2dm::load( const std::string &meshFile,
chunks = split( line, ' ' );
assert( edgeIndex < edgesCount );
assert( chunks.size() > 4 );
// in case we have gaps/reorders in native indexes, store it
size_t nativeID = MDAL::toSizeT( chunks[1] );
_persist_native_index( nativeEdgeIds, nativeID, edgeIndex, edgesCount );
size_t startVertexIndex = MDAL::toSizeT( chunks[2] ) - 1; // 2dm is numbered from 1
size_t endVertexIndex = MDAL::toSizeT( chunks[3] ) - 1; // 2dm is numbered from 1
Edge &edge = edges[edgeIndex];
@ -261,9 +292,11 @@ std::unique_ptr<MDAL::Mesh> MDAL::Driver2dm::load( const std::string &meshFile,
}
lastVertexID = nodeID;
}
nodeID -= 1; // 2dm is numbered from 1
_parse_vertex_id_gaps( vertexIDtoIndex, vertexIndex, nodeID );
// in case we have gaps/reorders in native indexes, store it
_persist_native_index( nativeVertexIds, nodeID, vertexIndex, vertexCount );
_parse_vertex_id_gaps( vertexIDtoIndex, vertexIndex, nodeID - 1 );
assert( vertexIndex < vertexCount );
Vertex &vertex = vertices[vertexIndex];
vertex.x = toDouble( chunks[2] );
@ -296,7 +329,7 @@ std::unique_ptr<MDAL::Mesh> MDAL::Driver2dm::load( const std::string &meshFile,
std::unique_ptr< Mesh2dm > mesh(
new Mesh2dm(
MAX_VERTICES_PER_FACE_2DM,
maxVerticesPerFace,
mMeshFile,
vertexIDtoIndex
)
@ -308,6 +341,13 @@ std::unique_ptr<MDAL::Mesh> MDAL::Driver2dm::load( const std::string &meshFile,
// Add Bed Elevation
MDAL::addBedElevationDatasetGroup( mesh.get(), mesh->vertices() );
if ( !nativeFaceIds.empty() )
MDAL::addFaceScalarDatasetGroup( mesh.get(), nativeFaceIds, "NativeFaceIds" );
if ( !nativeVertexIds.empty() )
MDAL::addVertexScalarDatasetGroup( mesh.get(), nativeVertexIds, "NativeVertexIds" );
if ( !nativeEdgeIds.empty() )
MDAL::addEdgeScalarDatasetGroup( mesh.get(), nativeEdgeIds, "NativeEdgeIds" );
// Add material IDs
if ( hasMaterialsDefinitionsForElements )
{
@ -367,12 +407,12 @@ void MDAL::Driver2dm::save( const std::string &uri, MDAL::Mesh *mesh )
}
// write faces
std::vector<int> vertexIndices( mesh->faceVerticesMaximumCount() );
std::unique_ptr<MDAL::MeshFaceIterator> faceIterator = mesh->readFaces();
for ( size_t i = 0; i < mesh->facesCount(); ++i )
{
int faceOffsets[1];
int vertexIndices[MAX_VERTICES_PER_FACE_2DM];
faceIterator->next( 1, faceOffsets, 4, vertexIndices );
faceIterator->next( 1, faceOffsets, 4, vertexIndices.data() );
if ( faceOffsets[0] > 2 && faceOffsets[0] < 5 )
{
@ -380,6 +420,8 @@ void MDAL::Driver2dm::save( const std::string &uri, MDAL::Mesh *mesh )
line = "E3T ";
if ( faceOffsets[0] == 4 )
line = "E4Q ";
if ( faceOffsets[0] == 6 )
line = "E6T ";
line.append( std::to_string( i + 1 ) );

View File

@ -14,9 +14,6 @@
#include "mdal.h"
#include "mdal_driver.hpp"
#define MAX_VERTICES_PER_FACE_2DM 4
namespace MDAL
{
class Mesh2dm: public MemoryMesh
@ -86,8 +83,7 @@ namespace MDAL
~Driver2dm() override;
Driver2dm *create() override;
int faceVerticesMaximumCount() const override
{return MAX_VERTICES_PER_FACE_2DM;}
int faceVerticesMaximumCount() const override {return 6;}
bool canReadMesh( const std::string &uri ) override;
std::unique_ptr< Mesh > load( const std::string &meshFile, const std::string &meshName = "" ) override;

View File

@ -485,7 +485,7 @@ bool MDAL::DriverAsciiDat::persist( MDAL::DatasetGroup *group )
if ( !MDAL::contains( uri, "_els" ) && group->dataLocation() != MDAL_DataLocation::DataOnVertices )
{
// Should contain _els in name for edges/faces dataset but it does not
int pos = uri.size() - 4;
int pos = MDAL::toInt( uri.size() ) - 4;
uri.insert( std::max( 0, pos ), "_els" );
group->replaceUri( uri );
}

457
external/mdal/frmts/mdal_dynamic_driver.cpp vendored Executable file
View File

@ -0,0 +1,457 @@
/*
MDAL - Mesh Data Abstraction Library (MIT License)
Copyright (C) 2020 Vincent Cloarec (vcloarec at gmail dot com)
*/
#include "mdal_dynamic_driver.hpp"
#include "mdal_logger.hpp"
#if not defined (WIN32)
#include <dlfcn.h>
#endif
#include <string.h>
#include <iostream>
MDAL::DriverDynamic::DriverDynamic( const std::string &name, const std::string &longName, const std::string &filters, int capabilityFlags, int maxVertexPerFace, const MDAL::Library &lib ):
Driver( name, longName, filters, capabilityFlags ),
mLibrary( lib ),
mCapabilityFlags( capabilityFlags ),
mMaxVertexPerFace( maxVertexPerFace )
{}
MDAL::Driver *MDAL::DriverDynamic::create()
{
std::unique_ptr<MDAL::DriverDynamic> driver( new DriverDynamic( name(), longName(), filters(), mCapabilityFlags, mMaxVertexPerFace, mLibrary ) );
if ( driver->loadSymbols() )
return driver.release();
else
return nullptr;
}
bool MDAL::DriverDynamic::canReadMesh( const std::string &uri )
{
if ( mCanReadMeshFunction )
{
return mCanReadMeshFunction( uri.c_str() );
}
return false;
}
std::unique_ptr<MDAL::Mesh> MDAL::DriverDynamic::load( const std::string &uri, const std::string &meshName )
{
if ( !mOpenMeshFunction )
return std::unique_ptr<MDAL::Mesh>();
int meshId = mOpenMeshFunction( uri.c_str(), meshName.c_str() );
if ( meshId != -1 )
{
if ( mMeshIds.find( meshId ) == mMeshIds.end() )
{
std::unique_ptr<MDAL::MeshDynamicDriver> mesh( new MeshDynamicDriver( name(), mMaxVertexPerFace, uri, mLibrary, meshId ) );
if ( mesh->loadSymbol() )
{
mMeshIds.insert( meshId );
mesh->setProjection();
if ( mesh->populateDatasetGroups() )
return mesh;
}
}
}
MDAL::Log::error( MDAL_Status::Err_UnknownFormat, name(), "Unable to load the mesh" );
return std::unique_ptr<MDAL::Mesh>();
}
MDAL::Driver *MDAL::DriverDynamic::create( const std::string &libFile )
{
Library library( libFile );
std::function<const char *()> driverNameFunction = library.getSymbol<const char *>( "MDAL_DRIVER_driverName" );
std::function<const char *()> driverLongNameFunction = library.getSymbol<const char *>( "MDAL_DRIVER_driverLongName" );
std::function<const char *()> driverFiltersFunction = library.getSymbol<const char *>( "MDAL_DRIVER_filters" );
std::function<int()> driverCapabilitiesFunction = library.getSymbol<int>( "MDAL_DRIVER_capabilities" );
std::function<int()> driverMaxVertexPerFaceFunction = library.getSymbol<int>( "MDAL_DRIVER_maxVertexPerFace" );
if ( !driverNameFunction ||
!driverLongNameFunction ||
!driverFiltersFunction ||
!driverCapabilitiesFunction ||
!driverMaxVertexPerFaceFunction )
{
// No log error here because MDAL can try any files to find the good one
return nullptr;
}
std::string name( driverNameFunction() );
std::string longName( driverLongNameFunction() );
std::string filters( driverFiltersFunction() );
MDAL::Capability capabilities = static_cast<MDAL::Capability>( driverCapabilitiesFunction() );
int maxVertexPerFace = driverMaxVertexPerFaceFunction();
std::unique_ptr<DriverDynamic> driver( new DriverDynamic( name, longName, filters, capabilities, maxVertexPerFace, library ) );
if ( !driver->loadSymbols() )
{
//Log error created by loadSymbols()
return nullptr;
}
return driver.release();
}
bool MDAL::DriverDynamic::loadSymbols()
{
mCanReadMeshFunction = mLibrary.getSymbol<bool, const char *>( "MDAL_DRIVER_canReadMesh" );
mOpenMeshFunction = mLibrary.getSymbol<int, const char *, const char *>( "MDAL_DRIVER_openMesh" );
if ( mCanReadMeshFunction == nullptr ||
mOpenMeshFunction == nullptr )
{
MDAL::Log::error( MDAL_Status::Err_MissingDriver, name(), "External driver is not valid" );
return false;
}
return true;
}
MDAL::MeshDynamicDriver::MeshDynamicDriver( const std::string &driverName,
size_t faceVerticesMaximumCount,
const std::string &uri,
const MDAL::Library &library,
int meshId ):
Mesh( driverName, faceVerticesMaximumCount, uri ),
mLibrary( library ),
mId( meshId )
{}
MDAL::MeshDynamicDriver::~MeshDynamicDriver()
{
mCloseMeshFunction( mId );
}
static int elementCount( int meshId, const std::function<int ( int )> &countFunction, const std::string &driverName )
{
if ( countFunction )
{
int count = countFunction( meshId );
if ( count >= 0 )
return count;
MDAL::Log::error( MDAL_Status::Err_InvalidData, driverName, "Invalid mesh" );
}
else
MDAL::Log::error( MDAL_Status::Err_MissingDriver, driverName, "Driver is not valid" );
return 0;
}
size_t MDAL::MeshDynamicDriver::verticesCount() const
{
return elementCount( mId, mMeshVertexCountFunction, driverName() );
}
size_t MDAL::MeshDynamicDriver::facesCount() const
{
return elementCount( mId, mMeshFaceCountFunction, driverName() );
}
size_t MDAL::MeshDynamicDriver::edgesCount() const
{
return elementCount( mId, mMeshEdgeCountFunction, driverName() );
}
MDAL::BBox MDAL::MeshDynamicDriver::extent() const
{
if ( mMeshExtentFunction )
{
double xMin, xMax, yMin, yMax;
mMeshExtentFunction( mId, &xMin, &xMax, &yMin, &yMax );
return BBox( xMin, xMax, yMin, yMax );
}
return BBox( std::numeric_limits<double>::quiet_NaN(),
std::numeric_limits<double>::quiet_NaN(),
std::numeric_limits<double>::quiet_NaN(),
std::numeric_limits<double>::quiet_NaN() );
}
void MDAL::MeshDynamicDriver::setProjection()
{
if ( !mMeshProjectionFunction )
return;
std::string projection = mMeshProjectionFunction( mId );
setSourceCrs( projection );
}
bool MDAL::MeshDynamicDriver::populateDatasetGroups()
{
if ( !mMeshDatasetGroupsCountFunction )
return false;
int datasetGroupCount = mMeshDatasetGroupsCountFunction( mId );
for ( int i = 0; i < datasetGroupCount; ++i )
{
const char *groupName = mDatasetgroupNameFunction( mId, i );
const char *referenceTime = mDatasetGroupReferencetimeFunction( mId, i );
bool isScalar = true;
int dataLocation = 0;
int datasetCount = 0;
if ( !mDatasetDescriptionFunction( mId, i, &isScalar, &dataLocation, &datasetCount ) )
return false;
std::shared_ptr<DatasetGroup> group = std::make_shared<DatasetGroup>( driverName(), this, uri() );
if ( groupName )
group->setName( groupName );
if ( referenceTime )
{
std::string referenceTimeIso8701 = referenceTime;
group->setReferenceTime( referenceTimeIso8701 );
}
group->setIsScalar( isScalar );
switch ( dataLocation )
{
case 1:
group->setDataLocation( MDAL_DataLocation::DataOnVertices );
break;
case 2:
group->setDataLocation( MDAL_DataLocation::DataOnFaces );
break;
case 3:
group->setDataLocation( MDAL_DataLocation::DataOnEdges );
break;
default:
group->setDataLocation( MDAL_DataLocation::DataInvalidLocation );
break;
}
int metadataCount = mDatasetGroupMetadataCountFunction( mId, i );
if ( metadataCount > 0 )
{
for ( int metaIndex = 0; metaIndex < metadataCount; ++metaIndex )
{
std::string key( mDatasetGroupMetadataKeyFunction( mId, i, metaIndex ) );
std::string value( mDatasetGroupMetadataValueFunction( mId, i, metaIndex ) );
group->setMetadata( key, value );
}
}
for ( int d = 0; d < datasetCount ; ++d )
{
std::shared_ptr<DatasetDynamicDriver> dataset = std::make_shared<DatasetDynamicDriver>( group.get(), mId, i, d, mLibrary );
dataset->setSupportsActiveFlag( mDatasetSupportActiveFlagFunction( mId, i, d ) );
if ( !dataset->loadSymbol() )
return false;
bool ok = true;
double time = mDatasetTimeFunction( mId, i, d, &ok );
if ( !ok )
return false;
dataset->setTime( RelativeTimestamp( time, RelativeTimestamp::hours ) );
dataset->setStatistics( MDAL::calculateStatistics( dataset ) );
dataset->unloadData();
group->datasets.push_back( dataset );
}
group->setStatistics( MDAL::calculateStatistics( group ) );
datasetGroups.push_back( group );
}
return true;
}
bool MDAL::MeshDynamicDriver::loadSymbol()
{
mMeshVertexCountFunction = mLibrary.getSymbol<int, int>( "MDAL_DRIVER_M_vertexCount" ) ;
mMeshFaceCountFunction = mLibrary.getSymbol<int, int>( "MDAL_DRIVER_M_faceCount" ) ;
mMeshEdgeCountFunction = mLibrary.getSymbol<int, int>( "MDAL_DRIVER_M_edgeCount" ) ;
mMeshExtentFunction = mLibrary.getSymbol<void, int, double *, double *, double *, double *>( "MDAL_DRIVER_M_extent" );
mMeshProjectionFunction = mLibrary.getSymbol<const char *, int>( "MDAL_DRIVER_M_projection" ) ;
mMeshDatasetGroupsCountFunction = mLibrary.getSymbol<int, int>( "MDAL_DRIVER_M_datasetGroupCount" );
mDatasetgroupNameFunction = mLibrary.getSymbol<const char *, int, int>( "MDAL_DRIVER_G_groupName" );
mDatasetGroupReferencetimeFunction = mLibrary.getSymbol<const char *, int, int>( "MDAL_DRIVER_G_referenceTime" );
mDatasetGroupMetadataCountFunction = mLibrary.getSymbol<int, int, int>( "MDAL_DRIVER_G_metadataCount" );
mDatasetGroupMetadataKeyFunction = mLibrary.getSymbol<const char *, int, int, int>( "MDAL_DRIVER_G_metadataKey" );
mDatasetGroupMetadataValueFunction = mLibrary.getSymbol<const char *, int, int, int>( "MDAL_DRIVER_G_metadataValue" );
mDatasetTimeFunction = mLibrary.getSymbol<double, int, int, int, bool *>( "MDAL_DRIVER_D_time" );
mDatasetDescriptionFunction = mLibrary.getSymbol<bool, int, int, bool *, int *, int *>( "MDAL_DRIVER_G_datasetsDescription" );
mDatasetSupportActiveFlagFunction = mLibrary.getSymbol<bool, int, int, int>( "MDAL_DRIVER_D_hasActiveFlagCapability" );
mCloseMeshFunction = mLibrary.getSymbol<void, int>( "MDAL_DRIVER_closeMesh" );
if ( mMeshVertexCountFunction == nullptr ||
mMeshFaceCountFunction == nullptr ||
mMeshEdgeCountFunction == nullptr ||
mMeshExtentFunction == nullptr ||
mMeshProjectionFunction == nullptr ||
mMeshDatasetGroupsCountFunction == nullptr ||
mDatasetgroupNameFunction == nullptr ||
mDatasetGroupReferencetimeFunction == nullptr ||
mDatasetGroupMetadataCountFunction == nullptr ||
mDatasetGroupMetadataKeyFunction == nullptr ||
mDatasetGroupMetadataValueFunction == nullptr ||
mDatasetDescriptionFunction == nullptr ||
mDatasetTimeFunction == nullptr ||
mDatasetSupportActiveFlagFunction == nullptr ||
mCloseMeshFunction == nullptr )
{
MDAL::Log::error( MDAL_Status::Err_MissingDriver, driverName(), "Driver is not valid, unable to load mesh access functions" );
return false;
}
return true;
}
std::unique_ptr<MDAL::MeshVertexIterator> MDAL::MeshDynamicDriver::readVertices()
{
return std::unique_ptr<MeshVertexIteratorDynamicDriver>( new MeshVertexIteratorDynamicDriver( mLibrary, mId ) );
}
std::unique_ptr<MDAL::MeshEdgeIterator> MDAL::MeshDynamicDriver::readEdges()
{
return std::unique_ptr<MeshEdgeIterator>( new MeshEdgeIteratorDynamicDriver( mLibrary, mId ) );
}
std::unique_ptr<MDAL::MeshFaceIterator> MDAL::MeshDynamicDriver::readFaces()
{
return std::unique_ptr<MeshFaceIterator>( new MeshFaceIteratorDynamicDriver( mLibrary, mId ) );
}
MDAL::MeshVertexIteratorDynamicDriver::MeshVertexIteratorDynamicDriver( const Library &library, int meshId ):
mLibrary( library ),
mMeshId( meshId )
{}
size_t MDAL::MeshVertexIteratorDynamicDriver::next( size_t vertexCount, double *coordinates )
{
if ( !mVerticesFunction )
{
mVerticesFunction = mLibrary.getSymbol<int, int, int, int, double *>( "MDAL_DRIVER_M_vertices" );
if ( !mVerticesFunction )
return 0;
}
int effectiveVerticesCount = mVerticesFunction( mMeshId, mPosition, MDAL::toInt( vertexCount ), coordinates );
if ( effectiveVerticesCount < 0 )
{
MDAL::Log::error( MDAL_Status::Err_InvalidData, "Invalid mesh, unable to read vertices" );
return 0;
}
mPosition += effectiveVerticesCount;
return effectiveVerticesCount;
}
MDAL::MeshFaceIteratorDynamicDriver::MeshFaceIteratorDynamicDriver( const MDAL::Library &library, int meshId ):
mLibrary( library ),
mMeshId( meshId )
{}
size_t MDAL::MeshFaceIteratorDynamicDriver::next( size_t faceOffsetsBufferLen, int *faceOffsetsBuffer, size_t vertexIndicesBufferLen, int *vertexIndicesBuffer )
{
if ( !mFacesFunction )
{
mFacesFunction = mLibrary.getSymbol<int, int, int, int, int *, int, int *>( "MDAL_DRIVER_M_faces" );
if ( !mFacesFunction )
return 0;
}
int effectiveFacesCount = mFacesFunction( mMeshId, mPosition, MDAL::toInt( faceOffsetsBufferLen ), faceOffsetsBuffer, MDAL::toInt( vertexIndicesBufferLen ), vertexIndicesBuffer );
if ( effectiveFacesCount < 0 )
{
MDAL::Log::error( MDAL_Status::Err_InvalidData, "Invalid mesh, unable to read faces" );
return 0;
}
mPosition += effectiveFacesCount;
return effectiveFacesCount;
}
MDAL::MeshEdgeIteratorDynamicDriver::MeshEdgeIteratorDynamicDriver( const MDAL::Library &library, int meshId ):
mLibrary( library ),
mMeshId( meshId )
{}
size_t MDAL::MeshEdgeIteratorDynamicDriver::next( size_t edgeCount, int *startVertexIndices, int *endVertexIndices )
{
if ( !mEdgesFunction )
{
mEdgesFunction = mLibrary.getSymbol<int, int, int, int, int *, int *>( "MDAL_DRIVER_M_edges" );
if ( !mEdgesFunction )
return 0;
}
int effectiveEdgesCount = mEdgesFunction( mMeshId, mPosition, MDAL::toInt( edgeCount ), startVertexIndices, endVertexIndices );
if ( effectiveEdgesCount < 0 )
{
MDAL::Log::error( MDAL_Status::Err_InvalidData, "Invalid mesh, unable to read edges" );
return 0;
}
mPosition += effectiveEdgesCount;
return effectiveEdgesCount;
}
MDAL::DatasetDynamicDriver::DatasetDynamicDriver( MDAL::DatasetGroup *parentGroup, int meshId, int groupIndex, int datasetIndex, const MDAL::Library &library ):
Dataset2D( parentGroup )
, mMeshId( meshId )
, mGroupIndex( groupIndex )
, mDatasetIndex( datasetIndex )
, mLibrary( library )
{}
size_t MDAL::DatasetDynamicDriver::scalarData( size_t indexStart, size_t count, double *buffer )
{
if ( !mDataFunction )
return 0;
return mDataFunction( mMeshId, mGroupIndex, mDatasetIndex, MDAL::toInt( indexStart ), MDAL::toInt( count ), buffer );
}
size_t MDAL::DatasetDynamicDriver::vectorData( size_t indexStart, size_t count, double *buffer )
{
if ( !mDataFunction )
return 0;
return mDataFunction( mMeshId, mGroupIndex, mDatasetIndex, MDAL::toInt( indexStart ), MDAL::toInt( count ), buffer );
}
size_t MDAL::DatasetDynamicDriver::activeData( size_t indexStart, size_t count, int *buffer )
{
if ( !supportsActiveFlag() )
return Dataset2D::activeData( indexStart, count, buffer );
if ( !mActiveFlagsFunction )
return 0;
return mActiveFlagsFunction( mMeshId, mGroupIndex, mDatasetIndex, MDAL::toInt( indexStart ), MDAL::toInt( count ), buffer );
}
bool MDAL::DatasetDynamicDriver::loadSymbol()
{
mDataFunction = mLibrary.getSymbol<int, int, int, int, int, int, double *>( "MDAL_DRIVER_D_data" );
mUnloadFunction = mLibrary.getSymbol<void, int, int, int>( "MDAL_DRIVER_D_unload" );
if ( supportsActiveFlag() )
mActiveFlagsFunction = mLibrary.getSymbol<int, int, int, int, int, int, int *>( "MDAL_DRIVER_D_activeFlags" );
if ( mDataFunction == nullptr ||
mUnloadFunction == nullptr ||
( supportsActiveFlag() && mActiveFlagsFunction == nullptr ) )
{
MDAL::Log::error( MDAL_Status::Err_MissingDriver, "Driver is not valid" );
return false;
}
return true;
}
void MDAL::DatasetDynamicDriver::unloadData()
{
if ( !mUnloadFunction )
return;
mUnloadFunction( mMeshId, mGroupIndex, mDatasetIndex );
}

187
external/mdal/frmts/mdal_dynamic_driver.hpp vendored Executable file
View File

@ -0,0 +1,187 @@
/*
MDAL - Mesh Data Abstraction Library (MIT License)
Copyright (C) 2020 Vincent Cloarec (vcloarec at gmail dot com)
*/
#ifndef MDAL_DYNAMIC_DRIVER_H
#define MDAL_DYNAMIC_DRIVER_H
#include "mdal_driver.hpp"
#include "mdal_utils.hpp"
#include "mdal.h"
#include <functional>
#include <set>
namespace MDAL
{
class DriverDynamic: public Driver
{
public:
~DriverDynamic() = default;
Driver *create() override;
bool canReadMesh( const std::string &uri ) override;
std::unique_ptr<Mesh> load( const std::string &uri, const std::string &meshName ) override;
//! Creates a dynamic driver from a library file
static Driver *create( const std::string &libFile );
private:
DriverDynamic( const std::string &name,
const std::string &longName,
const std::string &filters,
int capabilityFlags,
int maxVertexPerFace,
const Library &lib );
bool loadSymbols();
Library mLibrary;
int mCapabilityFlags = 0;
int mMaxVertexPerFace = std::numeric_limits<int>::max();
std::set<int> mMeshIds;
//************************************
std::function<bool ( const char * )> mCanReadMeshFunction;
std::function<int ( const char *, const char * )> mOpenMeshFunction;
};
class MeshDynamicDriver;
class MeshVertexIteratorDynamicDriver: public MeshVertexIterator
{
public:
MeshVertexIteratorDynamicDriver( const Library &library, int meshId );
size_t next( size_t vertexCount, double *coordinates ) override;
private:
Library mLibrary;
int mMeshId;
int mPosition = 0;
//************************************
std::function<int ( int, int, int, double * )> mVerticesFunction;
};
class MeshFaceIteratorDynamicDriver: public MeshFaceIterator
{
public:
MeshFaceIteratorDynamicDriver( const Library &library, int meshId );
size_t next( size_t faceOffsetsBufferLen,
int *faceOffsetsBuffer,
size_t vertexIndicesBufferLen,
int *vertexIndicesBuffer ) override;
private:
Library mLibrary;
int mMeshId;
int mPosition = 0;
//************************************
std::function<int ( int, int, int, int *, int, int * )> mFacesFunction;
};
class MeshEdgeIteratorDynamicDriver: public MeshEdgeIterator
{
public:
MeshEdgeIteratorDynamicDriver( const Library &library, int meshId );
size_t next( size_t edgeCount,
int *startVertexIndices,
int *endVertexIndices );
private:
Library mLibrary;
int mMeshId;
int mPosition = 0;
//************************************
std::function<int ( int, int, int, int *, int * )> mEdgesFunction;
};
class DatasetDynamicDriver: public Dataset2D
{
public:
DatasetDynamicDriver( DatasetGroup *parentGroup,
int meshId,
int groupIndex,
int datasetIndex,
const Library &library );
size_t scalarData( size_t indexStart, size_t count, double *buffer ) override;
size_t vectorData( size_t indexStart, size_t count, double *buffer ) override;
size_t activeData( size_t indexStart, size_t count, int *buffer ) override;
bool loadSymbol();
//! Removes stored data in memory (for drivers that support lazy loading)
void unloadData();
private:
int mMeshId = -1;
int mGroupIndex = -1;
int mDatasetIndex = -1;
Library mLibrary;
//************************************
std::function<int ( int, int, int, int, int, double * )> mDataFunction;
std::function<int ( int, int, int, int, int, int * )> mActiveFlagsFunction;
std::function<void( int, int, int )> mUnloadFunction;
};
class MeshDynamicDriver: public Mesh
{
public:
MeshDynamicDriver( const std::string &driverName,
size_t faceVerticesMaximumCount,
const std::string &uri,
const Library &library,
int meshId );
~MeshDynamicDriver();
std::unique_ptr<MeshVertexIterator> readVertices() override;
std::unique_ptr<MeshEdgeIterator> readEdges() override;
std::unique_ptr<MeshFaceIterator> readFaces() override;
size_t verticesCount() const override;
size_t edgesCount() const override;
size_t facesCount() const override;
BBox extent() const override;
//! Set the projection from the source
void setProjection();
bool populateDatasetGroups();
//! Returns whether all the symbols have been loaded
bool loadSymbol();
private:
Library mLibrary;
int mId = -1;
//************************************
std::function<int ( int )> mMeshVertexCountFunction;
std::function<int ( int )> mMeshFaceCountFunction;
std::function<int ( int )> mMeshEdgeCountFunction;
std::function<void ( int, double *, double *, double *, double * )> mMeshExtentFunction;
std::function<const char *( int )> mMeshProjectionFunction;
std::function<int ( int )> mMeshDatasetGroupsCountFunction;
std::function<const char *( int, int )> mDatasetgroupNameFunction;
std::function<const char *( int, int )> mDatasetGroupReferencetimeFunction;
std::function<int ( int, int )> mDatasetGroupMetadataCountFunction;
std::function<const char *( int, int, int )> mDatasetGroupMetadataKeyFunction;
std::function<const char *( int, int, int )> mDatasetGroupMetadataValueFunction;
std::function < bool ( int, int, bool *, int *, int * )> mDatasetDescriptionFunction;
std::function < double( int, int, int, bool * )> mDatasetTimeFunction;
std::function<bool ( int, int, int )> mDatasetSupportActiveFlagFunction;
std::function<void ( int )> mCloseMeshFunction;
};
}
#endif // MDAL_DYNAMIC_DRIVER_H

View File

@ -144,8 +144,8 @@ void MDAL::DriverFlo2D::parseCHANBANKFile( const std::string &datFileName,
{
throw MDAL::Error( MDAL_Status::Err_UnknownFormat, "Error while loading CHANBANK file, wrong lineparts count (2)" );
}
int leftBank = MDAL::toSizeT( lineParts[0] ) - 1; //numbered from 1
int rightBank = MDAL::toSizeT( lineParts[1] ) - 1;
int leftBank = MDAL::toInt( MDAL::toSizeT( lineParts[0] ) ) - 1; //numbered from 1
int rightBank = MDAL::toInt( MDAL::toSizeT( lineParts[1] ) ) - 1;
std::map<size_t, size_t>::const_iterator it = cellIdToVertices.find( rightBank );
if ( it != cellIdToVertices.end() )
@ -197,7 +197,7 @@ void MDAL::DriverFlo2D::parseCHANFile( const std::string &datFileName, const std
{
throw MDAL::Error( MDAL_Status::Err_UnknownFormat, "Error while loading CHAN file, wrong chanel element line" );
}
int currentCellId = MDAL::toSizeT( lineParts[1] ) - 1;
int currentCellId = MDAL::toInt( MDAL::toSizeT( lineParts[1] ) ) - 1;
if ( previousCellId >= 0 )
{
std::map<size_t, size_t>::const_iterator it1 = cellIdToVertices.find( previousCellId );
@ -818,8 +818,8 @@ void MDAL::DriverFlo2D::createMesh2d( const std::vector<CellCenter> &cells, cons
cellCenterExtent.minY - half_cell_size,
cellCenterExtent.maxY + half_cell_size );
size_t width = ( vertexExtent.maxX - vertexExtent.minX ) / cell_size + 1;
size_t heigh = ( vertexExtent.maxY - vertexExtent.minY ) / cell_size + 1;
size_t width = MDAL::toSizeT( ( vertexExtent.maxX - vertexExtent.minX ) / cell_size + 1 );
size_t heigh = MDAL::toSizeT( ( vertexExtent.maxY - vertexExtent.minY ) / cell_size + 1 );
std::vector<std::vector<size_t>> vertexGrid( width, std::vector<size_t>( heigh, INVALID_INDEX ) );
Vertices vertices;
@ -828,13 +828,13 @@ void MDAL::DriverFlo2D::createMesh2d( const std::vector<CellCenter> &cells, cons
{
Face &e = faces[i];
size_t xVertexIdx = ( cells[i].x - vertexExtent.minX ) / cell_size;
size_t yVertexIdx = ( cells[i].y - vertexExtent.minY ) / cell_size;
size_t xVertexIdx = MDAL::toSizeT( ( cells[i].x - vertexExtent.minX ) / cell_size );
size_t yVertexIdx = MDAL::toSizeT( ( cells[i].y - vertexExtent.minY ) / cell_size );
for ( size_t position = 0; position < 4; ++position )
{
size_t xPos;
size_t yPos;
size_t xPos = 0;
size_t yPos = 0;
switch ( position )
{

View File

@ -186,7 +186,7 @@ HdfDataset::HdfDataset( hid_t file, const std::string &path )
HdfDataset::~HdfDataset() = default;
bool HdfDataset::isValid() const { return d->id >= 0; }
bool HdfDataset::isValid() const { return d && d->id >= 0; }
hid_t HdfDataset::id() const { return d->id; }

View File

@ -193,9 +193,12 @@ class HdfDataset
public:
typedef HdfH<H5I_DATASET> Handle;
//! Create new, simple 1 dimensional dataset
//! creates invalid dataset
HdfDataset() = default;
//! Creates new, simple 1 dimensional dataset
HdfDataset( hid_t file, const std::string &path, HdfDataType dtype, size_t nItems = 1 );
//! Create new dataset with custom dimensions
//! Creates new dataset with custom dimensions
HdfDataset( hid_t file, const std::string &path, HdfDataType dtype, HdfDataspace dataspace );
//! Opens dataset for reading
HdfDataset( hid_t file, const std::string &path );
@ -286,9 +289,6 @@ class HdfDataset
protected:
std::shared_ptr<Handle> d;
hid_t m_fileId;
std::string m_path;
HdfDataType mType; // when in write mode
};

View File

@ -202,21 +202,6 @@ static std::vector<MDAL::RelativeTimestamp> readTimes( const HdfFile &hdfFile )
return convertTimeData( times, dataTimeUnits );
}
static std::vector<int> readFace2Cells( const HdfFile &hdfFile, const std::string &flowAreaName, size_t *nFaces )
{
// First read face to node mapping
HdfGroup gGeom = openHdfGroup( hdfFile, "Geometry" );
HdfGroup gGeom2DFlowAreas = openHdfGroup( gGeom, "2D Flow Areas" );
HdfGroup gArea = openHdfGroup( gGeom2DFlowAreas, flowAreaName );
HdfDataset dsFace2Cells = openHdfDataset( gArea, "Faces Cell Indexes" );
std::vector<hsize_t> fdims = dsFace2Cells.dims();
std::vector<int> face2Cells = dsFace2Cells.readArrayInt(); //2x nFaces
*nFaces = fdims[0];
return face2Cells;
}
void MDAL::DriverHec2D::readFaceOutput( const HdfFile &hdfFile,
const HdfGroup &rootGroup,
const std::vector<size_t> &areaElemStartIndex,
@ -226,8 +211,6 @@ void MDAL::DriverHec2D::readFaceOutput( const HdfFile &hdfFile,
const std::vector<RelativeTimestamp> &times,
const DateTime &referenceTime )
{
double eps = std::numeric_limits<double>::min();
std::shared_ptr<DatasetGroup> group = std::make_shared< DatasetGroup >(
name(),
mMesh.get(),
@ -235,7 +218,7 @@ void MDAL::DriverHec2D::readFaceOutput( const HdfFile &hdfFile,
datasetName
);
group->setDataLocation( MDAL_DataLocation::DataOnFaces );
group->setIsScalar( true );
group->setIsScalar( false );
group->setReferenceTime( referenceTime );
std::vector<std::shared_ptr<MDAL::MemoryDataset2D>> datasets;
@ -253,34 +236,99 @@ void MDAL::DriverHec2D::readFaceOutput( const HdfFile &hdfFile,
{
std::string flowAreaName = flowAreaNames[nArea];
size_t nFaces;
std::vector<int> face2Cells = readFace2Cells( hdfFile, flowAreaName, &nFaces );
HdfGroup gFlowAreaRes = openHdfGroup( rootGroup, flowAreaName );
HdfDataset dsVals = openHdfDataset( gFlowAreaRes, rawDatasetName );
std::vector<float> vals = dsVals.readArray();
HdfGroup gGeom = openHdfGroup( hdfFile, "Geometry" );
HdfGroup gGeom2DFlowAreas = openHdfGroup( gGeom, "2D Flow Areas" );
HdfGroup gArea = openHdfGroup( gGeom2DFlowAreas, flowAreaName );
HdfDataset dsCellFaceInfo = openHdfDataset( gArea, "Cells Face and Orientation Info" );
std::vector<hsize_t> celldims = dsCellFaceInfo.dims();
std::vector<int> cellFaceInfo = dsCellFaceInfo.readArrayInt();
HdfDataset dsCellFaceOrValues = openHdfDataset( gArea, "Cells Face and Orientation Values" );
std::vector<int> cellFaceOrValues = dsCellFaceOrValues.readArrayInt();
HdfDataset dsFacePointIndex = openHdfDataset( gArea, "Faces FacePoint Indexes" );
std::vector<hsize_t> fdims = dsFacePointIndex.dims();
size_t nFaces = static_cast<size_t>( fdims[0] );
std::vector<int> facePointIndex = dsFacePointIndex.readArrayInt();
HdfDataset dsCoords = openHdfDataset( gArea, "FacePoints Coordinate" );
std::vector<hsize_t> cdims = dsCoords.dims();
std::vector<double> coords = dsCoords.readArrayDouble(); //2xnNodes matrix in array
for ( size_t tidx = 0; tidx < times.size(); ++tidx )
{
std::shared_ptr<MDAL::MemoryDataset2D> dataset = datasets[tidx];
double *values = dataset->values();
for ( size_t i = 0; i < nFaces; ++i )
for ( size_t cell_idx = 0; cell_idx < celldims.at( 0 ); ++cell_idx )
{
size_t idx = tidx * nFaces + i;
double val = static_cast<double>( vals[idx] ); // This is value on face!
if ( !std::isnan( val ) && fabs( val ) > eps ) //not nan and not 0
size_t cell_mdal_idx = cell_idx + areaElemStartIndex[nArea];
double valx = 0;
double valy = 0;
size_t consideredValueCount = 0;
size_t firstPosition = static_cast<size_t>( cellFaceInfo[cell_idx * 2] );
size_t faceCount = static_cast<size_t>( cellFaceInfo[cell_idx * 2 + 1] );
for ( size_t f = 0; f < faceCount; ++f )
{
for ( size_t c = 0; c < 2; ++c )
//get face indexes
size_t faceIndex1 = static_cast<size_t>( cellFaceOrValues[( firstPosition + f ) * 2] );
size_t faceIndex2 = static_cast<size_t>( cellFaceOrValues[( firstPosition + ( f + 1 ) % faceCount ) * 2] );
double val1 = static_cast<double>( vals[faceIndex1 + tidx * nFaces] );
double val2 = static_cast<double>( vals[faceIndex2 + tidx * nFaces] );
if ( std::isnan( val1 ) || std::isnan( val2 ) )
continue;
size_t indexPoint11 = facePointIndex[faceIndex1 * 2];
size_t indexPoint12 = facePointIndex[faceIndex1 * 2 + 1];
size_t indexPoint21 = facePointIndex[faceIndex2 * 2];
size_t indexPoint22 = facePointIndex[faceIndex2 * 2 + 1];
bool commonIndex = ( indexPoint11 == indexPoint21 ||
indexPoint11 == indexPoint22 ||
indexPoint12 == indexPoint21 ||
indexPoint12 == indexPoint22 );
if ( !commonIndex )
{
size_t cell_idx = static_cast<size_t>( face2Cells[2 * i + c] ) + areaElemStartIndex[nArea];
// Take just maximum
if ( std::isnan( values[cell_idx] ) || values[cell_idx] < val )
{
values[cell_idx] = val;
}
// should not happen, but better to prevent
continue;
}
double dx1 = coords[indexPoint11 * 2] - coords[indexPoint12 * 2];
double dy1 = coords[indexPoint11 * 2 + 1] - coords[indexPoint12 * 2 + 1];
double dx2 = coords[indexPoint21 * 2] - coords[indexPoint22 * 2];
double dy2 = coords[indexPoint21 * 2 + 1] - coords[indexPoint22 * 2 + 1];
double l1 = sqrt( dx1 * dx1 + dy1 * dy1 );
double l2 = sqrt( dx2 * dx2 + dy2 * dy2 );
if ( l1 == 0 || l2 == 0 )
{
continue;
}
double nx1 = -dy1 / l1;
double ny1 = dx1 / l1;
double nx2 = -dy2 / l2;
double ny2 = dx2 / l2;
double deter = nx1 * ny2 - nx2 * ny1;
if ( deter == 0 ) //colinear face, forbidden by hecras, but better to prevent
continue;
valx += ( ny2 * val1 - ny1 * val2 ) / deter;
valy += ( nx1 * val2 - nx2 * val1 ) / deter;
consideredValueCount++;
}
if ( consideredValueCount != 0 )
{
valx /= consideredValueCount;
valy /= consideredValueCount;
values[cell_mdal_idx * 2] = valx;
values[cell_mdal_idx * 2 + 1] = valy;
}
else
{
values[cell_mdal_idx * 2] = std::numeric_limits<double>::quiet_NaN();
values[cell_mdal_idx * 2 + 1] = std::numeric_limits<double>::quiet_NaN();
}
}
}
@ -302,15 +350,15 @@ void MDAL::DriverHec2D::readFaceResults( const HdfFile &hdfFile,
// UNSTEADY
HdfGroup flowGroup = get2DFlowAreasGroup( hdfFile, "Unsteady Time Series" );
MDAL::DateTime referenceDateTime = readReferenceDateTime( hdfFile );
readFaceOutput( hdfFile, flowGroup, areaElemStartIndex, flowAreaNames, "Face Shear Stress", "Face Shear Stress", mTimes, referenceDateTime );
readFaceOutput( hdfFile, flowGroup, areaElemStartIndex, flowAreaNames, "Face Velocity", "Face Velocity", mTimes, referenceDateTime );
readFaceOutput( hdfFile, flowGroup, areaElemStartIndex, flowAreaNames, "Face Shear Stress", "Shear Stress", mTimes, referenceDateTime );
readFaceOutput( hdfFile, flowGroup, areaElemStartIndex, flowAreaNames, "Face Velocity", "Velocity", mTimes, referenceDateTime );
// SUMMARY
flowGroup = get2DFlowAreasGroup( hdfFile, "Summary Output" );
std::vector<MDAL::RelativeTimestamp> dummyTimes( 1, MDAL::RelativeTimestamp() );
readFaceOutput( hdfFile, flowGroup, areaElemStartIndex, flowAreaNames, "Maximum Face Shear Stress", "Face Shear Stress/Maximums", dummyTimes, referenceDateTime );
readFaceOutput( hdfFile, flowGroup, areaElemStartIndex, flowAreaNames, "Maximum Face Velocity", "Face Velocity/Maximums", dummyTimes, referenceDateTime );
readFaceOutput( hdfFile, flowGroup, areaElemStartIndex, flowAreaNames, "Maximum Face Shear Stress", "Shear Stress/Maximums", dummyTimes, referenceDateTime );
readFaceOutput( hdfFile, flowGroup, areaElemStartIndex, flowAreaNames, "Maximum Face Velocity", "Velocity/Maximums", dummyTimes, referenceDateTime );
}

View File

@ -863,7 +863,7 @@ size_t MDAL::MeshSelafinFaceIterator::next( size_t faceOffsetsBufferLen, int *fa
throw MDAL::Error( MDAL_Status::Err_UnknownFormat, "File format problem while reading faces" );
vertexIndicesBuffer[vertexLocalIndex + j] = indexes[j + i * verticesPerFace] - 1;
}
vertexLocalIndex += verticesPerFace;
vertexLocalIndex += MDAL::toInt( verticesPerFace );
faceOffsetsBuffer[i] = vertexLocalIndex;
}
@ -936,9 +936,9 @@ static void writeInt( std::ofstream &file, int i )
static void writeStringRecord( std::ofstream &file, const std::string &str )
{
writeInt( file, str.size() );
writeInt( file, MDAL::toInt( str.size() ) );
file.write( str.data(), str.size() );
writeInt( file, str.size() );
writeInt( file, MDAL::toInt( str.size() ) );
}
template<typename T>
@ -1011,9 +1011,9 @@ void MDAL::DriverSelafin::save( const std::string &uri, MDAL::Mesh *mesh )
size_t verticesCount = mesh->verticesCount();
size_t facesCount = mesh->facesCount();
std::vector<int> elem( 4 );
elem[0] = facesCount;
elem[1] = verticesCount;
elem[2] = verticesPerFace;
elem[0] = MDAL::toInt( facesCount );
elem[1] = MDAL::toInt( verticesCount );
elem[2] = MDAL::toInt( verticesPerFace );
elem[3] = 1;
writeValueArrayRecord( file, elem );
@ -1022,7 +1022,7 @@ void MDAL::DriverSelafin::save( const std::string &uri, MDAL::Mesh *mesh )
std::vector<int> faceOffsetBuffer( bufferSize );
std::unique_ptr<MeshFaceIterator> faceIter = mesh->readFaces();
size_t count = 0;
writeInt( file, facesCount * verticesPerFace * 4 );
writeInt( file, MDAL::toInt( facesCount * verticesPerFace * 4 ) );
do
{
std::vector<int> inkle( bufferSize * verticesPerFace );
@ -1034,7 +1034,7 @@ void MDAL::DriverSelafin::save( const std::string &uri, MDAL::Mesh *mesh )
writeValueArray( file, inkle );
}
while ( count != 0 );
writeInt( file, facesCount * verticesPerFace * 4 );
writeInt( file, MDAL::toInt( facesCount * verticesPerFace * 4 ) );
// IPOBO filled with 0
writeValueArrayRecord( file, std::vector<int>( verticesCount, 0 ) );
@ -1077,9 +1077,9 @@ static void writeScalarDataset( std::ofstream &file, MDAL::Dataset *dataset, boo
{
size_t valuesCount = dataset->valuesCount();
size_t bufferSize = BUFFER_SIZE;
int count = 0;
int indexStart = 0;
writeInt( file, valuesCount * ( isFloat ? 4 : 8 ) );
size_t count = 0;
size_t indexStart = 0;
writeInt( file, MDAL::toInt( valuesCount * ( isFloat ? 4 : 8 ) ) );
do
{
std::vector<double> values( bufferSize );
@ -1088,8 +1088,8 @@ static void writeScalarDataset( std::ofstream &file, MDAL::Dataset *dataset, boo
if ( isFloat )
{
std::vector<float> floatValues( count );
for ( int i = 0; i < count; ++i )
floatValues[i] = values[i];
for ( int i = 0; i < MDAL::toInt( count ); ++i )
floatValues[i] = static_cast<float>( values[i] );
writeValueArray( file, floatValues );
}
else
@ -1098,7 +1098,7 @@ static void writeScalarDataset( std::ofstream &file, MDAL::Dataset *dataset, boo
indexStart += count;
}
while ( count != 0 );
writeInt( file, valuesCount * ( isFloat ? 4 : 8 ) );
writeInt( file, MDAL::toInt( valuesCount * ( isFloat ? 4 : 8 ) ) );
}
template<typename T>
@ -1109,17 +1109,17 @@ static void writeVectorDataset( std::ofstream &file, MDAL::Dataset *dataset )
std::vector<T> valuesX( valuesCount );
std::vector<T> valuesY( valuesCount );
size_t bufferSize = BUFFER_SIZE;
int count = 0;
int indexStart = 0;
size_t count = 0;
size_t indexStart = 0;
do
{
std::vector<double> values( bufferSize * 2 );
count = dataset->vectorData( indexStart, bufferSize, values.data() );
values.resize( count * 2 );
for ( int i = 0; i < count; ++i )
for ( int i = 0; i < MDAL::toInt( count ); ++i )
{
valuesX[indexStart + i] = values[i * 2];
valuesY[indexStart + i] = values[i * 2 + 1];
valuesX[indexStart + i] = static_cast< T >( values[i * 2] );
valuesY[indexStart + i] = static_cast< T >( values[i * 2 + 1] );
}
indexStart += count;
}
@ -1224,24 +1224,24 @@ bool MDAL::SelafinFile::addDatasetGroup( MDAL::DatasetGroup *datasetGroup )
writeValueArrayRecord( out, std::vector<int> {int( mFacesCount ), int( mVerticesCount ), int( mVerticesPerFace ), 1} );
//IKLE
writeInt( out, mFacesCount * mVerticesPerFace * 4 );
writeInt( out, MDAL::toInt( mFacesCount * mVerticesPerFace * 4 ) );
streamToStream( out, mIn, mConnectivityStreamPosition, mFacesCount * mVerticesPerFace * 4, BUFFER_SIZE );
writeInt( out, mFacesCount * mVerticesPerFace * 4 );
writeInt( out, MDAL::toInt( mFacesCount * mVerticesPerFace * 4 ) );
//vertices
//IPOBO
writeInt( out, mVerticesCount * 4 );
writeInt( out, MDAL::toInt( mVerticesCount * 4 ) );
streamToStream( out, mIn, mIPOBOStreamPosition, mVerticesCount * 4, BUFFER_SIZE );
writeInt( out, mVerticesCount * 4 );
writeInt( out, MDAL::toInt( mVerticesCount * 4 ) );
//X Vertices
writeInt( out, mVerticesCount * realSize );
writeInt( out, MDAL::toInt( mVerticesCount * realSize ) );
streamToStream( out, mIn, mXStreamPosition, mVerticesCount * realSize, BUFFER_SIZE );
writeInt( out, mVerticesCount * realSize );
writeInt( out, MDAL::toInt( mVerticesCount * realSize ) );
//Y Vertices
writeInt( out, mVerticesCount * realSize );
writeInt( out, MDAL::toInt( mVerticesCount * realSize ) );
streamToStream( out, mIn, mYStreamPosition, mVerticesCount * realSize, BUFFER_SIZE );
writeInt( out, mVerticesCount * realSize );
writeInt( out, MDAL::toInt( mVerticesCount * realSize ) );
// Write datasets
for ( size_t nT = 0; nT < mTimeSteps.size(); nT++ )
@ -1249,7 +1249,7 @@ bool MDAL::SelafinFile::addDatasetGroup( MDAL::DatasetGroup *datasetGroup )
// Time step
if ( mStreamInFloatPrecision )
{
std::vector<float> time( 1, mTimeSteps.at( nT ).value( RelativeTimestamp::seconds ) );
std::vector<float> time( 1, static_cast<float>( mTimeSteps.at( nT ).value( RelativeTimestamp::seconds ) ) );
writeValueArrayRecord( out, time );
}
else
@ -1261,9 +1261,9 @@ bool MDAL::SelafinFile::addDatasetGroup( MDAL::DatasetGroup *datasetGroup )
// First, prexisting datasets from the original file
for ( int i = 0; i < nbv[0] - addedVariable; ++i )
{
writeInt( out, mVerticesCount * realSize );
writeInt( out, MDAL::toInt( mVerticesCount * realSize ) );
streamToStream( out, mIn, mVariableStreamPosition[i][nT], realSize * mVerticesCount, BUFFER_SIZE );
writeInt( out, mVerticesCount * realSize );
writeInt( out, MDAL::toInt( mVerticesCount * realSize ) );
}
// Then, new datasets from the new dataset group

View File

@ -315,8 +315,8 @@ void MDAL::DriverUgrid::populateEdges( MDAL::Edges &edges )
for ( size_t i = 0; i < edgesCount; ++i )
{
int startEdgeIx = i * 2;
int endEdgeIx = i * 2 + 1;
int startEdgeIx = MDAL::toInt( i ) * 2;
int endEdgeIx = MDAL::toInt( i ) * 2 + 1;
edges[i].startVertex = edgeNodesIdxs[startEdgeIx] - startIndex;
edges[i].endVertex = edgeNodesIdxs[endEdgeIx] - startIndex;

View File

@ -74,6 +74,8 @@ size_t MDAL::XmdfDataset::vectorData( size_t indexStart, size_t count, double *b
size_t MDAL::XmdfDataset::activeData( size_t indexStart, size_t count, int *buffer )
{
if ( !dsActive().isValid() )
return 0;
std::vector<hsize_t> offsets = {timeIndex(), indexStart};
std::vector<hsize_t> counts = {1, count};
std::vector<uchar> active = dsActive().readArrayUint8( offsets, counts );
@ -117,6 +119,27 @@ bool MDAL::DriverXmdf::canReadDatasets( const std::string &uri )
return true;
}
void MDAL::DriverXmdf::readGroupsTree( HdfFile &file, const std::string &name, MDAL::DatasetGroups &groups, size_t vertexCount, size_t faceCount ) const
{
HdfGroup gMesh = file.group( name );
for ( const std::string &groupName : gMesh.groups() )
{
HdfGroup gGroup = gMesh.group( groupName );
if ( gGroup.isValid() )
{
if ( groupName == "Maximums" )
{
addDatasetGroupsFromXmdfGroup( groups, gGroup, "/Maximums", vertexCount, faceCount );
}
else
{
addDatasetGroupsFromXmdfGroup( groups, gGroup, "", vertexCount, faceCount );
}
}
}
}
void MDAL::DriverXmdf::load( const std::string &datFile, MDAL::Mesh *mesh )
{
mDatFile = datFile;
@ -143,26 +166,25 @@ void MDAL::DriverXmdf::load( const std::string &datFile, MDAL::Mesh *mesh )
size_t faceCount = mesh->facesCount();
std::vector<std::string> rootGroups = file.groups();
if ( rootGroups.size() != 1 )
if ( rootGroups.empty() )
{
MDAL::Log::error( MDAL_Status::Err_UnknownFormat, name(), "Expecting exactly one root group for the mesh data" );
MDAL::Log::error( MDAL_Status::Err_UnknownFormat, name(), "Expecting at least one root group for the mesh data" );
return;
}
HdfGroup gMesh = file.group( rootGroups[0] );
DatasetGroups groups; // DAT outputs data
for ( const std::string &groupName : gMesh.groups() )
for ( std::string &name : rootGroups )
{
HdfGroup gGroup = gMesh.group( groupName );
if ( gGroup.isValid() )
HdfGroup rootGroup = file.group( name );
if ( rootGroup.groups().size() > 0 )
readGroupsTree( file, name, groups, vertexCount, faceCount );
else
{
if ( groupName == "Maximums" )
std::shared_ptr<DatasetGroup> ds = readXmdfGroupAsDatasetGroup( rootGroup, name, vertexCount, faceCount );
if ( ds && ds->datasets.size() > 0 )
{
addDatasetGroupsFromXmdfGroup( groups, gGroup, "/Maximums", vertexCount, faceCount );
}
else
{
addDatasetGroupsFromXmdfGroup( groups, gGroup, "", vertexCount, faceCount );
groups.push_back( ds );
}
}
}
@ -178,7 +200,7 @@ void MDAL::DriverXmdf::addDatasetGroupsFromXmdfGroup( DatasetGroups &groups,
const HdfGroup &rootGroup,
const std::string &nameSuffix,
size_t vertexCount,
size_t faceCount )
size_t faceCount ) const
{
for ( const std::string &groupName : rootGroup.groups() )
{
@ -193,13 +215,12 @@ void MDAL::DriverXmdf::addDatasetGroupsFromXmdfGroup( DatasetGroups &groups,
std::shared_ptr<MDAL::DatasetGroup> MDAL::DriverXmdf::readXmdfGroupAsDatasetGroup(
const HdfGroup &rootGroup, const std::string &groupName, size_t vertexCount, size_t faceCount )
const HdfGroup &rootGroup, const std::string &groupName, size_t vertexCount, size_t faceCount ) const
{
std::shared_ptr<DatasetGroup> group;
std::vector<std::string> gDataNames = rootGroup.datasets();
if ( !MDAL::contains( gDataNames, "Times" ) ||
!MDAL::contains( gDataNames, "Values" ) ||
!MDAL::contains( gDataNames, "Active" ) ||
!MDAL::contains( gDataNames, "Mins" ) ||
!MDAL::contains( gDataNames, "Maxs" ) )
{
@ -207,21 +228,29 @@ std::shared_ptr<MDAL::DatasetGroup> MDAL::DriverXmdf::readXmdfGroupAsDatasetGrou
return group;
}
bool activeFlagSupported = MDAL::contains( gDataNames, "Active" );
HdfDataset dsTimes = rootGroup.dataset( "Times" );
HdfDataset dsValues = rootGroup.dataset( "Values" );
HdfDataset dsActive = rootGroup.dataset( "Active" );
HdfDataset dsMins = rootGroup.dataset( "Mins" );
HdfDataset dsMaxs = rootGroup.dataset( "Maxs" );
std::vector<hsize_t> dimTimes = dsTimes.dims();
std::vector<hsize_t> dimValues = dsValues.dims();
std::vector<hsize_t> dimActive = dsActive.dims();
std::vector<hsize_t> dimMins = dsMins.dims();
std::vector<hsize_t> dimActive;
std::vector<hsize_t> dimMaxs = dsMaxs.dims();
HdfDataset dsActive;
if ( activeFlagSupported )
{
dsActive = rootGroup.dataset( "Active" );
dimActive = dsActive.dims();
}
if ( dimTimes.size() != 1 ||
( dimValues.size() != 2 && dimValues.size() != 3 ) ||
dimActive.size() != 2 ||
( activeFlagSupported && dimActive.size() != 2 ) ||
dimMins.size() != 1 ||
dimMaxs.size() != 1
)
@ -232,14 +261,15 @@ std::shared_ptr<MDAL::DatasetGroup> MDAL::DriverXmdf::readXmdfGroupAsDatasetGrou
hsize_t nTimeSteps = dimTimes[0];
if ( dimValues[0] != nTimeSteps ||
dimActive[0] != nTimeSteps ||
( activeFlagSupported && dimActive[0] != nTimeSteps ) ||
dimMins[0] != nTimeSteps ||
dimMaxs[0] != nTimeSteps )
{
MDAL::Log::debug( "ignoring dataset " + groupName + " - arrays not having correct dimension sizes" );
return group;
}
if ( dimValues[1] != vertexCount || dimActive[1] != faceCount )
if ( dimValues[1] != vertexCount || ( activeFlagSupported && dimActive[1] != faceCount ) )
{
MDAL::Log::debug( "ignoring dataset " + groupName + " - not aligned with the used mesh" );
return group;
@ -252,6 +282,7 @@ std::shared_ptr<MDAL::DatasetGroup> MDAL::DriverXmdf::readXmdfGroupAsDatasetGrou
mDatFile,
groupName
);
bool isVector = dimValues.size() == 3;
group->setIsScalar( !isVector );
group->setDataLocation( MDAL_DataLocation::DataOnVertices );
@ -286,6 +317,7 @@ std::shared_ptr<MDAL::DatasetGroup> MDAL::DriverXmdf::readXmdfGroupAsDatasetGrou
{
std::shared_ptr<XmdfDataset> dataset = std::make_shared< XmdfDataset >( group.get(), dsValues, dsActive, i );
dataset->setTime( times[i], timeUnit );
dataset->setSupportsActiveFlag( activeFlagSupported );
Statistics stats;
stats.minimum = static_cast<double>( mins[i] );
stats.maximum = static_cast<double>( maxs[i] );

View File

@ -23,13 +23,17 @@ namespace MDAL
/**
* The XmdfDataset reads the data directly from HDF5 file
* by usage of hyperslabs retrieval
*
* by usage of hyperslabs retrieval. This format is used by TUFLOW and HYDRO_AS-2D
* basically all (timesteps) data for one particular dataset groups
* are stored in single
* 3D arrays (time, x, y) for vector datasets
* 2D arrays (time, x) for scalar datasets
* 2D arrays (time, active) for active flags
* 2D arrays (time, active) for active flags (optional, supported by default)
*
* For TUFLOW, the dataset groups are structured with a tree starting from a unique group and datasets support active flag value.
*
* For HYDRO_AS-2D, all the groups are on the root of the file and the datasets don't support active flag value.
*
*/
class XmdfDataset: public Dataset2D
{
@ -92,14 +96,21 @@ namespace MDAL
const HdfGroup &rootGroup,
const std::string &groupName,
size_t vertexCount,
size_t faceCount );
size_t faceCount ) const;
void addDatasetGroupsFromXmdfGroup(
DatasetGroups &groups,
const HdfGroup &rootGroup,
const std::string &nameSuffix,
size_t vertexCount,
size_t faceCount );
size_t faceCount ) const;
void readGroupsTree( HdfFile &file,
const std::string &name,
MDAL::DatasetGroups &groups,
size_t vertexCount,
size_t faceCount ) const;
};
} // namespace MDAL

View File

@ -21,7 +21,7 @@ static const char *EMPTY_STR = "";
const char *MDAL_Version()
{
return "0.7.1";
return "0.7.91";
}
MDAL_Status MDAL_LastStatus()

View File

@ -31,7 +31,7 @@ namespace MDAL
double maxY = -std::numeric_limits<double>::max();
};
typedef struct
typedef struct StatisticsType
{
double minimum = std::numeric_limits<double>::quiet_NaN();
double maximum = std::numeric_limits<double>::quiet_NaN();

View File

@ -12,6 +12,7 @@
#include "frmts/mdal_selafin.hpp"
#include "frmts/mdal_esri_tin.hpp"
#include "frmts/mdal_ply.hpp"
#include "frmts/mdal_dynamic_driver.hpp"
#include "mdal_utils.hpp"
#ifdef HAVE_HDF5
@ -240,5 +241,25 @@ MDAL::DriverManager::DriverManager()
#if defined HAVE_HDF5 && defined HAVE_XML
mDrivers.push_back( std::make_shared<MDAL::DriverXdmf>() );
#endif
loadDynamicDrivers();
}
void MDAL::DriverManager::loadDynamicDrivers()
{
std::string dirPath = MDAL::getEnvVar( "MDAL_DRIVER_PATH" );
if ( dirPath.empty() )
return;
dirPath += '/';
std::vector<std::string> libList = MDAL::Library::libraryFilesInDir( dirPath );
for ( const std::string &libFile : libList )
{
std::shared_ptr<MDAL::Driver> driver( MDAL::DriverDynamic::create( dirPath + libFile ) );
if ( driver )
mDrivers.push_back( driver );
}
}

View File

@ -44,6 +44,8 @@ namespace MDAL
std::shared_ptr<MDAL::Driver> driver( const std::string &driverName ) const;
std::shared_ptr<MDAL::Driver> driver( size_t index ) const;
void loadDynamicDrivers();
private:
DriverManager();

View File

@ -308,8 +308,8 @@ size_t MDAL::MemoryMeshEdgeIterator::next( size_t edgeCount,
break;
const Edge &e = edges[mLastEdgeIndex + i];
startVertexIndices[i] = e.startVertex;
endVertexIndices[i] = e.endVertex;
startVertexIndices[i] = MDAL::toInt( e.startVertex );
endVertexIndices[i] = MDAL::toInt( e.endVertex );
++i;
}

View File

@ -19,7 +19,7 @@ namespace MDAL
{
class MemoryMesh;
typedef struct
typedef struct VertexType
{
double x = std::numeric_limits<double>::quiet_NaN();
double y = std::numeric_limits<double>::quiet_NaN();

View File

@ -14,6 +14,33 @@
#include <string.h>
#include <stdio.h>
#include <ctime>
#include <stdlib.h>
std::string MDAL::getEnvVar( const std::string &varname, const std::string &defaultVal )
{
if ( varname.empty() )
return std::string();
char *envVarC = nullptr;
#ifdef WIN32
size_t requiredSize = 0;
getenv_s( &requiredSize, NULL, 0, varname.c_str() );
if ( requiredSize != 0 )
{
envVarC = ( char * )malloc( requiredSize * sizeof( char ) );
getenv_s( &requiredSize, envVarC, requiredSize, varname.c_str() );
}
else
envVarC = nullptr;
#else
envVarC = getenv( varname.c_str() );
#endif
if ( !envVarC )
return defaultVal;
else
return std::string( envVarC );
}
bool MDAL::fileExists( const std::string &filename )
{
@ -119,6 +146,23 @@ size_t MDAL::toSizeT( const char &str )
return static_cast< size_t >( i );
}
size_t MDAL::toSizeT( const double value )
{
return static_cast<size_t>( value );
}
int MDAL::toInt( const size_t value )
{
if ( value > std::numeric_limits<int>::max() )
throw std::runtime_error( "Invalid cast" );
return static_cast< int >( value );
}
double MDAL::toDouble( const size_t value )
{
return static_cast< double >( value );
}
double MDAL::toDouble( const std::string &str )
{
return atof( str.c_str() );
@ -430,7 +474,7 @@ std::string MDAL::getCurrentTimeStamp()
return s;
}
MDAL::Statistics _calculateStatistics( const std::vector<double> &values, size_t count, bool isVector )
MDAL::Statistics _calculateStatistics( const std::vector<double> &values, size_t count, bool isVector, const std::vector<int> &active )
{
MDAL::Statistics ret;
@ -440,6 +484,9 @@ MDAL::Statistics _calculateStatistics( const std::vector<double> &values, size_t
for ( size_t i = 0; i < count; ++i )
{
if ( !active.empty() && active.at( i ) == 0 )
continue;
double magnitude;
if ( isVector )
{
@ -510,6 +557,11 @@ MDAL::Statistics MDAL::calculateStatistics( std::shared_ptr<Dataset> dataset )
bool is3D = dataset->group()->dataLocation() == MDAL_DataLocation::DataOnVolumes;
size_t bufLen = 2000;
std::vector<double> buffer( isVector ? bufLen * 2 : bufLen );
std::vector<int> activeBuffer;
bool activeFaceFlag = dataset->group()->dataLocation() == MDAL_DataLocation::DataOnFaces && dataset->supportsActiveFlag();
if ( activeFaceFlag )
activeBuffer.resize( bufLen );
size_t i = 0;
while ( i < dataset->valuesCount() )
@ -536,11 +588,14 @@ MDAL::Statistics MDAL::calculateStatistics( std::shared_ptr<Dataset> dataset )
{
valsRead = dataset->scalarData( i, bufLen, buffer.data() );
}
if ( activeFaceFlag )
dataset->activeData( i, bufLen, activeBuffer.data() );
}
if ( valsRead == 0 )
return ret;
MDAL::Statistics dsStats = _calculateStatistics( buffer, valsRead, isVector );
MDAL::Statistics dsStats = _calculateStatistics( buffer, valsRead, isVector, activeBuffer );
combineStatistics( ret, dsStats );
i += valsRead;
}
@ -565,58 +620,51 @@ void MDAL::combineStatistics( MDAL::Statistics &main, const MDAL::Statistics &ot
void MDAL::addBedElevationDatasetGroup( MDAL::Mesh *mesh, const Vertices &vertices )
{
if ( !mesh )
return;
if ( 0 == mesh->verticesCount() )
return;
std::shared_ptr<DatasetGroup> group = std::make_shared< DatasetGroup >(
mesh->driverName(),
mesh,
mesh->uri(),
"Bed Elevation"
);
group->setDataLocation( MDAL_DataLocation::DataOnVertices );
group->setIsScalar( true );
std::shared_ptr<MDAL::MemoryDataset2D> dataset = std::make_shared< MemoryDataset2D >( group.get() );
dataset->setTime( 0.0 );
std::vector<double> values( mesh->verticesCount() );
for ( size_t i = 0; i < vertices.size(); ++i )
{
dataset->setScalarValue( i, vertices[i].z );
values[i] = vertices[i].z;
}
dataset->setStatistics( MDAL::calculateStatistics( dataset ) );
group->datasets.push_back( dataset );
group->setStatistics( MDAL::calculateStatistics( group ) );
mesh->datasetGroups.push_back( group );
addVertexScalarDatasetGroup( mesh, values, "Bed Elevation" );
}
void MDAL::addFaceScalarDatasetGroup( MDAL::Mesh *mesh,
const std::vector<double> &values,
const std::string &name )
static void _addScalarDatasetGroup( MDAL::Mesh *mesh,
const std::vector<double> &values,
const std::string &name,
MDAL_DataLocation location
)
{
if ( !mesh )
return;
size_t maxCount = 0;
switch ( location )
{
case MDAL_DataLocation::DataOnVertices: maxCount = mesh->verticesCount(); break;
case MDAL_DataLocation::DataOnFaces: maxCount = mesh->facesCount(); break;
case MDAL_DataLocation::DataOnEdges: maxCount = mesh->edgesCount(); break;
default:
assert( false );
}
if ( values.empty() )
return;
if ( mesh->facesCount() == 0 )
if ( maxCount == 0 )
return;
assert( values.size() == mesh->facesCount() );
assert( values.size() == maxCount );
std::shared_ptr<DatasetGroup> group = std::make_shared< DatasetGroup >(
mesh->driverName(),
mesh,
mesh->uri(),
name
);
group->setDataLocation( MDAL_DataLocation::DataOnFaces );
std::shared_ptr<MDAL::DatasetGroup> group = std::make_shared< MDAL::DatasetGroup >(
mesh->driverName(),
mesh,
mesh->uri(),
name
);
group->setDataLocation( location );
group->setIsScalar( true );
std::shared_ptr<MDAL::MemoryDataset2D> dataset = std::make_shared< MemoryDataset2D >( group.get() );
std::shared_ptr<MDAL::MemoryDataset2D> dataset = std::make_shared< MDAL::MemoryDataset2D >( group.get() );
dataset->setTime( 0.0 );
memcpy( dataset->values(), values.data(), sizeof( double )*values.size() );
dataset->setStatistics( MDAL::calculateStatistics( dataset ) );
@ -625,6 +673,24 @@ void MDAL::addFaceScalarDatasetGroup( MDAL::Mesh *mesh,
mesh->datasetGroups.push_back( group );
}
void MDAL::addFaceScalarDatasetGroup( MDAL::Mesh *mesh,
const std::vector<double> &values,
const std::string &name )
{
_addScalarDatasetGroup( mesh, values, name, MDAL_DataLocation::DataOnFaces );
}
void MDAL::addVertexScalarDatasetGroup( MDAL::Mesh *mesh, const std::vector<double> &values, const std::string &name )
{
_addScalarDatasetGroup( mesh, values, name, MDAL_DataLocation::DataOnVertices );
}
void MDAL::addEdgeScalarDatasetGroup( MDAL::Mesh *mesh, const std::vector<double> &values, const std::string &name )
{
_addScalarDatasetGroup( mesh, values, name, MDAL_DataLocation::DataOnEdges );
}
bool MDAL::isNativeLittleEndian()
{
// https://stackoverflow.com/a/4181991/2838364
@ -644,7 +710,6 @@ std::string MDAL::coordinateToString( double coordinate, int precision )
oss << coordinate;
std::string returnString = oss.str();
returnString.back();
//remove unnecessary '0' or '.'
if ( returnString.size() > 0 )
@ -919,3 +984,102 @@ std::string MDAL::buildAndMergeMeshUris( const std::string &meshFile, const std:
return mergedUris;
}
MDAL::Library::Library( std::string libraryFile )
{
d = new Data;
d->mLibraryFile = libraryFile;
}
MDAL::Library::~Library()
{
d->mRef--;
#ifdef WIN32
if ( d->mLibrary && d->mRef == 0 )
FreeLibrary( d->mLibrary );
#else
if ( d->mLibrary && d->mRef == 0 )
dlclose( d->mLibrary );
#endif
}
MDAL::Library::Library( const MDAL::Library &other )
{
*this = other;
}
MDAL::Library &MDAL::Library::operator=( const MDAL::Library &other )
{
d = other.d;
d->mRef++;
return ( *this );
}
bool MDAL::Library::isValid()
{
if ( !d->mLibrary )
loadLibrary();
return d->mLibrary != nullptr;
}
std::vector<std::string> MDAL::Library::libraryFilesInDir( const std::string &dirPath )
{
std::vector<std::string> filesList;
#if defined(WIN32)
WIN32_FIND_DATA data;
HANDLE hFind;
std::string pattern = dirPath;
pattern.push_back( '*' );
hFind = FindFirstFile( pattern.c_str(), &data );
if ( hFind == INVALID_HANDLE_VALUE )
return filesList;
do
{
std::string fileName( data.cFileName );
if ( !fileName.empty() && fileExtension( fileName ) == ".dll" )
filesList.push_back( fileName );
}
while ( FindNextFile( hFind, &data ) != 0 );
FindClose( hFind );
#else
DIR *dir = opendir( dirPath.c_str() );
struct dirent *de = readdir( dir );
while ( de != nullptr )
{
std::string fileName( de->d_name );
if ( !fileName.empty() )
{
std::string extentsion = fileExtension( fileName );
if ( extentsion == ".so" || extentsion == ".dylib" )
filesList.push_back( fileName );
}
de = readdir( dir );
}
closedir( dir );
#endif
return filesList;
}
bool MDAL::Library::loadLibrary()
{
//should we allow only one successful loading?
if ( d->mLibrary )
return false;
#ifdef WIN32
UINT uOldErrorMode =
SetErrorMode( SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS );
d->mLibrary = LoadLibrary( d->mLibraryFile.c_str() );
SetErrorMode( uOldErrorMode );
#else
d->mLibrary = dlopen( d->mLibraryFile.c_str(), RTLD_LAZY );
#endif
return d->mLibrary != nullptr;
}

View File

@ -13,6 +13,16 @@
#include <sstream>
#include <fstream>
#include <cmath>
#include <functional>
#if defined (WIN32)
#include <windows.h>
#undef min
#undef max
#else
#include <dlfcn.h>
#include <dirent.h>
#endif
#include <algorithm>
@ -30,6 +40,9 @@
namespace MDAL
{
std::string getEnvVar( const std::string &varname, const std::string &defaultVal = std::string() );
// endianness
bool isNativeLittleEndian();
@ -75,8 +88,11 @@ namespace MDAL
/** Return 0 if not possible to convert */
size_t toSizeT( const std::string &str );
size_t toSizeT( const char &str );
size_t toSizeT( const double value );
int toInt( const std::string &str );
int toInt( const size_t value );
double toDouble( const std::string &str );
double toDouble( const size_t value );
bool toBool( const std::string &str );
//! Returns the string with a adapted format to coordinate
@ -136,8 +152,12 @@ namespace MDAL
// mesh & datasets
//! Adds bed elevatiom dataset group to mesh
void addBedElevationDatasetGroup( MDAL::Mesh *mesh, const Vertices &vertices );
//! Adds altitude dataset group to mesh
//! Adds a scalar face dataset group with 1 timestep to mesh
void addFaceScalarDatasetGroup( MDAL::Mesh *mesh, const std::vector<double> &values, const std::string &name );
//! Adds a scalar vertex dataset group with 1 timestep to mesh
void addVertexScalarDatasetGroup( MDAL::Mesh *mesh, const std::vector<double> &values, const std::string &name );
//! Adds a scalar edge dataset group with 1 timestep to mesh
void addEdgeScalarDatasetGroup( MDAL::Mesh *mesh, const std::vector<double> &values, const std::string &name );
//! Reads all of type of value. Option to change the endianness is provided
template<typename T>
@ -222,5 +242,75 @@ namespace MDAL
std::string mssg;
std::string driver;
};
//! Class to handle dynamic library. The loaded library is implicity shared when copying this object
class Library
{
public:
//! Creater a instance from a library file
Library( std::string libraryFile );
~Library();
Library( const Library &other );
Library &operator=( const Library &other );
//! Returns whether the library is valid after loading the file if needed
bool isValid();
//! Returns a list of library file in the folder \a dirPath
static std::vector<std::string> libraryFilesInDir( const std::string &dirPath );
/**
* Returns a function from a symbol name. Caller needs to define what are the types of the arguments and of the returned value :
* <Type of the returned Value, Type of arg1, Type of arg2, ...>
*/
template<typename T, typename ... Ts>
std::function<T( Ts ... args )> getSymbol( const std::string &symbolName )
{
if ( !isValid() )
return std::function<T( Ts ... args )>();
#ifdef WIN32
FARPROC proc = GetProcAddress( d->mLibrary, symbolName.c_str() );
if ( !proc )
return std::function<T( Ts ... args )>();
std::function<T( Ts ... args )> symbol = reinterpret_cast<T( * )( Ts ... args )>( proc );
#else
std::function<T( Ts ... args )> symbol =
reinterpret_cast<T( * )( Ts ... args )>( dlsym( d->mLibrary, symbolName.c_str() ) );
#if (defined(__APPLE__) && defined(__MACH__))
/* On mach-o systems, C symbols have a leading underscore and depending
* on how dlcompat is configured it may or may not add the leading
* underscore. If dlsym() fails, add an underscore and try again.
*/
if ( symbol == nullptr )
{
char withUnder[256] = {};
snprintf( withUnder, sizeof( withUnder ), "_%s", symbolName.c_str() );
std::function<T( Ts ... args )> symbol = reinterpret_cast<T( * )( Ts ... args )>( dlsym( d->mLibrary, withUnder ) );
}
#endif
#endif
return symbol;
}
private:
struct Data
{
#ifdef WIN32
HINSTANCE mLibrary = nullptr;
#else
void *mLibrary = nullptr;
#endif
mutable int mRef = 1;
std::string mLibraryFile;
};
Data *d;
bool loadLibrary();
};
} // namespace MDAL
#endif //MDAL_UTILS_HPP

View File

@ -40,6 +40,7 @@ if (WITH_INTERNAL_MDAL)
${CMAKE_SOURCE_DIR}/external/mdal/mdal_logger.cpp
${CMAKE_SOURCE_DIR}/external/mdal/mdal_logger.hpp
${CMAKE_SOURCE_DIR}/external/mdal/frmts/mdal_driver.cpp
${CMAKE_SOURCE_DIR}/external/mdal/frmts/mdal_dynamic_driver.cpp
${CMAKE_SOURCE_DIR}/external/mdal/frmts/mdal_2dm.cpp
${CMAKE_SOURCE_DIR}/external/mdal/frmts/mdal_ascii_dat.cpp
${CMAKE_SOURCE_DIR}/external/mdal/frmts/mdal_binary_dat.cpp
@ -57,6 +58,7 @@ if (WITH_INTERNAL_MDAL)
${CMAKE_SOURCE_DIR}/external/mdal/mdal_memory_data_model.hpp
${CMAKE_SOURCE_DIR}/external/mdal/mdal_driver_manager.hpp
${CMAKE_SOURCE_DIR}/external/mdal/frmts/mdal_driver.hpp
${CMAKE_SOURCE_DIR}/external/mdal/frmts/mdal_dynamic_driver.hpp
${CMAKE_SOURCE_DIR}/external/mdal/frmts/mdal_2dm.hpp
${CMAKE_SOURCE_DIR}/external/mdal/frmts/mdal_ascii_dat.hpp
${CMAKE_SOURCE_DIR}/external/mdal/frmts/mdal_binary_dat.hpp
@ -79,7 +81,6 @@ if (WITH_INTERNAL_MDAL)
${CMAKE_SOURCE_DIR}/external/mdal/frmts/mdal_hec2d.hpp
${CMAKE_SOURCE_DIR}/external/mdal/frmts/mdal_flo2d.hpp
)
set(MDAL_DEPS ${MDAL_DEPS} )
set (HAVE_HDF5 TRUE)
endif()
@ -191,6 +192,10 @@ target_link_libraries (mdalprovider
${MDAL_LIBRARY}
)
if (WITH_INTERNAL_MDAL)
target_link_libraries(mdalprovider ${CMAKE_DL_LIBS})
endif()
if (WITH_GUI)
target_link_libraries (mdalprovider
qgis_gui