/* MDAL - Mesh Data Abstraction Library (MIT License) Copyright (C) 2018 Peter Petrik (zilolv at gmail dot com) */ #include #include #include #include #include #include "mdal.h" #include "mdal_driver_manager.hpp" #include "mdal_data_model.hpp" #include "mdal_utils.hpp" #define NODATA std::numeric_limits::quiet_NaN() static const char *EMPTY_STR = ""; static MDAL_Status sLastStatus; const char *MDAL_Version() { return "0.4.0"; } MDAL_Status MDAL_LastStatus() { return sLastStatus; } // helper to return string data - without having to deal with memory too much. // returned pointer is valid only next call. also not thread-safe. const char *_return_str( const std::string &str ) { static std::string lastStr; lastStr = str; return lastStr.c_str(); } /////////////////////////////////////////////////////////////////////////////////////// /// DRIVERS /////////////////////////////////////////////////////////////////////////////////////// int MDAL_driverCount() { size_t count = MDAL::DriverManager::instance().driversCount(); return static_cast( count ); } DriverH MDAL_driverFromIndex( int index ) { if ( index < 0 ) { sLastStatus = MDAL_Status::Err_MissingDriver; return nullptr; } size_t idx = static_cast( index ); std::shared_ptr driver = MDAL::DriverManager::instance().driver( idx ); return static_cast( driver.get() ); } DriverH MDAL_driverFromName( const char *name ) { std::string nm = name; std::shared_ptr driver = MDAL::DriverManager::instance().driver( nm ); return static_cast( driver.get() ); } bool MDAL_DR_meshLoadCapability( DriverH driver ) { if ( !driver ) { sLastStatus = MDAL_Status::Err_MissingDriver; return false; } MDAL::Driver *d = static_cast< MDAL::Driver * >( driver ); return d->hasCapability( MDAL::Capability::ReadMesh ); } bool MDAL_DR_writeDatasetsCapability( DriverH driver ) { if ( !driver ) { sLastStatus = MDAL_Status::Err_MissingDriver; return false; } MDAL::Driver *d = static_cast< MDAL::Driver * >( driver ); return d->hasCapability( MDAL::Capability::WriteDatasets ); } bool MDAL_DR_SaveMeshCapability( DriverH driver ) { if ( !driver ) { sLastStatus = MDAL_Status::Err_MissingDriver; return false; } MDAL::Driver *d = static_cast< MDAL::Driver * >( driver ); return d->hasCapability( MDAL::Capability::SaveMesh ); } const char *MDAL_DR_longName( DriverH driver ) { if ( !driver ) { sLastStatus = MDAL_Status::Err_MissingDriver; return EMPTY_STR; } MDAL::Driver *d = static_cast< MDAL::Driver * >( driver ); return _return_str( d->longName() ); } const char *MDAL_DR_name( DriverH driver ) { if ( !driver ) { sLastStatus = MDAL_Status::Err_MissingDriver; return EMPTY_STR; } MDAL::Driver *d = static_cast< MDAL::Driver * >( driver ); return _return_str( d->name() ); } const char *MDAL_DR_filters( DriverH driver ) { if ( !driver ) { sLastStatus = MDAL_Status::Err_MissingDriver; return EMPTY_STR; } MDAL::Driver *d = static_cast< MDAL::Driver * >( driver ); return _return_str( d->filters() ); } /////////////////////////////////////////////////////////////////////////////////////// /// MESH /////////////////////////////////////////////////////////////////////////////////////// MeshH MDAL_LoadMesh( const char *meshFile ) { if ( !meshFile ) { sLastStatus = MDAL_Status::Err_FileNotFound; return nullptr; } std::string filename( meshFile ); return static_cast< MeshH >( MDAL::DriverManager::instance().load( filename, &sLastStatus ).release() ); } void MDAL_SaveMesh( MeshH mesh, const char *meshFile, const char *driver ) { if ( !meshFile ) { sLastStatus = MDAL_Status::Err_FileNotFound; return; } std::string driverName( driver ); auto d = MDAL::DriverManager::instance().driver( driver ); if ( !d ) { sLastStatus = MDAL_Status::Err_MissingDriver; return; } if ( !d->hasCapability( MDAL::Capability::SaveMesh ) ) { sLastStatus = MDAL_Status::Err_MissingDriverCapability; return; } if ( d->faceVerticesMaximumCount() < MDAL_M_faceVerticesMaximumCount( mesh ) ) { sLastStatus = MDAL_Status::Err_IncompatibleMesh; return; } std::string filename( meshFile ); MDAL::DriverManager::instance().save( static_cast< MDAL::Mesh * >( mesh ), filename, driverName, &sLastStatus ); } void MDAL_CloseMesh( MeshH mesh ) { if ( mesh ) { MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); delete m; } } const char *MDAL_M_projection( MeshH mesh ) { if ( !mesh ) { sLastStatus = MDAL_Status::Err_IncompatibleMesh; return EMPTY_STR; } MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); return _return_str( m->crs() ); } void MDAL_M_extent( MeshH mesh, double *minX, double *maxX, double *minY, double *maxY ) { if ( !mesh ) { sLastStatus = MDAL_Status::Err_IncompatibleMesh; *minX = std::numeric_limits::quiet_NaN(); *maxX = std::numeric_limits::quiet_NaN(); *minY = std::numeric_limits::quiet_NaN(); *maxY = std::numeric_limits::quiet_NaN(); } else { MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); const MDAL::BBox extent = m->extent(); *minX = extent.minX; *maxX = extent.maxX; *minY = extent.minY; *maxY = extent.maxY; } } int MDAL_M_vertexCount( MeshH mesh ) { if ( !mesh ) { sLastStatus = MDAL_Status::Err_IncompatibleMesh; return 0; } MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); int len = static_cast( m->verticesCount() ); return len; } int MDAL_M_faceCount( MeshH mesh ) { if ( !mesh ) { sLastStatus = MDAL_Status::Err_IncompatibleMesh; return 0; } MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); int len = static_cast( m->facesCount() ); return len; } int MDAL_M_faceVerticesMaximumCount( MeshH mesh ) { if ( !mesh ) { sLastStatus = MDAL_Status::Err_IncompatibleMesh; return 0; } MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); int len = static_cast( m->faceVerticesMaximumCount() ); 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::DriverManager::instance().loadDatasets( m, datasetFile, &sLastStatus ); } int MDAL_M_datasetGroupCount( MeshH mesh ) { if ( !mesh ) { sLastStatus = MDAL_Status::Err_IncompatibleMesh; return 0; } MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); int len = static_cast( m->datasetGroups.size() ); return len; } DatasetGroupH MDAL_M_datasetGroup( MeshH mesh, int index ) { if ( !mesh ) { sLastStatus = MDAL_Status::Err_IncompatibleMesh; return nullptr; } if ( index < 0 ) { sLastStatus = MDAL_Status::Err_IncompatibleMesh; return nullptr; } MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); int len = static_cast( m->datasetGroups.size() ); if ( len <= index ) { sLastStatus = MDAL_Status::Err_IncompatibleMesh; return nullptr; } size_t i = static_cast( index ); return static_cast< DatasetH >( m->datasetGroups[i].get() ); } DatasetGroupH MDAL_M_addDatasetGroup( MeshH mesh, const char *name, bool isOnVertices, bool hasScalarData, DriverH driver, const char *datasetGroupFile ) { if ( !mesh ) { sLastStatus = MDAL_Status::Err_IncompatibleMesh; return nullptr; } if ( !name ) { sLastStatus = MDAL_Status::Err_InvalidData; return nullptr; } if ( !datasetGroupFile ) { sLastStatus = MDAL_Status::Err_InvalidData; return nullptr; } if ( !driver ) { sLastStatus = MDAL_Status::Err_MissingDriver; return nullptr; } MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); MDAL::Driver *dr = static_cast< MDAL::Driver * >( driver ); if ( !dr->hasCapability( MDAL::Capability::WriteDatasets ) ) { sLastStatus = MDAL_Status::Err_MissingDriverCapability; return nullptr; } const size_t index = m->datasetGroups.size(); dr->createDatasetGroup( m, name, isOnVertices, hasScalarData, datasetGroupFile ); if ( index < m->datasetGroups.size() ) // we have new dataset group return static_cast< DatasetGroupH >( m->datasetGroups[ index ].get() ); else return nullptr; } const char *MDAL_M_driverName( MeshH mesh ) { if ( !mesh ) { sLastStatus = MDAL_Status::Err_IncompatibleMesh; return nullptr; } MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); return _return_str( m->driverName() ); } /////////////////////////////////////////////////////////////////////////////////////// /// MESH VERTICES /////////////////////////////////////////////////////////////////////////////////////// MeshVertexIteratorH MDAL_M_vertexIterator( MeshH mesh ) { if ( !mesh ) { sLastStatus = MDAL_Status::Err_IncompatibleMesh; return nullptr; } MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); std::unique_ptr it = m->readVertices(); return static_cast< MeshVertexIteratorH >( it.release() ); } int MDAL_VI_next( MeshVertexIteratorH iterator, int verticesCount, double *coordinates ) { if ( !iterator ) { sLastStatus = MDAL_Status::Err_IncompatibleMesh; return 0; } MDAL::MeshVertexIterator *it = static_cast< MDAL::MeshVertexIterator * >( iterator ); size_t size = static_cast( verticesCount ); if ( size == 0 ) { return 0; } size_t ret = it->next( size, coordinates ); return static_cast( ret ); } void MDAL_VI_close( MeshVertexIteratorH iterator ) { if ( iterator ) { MDAL::MeshVertexIterator *it = static_cast< MDAL::MeshVertexIterator * >( iterator ); delete it; } } /////////////////////////////////////////////////////////////////////////////////////// /// MESH FACES /////////////////////////////////////////////////////////////////////////////////////// MeshFaceIteratorH MDAL_M_faceIterator( MeshH mesh ) { if ( !mesh ) { sLastStatus = MDAL_Status::Err_IncompatibleMesh; return nullptr; } MDAL::Mesh *m = static_cast< MDAL::Mesh * >( mesh ); std::unique_ptr it = m->readFaces(); return static_cast< MeshFaceIteratorH >( it.release() ); } int MDAL_FI_next( MeshFaceIteratorH iterator, int faceOffsetsBufferLen, int *faceOffsetsBuffer, int vertexIndicesBufferLen, int *vertexIndicesBuffer ) { if ( !iterator ) { sLastStatus = MDAL_Status::Err_IncompatibleMesh; return 0; } MDAL::MeshFaceIterator *it = static_cast< MDAL::MeshFaceIterator * >( iterator ); size_t ret = it->next( static_cast( faceOffsetsBufferLen ), faceOffsetsBuffer, static_cast( vertexIndicesBufferLen ), vertexIndicesBuffer ); return static_cast( ret ); } void MDAL_FI_close( MeshFaceIteratorH iterator ) { if ( iterator ) { MDAL::MeshFaceIterator *it = static_cast< MDAL::MeshFaceIterator * >( iterator ); delete it; } } /////////////////////////////////////////////////////////////////////////////////////// /// DATASET GROUPS /////////////////////////////////////////////////////////////////////////////////////// MeshH MDAL_G_mesh( DatasetGroupH group ) { if ( !group ) { sLastStatus = MDAL_Status::Err_IncompatibleDatasetGroup; return nullptr; } MDAL::DatasetGroup *g = static_cast< MDAL::DatasetGroup * >( group ); MDAL::Mesh *m = g->mesh(); return static_cast< MeshH >( m ); } int MDAL_G_datasetCount( DatasetGroupH group ) { if ( !group ) { sLastStatus = MDAL_Status::Err_IncompatibleDatasetGroup; return 0; } MDAL::DatasetGroup *g = static_cast< MDAL::DatasetGroup * >( group ); int len = static_cast( g->datasets.size() ); return len; } DatasetH MDAL_G_dataset( DatasetGroupH group, int index ) { if ( !group ) { sLastStatus = MDAL_Status::Err_IncompatibleDatasetGroup; return nullptr; } if ( index < 0 ) { sLastStatus = MDAL_Status::Err_IncompatibleDatasetGroup; return nullptr; } MDAL::DatasetGroup *g = static_cast< MDAL::DatasetGroup * >( group ); int len = static_cast( g->datasets.size() ); if ( len <= index ) { sLastStatus = MDAL_Status::Err_IncompatibleDatasetGroup; return nullptr; } size_t i = static_cast( index ); return static_cast< DatasetH >( g->datasets[i].get() ); } int MDAL_G_metadataCount( DatasetGroupH group ) { if ( !group ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return 0; } MDAL::DatasetGroup *g = static_cast< MDAL::DatasetGroup * >( group ); int len = static_cast( g->metadata.size() ); return len; } const char *MDAL_G_metadataKey( DatasetGroupH group, int index ) { if ( !group ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return EMPTY_STR; } MDAL::DatasetGroup *g = static_cast< MDAL::DatasetGroup * >( group ); int len = static_cast( g->metadata.size() ); if ( len <= index ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return EMPTY_STR; } size_t i = static_cast( index ); return _return_str( g->metadata[i].first ); } const char *MDAL_G_metadataValue( DatasetGroupH group, int index ) { if ( !group ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return EMPTY_STR; } MDAL::DatasetGroup *g = static_cast< MDAL::DatasetGroup * >( group ); int len = static_cast( g->metadata.size() ); if ( len <= index ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return EMPTY_STR; } size_t i = static_cast( index ); return _return_str( g->metadata[i].second ); } const char *MDAL_G_name( DatasetGroupH group ) { if ( !group ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return EMPTY_STR; } MDAL::DatasetGroup *g = static_cast< MDAL::DatasetGroup * >( group ); return _return_str( g->name() ); } bool MDAL_G_hasScalarData( DatasetGroupH group ) { if ( !group ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return true; } MDAL::DatasetGroup *g = static_cast< MDAL::DatasetGroup * >( group ); return g->isScalar(); } bool MDAL_G_isOnVertices( DatasetGroupH group ) { if ( !group ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return true; } MDAL::DatasetGroup *g = static_cast< MDAL::DatasetGroup * >( group ); return g->isOnVertices(); } void MDAL_G_minimumMaximum( DatasetGroupH group, double *min, double *max ) { if ( !min || !max ) { sLastStatus = MDAL_Status::Err_InvalidData; return; } if ( !group ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; *min = NODATA; *max = NODATA; return; } MDAL::DatasetGroup *g = static_cast< MDAL::DatasetGroup * >( group ); MDAL::Statistics stats = g->statistics(); *min = stats.minimum; *max = stats.maximum; } DatasetH MDAL_G_addDataset( DatasetGroupH group, double time, const double *values, const int *active ) { if ( !group ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return nullptr; } if ( !values ) { sLastStatus = MDAL_Status::Err_InvalidData; return nullptr; } MDAL::DatasetGroup *g = static_cast< MDAL::DatasetGroup * >( group ); if ( !g->isInEditMode() ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return nullptr; } const std::string driverName = g->driverName(); std::shared_ptr dr = MDAL::DriverManager::instance().driver( driverName ); if ( !dr ) { sLastStatus = MDAL_Status::Err_MissingDriver; return nullptr; } if ( !dr->hasCapability( MDAL::Capability::WriteDatasets ) ) { sLastStatus = MDAL_Status::Err_MissingDriverCapability; return nullptr; } const size_t index = g->datasets.size(); dr->createDataset( g, time, values, active ); if ( index < g->datasets.size() ) // we have new dataset return static_cast< DatasetGroupH >( g->datasets[ index ].get() ); else return nullptr; } bool MDAL_G_isInEditMode( DatasetGroupH group ) { if ( !group ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return true; } MDAL::DatasetGroup *g = static_cast< MDAL::DatasetGroup * >( group ); return g->isInEditMode(); } void MDAL_G_closeEditMode( DatasetGroupH group ) { if ( !group ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return; } MDAL::DatasetGroup *g = static_cast< MDAL::DatasetGroup * >( group ); if ( !g->isInEditMode() ) { return; } g->setStatistics( MDAL::calculateStatistics( g ) ); g->stopEditing(); const std::string driverName = g->driverName(); std::shared_ptr dr = MDAL::DriverManager::instance().driver( driverName ); if ( !dr ) { sLastStatus = MDAL_Status::Err_MissingDriver; return; } if ( !dr->hasCapability( MDAL::Capability::WriteDatasets ) ) { sLastStatus = MDAL_Status::Err_MissingDriverCapability; return; } bool error = dr->persist( g ); if ( error ) { sLastStatus = MDAL_Status::Err_InvalidData; } } const char *MDAL_G_referenceTime( DatasetGroupH group ) { if ( !group ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return EMPTY_STR; } MDAL::DatasetGroup *g = static_cast< MDAL::DatasetGroup * >( group ); return _return_str( g->referenceTime() ); } void MDAL_G_setMetadata( DatasetGroupH group, const char *key, const char *val ) { if ( !group ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; } if ( !key ) { sLastStatus = MDAL_Status::Err_InvalidData; return; } if ( !val ) { sLastStatus = MDAL_Status::Err_InvalidData; return; } const std::string k( key ); const std::string v( val ); MDAL::DatasetGroup *g = static_cast< MDAL::DatasetGroup * >( group ); g->setMetadata( k, v ); } const char *MDAL_G_driverName( DatasetGroupH group ) { if ( !group ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return EMPTY_STR; } MDAL::DatasetGroup *g = static_cast< MDAL::DatasetGroup * >( group ); return _return_str( g->driverName() ); } /////////////////////////////////////////////////////////////////////////////////////// /// DATASETS /////////////////////////////////////////////////////////////////////////////////////// DatasetGroupH MDAL_D_group( DatasetH dataset ) { if ( !dataset ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return nullptr; } MDAL::Dataset *d = static_cast< MDAL::Dataset * >( dataset ); return static_cast< MDAL::DatasetGroup * >( d->group() ); } double MDAL_D_time( DatasetH dataset ) { if ( !dataset ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return NODATA; } MDAL::Dataset *d = static_cast< MDAL::Dataset * >( dataset ); return d->time(); } int MDAL_D_valueCount( DatasetH dataset ) { if ( !dataset ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return 0; } MDAL::Dataset *d = static_cast< MDAL::Dataset * >( dataset ); int len = static_cast( d->valuesCount() ); return len; } 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(); } int MDAL_D_data( DatasetH dataset, int indexStart, int count, MDAL_DataType dataType, void *buffer ) { if ( !dataset ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return 0; } MDAL::Dataset *d = static_cast< MDAL::Dataset * >( dataset ); size_t indexStartSizeT = static_cast( indexStart ); size_t countSizeT = static_cast( count ); MDAL::DatasetGroup *g = d->group(); assert( g ); MDAL::Mesh *m = d->mesh(); assert( m ); size_t valuesCount = 0; // Check that we are requesting correct 1D/2D for given dataset switch ( dataType ) { case MDAL_DataType::SCALAR_DOUBLE: if ( !g->isScalar() ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return 0; } valuesCount = d->valuesCount(); break; case MDAL_DataType::VECTOR_2D_DOUBLE: if ( g->isScalar() ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return 0; } valuesCount = d->valuesCount(); break; case MDAL_DataType::ACTIVE_INTEGER: valuesCount = m->facesCount(); break; } // Check that we are not reaching out of values limit if ( valuesCount <= indexStartSizeT ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return 0; } if ( valuesCount < indexStartSizeT + countSizeT ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; return 0; } // Request data size_t writtenValuesCount = 0; switch ( dataType ) { case MDAL_DataType::SCALAR_DOUBLE: writtenValuesCount = d->scalarData( indexStartSizeT, countSizeT, static_cast( buffer ) ); break; case MDAL_DataType::VECTOR_2D_DOUBLE: writtenValuesCount = d->vectorData( indexStartSizeT, countSizeT, static_cast( buffer ) ); break; case MDAL_DataType::ACTIVE_INTEGER: writtenValuesCount = d->activeData( indexStartSizeT, countSizeT, static_cast( buffer ) ); break; } return static_cast( writtenValuesCount ); } void MDAL_D_minimumMaximum( DatasetH dataset, double *min, double *max ) { if ( !min || !max ) { sLastStatus = MDAL_Status::Err_InvalidData; return; } if ( !dataset ) { sLastStatus = MDAL_Status::Err_IncompatibleDataset; *min = NODATA; *max = NODATA; return; } MDAL::Dataset *ds = static_cast< MDAL::Dataset * >( dataset ); MDAL::Statistics stats = ds->statistics(); *min = stats.minimum; *max = stats.maximum; }