void MDAL::LoaderGdal::addDatasetGroups() { // Add dataset to mMesh for ( data_hash::const_iterator band = mBands.begin(); band != mBands.end(); band++ ) { std::shared_ptr<DatasetGroup> group = std::make_shared< DatasetGroup >(); group->uri = mFileName; group->setName( band->first ); group->isOnVertices = true; for ( timestep_map::const_iterator time_step = band->second.begin(); time_step != band->second.end(); time_step++ ) { std::vector<GDALRasterBandH> raster_bands = time_step->second; bool is_vector = ( raster_bands.size() > 1 ); std::shared_ptr<MDAL::Dataset> dataset = std::make_shared< MDAL::Dataset >(); group->isScalar = !is_vector; dataset->time = time_step->first; dataset->values.resize( meshGDALDataset()->mNPoints ); dataset->active.resize( meshGDALDataset()->mNVolumes ); dataset->parent = group.get(); for ( std::vector<GDALRasterBandH>::size_type i = 0; i < raster_bands.size(); ++i ) { addDataToOutput( raster_bands[i], dataset, is_vector, i == 0 ); } activateFaces( dataset ); group->datasets.push_back( dataset ); } mMesh->datasetGroups.push_back( group ); } }
void MDAL::DriverGdal::createMesh() { Vertices vertices( meshGDALDataset()->mNPoints ); bool is_longitude_shifted = initVertices( vertices ); Faces faces( meshGDALDataset()->mNVolumes ); initFaces( vertices, faces, is_longitude_shifted ); mMesh.reset( new MemoryMesh( name(), vertices.size(), faces.size(), 4, //maximum quads computeExtent( vertices ), mFileName ) ); mMesh->vertices = vertices; mMesh->faces = faces; bool proj_added = addSrcProj(); if ( ( !proj_added ) && is_longitude_shifted ) { std::string wgs84( "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs" ); mMesh->setSourceCrs( wgs84 ); } }
void MDAL::DriverGdal::addDataToOutput( GDALRasterBandH raster_band, std::shared_ptr<MemoryDataset> tos, bool is_vector, bool is_x ) { assert( raster_band ); double nodata = GDALGetRasterNoDataValue( raster_band, nullptr ); unsigned int mXSize = meshGDALDataset()->mXSize; unsigned int mYSize = meshGDALDataset()->mYSize; double *values = tos->values(); for ( unsigned int y = 0; y < mYSize; ++y ) { // buffering per-line CPLErr err = GDALRasterIO( raster_band, GF_Read, 0, //nXOff static_cast<int>( y ), //nYOff static_cast<int>( mXSize ), //nXSize 1, //nYSize mPafScanline, //pData static_cast<int>( mXSize ), //nBufXSize 1, //nBufYSize GDT_Float64, //eBufType 0, //nPixelSpace 0 //nLineSpace ); if ( err != CE_None ) { throw MDAL_Status::Err_InvalidData; } for ( unsigned int x = 0; x < mXSize; ++x ) { unsigned int idx = x + mXSize * y; double val = mPafScanline[x]; if ( !MDAL::equals( val, nodata ) ) { // values is prepolulated with NODATA values, so store only legal values if ( is_vector ) { if ( is_x ) { values[2 * idx] = val; } else { values[2 * idx + 1] = val; } } else { values[idx] = val; } } } } }
void MDAL::LoaderGdal::initFaces( Vertices &Vertexs, Faces &Faces, bool is_longitude_shifted ) { int reconnected = 0; unsigned int mXSize = meshGDALDataset()->mXSize; unsigned int mYSize = meshGDALDataset()->mYSize; size_t i = 0; for ( unsigned int y = 0; y < mYSize - 1; ++y ) { for ( unsigned int x = 0; x < mXSize - 1; ++x ) { if ( is_longitude_shifted && ( Vertexs[x + mXSize * y].x > 0.0 ) && ( Vertexs[x + 1 + mXSize * y].x < 0.0 ) ) // omit border face { --reconnected; continue; } if ( is_longitude_shifted && ( x == 0 ) ) { // create extra faces around prime meridian Faces[i].resize( 4 ); Faces[i][0] = mXSize * ( y + 1 ); Faces[i][3] = mXSize * y; Faces[i][2] = mXSize - 1 + mXSize * y; Faces[i][1] = mXSize - 1 + mXSize * ( y + 1 ); ++reconnected; ++i; } // other faces Faces[i].resize( 4 ); Faces[i][0] = x + 1 + mXSize * ( y + 1 ); Faces[i][3] = x + 1 + mXSize * y; Faces[i][2] = x + mXSize * y; Faces[i][1] = x + mXSize * ( y + 1 ); ++i; } } //make sure we have discarded same amount of faces that we have added assert( reconnected == 0 ); }
void MDAL::LoaderGdal::createMesh() { Vertices vertices( meshGDALDataset()->mNPoints ); bool is_longitude_shifted = initVertices( vertices ); Faces faces( meshGDALDataset()->mNVolumes ); initFaces( vertices, faces, is_longitude_shifted ); mMesh.reset( new Mesh() ); mMesh->vertices = vertices; mMesh->faces = faces; bool proj_added = addSrcProj(); if ( ( !proj_added ) && is_longitude_shifted ) { std::string wgs84( "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs" ); mMesh->setSourceCrs( wgs84 ); } }
bool MDAL::LoaderGdal::addSrcProj() { std::string proj = meshGDALDataset()->mProj; if ( !proj.empty() ) { mMesh->setSourceCrsFromWKT( proj ); return true; } return false; }
bool MDAL::LoaderGdal::initVertices( Vertices &vertices ) { Vertex *VertexsPtr = vertices.data(); unsigned int mXSize = meshGDALDataset()->mXSize; unsigned int mYSize = meshGDALDataset()->mYSize; const double *mGT = meshGDALDataset()->mGT; for ( unsigned int y = 0; y < mYSize; ++y ) { for ( unsigned int x = 0; x < mXSize; ++x, ++VertexsPtr ) { // VertexsPtr->setId(x + mXSize*y); VertexsPtr->x = mGT[0] + ( x + 0.5 ) * mGT[1] + ( y + 0.5 ) * mGT[2]; VertexsPtr->y = mGT[3] + ( x + 0.5 ) * mGT[4] + ( y + 0.5 ) * mGT[5]; VertexsPtr->z = 0.0; } } BBox extent = computeExtent( vertices ); // we want to detect situation when there is whole earth represented in dataset bool is_longitude_shifted = ( extent.minX >= 0.0 ) && ( fabs( extent.minX + extent.maxX - 360.0 ) < 1.0 ) && ( extent.minY >= -90.0 ) && ( extent.maxX <= 360.0 ) && ( extent.maxX > 180.0 ) && ( extent.maxY <= 90.0 ); if ( is_longitude_shifted ) { for ( Vertices::size_type n = 0; n < vertices.size(); ++n ) { if ( vertices[n].x > 180.0 ) { vertices[n].x -= 360.0; } } } return is_longitude_shifted; }
void MDAL::LoaderGdal::activateFaces( std::shared_ptr<Dataset> tos ) { // Activate only Faces that do all Vertex's outputs with some data for ( unsigned int idx = 0; idx < meshGDALDataset()->mNVolumes; ++idx ) { Face elem = mMesh->faces.at( idx ); if ( tos->values[elem[0]].noData || tos->values[elem[1]].noData || tos->values[elem[2]].noData || tos->values[elem[3]].noData ) { tos->active[idx] = 0; //NOT ACTIVE } else { tos->active[idx] = 1; //ACTIVE } } }
void MDAL::DriverGdal::activateFaces( std::shared_ptr<MemoryDataset> tos ) { // only for data on vertices if ( !tos->group()->isOnVertices() ) return; bool isScalar = tos->group()->isScalar(); // Activate only Faces that do all Vertex's outputs with some data int *active = tos->active(); const double *values = tos->constValues(); for ( unsigned int idx = 0; idx < meshGDALDataset()->mNVolumes; ++idx ) { Face elem = mMesh->faces.at( idx ); for ( size_t i = 0; i < 4; ++i ) { const size_t vertexIndex = elem[i]; if ( isScalar ) { double val = values[vertexIndex]; if ( std::isnan( val ) ) { active[idx] = 0; //NOT ACTIVE break; } } else { double x = values[2 * vertexIndex]; double y = values[2 * vertexIndex + 1]; if ( std::isnan( x ) || std::isnan( y ) ) { active[idx] = 0; //NOT ACTIVE break; } } } } }
std::unique_ptr<MDAL::Mesh> MDAL::LoaderGdal::load( MDAL_Status *status ) { if ( status ) *status = MDAL_Status::None ; mPafScanline = nullptr; mMesh.reset(); try { registerDriver(); // some formats like NETCFD has data stored in subdatasets std::vector<std::string> subdatasets = parseDatasetNames( mFileName ); // First parse ALL datasets/bands to gather vector quantities // if case they are splitted in different subdatasets for ( auto iter = subdatasets.begin(); iter != subdatasets.end(); ++iter ) { std::string gdal_dataset_name = *iter; // Parse dataset parameters and projection MDAL::GdalDataset *cfGDALDataset = new MDAL::GdalDataset; cfGDALDataset->init( gdal_dataset_name ); if ( !mMesh ) { // If it is first dataset, create mesh from it gdal_datasets.push_back( cfGDALDataset ); // Init memory for data reader mPafScanline = new double [cfGDALDataset->mXSize]; // Create mMesh createMesh(); // Parse bands parseRasterBands( cfGDALDataset ); } else if ( meshes_equals( meshGDALDataset(), cfGDALDataset ) ) { gdal_datasets.push_back( cfGDALDataset ); // Parse bands parseRasterBands( cfGDALDataset ); } else { // Do not use delete cfGDALDataset; } } // Create MDAL datasets addDatasetGroups(); } catch ( MDAL_Status error ) { if ( status ) *status = ( error ); mMesh.reset(); } for ( auto it = gdal_datasets.begin(); it != gdal_datasets.end(); ++it ) { delete ( *it ); } gdal_datasets.clear(); if ( mPafScanline ) delete[] mPafScanline; // do not allow mesh without any valid datasets if ( mMesh && ( mMesh->datasetGroups.empty() ) ) { if ( status ) *status = MDAL_Status::Err_InvalidData; mMesh.reset(); } return std::unique_ptr<Mesh>( mMesh.release() ); }
void MDAL::LoaderGdal::addDataToOutput( GDALRasterBandH raster_band, std::shared_ptr<Dataset> tos, bool is_vector, bool is_x ) { assert( raster_band ); double nodata = GDALGetRasterNoDataValue( raster_band, nullptr ); unsigned int mXSize = meshGDALDataset()->mXSize; unsigned int mYSize = meshGDALDataset()->mYSize; for ( unsigned int y = 0; y < mYSize; ++y ) { // buffering per-line CPLErr err = GDALRasterIO( raster_band, GF_Read, 0, //nXOff static_cast<int>( y ), //nYOff static_cast<int>( mXSize ), //nXSize 1, //nYSize mPafScanline, //pData static_cast<int>( mXSize ), //nBufXSize 1, //nBufYSize GDT_Float64, //eBufType 0, //nPixelSpace 0 //nLineSpace ); if ( err != CE_None ) { throw MDAL_Status::Err_InvalidData; } for ( unsigned int x = 0; x < mXSize; ++x ) { unsigned int idx = x + mXSize * y; double val = mPafScanline[x]; bool noData = false; if ( MDAL::equals( val, nodata ) ) { // store all nodata value as this hardcoded number val = MDAL_NODATA; noData = true; } if ( is_vector ) { if ( is_x ) { tos->values[idx].x = val; tos->values[idx].noData = noData; } else { tos->values[idx].y = val; tos->values[idx].noData = noData; } } else { tos->values[idx].x = val; tos->values[idx].noData = noData; } } } }
std::unique_ptr<MDAL::Mesh> MDAL::DriverGdal::load( const std::string &fileName, MDAL_Status *status ) { mFileName = fileName; if ( status ) *status = MDAL_Status::None ; mPafScanline = nullptr; mMesh.reset(); try { registerDriver(); // some formats like NETCFD has data stored in subdatasets std::vector<std::string> subdatasets = parseDatasetNames( mFileName ); // First parse ALL datasets/bands to gather vector quantities // if case they are splitted in different subdatasets for ( auto iter = subdatasets.begin(); iter != subdatasets.end(); ++iter ) { std::string gdal_dataset_name = *iter; // Parse dataset parameters and projection std::shared_ptr<MDAL::GdalDataset> cfGDALDataset = std::make_shared<MDAL::GdalDataset>(); cfGDALDataset->init( gdal_dataset_name ); if ( !mMesh ) { // If it is first dataset, create mesh from it gdal_datasets.push_back( cfGDALDataset ); // Init memory for data reader mPafScanline = new double [cfGDALDataset->mXSize]; // Create mMesh createMesh(); // Parse bands parseRasterBands( cfGDALDataset.get() ); } else if ( meshes_equals( meshGDALDataset(), cfGDALDataset.get() ) ) { gdal_datasets.push_back( cfGDALDataset ); // Parse bands parseRasterBands( cfGDALDataset.get() ); } } // Fix consistency of groups // It can happen that we thought that the // group is vector based on name, but it could be just coicidence // or clash in naming fixRasterBands(); // Create MDAL datasets addDatasetGroups(); } catch ( MDAL_Status error ) { if ( status ) *status = ( error ); mMesh.reset(); } gdal_datasets.clear(); if ( mPafScanline ) delete[] mPafScanline; // do not allow mesh without any valid datasets if ( mMesh && ( mMesh->datasetGroups.empty() ) ) { if ( status ) *status = MDAL_Status::Err_InvalidData; mMesh.reset(); } return std::unique_ptr<Mesh>( mMesh.release() ); }