Merge branch 'master' into sirs_db_manager

This commit is contained in:
Corentin.F 2019-01-23 11:22:12 +01:00 committed by GitHub
commit a80f3d01ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
549 changed files with 38291 additions and 8477 deletions

View File

@ -65,7 +65,7 @@ COPY .docker/qgis_resources/supervisor/supervisor.xvfb.conf /etc/supervisor/supe
# - deb installed
# - built from git
# needed to find PyQt wrapper provided by QGIS
ENV PYTHONPATH=/usr/share/qgis/python/:/usr/lib/python3/dist-packages/qgis:/usr/share/qgis/python/qgis
ENV PYTHONPATH=/usr/share/qgis/python/:/usr/share/qgis/python/plugins:/usr/lib/python3/dist-packages/qgis:/usr/share/qgis/python/qgis
WORKDIR /

View File

@ -32,6 +32,7 @@ matrix:
# QGIS TESTS ON BIONIC
##########################################################
- os: linux
name: building and testing on linux
if: type != cron
services: docker
env:
@ -44,6 +45,7 @@ matrix:
# CODE LAYOUT
##########################################################
- os: linux
name: code layout
if: type != cron
env:
- TRAVIS_CONFIG=code_layout
@ -93,6 +95,7 @@ matrix:
# BIONIC DOCKER BUILD ON CRON OR TAG
##########################################################
- os: linux
name: bionic docker build
if: repo = qgis/QGIS AND (tag IS PRESENT OR type = cron)
services: docker
env:
@ -105,6 +108,7 @@ matrix:
# COSMIC DOCKER BUILD ON CRON OR TAG
##########################################################
- os: linux
name: cosmic docker build
if: repo = qgis/QGIS AND (tag IS PRESENT OR type = cron)
services: docker
env:

View File

@ -94,6 +94,7 @@ IF(WITH_APIDOC)
${CMAKE_SOURCE_DIR}/src/gui/raster
${CMAKE_SOURCE_DIR}/src/gui/symbology
${CMAKE_SOURCE_DIR}/src/analysis
${CMAKE_SOURCE_DIR}/src/analysis/mesh
${CMAKE_SOURCE_DIR}/src/analysis/interpolation
${CMAKE_SOURCE_DIR}/src/analysis/network
${CMAKE_SOURCE_DIR}/src/analysis/processing

View File

@ -31,7 +31,7 @@
<tr><td align="center"><img src="qrc:/images/flags/vi.svg" height="20"></td><td>Vietnamese</td><td><div title="finished:12244 unfinished:57 untranslated:6734" class="bartodo"><div class="bardone" style="width:64px">64.5</div></div></td><td>Phùng Văn Doanh, Bùi Hữu Mạnh, Nguyễn Văn Thanh, Nguyễn Hữu Phúc, Cao Minh Tu</td></tr>
<tr><td align="center"><img src="qrc:/images/flags/ky.svg" height="20"></td><td>Kirghiz</td><td><div title="finished:11363 unfinished:53 untranslated:7619" class="bartodo"><div class="bardone" style="width:59px">59.8</div></div></td><td>Stéphane Henriod, Azamat Karypov, Salaidin Kamaldinov, Akylbek Chymyrov, Chinara Saparova, Almaz Abdiev, Nurlan Tokbaev, Tatygul Urmambetova, Adilet Bekturov, Nursultan Ismailov, Nurlan Zhusupov</td></tr>
<tr><td align="center"><img src="qrc:/images/flags/ca.svg" height="20"></td><td>Catalan</td><td><div title="finished:11258 unfinished:51 untranslated:7726" class="bartodo"><div class="bardone" style="width:59px">59.3</div></div></td><td>Albert F, Pau Reguant Ridó, Xavier Roijals</td></tr>
<tr><td align="center"><img src="qrc:/images/flags/zh.svg" height="20"></td><td>Chinese traditional</td><td><div title="finished:10778 unfinished:151 untranslated:8106" class="bartodo"><div class="bardone" style="width:57px">57.0</div></div></td><td>Calvin Ngei, Zhang Jun, Richard Xie, Dennis Raylin Chen</td></tr>
<tr><td align="center"><img src="qrc:/images/flags/zh-Hant.svg" height="20"></td><td>Chinese traditional</td><td><div title="finished:10778 unfinished:151 untranslated:8106" class="bartodo"><div class="bardone" style="width:57px">57.0</div></div></td><td>Calvin Ngei, Zhang Jun, Richard Xie, Dennis Raylin Chen</td></tr>
<tr><td align="center"><img src="qrc:/images/flags/hi.svg" height="20"></td><td>Hindi</td><td><div title="finished:9409 unfinished:75 untranslated:9551" class="bartodo"><div class="bardone" style="width:49px">49.6</div></div></td><td>Harish Kumar Solanki</td></tr>
<tr><td align="center"><img src="qrc:/images/flags/sl.svg" height="20"></td><td>Slovenian</td><td><div title="finished:9233 unfinished:85 untranslated:9717" class="bartodo"><div class="bardone" style="width:48px">48.7</div></div></td><td>Jože Detečnik, Dejan Gregor, Jaka Kranjc</td></tr>
<tr><td align="center"><img src="qrc:/images/flags/tr.svg" height="20"></td><td>Turkish</td><td><div title="finished:8972 unfinished:62 untranslated:10001" class="bartodo"><div class="bardone" style="width:47px">47.3</div></div></td><td>Osman Yalçın YILMAZ, Omur Saygin</td></tr>

View File

@ -61,7 +61,6 @@ Moved Classes {#qgis_api_break_3_0_moved_classes}
-------------
<table>
<caption id="moved_classes">Moved classes</caption>
<tr><th>class<th>Module 2.X<th>Module 3.x
<tr><td>QgsMapLayerModel<td>gui<td>core
<tr><td>QgsMapLayerProxyModel<td>gui<td>core
@ -72,7 +71,6 @@ Renamed Classes {#qgis_api_break_3_0_renamed_classes}
---------------
<table>
<caption id="renamed_classes">Renamed classes</caption>
<tr><th>API 2.x<th>API 3.X
<tr><td>QgisGui<td>QgsGuiUtils
<tr><td>QgsAbstractGeometryV2<td>QgsAbstractGeometry
@ -230,15 +228,21 @@ Renamed Classes {#qgis_api_break_3_0_renamed_classes}
<tr><td>vertexData<td>QgsInterpolatorVertexData
</table>
Renamed Enum Values {#qgis_api_break_3_0_renamed_enum_values}
-------------------
<table>
<caption id="renamed_enum_values">Renamed enum values</caption>
<tr><th>class</th><th>API 2.x<th>API 3.X
<tr><td>QgsLayerTreeModelLegendNode<td>SymbolV2LegacyRuleKeyRole<td>SymbolLegacyRuleKeyRole
<tr><td>QgsVectorLayer<td>EditorWidgetV2<td>EditorWidget
</table>
Renamed Methods {#qgis_api_break_3_0_renamed_methods}
---------------
<table>
<caption id="renamed_methods">Renamed method names</caption>
<tr><th>class</th><th>API 2.x<th>API 3.X
<tr><td>QgsAnnotation<td>mapPositionFixed<td>hasFixedMapPosition
<tr><td>QgsApplication<td>defaultStyleV2Path<td>defaultStylePath
@ -2430,6 +2434,7 @@ displayExpression instead. For the map tip use mapTipTemplate() instead.
- select() replaced by selectByRect()
- selectedFeaturesIds() replaced by selectedFeatureIds()
- selectedFeaturesIterator() was replaced by getSelectedFeatures()
- setDisplayField() has been removed, and its functionality split between setMapTipTemplate() and setDisplayExpression()
- setSelectedFeatures() replaced by selectByIds()
- applyNamedStyle() replaced by importNamedStyle()
- isReadOnly() use readOnly()

View File

@ -55,6 +55,7 @@ enum MDAL_Status
Err_IncompatibleDataset,
Err_IncompatibleDatasetGroup,
Err_MissingDriver,
Err_MissingDriverCapability,
// Warnings
Warn_UnsupportedElement,
Warn_InvalidElements,
@ -101,6 +102,9 @@ MDAL_EXPORT DriverH MDAL_driverFromName( const char *name );
*/
MDAL_EXPORT bool MDAL_DR_meshLoadCapability( DriverH driver );
//! Returns whether driver has capability to write/edit dataset (groups)
MDAL_EXPORT bool MDAL_DR_writeDatasetsCapability( DriverH driver );
/**
* Returns name of MDAL driver
* not thread-safe and valid only till next call
@ -163,6 +167,37 @@ MDAL_EXPORT int MDAL_M_datasetGroupCount( MeshH mesh );
//! Returns dataset group handle
MDAL_EXPORT DatasetGroupH MDAL_M_datasetGroup( MeshH mesh, int index );
/**
* Adds empty (new) dataset group to the mesh
* This increases dataset group count MDAL_M_datasetGroupCount() by 1
*
* The Dataset Group is opened in edit mode.
* To persist dataset group, call MDAL_G_closeEditMode();
*
* It is not possible to read and write to the same group
* at the same time. Finalize edits before reading.
*
* \param mesh mesh handle
* \param driver the driver to use for storing the data
* \param name dataset group name
* \param isOnVertices whether data is defined on vertices
* \param hasScalarData whether data is scalar (false = vector data)
* \param datasetGroupFile file to store the new dataset group
* \returns empty pointer if not possible to create group, otherwise handle to new group
*/
MDAL_EXPORT DatasetGroupH MDAL_M_addDatasetGroup( MeshH mesh,
const char *name,
bool isOnVertices,
bool hasScalarData,
DriverH driver,
const char *datasetGroupFile );
/**
* Returns name of MDAL driver
* not thread-safe and valid only till next call
*/
MDAL_EXPORT const char *MDAL_M_driverName( MeshH mesh );
///////////////////////////////////////////////////////////////////////////////////////
/// MESH VERTICES
///////////////////////////////////////////////////////////////////////////////////////
@ -247,12 +282,24 @@ MDAL_EXPORT const char *MDAL_G_metadataKey( DatasetGroupH group, int index );
*/
MDAL_EXPORT const char *MDAL_G_metadataValue( DatasetGroupH group, int index );
/**
* Adds new metadata to the group
* Group must be in edit mode MDAL_G_isInEditMode()
*/
MDAL_EXPORT void MDAL_G_setMetadata( DatasetGroupH group, const char *key, const char *val );
/**
* Returns dataset group name
* not thread-safe and valid only till next call
*/
MDAL_EXPORT const char *MDAL_G_name( DatasetGroupH group );
/**
* Returns name of MDAL driver
* not thread-safe and valid only till next call
*/
MDAL_EXPORT const char *MDAL_G_driverName( DatasetGroupH group );
//! Whether dataset has scalar data associated
MDAL_EXPORT bool MDAL_G_hasScalarData( DatasetGroupH group );
@ -260,11 +307,48 @@ MDAL_EXPORT bool MDAL_G_hasScalarData( DatasetGroupH group );
MDAL_EXPORT bool MDAL_G_isOnVertices( DatasetGroupH group );
/**
* Returns the min and max values of the group
* Returns the minimum and maximum values of the group
* Returns NaN on error
*/
MDAL_EXPORT void MDAL_G_minimumMaximum( DatasetGroupH group, double *min, double *max );
/**
* Adds empty (new) dataset to the group
* This increases dataset group count MDAL_G_datasetCount() by 1
*
* The dataset is opened in edit mode.
* To persist dataset, call MDAL_G_closeEditMode() on parent group
*
* Minimum and maximum dataset values are automatically calculated
*
* \param group parent group handle
* \param time time for dataset
* \param values For scalar data on vertices, the size must be vertex count
* For scalar data on faces, the size must be faces count
* For vector data on vertices, the size must be vertex count * 2 (x1, y1, x2, y2, ..., xN, yN)
* For vector data on faces, the size must be faces count * 2 (x1, y1, x2, y2, ..., xN, yN)
* \param active if null pointer, all faces are active. Otherwise size must be equal to face count.
* \returns empty pointer if not possible to create dataset (e.g. group opened in read mode), otherwise handle to new dataset
*/
MDAL_EXPORT DatasetH MDAL_G_addDataset( DatasetGroupH group,
double time,
const double *values,
const int *active
);
//! Returns whether dataset group is in edit mode
MDAL_EXPORT bool MDAL_G_isInEditMode( DatasetGroupH group );
/**
* Close edit mode for group and all its datasets.
* This may effectively write the data to the files and/or
* reopen the file in read-only mode
*
* When closed, minimum and maximum dataset group values are automatically calculated
*/
MDAL_EXPORT void MDAL_G_closeEditMode( DatasetGroupH group );
///////////////////////////////////////////////////////////////////////////////////////
/// DATASETS
///////////////////////////////////////////////////////////////////////////////////////
@ -307,7 +391,7 @@ enum MDAL_DataType
MDAL_EXPORT int MDAL_D_data( DatasetH dataset, int indexStart, int count, MDAL_DataType dataType, void *buffer );
/**
* Returns the min and max values of the dataset
* Returns the minimum and maximum values of the dataset
* Returns NaN on error
*/
MDAL_EXPORT void MDAL_D_minimumMaximum( DatasetH dataset, double *min, double *max );

View File

@ -17,13 +17,20 @@
#include "mdal.h"
#include "mdal_utils.hpp"
#define DRIVER_NAME "2DM"
MDAL::Mesh2dm::Mesh2dm( size_t verticesCount,
size_t facesCount,
size_t faceVerticesMaximumCount,
MDAL::BBox extent,
const std::string &uri,
const std::map<size_t, size_t> vertexIDtoIndex )
: MemoryMesh( verticesCount, facesCount, faceVerticesMaximumCount, extent, uri )
: MemoryMesh( DRIVER_NAME,
verticesCount,
facesCount,
faceVerticesMaximumCount,
extent,
uri )
, mVertexIDtoIndex( vertexIDtoIndex )
{
}
@ -58,10 +65,10 @@ size_t MDAL::Mesh2dm::vertexIndex( size_t vertexID ) const
MDAL::Driver2dm::Driver2dm():
Driver( "2DM",
Driver( DRIVER_NAME,
"2DM Mesh File",
"*.2dm",
DriverType::CanReadMeshAndDatasets
Capability::ReadMesh
)
{
}

View File

@ -4,6 +4,8 @@
*/
#include "mdal_3di.hpp"
#include <netcdf.h>
#include <assert.h>
MDAL::Driver3Di::Driver3Di()
: DriverCF(
@ -126,6 +128,7 @@ void MDAL::Driver3Di::addBedElevation( MDAL::Mesh *mesh )
std::shared_ptr<DatasetGroup> group = std::make_shared< DatasetGroup >(
name(),
mesh,
mesh->uri(),
"Bed Elevation"

View File

@ -27,7 +27,7 @@ MDAL::DriverAsciiDat::DriverAsciiDat( ):
Driver( "ASCII_DAT",
"DAT",
"*.dat",
DriverType::CanReadOnlyDatasets
Capability::ReadDatasets
)
{
}
@ -49,15 +49,203 @@ bool MDAL::DriverAsciiDat::canRead( const std::string &uri )
}
line = trim( line );
if ( line != "DATASET" &&
line != "SCALAR" &&
line != "VECTOR" )
{
return false;
}
return true;
return canReadNewFormat( line ) || canReadOldFormat( line );
}
bool MDAL::DriverAsciiDat::canReadOldFormat( const std::string &line ) const
{
return MDAL::contains( line, "SCALAR" ) ||
MDAL::contains( line, "VECTOR" ) ||
MDAL::contains( line, "TS" );
}
bool MDAL::DriverAsciiDat::canReadNewFormat( const std::string &line ) const
{
return line == "DATASET";
}
void MDAL::DriverAsciiDat::loadOldFormat( std::ifstream &in,
Mesh *mesh,
MDAL_Status *status ) const
{
std::shared_ptr<DatasetGroup> group; // DAT outputs data
std::string groupName( MDAL::baseName( mDatFile ) );
std::string line;
std::getline( in, line );
// Read the first line
bool isVector = MDAL::contains( line, "VECTOR" );
group = std::make_shared< DatasetGroup >(
name(),
mesh,
mDatFile,
groupName
);
group->setIsScalar( !isVector );
group->setIsOnVertices( true );
do
{
// Replace tabs by spaces,
// since basement v.2.8 uses tabs instead of spaces (e.g. 'TS 0\t0.0')
line = replace( line, "\t", " " );
// Trim string for cases when file has inconsistent new line symbols
line = MDAL::trim( line );
// Split to tokens
std::vector<std::string> items = split( line, " ", SplitBehaviour::SkipEmptyParts );
if ( items.size() < 1 )
continue; // empty line?? let's skip it
std::string cardType = items[0];
if ( cardType == "ND" && items.size() >= 2 )
{
size_t fileNodeCount = toSizeT( items[1] );
if ( mesh->verticesCount() != fileNodeCount )
EXIT_WITH_ERROR( MDAL_Status::Err_IncompatibleMesh );
}
else if ( cardType == "SCALAR" || cardType == "VECTOR" )
{
// just ignore - we know the type from earlier...
}
else if ( cardType == "TS" && items.size() >= 2 )
{
double t = toDouble( items[ 1 ] );
readVertexTimestep( mesh, group, t, isVector, false, in );
}
else
{
std::stringstream str;
str << " Unknown card:" << line;
debug( str.str() );
}
}
while ( std::getline( in, line ) );
if ( !group || group->datasets.size() == 0 )
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
group->setStatistics( MDAL::calculateStatistics( group ) );
mesh->datasetGroups.push_back( group );
group.reset();
}
void MDAL::DriverAsciiDat::loadNewFormat( std::ifstream &in,
Mesh *mesh,
MDAL_Status *status ) const
{
bool isVector = false;
std::shared_ptr<DatasetGroup> group; // DAT outputs data
std::string groupName( MDAL::baseName( mDatFile ) );
std::string line;
// see if it contains face-centered results - supported by BASEMENT
bool faceCentered = false;
if ( contains( groupName, "_els_" ) )
faceCentered = true;
if ( group )
group->setIsOnVertices( !faceCentered );
while ( std::getline( in, line ) )
{
// Replace tabs by spaces,
// since basement v.2.8 uses tabs instead of spaces (e.g. 'TS 0\t0.0')
line = replace( line, "\t", " " );
// Trim string for cases when file has inconsistent new line symbols
line = MDAL::trim( line );
// Split to tokens
std::vector<std::string> items = split( line, " ", SplitBehaviour::SkipEmptyParts );
if ( items.size() < 1 )
continue; // empty line?? let's skip it
std::string cardType = items[0];
if ( cardType == "ND" && items.size() >= 2 )
{
size_t fileNodeCount = toSizeT( items[1] );
if ( mesh->verticesCount() != fileNodeCount )
EXIT_WITH_ERROR( MDAL_Status::Err_IncompatibleMesh );
}
else if ( cardType == "NC" && items.size() >= 2 )
{
size_t fileElemCount = toSizeT( items[1] );
if ( mesh->facesCount() != fileElemCount )
EXIT_WITH_ERROR( MDAL_Status::Err_IncompatibleMesh );
}
else if ( cardType == "OBJTYPE" )
{
if ( items[1] != "mesh2d" && items[1] != "\"mesh2d\"" )
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
}
else if ( cardType == "BEGSCL" || cardType == "BEGVEC" )
{
if ( group )
{
debug( "New dataset while previous one is still active!" );
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
}
isVector = cardType == "BEGVEC";
group = std::make_shared< DatasetGroup >(
name(),
mesh,
mDatFile,
groupName
);
group->setIsScalar( !isVector );
group->setIsOnVertices( !faceCentered );
}
else if ( cardType == "ENDDS" )
{
if ( !group )
{
debug( "ENDDS card for no active dataset!" );
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
}
group->setStatistics( MDAL::calculateStatistics( group ) );
mesh->datasetGroups.push_back( group );
group.reset();
}
else if ( cardType == "NAME" && items.size() >= 2 )
{
if ( !group )
{
debug( "NAME card for no active dataset!" );
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
}
size_t quoteIdx1 = line.find( '\"' );
size_t quoteIdx2 = line.find( '\"', quoteIdx1 + 1 );
if ( quoteIdx1 != std::string::npos && quoteIdx2 != std::string::npos )
group->setName( line.substr( quoteIdx1 + 1, quoteIdx2 - quoteIdx1 - 1 ) );
}
else if ( cardType == "TS" && items.size() >= 3 )
{
double t = toDouble( items[2] );
if ( faceCentered )
{
readFaceTimestep( mesh, group, t, isVector, in );
}
else
{
bool hasStatus = ( toBool( items[1] ) );
readVertexTimestep( mesh, group, t, isVector, hasStatus, in );
}
}
else
{
std::stringstream str;
str << " Unknown card:" << line;
debug( str.str() );
}
}
}
/**
* The DAT format contains "datasets" and each dataset has N-outputs. One output
@ -85,145 +273,18 @@ void MDAL::DriverAsciiDat::load( const std::string &datFile, MDAL::Mesh *mesh, M
return;
}
line = trim( line );
// http://www.xmswiki.com/xms/SMS:ASCII_Dataset_Files_*.dat
// Apart from the format specified above, there is an older supported format used in BASEMENT (and SMS?)
// which is simpler (has only one dataset in one file, no status flags etc)
bool oldFormat;
bool isVector = false;
std::shared_ptr<DatasetGroup> group; // DAT outputs data
std::string name( MDAL::baseName( mDatFile ) );
if ( line == "DATASET" )
oldFormat = false;
else if ( line == "SCALAR" || line == "VECTOR" )
if ( canReadNewFormat( line ) )
{
oldFormat = true;
isVector = ( line == "VECTOR" );
group = std::make_shared< DatasetGroup >(
mesh,
mDatFile,
name
);
group->setIsScalar( !isVector );
// we do not need to parse first line again
loadNewFormat( in, mesh, status );
}
else
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
// see if it contains face-centered results - supported by BASEMENT
bool faceCentered = false;
if ( !oldFormat && contains( name, "_els_" ) )
faceCentered = true;
if ( group )
group->setIsOnVertices( !faceCentered );
while ( std::getline( in, line ) )
{
// Replace tabs by spaces,
// since basement v.2.8 uses tabs instead of spaces (e.g. 'TS 0\t0.0')
line = replace( line, "\t", " " );
std::vector<std::string> items = split( line, " ", SplitBehaviour::SkipEmptyParts );
if ( items.size() < 1 )
continue; // empty line?? let's skip it
std::string cardType = items[0];
if ( cardType == "ND" && items.size() >= 2 )
{
size_t fileNodeCount = toSizeT( items[1] );
if ( mesh->verticesCount() != fileNodeCount )
EXIT_WITH_ERROR( MDAL_Status::Err_IncompatibleMesh );
}
else if ( !oldFormat && cardType == "NC" && items.size() >= 2 )
{
size_t fileElemCount = toSizeT( items[1] );
if ( mesh->facesCount() != fileElemCount )
EXIT_WITH_ERROR( MDAL_Status::Err_IncompatibleMesh );
}
else if ( !oldFormat && cardType == "OBJTYPE" )
{
if ( items[1] != "mesh2d" && items[1] != "\"mesh2d\"" )
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
}
else if ( !oldFormat && ( cardType == "BEGSCL" || cardType == "BEGVEC" ) )
{
if ( group )
{
debug( "New dataset while previous one is still active!" );
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
}
isVector = cardType == "BEGVEC";
group = std::make_shared< DatasetGroup >(
mesh,
mDatFile,
name
);
group->setIsScalar( !isVector );
group->setIsOnVertices( !faceCentered );
}
else if ( !oldFormat && cardType == "ENDDS" )
{
if ( !group )
{
debug( "ENDDS card for no active dataset!" );
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
}
group->setStatistics( MDAL::calculateStatistics( group ) );
mesh->datasetGroups.push_back( group );
group.reset();
}
else if ( !oldFormat && cardType == "NAME" && items.size() >= 2 )
{
if ( !group )
{
debug( "NAME card for no active dataset!" );
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
}
size_t quoteIdx1 = line.find( '\"' );
size_t quoteIdx2 = line.find( '\"', quoteIdx1 + 1 );
if ( quoteIdx1 != std::string::npos && quoteIdx2 != std::string::npos )
group->setName( line.substr( quoteIdx1 + 1, quoteIdx2 - quoteIdx1 - 1 ) );
}
else if ( oldFormat && ( cardType == "SCALAR" || cardType == "VECTOR" ) )
{
// just ignore - we know the type from earlier...
}
else if ( cardType == "TS" && items.size() >= ( oldFormat ? 2 : 3 ) )
{
double t = toDouble( items[oldFormat ? 1 : 2] );
if ( faceCentered )
{
readFaceTimestep( mesh, group, t, isVector, in );
}
else
{
bool hasStatus = ( oldFormat ? false : toBool( items[1] ) );
readVertexTimestep( mesh, group, t, isVector, hasStatus, in );
}
}
else
{
std::stringstream str;
str << " Unknown card:" << line;
debug( str.str() );
}
}
if ( oldFormat )
{
if ( !group || group->datasets.size() == 0 )
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
group->setStatistics( MDAL::calculateStatistics( group ) );
mesh->datasetGroups.push_back( group );
group.reset();
// we need to parse first line again to see
// scalar/vector flag or timestep flag
in.clear();
in.seekg( 0 );
loadOldFormat( in, mesh, status );
}
}
@ -233,7 +294,7 @@ void MDAL::DriverAsciiDat::readVertexTimestep(
double t,
bool isVector,
bool hasStatus,
std::ifstream &stream )
std::ifstream &stream ) const
{
assert( group );
size_t faceCount = mesh->facesCount();
@ -299,7 +360,7 @@ void MDAL::DriverAsciiDat::readFaceTimestep(
std::shared_ptr<DatasetGroup> group,
double t,
bool isVector,
std::ifstream &stream )
std::ifstream &stream ) const
{
assert( group );

View File

@ -20,6 +20,29 @@
namespace MDAL
{
/**
* ASCII Dat format is used by various solvers and the output
* from various solvers can have slightly different header.
* The format is used by TUFLOW, BASEMENT and HYDRO_AS-2D solvers.
*
* The most frequent form is based on official SMS documentation
* https://www.xmswiki.com/wiki/SMS:ASCII_Dataset_Files_*.dat
* The official format only supports data defined on vertices,
* both scalar vector. The new format is recognized by keyword
* "DATASET" on the first line of the file.
*
* BASEMENT solver also stores data defined on faces. To recognize
* such dataset, the dataset name contains "_els_" substring
* (e.g. depth_els_1.dat)
*
* In one file, there is always one dataset group stored.
*
* Sometime the "older" datasets may have some part of the
* header missing, e.g. the file starts with SCALAR or VECTOR or TS
* keyword. The older format does not have "active" flags for faces
* and does not recognize most of the keywords. Old format data
* are always defined on vertices
*/
class DriverAsciiDat: public Driver
{
public:
@ -30,22 +53,27 @@ namespace MDAL
bool canRead( const std::string &uri ) override;
void load( const std::string &datFile, Mesh *mesh, MDAL_Status *status ) override;
private:
bool canReadOldFormat( const std::string &line ) const;
bool canReadNewFormat( const std::string &line ) const;
void loadOldFormat( std::ifstream &in, Mesh *mesh, MDAL_Status *status ) const;
void loadNewFormat( std::ifstream &in, Mesh *mesh, MDAL_Status *status ) const;
void readVertexTimestep(
const Mesh *mesh,
std::shared_ptr<DatasetGroup> group,
double t,
bool isVector,
bool hasStatus,
std::ifstream &stream );
std::ifstream &stream ) const;
void readFaceTimestep(
const Mesh *mesh,
std::shared_ptr<DatasetGroup> group,
double t,
bool isVector,
std::ifstream &stream );
std::ifstream &stream ) const;
std::string mDatFile;
};

View File

@ -75,7 +75,7 @@ MDAL::DriverBinaryDat::DriverBinaryDat():
Driver( "BINARY_DAT",
"Binary DAT",
"*.dat",
DriverType::CanReadOnlyDatasets
Capability::ReadDatasets | Capability::WriteDatasets
)
{
}
@ -141,7 +141,7 @@ void MDAL::DriverBinaryDat::load( const std::string &datFile, MDAL::Mesh *mesh,
int objid;
int numdata;
int numcells;
char name[40];
char groupName[40];
char istat;
float time;
@ -152,6 +152,7 @@ void MDAL::DriverBinaryDat::load( const std::string &datFile, MDAL::Mesh *mesh,
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
std::shared_ptr<DatasetGroup> group = std::make_shared< DatasetGroup >(
name(),
mesh,
mDatFile
); // DAT datasets
@ -160,6 +161,7 @@ void MDAL::DriverBinaryDat::load( const std::string &datFile, MDAL::Mesh *mesh,
// in TUFLOW results there could be also a special timestep (99999) with maximums
// we will put it into a separate dataset
std::shared_ptr<DatasetGroup> groupMax = std::make_shared< DatasetGroup >(
name(),
mesh,
mDatFile
);
@ -235,11 +237,11 @@ void MDAL::DriverBinaryDat::load( const std::string &datFile, MDAL::Mesh *mesh,
case CT_NAME:
// Name
if ( read( in, reinterpret_cast< char * >( &name ), 40 ) )
if ( read( in, reinterpret_cast< char * >( &groupName ), 40 ) )
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
if ( name[39] != 0 )
name[39] = 0;
group->setName( trim( std::string( name ) ) );
if ( groupName[39] != 0 )
groupName[39] = 0;
group->setName( trim( std::string( groupName ) ) );
groupMax->setName( group->name() + "/Maximums" );
break;
@ -340,3 +342,122 @@ bool MDAL::DriverBinaryDat::readVertexTimestep( const MDAL::Mesh *mesh,
}
return false; //OK
}
// ////////////////////////////////////////////
// WRITE
// ////////////////////////////////////////////
static bool writeRawData( std::ofstream &out, const char *s, int n )
{
out.write( s, n );
if ( !out )
return true; //error
else
return false; //OK
}
bool MDAL::DriverBinaryDat::persist( MDAL::DatasetGroup *group )
{
std::ofstream out( group->uri(), std::ofstream::out | std::ofstream::binary );
// implementation based on information from:
// http://www.xmswiki.com/wiki/SMS:Binary_Dataset_Files_*.dat
if ( !out )
return true; // Couldn't open the file
const Mesh *mesh = group->mesh();
size_t nodeCount = mesh->verticesCount();
size_t elemCount = mesh->facesCount();
if ( !group->isOnVertices() )
{
// Element outputs not supported in the format
return true;
}
// version card
writeRawData( out, reinterpret_cast< const char * >( &CT_VERSION ), 4 );
// objecttype
writeRawData( out, reinterpret_cast< const char * >( &CT_OBJTYPE ), 4 );
writeRawData( out, reinterpret_cast< const char * >( &CT_2D_MESHES ), 4 );
// float size
writeRawData( out, reinterpret_cast< const char * >( &CT_SFLT ), 4 );
writeRawData( out, reinterpret_cast< const char * >( &CT_FLOAT_SIZE ), 4 );
// Flag size
writeRawData( out, reinterpret_cast< const char * >( &CT_SFLG ), 4 );
writeRawData( out, reinterpret_cast< const char * >( &CF_FLAG_SIZE ), 4 );
// Dataset Group Type
if ( group->isScalar() )
{
writeRawData( out, reinterpret_cast< const char * >( &CT_BEGSCL ), 4 );
}
else
{
writeRawData( out, reinterpret_cast< const char * >( &CT_BEGVEC ), 4 );
}
// Object id (ignored)
int ignored_val = 1;
writeRawData( out, reinterpret_cast< const char * >( &CT_OBJID ), 4 );
writeRawData( out, reinterpret_cast< const char * >( &ignored_val ), 4 );
// Num nodes
writeRawData( out, reinterpret_cast< const char * >( &CT_NUMDATA ), 4 );
writeRawData( out, reinterpret_cast< const char * >( &nodeCount ), 4 );
// Num cells
writeRawData( out, reinterpret_cast< const char * >( &CT_NUMCELLS ), 4 );
writeRawData( out, reinterpret_cast< const char * >( &elemCount ), 4 );
// Name
writeRawData( out, reinterpret_cast< const char * >( &CT_NAME ), 4 );
writeRawData( out, MDAL::leftJustified( group->name(), 39 ).c_str(), 40 );
// Time steps
int istat = 1; // include if elements are active
for ( size_t time_index = 0; time_index < group->datasets.size(); ++ time_index )
{
const std::shared_ptr<MDAL::MemoryDataset> dataset = std::dynamic_pointer_cast<MDAL::MemoryDataset>( group->datasets[time_index] );
writeRawData( out, reinterpret_cast< const char * >( &CT_TS ), 4 );
writeRawData( out, reinterpret_cast< const char * >( &istat ), 1 );
float ftime = static_cast<float>( dataset->time() );
writeRawData( out, reinterpret_cast< const char * >( &ftime ), 4 );
if ( istat )
{
// Write status flags
for ( size_t i = 0; i < elemCount; i++ )
{
bool active = static_cast<bool>( dataset->active()[i] );
writeRawData( out, reinterpret_cast< const char * >( &active ), 1 );
}
}
for ( size_t i = 0; i < nodeCount; i++ )
{
// Read values flags
if ( !group->isScalar() )
{
float x = static_cast<float>( dataset->values()[2 * i] );
float y = static_cast<float>( dataset->values()[2 * i + 1 ] );
writeRawData( out, reinterpret_cast< const char * >( &x ), 4 );
writeRawData( out, reinterpret_cast< const char * >( &y ), 4 );
}
else
{
float val = static_cast<float>( dataset->values()[i] );
writeRawData( out, reinterpret_cast< const char * >( &val ), 4 );
}
}
}
if ( writeRawData( out, reinterpret_cast< const char * >( &CT_ENDDS ), 4 ) ) return true;
return false;
}

View File

@ -29,6 +29,7 @@ namespace MDAL
bool canRead( const std::string &uri ) override;
void load( const std::string &datFile, Mesh *mesh, MDAL_Status *status ) override;
bool persist( DatasetGroup *group ) override;
private:
bool readVertexTimestep( const Mesh *mesh,

View File

@ -5,14 +5,15 @@
#include <vector>
#include <string>
#include <netcdf.h>
#include "math.h"
#include <stdlib.h>
#include <assert.h>
#include "mdal_data_model.hpp"
#include "mdal_cf.hpp"
#include "mdal_utils.hpp"
#include "math.h"
#include <stdlib.h>
#define CF_THROW_ERR throw MDAL_Status::Err_UnknownFormat
MDAL::cfdataset_info_map MDAL::DriverCF::parseDatasetGroupInfo()
@ -182,6 +183,7 @@ void MDAL::DriverCF::addDatasetGroups( MDAL::Mesh *mesh, const std::vector<doubl
const CFDatasetGroupInfo dsi = it.second;
// Create a dataset group
std::shared_ptr<MDAL::DatasetGroup> group = std::make_shared<MDAL::DatasetGroup>(
name(),
mesh,
mFileName,
dsi.name
@ -245,7 +247,7 @@ void MDAL::DriverCF::parseTime( std::vector<double> &times )
MDAL::DriverCF::DriverCF( const std::string &name,
const std::string &longName,
const std::string &filters ):
Driver( name, longName, filters, DriverType::CanReadMeshAndDatasets )
Driver( name, longName, filters, Capability::ReadMesh )
{
}
@ -327,6 +329,7 @@ std::unique_ptr< MDAL::Mesh > MDAL::DriverCF::load( const std::string &fileName,
populateFacesAndVertices( vertices, faces );
std::unique_ptr< MemoryMesh > mesh(
new MemoryMesh(
name(),
vertices.size(),
faces.size(),
mDimensions.MaxVerticesInFace,

View File

@ -3,17 +3,19 @@
Copyright (C) 2018 Lutra Consulting Ltd.
*/
#include <string.h>
#include "mdal_driver.hpp"
#include "mdal_utils.hpp"
#include "mdal_memory_data_model.hpp"
MDAL::Driver::Driver( const std::string &name,
const std::string &longName,
const std::string &filters,
DriverType type )
int capabilityFlags )
: mName( name )
, mLongName( longName )
, mFilters( filters )
, mType( type )
, mCapabilityFlags( capabilityFlags )
{
}
@ -35,9 +37,9 @@ std::string MDAL::Driver::filters() const
return mFilters;
}
MDAL::DriverType MDAL::Driver::type() const
bool MDAL::Driver::hasCapability( MDAL::Capability capability ) const
{
return mType;
return capability == ( mCapabilityFlags & capability );
}
std::unique_ptr< MDAL::Mesh > MDAL::Driver::load( const std::string &uri, MDAL_Status *status )
@ -54,3 +56,34 @@ void MDAL::Driver::load( const std::string &uri, Mesh *mesh, MDAL_Status *status
MDAL_UNUSED( status );
return;
}
void MDAL::Driver::createDatasetGroup( MDAL::Mesh *mesh, const std::string &groupName, bool isOnVertices, bool hasScalarData, const std::string &datasetGroupFile )
{
std::shared_ptr<MDAL::DatasetGroup> grp(
new MDAL::DatasetGroup( name(),
mesh,
datasetGroupFile )
);
grp->setName( groupName );
grp->setIsOnVertices( isOnVertices );
grp->setIsScalar( hasScalarData );
grp->startEditing();
mesh->datasetGroups.push_back( grp );
}
void MDAL::Driver::createDataset( MDAL::DatasetGroup *group, double time, const double *values, const int *active )
{
std::shared_ptr<MDAL::MemoryDataset> dataset = std::make_shared< MemoryDataset >( group );
dataset->setTime( time );
memcpy( dataset->values(), values, sizeof( double ) * dataset->valuesCount() );
if ( active && dataset->active() )
memcpy( dataset->active(), active, sizeof( int ) * dataset->mesh()->facesCount() );
dataset->setStatistics( MDAL::calculateStatistics( dataset ) );
group->datasets.push_back( dataset );
}
bool MDAL::Driver::persist( MDAL::DatasetGroup *group )
{
MDAL_UNUSED( group );
return true; // failure
}

View File

@ -12,10 +12,12 @@
namespace MDAL
{
enum DriverType
enum Capability
{
CanReadMeshAndDatasets,
CanReadOnlyDatasets
None = 0,
ReadMesh = 1 << 0, //! Can read mesh and all datasets stored in the mesh file
ReadDatasets = 1 << 1, //! Can read only datasets (groups) from existing mesh
WriteDatasets = 1 << 2, //! Can write datasets (groups)
};
class Driver
@ -24,7 +26,7 @@ namespace MDAL
Driver( const std::string &name,
const std::string &longName,
const std::string &filters,
DriverType type
int capabilityFlags
);
virtual ~Driver();
@ -33,7 +35,7 @@ namespace MDAL
std::string name() const;
std::string longName() const;
std::string filters() const;
DriverType type() const;
bool hasCapability( Capability capability ) const;
virtual bool canRead( const std::string &uri ) = 0;
@ -42,11 +44,29 @@ namespace MDAL
// loads datasets
virtual void load( const std::string &uri, Mesh *mesh, MDAL_Status *status );
// create new dataset group
virtual void createDatasetGroup(
Mesh *mesh,
const std::string &groupName,
bool isOnVertices,
bool hasScalarData,
const std::string &datasetGroupFile );
// create new dataset from array
virtual void createDataset( DatasetGroup *group,
double time,
const double *values,
const int *active );
// persist to the file
// returns true on error, false on success
virtual bool persist( DatasetGroup *group );
private:
std::string mName;
std::string mLongName;
std::string mFilters;
DriverType mType;
int mCapabilityFlags;
};
} // namespace MDAL

View File

@ -73,13 +73,14 @@ static double getDouble( const std::string &val )
void MDAL::DriverFlo2D::addStaticDataset(
bool isOnVertices,
std::vector<double> &vals,
const std::string &name,
const std::string &groupName,
const std::string &datFileName )
{
std::shared_ptr<DatasetGroup> group = std::make_shared< DatasetGroup >(
name(),
mMesh.get(),
datFileName,
name
groupName
);
group->setIsOnVertices( isOnVertices );
group->setIsScalar( true );
@ -186,6 +187,7 @@ void MDAL::DriverFlo2D::parseTIMDEPFile( const std::string &datFileName, const s
size_t face_idx = 0;
std::shared_ptr<DatasetGroup> depthDsGroup = std::make_shared< DatasetGroup >(
name(),
mMesh.get(),
datFileName,
"Depth"
@ -195,6 +197,7 @@ void MDAL::DriverFlo2D::parseTIMDEPFile( const std::string &datFileName, const s
std::shared_ptr<DatasetGroup> waterLevelDsGroup = std::make_shared< DatasetGroup >(
name(),
mMesh.get(),
datFileName,
"Water Level"
@ -203,6 +206,7 @@ void MDAL::DriverFlo2D::parseTIMDEPFile( const std::string &datFileName, const s
waterLevelDsGroup->setIsScalar( true );
std::shared_ptr<DatasetGroup> flowDsGroup = std::make_shared< DatasetGroup >(
name(),
mMesh.get(),
datFileName,
"Velocity"
@ -486,6 +490,7 @@ void MDAL::DriverFlo2D::createMesh( const std::vector<CellCenter> &cells, double
mMesh.reset(
new MemoryMesh(
name(),
vertices.size(),
faces.size(),
4, //maximum quads
@ -567,6 +572,7 @@ bool MDAL::DriverFlo2D::parseHDF5Datasets( const std::string &datFileName )
// Create dataset now
std::shared_ptr<DatasetGroup> ds = std::make_shared< DatasetGroup >(
name(),
mMesh.get(),
datFileName,
grpName
@ -630,7 +636,7 @@ MDAL::DriverFlo2D::DriverFlo2D()
"FLO2D",
"Flo2D",
"*.nc",
DriverType::CanReadMeshAndDatasets )
Capability::ReadMesh )
{
}

View File

@ -47,7 +47,7 @@ namespace MDAL
void parseTIMDEPFile( const std::string &datFileName, const std::vector<double> &elevations );
void parseFPLAINFile( std::vector<double> &elevations, const std::string &datFileName, std::vector<CellCenter> &cells );
void parseCADPTSFile( const std::string &datFileName, std::vector<CellCenter> &cells );
void addStaticDataset( bool isOnVertices, std::vector<double> &vals, const std::string &name, const std::string &datFileName );
void addStaticDataset( bool isOnVertices, std::vector<double> &vals, const std::string &groupName, const std::string &datFileName );
static MDAL::Vertex createVertex( size_t position, double half_cell_size, const CellCenter &cell );
static double calcCellSize( const std::vector<CellCenter> &cells );
};

View File

@ -259,6 +259,60 @@ void MDAL::DriverGdal::parseRasterBands( const MDAL::GdalDataset *cfGDALDataset
}
}
void MDAL::DriverGdal::fixRasterBands()
{
// go through all bands and find out if both x and y dataset are valid
// if such pair if found, make the group scalar by removal of null band pointer
// this can happen is parseBandInfo() returns false-positive in vector detection
for ( data_hash::iterator band = mBands.begin(); band != mBands.end(); band++ )
{
if ( band->second.empty() )
continue;
// scalars are always ok
bool is_scalar = ( band->second.begin()->second.size() == 1 );
if ( is_scalar )
continue;
// check if we have some null bands
int needs_fix = false;
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;
if ( !raster_bands[0] )
{
needs_fix = true;
break;
}
if ( !raster_bands[1] )
{
needs_fix = true;
break;
}
}
// convert this vector to scalar
if ( needs_fix )
{
for ( timestep_map::iterator time_step = band->second.begin(); time_step != band->second.end(); time_step++ )
{
std::vector<GDALRasterBandH> &raster_bands = time_step->second;
if ( !raster_bands[0] )
{
raster_bands[0] = raster_bands[1];
}
// get rid of y-coord
raster_bands.resize( 1 );
// not we should have only 1 band and valid
assert( raster_bands[0] );
}
}
}
}
void MDAL::DriverGdal::addDataToOutput( GDALRasterBandH raster_band, std::shared_ptr<MemoryDataset> tos, bool is_vector, bool is_x )
{
assert( raster_band );
@ -335,9 +389,10 @@ void MDAL::DriverGdal::activateFaces( std::shared_ptr<MemoryDataset> tos )
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[elem[i]];
double val = values[vertexIndex];
if ( std::isnan( val ) )
{
active[idx] = 0; //NOT ACTIVE
@ -346,8 +401,8 @@ void MDAL::DriverGdal::activateFaces( std::shared_ptr<MemoryDataset> tos )
}
else
{
double x = values[elem[2 * i]];
double y = values[elem[2 * i + 1]];
double x = values[2 * vertexIndex];
double y = values[2 * vertexIndex + 1];
if ( std::isnan( x ) || std::isnan( y ) )
{
active[idx] = 0; //NOT ACTIVE
@ -367,6 +422,7 @@ void MDAL::DriverGdal::addDatasetGroups()
continue;
std::shared_ptr<DatasetGroup> group = std::make_shared< DatasetGroup >(
name(),
mMesh.get(),
mFileName,
band->first
@ -405,6 +461,7 @@ void MDAL::DriverGdal::createMesh()
initFaces( vertices, faces, is_longitude_shifted );
mMesh.reset( new MemoryMesh(
name(),
vertices.size(),
faces.size(),
4, //maximum quads
@ -483,7 +540,7 @@ MDAL::DriverGdal::DriverGdal( const std::string &name,
const std::string &description,
const std::string &filter,
const std::string &gdalDriverName ):
Driver( name, description, filter, DriverType::CanReadMeshAndDatasets ),
Driver( name, description, filter, Capability::ReadMesh ),
mGdalDriverName( gdalDriverName ),
mPafScanline( nullptr )
{}
@ -549,6 +606,12 @@ std::unique_ptr<MDAL::Mesh> MDAL::DriverGdal::load( const std::string &fileName,
}
}
// 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();
}

View File

@ -94,6 +94,7 @@ namespace MDAL
void addDatasetGroups();
void createMesh();
void parseRasterBands( const GdalDataset *cfGDALDataset );
void fixRasterBands();
std::string mFileName;
const std::string mGdalDriverName; /* GDAL driver name */

View File

@ -119,6 +119,7 @@ void MDAL::DriverHec2D::readFaceOutput( const HdfFile &hdfFile,
double eps = std::numeric_limits<double>::min();
std::shared_ptr<DatasetGroup> group = std::make_shared< DatasetGroup >(
name(),
mMesh.get(),
mFileName,
datasetName
@ -163,7 +164,7 @@ void MDAL::DriverHec2D::readFaceOutput( const HdfFile &hdfFile,
{
for ( size_t c = 0; c < 2; ++c )
{
size_t cell_idx = face2Cells[2 * i + c] + areaElemStartIndex[nArea];
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 )
{
@ -216,6 +217,7 @@ std::shared_ptr<MDAL::MemoryDataset> MDAL::DriverHec2D::readElemOutput( const Hd
double eps = std::numeric_limits<double>::min();
std::shared_ptr<DatasetGroup> group = std::make_shared< DatasetGroup >(
name(),
mMesh.get(),
mFileName,
datasetName
@ -354,7 +356,7 @@ void MDAL::DriverHec2D::readElemResults(
);
}
std::vector<std::string> read2DFlowAreasNames( HdfGroup gGeom2DFlowAreas )
std::vector<std::string> MDAL::DriverHec2D::read2DFlowAreasNamesOld( HdfGroup gGeom2DFlowAreas ) const
{
HdfDataset dsNames = openHdfDataset( gGeom2DFlowAreas, "Names" );
std::vector<std::string> names = dsNames.readArrayString();
@ -365,6 +367,85 @@ std::vector<std::string> read2DFlowAreasNames( HdfGroup gGeom2DFlowAreas )
return names;
}
/**
For 5.0.5+ format
DATATYPE H5T_COMPOUND {
H5T_STRING {
STRSIZE 16;
STRPAD H5T_STR_NULLTERM;
CSET H5T_CSET_ASCII;
CTYPE H5T_C_S1;
} "Name";
H5T_IEEE_F32LE "Mann";
H5T_IEEE_F32LE "Cell Vol Tol";
H5T_IEEE_F32LE "Cell Min Area Fraction";
H5T_IEEE_F32LE "Face Profile Tol";
H5T_IEEE_F32LE "Face Area Tol";
H5T_IEEE_F32LE "Face Conv Ratio";
H5T_IEEE_F32LE "Laminar Depth";
H5T_IEEE_F32LE "Spacing dx";
H5T_IEEE_F32LE "Spacing dy";
H5T_IEEE_F32LE "Shift dx";
H5T_IEEE_F32LE "Shift dy";
H5T_STD_I32LE "Cell Count";
}
*/
typedef struct FlowAreasAttribute505
{
char name[HDF_MAX_NAME];
float mann;
float cellVolTol;
float cellMinAreaFraction;
float faceProfileTol;
float faceAreaTol;
float faceConvRatio;
float laminarDepth;
float spacingDx;
float spacingDy;
float shifyDx;
float shifyDy;
int cellCount;
} FlowAreasAttribute505;
std::vector<std::string> MDAL::DriverHec2D::read2DFlowAreasNames505( HdfGroup gGeom2DFlowAreas ) const
{
HdfDataset dsAttributes = openHdfDataset( gGeom2DFlowAreas, "Attributes" );
hid_t attributeHID = H5Tcreate( H5T_COMPOUND, sizeof( FlowAreasAttribute505 ) );
hid_t stringHID = H5Tcopy( H5T_C_S1 );
H5Tset_size( stringHID, HDF_MAX_NAME );
H5Tinsert( attributeHID, "Name", HOFFSET( FlowAreasAttribute505, name ), stringHID );
H5Tinsert( attributeHID, "Mann", HOFFSET( FlowAreasAttribute505, mann ), H5T_NATIVE_FLOAT );
H5Tinsert( attributeHID, "Cell Vol Tol", HOFFSET( FlowAreasAttribute505, cellVolTol ), H5T_NATIVE_FLOAT );
H5Tinsert( attributeHID, "Cell Min Area Fraction", HOFFSET( FlowAreasAttribute505, cellMinAreaFraction ), H5T_NATIVE_FLOAT );
H5Tinsert( attributeHID, "Face Profile Tol", HOFFSET( FlowAreasAttribute505, faceProfileTol ), H5T_NATIVE_FLOAT );
H5Tinsert( attributeHID, "Face Area Tol", HOFFSET( FlowAreasAttribute505, faceAreaTol ), H5T_NATIVE_FLOAT );
H5Tinsert( attributeHID, "Face Conv Ratio", HOFFSET( FlowAreasAttribute505, faceConvRatio ), H5T_NATIVE_FLOAT );
H5Tinsert( attributeHID, "Laminar Depth", HOFFSET( FlowAreasAttribute505, laminarDepth ), H5T_NATIVE_FLOAT );
H5Tinsert( attributeHID, "Spacing dx", HOFFSET( FlowAreasAttribute505, spacingDx ), H5T_NATIVE_FLOAT );
H5Tinsert( attributeHID, "Spacing dy", HOFFSET( FlowAreasAttribute505, spacingDy ), H5T_NATIVE_FLOAT );
H5Tinsert( attributeHID, "Shift dx", HOFFSET( FlowAreasAttribute505, shifyDx ), H5T_NATIVE_FLOAT );
H5Tinsert( attributeHID, "Shift dy", HOFFSET( FlowAreasAttribute505, shifyDy ), H5T_NATIVE_FLOAT );
H5Tinsert( attributeHID, "Cell Count", HOFFSET( FlowAreasAttribute505, cellCount ), H5T_NATIVE_INT );
std::vector<FlowAreasAttribute505> attributes = dsAttributes.readArray<FlowAreasAttribute505>( attributeHID );
H5Tclose( attributeHID );
H5Tclose( stringHID );
std::vector<std::string> names;
if ( attributes.empty() )
{
throw MDAL_Status::Err_InvalidData;
}
for ( const auto &attr : attributes )
{
std::string dat = std::string( attr.name );
names.push_back( MDAL::trim( dat ) );
}
return names;
}
void MDAL::DriverHec2D::setProjection( HdfFile hdfFile )
{
try
@ -441,6 +522,7 @@ void MDAL::DriverHec2D::parseMesh(
mMesh.reset(
new MemoryMesh(
name(),
vertices.size(),
faces.size(),
maxVerticesInFace,
@ -456,7 +538,7 @@ MDAL::DriverHec2D::DriverHec2D()
: Driver( "HEC2D",
"HEC-RAS 2D",
"*.hdf",
DriverType::CanReadMeshAndDatasets )
Capability::ReadMesh )
{
}
@ -471,16 +553,22 @@ bool MDAL::DriverHec2D::canRead( const std::string &uri )
{
HdfFile hdfFile = openHdfFile( uri );
std::string fileType = openHdfAttribute( hdfFile, "File Type" );
if ( fileType != "HEC-RAS Results" )
{
return false;
}
return canReadOldFormat( fileType ) || canReadFormat505( fileType );
}
catch ( MDAL_Status )
{
return false;
}
return true;
}
bool MDAL::DriverHec2D::canReadOldFormat( const std::string &fileType ) const
{
return fileType == "HEC-RAS Results";
}
bool MDAL::DriverHec2D::canReadFormat505( const std::string &fileType ) const
{
return fileType == "HEC-RAS Geometry";
}
std::unique_ptr<MDAL::Mesh> MDAL::DriverHec2D::load( const std::string &resultsFile, MDAL_Status *status )
@ -495,15 +583,17 @@ std::unique_ptr<MDAL::Mesh> MDAL::DriverHec2D::load( const std::string &resultsF
// Verify it is correct file
std::string fileType = openHdfAttribute( hdfFile, "File Type" );
if ( fileType != "HEC-RAS Results" )
{
throw MDAL_Status::Err_UnknownFormat;
}
bool oldFormat = canReadOldFormat( fileType );
HdfGroup gGeom = openHdfGroup( hdfFile, "Geometry" );
HdfGroup gGeom2DFlowAreas = openHdfGroup( gGeom, "2D Flow Areas" );
std::vector<std::string> flowAreaNames = read2DFlowAreasNames( gGeom2DFlowAreas );
std::vector<std::string> flowAreaNames;
if ( oldFormat )
flowAreaNames = read2DFlowAreasNamesOld( gGeom2DFlowAreas );
else
flowAreaNames = read2DFlowAreasNames505( gGeom2DFlowAreas );
std::vector<size_t> areaElemStartIndex( flowAreaNames.size() + 1 );
parseMesh( gGeom2DFlowAreas, areaElemStartIndex, flowAreaNames );
@ -517,6 +607,7 @@ std::unique_ptr<MDAL::Mesh> MDAL::DriverHec2D::load( const std::string &resultsF
// Face centered Values
readFaceResults( hdfFile, areaElemStartIndex, flowAreaNames );
}
catch ( MDAL_Status error )
{

View File

@ -16,6 +16,17 @@
namespace MDAL
{
/**
* HEC-RAS 2D format.
*
* This is a HDF5-based format to store mesh and datasets
* in a single file. The format supports meshes is multiple
* (disconnected) areas.
*
* There is a small change in the format in HEC-RAS 5.0.5+, where
* - Header File Type is different (HEC-RAS Results vs HEC-RAS Geometry)
* - Names or areas are stored in different place (names array vs attributes array)
*/
class DriverHec2D: public Driver
{
public:
@ -30,6 +41,15 @@ namespace MDAL
std::unique_ptr< MDAL::MemoryMesh > mMesh;
std::string mFileName;
// Pre 5.0.5 format
bool canReadOldFormat( const std::string &fileType ) const;
std::vector<std::string> read2DFlowAreasNamesOld( HdfGroup gGeom2DFlowAreas ) const;
// 5.0.5 + format
bool canReadFormat505( const std::string &fileType ) const;
std::vector<std::string> read2DFlowAreasNames505( HdfGroup gGeom2DFlowAreas ) const;
// Common functions
void readFaceOutput( const HdfFile &hdfFile,
const HdfGroup &rootGroup,
const std::vector<size_t> &areaElemStartIndex,
@ -37,9 +57,11 @@ namespace MDAL
const std::string rawDatasetName,
const std::string datasetName,
const std::vector<float> &times );
void readFaceResults( const HdfFile &hdfFile,
const std::vector<size_t> &areaElemStartIndex,
const std::vector<std::string> &flowAreaNames );
std::shared_ptr<MDAL::MemoryDataset> readElemOutput(
const HdfGroup &rootGroup,
const std::vector<size_t> &areaElemStartIndex,
@ -48,14 +70,18 @@ namespace MDAL
const std::string datasetName,
const std::vector<float> &times,
std::shared_ptr<MDAL::MemoryDataset> bed_elevation );
std::shared_ptr<MDAL::MemoryDataset> readBedElevation(
const HdfGroup &gGeom2DFlowAreas,
const std::vector<size_t> &areaElemStartIndex,
const std::vector<std::string> &flowAreaNames );
void setProjection( HdfFile hdfFile );
void parseMesh( HdfGroup gGeom2DFlowAreas,
std::vector<size_t> &areaElemStartIndex,
const std::vector<std::string> &flowAreaNames );
void readElemResults(
const HdfFile &hdfFile,
std::shared_ptr<MDAL::MemoryDataset> bed_elevation,

206
external/mdal/frmts/mdal_netcdf.cpp vendored Normal file
View File

@ -0,0 +1,206 @@
/*
MDAL - Mesh Data Abstraction Library (MIT License)
Copyright (C) 2019 Peter Petrik (zilolv at gmail dot com)
*/
#include <string>
#include <vector>
#include <assert.h>
#include <netcdf.h>
#include "mdal_netcdf.hpp"
#include "mdal.h"
#include "mdal_utils.hpp"
NetCDFFile::NetCDFFile(): mNcid( 0 ) {}
NetCDFFile::~NetCDFFile()
{
if ( mNcid != 0 ) nc_close( mNcid );
}
int NetCDFFile::handle() const
{
return mNcid;
}
void NetCDFFile::openFile( const std::string &fileName )
{
int res = nc_open( fileName.c_str(), NC_NOWRITE, &mNcid );
if ( res != NC_NOERR )
{
MDAL::debug( nc_strerror( res ) );
throw MDAL_Status::Err_UnknownFormat;
}
}
bool NetCDFFile::hasVariable( const std::string &name ) const
{
assert( mNcid != 0 );
int varid;
return ( nc_inq_varid( mNcid, name.c_str(), &varid ) == NC_NOERR );
}
std::vector<int> NetCDFFile::readIntArr( const std::string &name, size_t dim ) const
{
assert( mNcid != 0 );
int arr_id;
if ( nc_inq_varid( mNcid, name.c_str(), &arr_id ) != NC_NOERR )
{
throw MDAL_Status::Err_UnknownFormat;
}
std::vector<int> arr_val( dim );
if ( nc_get_var_int( mNcid, arr_id, arr_val.data() ) != NC_NOERR )
{
throw MDAL_Status::Err_UnknownFormat;
}
return arr_val;
}
std::vector<double> NetCDFFile::readDoubleArr( const std::string &name, size_t dim ) const
{
assert( mNcid != 0 );
int arr_id;
if ( nc_inq_varid( mNcid, name.c_str(), &arr_id ) != NC_NOERR )
{
throw MDAL_Status::Err_UnknownFormat;
}
std::vector<double> arr_val( dim );
if ( nc_get_var_double( mNcid, arr_id, arr_val.data() ) != NC_NOERR )
{
throw MDAL_Status::Err_UnknownFormat;
}
return arr_val;
}
bool NetCDFFile::hasArr( const std::string &name ) const
{
assert( mNcid != 0 );
int arr_id;
return nc_inq_varid( mNcid, name.c_str(), &arr_id ) == NC_NOERR;
}
std::vector<std::string> NetCDFFile::readArrNames() const
{
assert( mNcid != 0 );
std::vector<std::string> res;
int nvars;
if ( nc_inq_varids( mNcid, &nvars, nullptr ) != NC_NOERR )
{
throw MDAL_Status::Err_UnknownFormat;
}
std::vector<int> varids( static_cast<size_t>( nvars ) );
if ( nc_inq_varids( mNcid, &nvars, varids.data() ) != NC_NOERR )
{
throw MDAL_Status::Err_UnknownFormat;
}
for ( size_t i = 0; i < static_cast<size_t>( nvars ); ++i )
{
std::vector<char> cname( NC_MAX_NAME + 1 );
if ( nc_inq_varname( mNcid, varids[i], cname.data() ) != NC_NOERR )
{
throw MDAL_Status::Err_UnknownFormat;
}
res.push_back( cname.data() );
}
return res;
}
int NetCDFFile::getAttrInt( const std::string &name, const std::string &attr_name ) const
{
assert( mNcid != 0 );
int arr_id;
if ( nc_inq_varid( mNcid, name.c_str(), &arr_id ) != NC_NOERR )
{
throw MDAL_Status::Err_UnknownFormat;
}
int val;
if ( nc_get_att_int( mNcid, arr_id, attr_name.c_str(), &val ) )
{
throw MDAL_Status::Err_UnknownFormat;
}
return val;
}
std::string NetCDFFile::getAttrStr( const std::string &name, const std::string &attr_name ) const
{
assert( mNcid != 0 );
int arr_id;
if ( nc_inq_varid( mNcid, name.c_str(), &arr_id ) ) throw MDAL_Status::Err_UnknownFormat;
return getAttrStr( attr_name, arr_id );
}
std::string NetCDFFile::getAttrStr( const std::string &name, int varid ) const
{
assert( mNcid != 0 );
size_t attlen = 0;
if ( nc_inq_attlen( mNcid, varid, name.c_str(), &attlen ) )
{
// attribute is missing
return std::string();
}
char *string_attr;
string_attr = ( char * ) malloc( attlen + 1 );
if ( nc_get_att_text( mNcid, varid, name.c_str(), string_attr ) ) throw MDAL_Status::Err_UnknownFormat;
string_attr[attlen] = '\0';
std::string res( string_attr );
free( string_attr );
return res;
}
double NetCDFFile::getFillValue( int varid ) const
{
return getAttrDouble( varid, "_FillValue" );
}
double NetCDFFile::getAttrDouble( int varid, const std::string &attr_name ) const
{
double res;
if ( nc_get_att_double( mNcid, varid, attr_name.c_str(), &res ) )
res = std::numeric_limits<double>::quiet_NaN(); // not present/set
return res;
}
int NetCDFFile::getVarId( const std::string &name )
{
int ncid_val;
if ( nc_inq_varid( mNcid, name.c_str(), &ncid_val ) != NC_NOERR ) throw MDAL_Status::Err_UnknownFormat;
return ncid_val;
}
void NetCDFFile::getDimension( const std::string &name, size_t *val, int *ncid_val ) const
{
assert( mNcid != 0 );
if ( nc_inq_dimid( mNcid, name.c_str(), ncid_val ) != NC_NOERR ) throw MDAL_Status::Err_UnknownFormat;
if ( nc_inq_dimlen( mNcid, *ncid_val, val ) != NC_NOERR ) throw MDAL_Status::Err_UnknownFormat;
}
void NetCDFFile::getDimensionOptional( const std::string &name, size_t *val, int *ncid_val ) const
{
assert( mNcid != 0 );
try
{
getDimension( name, val, ncid_val );
}
catch ( MDAL_Status )
{
*ncid_val = -1;
*val = 0;
}
}

View File

@ -8,168 +8,35 @@
#include <string>
#include <vector>
#include <assert.h>
#include <netcdf.h>
#include "mdal_utils.hpp"
#include "mdal.h"
//! C++ Wrapper around netcdf C library
class NetCDFFile
{
public:
NetCDFFile(): mNcid( 0 ) {}
~NetCDFFile()
{
if ( mNcid != 0 ) nc_close( mNcid );
}
//! Create file with invalid handle
NetCDFFile();
//! Closes the file
~NetCDFFile();
int handle() const
{
return mNcid;
}
int handle() const;
void openFile( const std::string &fileName );
bool hasVariable( const std::string &name ) const;
void openFile( const std::string &fileName )
{
int res = nc_open( fileName.c_str(), NC_NOWRITE, &mNcid );
if ( res != NC_NOERR )
{
MDAL::debug( nc_strerror( res ) );
throw MDAL_Status::Err_UnknownFormat;
}
}
std::vector<int> readIntArr( const std::string &name, size_t dim ) const;
std::vector<double> readDoubleArr( const std::string &name, size_t dim ) const;
bool hasArr( const std::string &name ) const;
std::vector<std::string> readArrNames() const;
bool hasVariable( const std::string &name ) const
{
assert( mNcid != 0 );
int varid;
return ( nc_inq_varid( mNcid, name.c_str(), &varid ) == NC_NOERR );
}
std::vector<int> readIntArr( const std::string &name, size_t dim ) const
{
assert( mNcid != 0 );
int arr_id;
if ( nc_inq_varid( mNcid, name.c_str(), &arr_id ) != NC_NOERR )
{
throw MDAL_Status::Err_UnknownFormat;
}
std::vector<int> arr_val( dim );
if ( nc_get_var_int( mNcid, arr_id, arr_val.data() ) != NC_NOERR )
{
throw MDAL_Status::Err_UnknownFormat;
}
return arr_val;
}
std::vector<double> readDoubleArr( const std::string &name, size_t dim ) const
{
assert( mNcid != 0 );
int arr_id;
if ( nc_inq_varid( mNcid, name.c_str(), &arr_id ) != NC_NOERR )
{
throw MDAL_Status::Err_UnknownFormat;
}
std::vector<double> arr_val( dim );
if ( nc_get_var_double( mNcid, arr_id, arr_val.data() ) != NC_NOERR )
{
throw MDAL_Status::Err_UnknownFormat;
}
return arr_val;
}
int getAttrInt( const std::string &name, const std::string &attr_name ) const
{
assert( mNcid != 0 );
int arr_id;
if ( nc_inq_varid( mNcid, name.c_str(), &arr_id ) != NC_NOERR )
{
throw MDAL_Status::Err_UnknownFormat;
}
int val;
if ( nc_get_att_int( mNcid, arr_id, attr_name.c_str(), &val ) )
{
throw MDAL_Status::Err_UnknownFormat;
}
return val;
}
std::string getAttrStr( const std::string &name, const std::string &attr_name ) const
{
assert( mNcid != 0 );
int arr_id;
if ( nc_inq_varid( mNcid, name.c_str(), &arr_id ) ) throw MDAL_Status::Err_UnknownFormat;
return getAttrStr( attr_name, arr_id );
}
std::string getAttrStr( const std::string &name, int varid ) const
{
assert( mNcid != 0 );
size_t attlen = 0;
if ( nc_inq_attlen( mNcid, varid, name.c_str(), &attlen ) )
{
// attribute is missing
return std::string();
}
char *string_attr;
string_attr = ( char * ) malloc( attlen + 1 );
if ( nc_get_att_text( mNcid, varid, name.c_str(), string_attr ) ) throw MDAL_Status::Err_UnknownFormat;
string_attr[attlen] = '\0';
std::string res( string_attr );
free( string_attr );
return res;
}
double getFillValue( int varid ) const
{
double fill;
if ( nc_get_att_double( mNcid, varid, "_FillValue", &fill ) )
fill = std::numeric_limits<double>::quiet_NaN(); // not present/set
return fill;
}
int getVarId( const std::string &name )
{
int ncid_val;
if ( nc_inq_varid( mNcid, name.c_str(), &ncid_val ) != NC_NOERR ) throw MDAL_Status::Err_UnknownFormat;
return ncid_val;
}
void getDimension( const std::string &name, size_t *val, int *ncid_val ) const
{
assert( mNcid != 0 );
if ( nc_inq_dimid( mNcid, name.c_str(), ncid_val ) != NC_NOERR ) throw MDAL_Status::Err_UnknownFormat;
if ( nc_inq_dimlen( mNcid, *ncid_val, val ) != NC_NOERR ) throw MDAL_Status::Err_UnknownFormat;
}
void getDimensionOptional( const std::string &name, size_t *val, int *ncid_val ) const
{
assert( mNcid != 0 );
try
{
getDimension( name, val, ncid_val );
}
catch ( MDAL_Status )
{
*ncid_val = -1;
*val = 0;
}
}
int getAttrInt( const std::string &name, const std::string &attr_name ) const;
double getAttrDouble( int varid, const std::string &attr_name ) const;
std::string getAttrStr( const std::string &name, const std::string &attr_name ) const;
std::string getAttrStr( const std::string &name, int varid ) const;
double getFillValue( int varid ) const;
int getVarId( const std::string &name );
void getDimension( const std::string &name, size_t *val, int *ncid_val ) const;
void getDimensionOptional( const std::string &name, size_t *val, int *ncid_val ) const;
private:
int mNcid;
int mNcid; // C handle to the file
};
#endif // MDAL_NETCDF_HPP

View File

@ -7,20 +7,17 @@
#include <string>
#include <string.h>
#include <vector>
#include <netcdf.h>
#include <set>
#include "mdal_netcdf.hpp"
#include "mdal_sww.hpp"
// threshold for determining whether an element is active (wet)
// the format does not explicitly store that information so we
// determine that when loading data
#define DEPTH_THRESHOLD 0.0001 // in meters
#include "mdal_utils.hpp"
MDAL::DriverSWW::DriverSWW()
: Driver( "SWW",
"AnuGA",
"*.sww",
DriverType::CanReadMeshAndDatasets )
Capability::ReadMesh )
{
}
@ -29,345 +26,442 @@ MDAL::DriverSWW *MDAL::DriverSWW::create()
return new DriverSWW();
}
bool MDAL::DriverSWW::canRead( const std::string &uri )
size_t MDAL::DriverSWW::getVertexCount( const NetCDFFile &ncFile ) const
{
int ncid;
int res;
// open
res = nc_open( uri.c_str(), NC_NOWRITE, &ncid );
if ( res != NC_NOERR )
{
MDAL::debug( nc_strerror( res ) );
nc_close( ncid );
return false;
}
// get dimensions
int nVolumesId, nVerticesId, nPointsId, nTimestepsId;
if ( nc_inq_dimid( ncid, "number_of_volumes", &nVolumesId ) != NC_NOERR ||
nc_inq_dimid( ncid, "number_of_vertices", &nVerticesId ) != NC_NOERR ||
nc_inq_dimid( ncid, "number_of_points", &nPointsId ) != NC_NOERR ||
nc_inq_dimid( ncid, "number_of_timesteps", &nTimestepsId ) != NC_NOERR )
{
nc_close( ncid );
return false;
}
return true;
int nPointsId;
size_t res;
ncFile.getDimension( "number_of_points", &res, &nPointsId );
return res;
}
std::unique_ptr<MDAL::Mesh> MDAL::DriverSWW::load( const std::string &resultsFile,
MDAL_Status *status )
bool MDAL::DriverSWW::canRead( const std::string &uri )
{
NetCDFFile ncFile;
try
{
ncFile.openFile( uri );
getVertexCount( ncFile );
}
catch ( MDAL_Status )
{
return false;
}
return true;
}
std::vector<double> MDAL::DriverSWW::readZCoords( const NetCDFFile &ncFile ) const
{
size_t nPoints = getVertexCount( ncFile );
std::vector<double> pz;
// newer sww files does have elevation array that is time-dependent
if ( ncFile.hasArr( "z" ) )
{
pz = ncFile.readDoubleArr( "z", nPoints );
}
else if ( ncFile.hasArr( "elevation" ) )
{
int zDims = 0;
int zid;
if ( nc_inq_varid( ncFile.handle(), "elevation", &zid ) == NC_NOERR &&
nc_inq_varndims( ncFile.handle(), zid, &zDims ) == NC_NOERR )
{
if ( zDims == 1 )
{
// just one elevation for all times, treat as z coord
pz = ncFile.readDoubleArr( "elevation", nPoints );
}
else
{
pz.resize( nPoints );
// fetching "elevation" data for the first timestep,
// and threat it as z coord
size_t start[2], count[2];
const ptrdiff_t stride[2] = {1, 1};
start[0] = 0; // t = 0
start[1] = 0;
count[0] = 1;
count[1] = nPoints;
nc_get_vars_double( ncFile.handle(), zid, start, count, stride, pz.data() );
}
}
}
return pz;
}
void MDAL::DriverSWW::addBedElevation( const NetCDFFile &ncFile,
MDAL::MemoryMesh *mesh,
const std::vector<double> &times
) const
{
if ( ncFile.hasArr( "elevation" ) )
{
std::shared_ptr<MDAL::DatasetGroup> grp = readScalarGroup( ncFile,
mesh,
times,
"Bed Elevation",
"elevation" );
mesh->datasetGroups.push_back( grp );
}
else
{
MDAL::addBedElevationDatasetGroup( mesh, mesh->vertices );
}
}
MDAL::Vertices MDAL::DriverSWW::readVertices( const NetCDFFile &ncFile ) const
{
size_t nPoints = getVertexCount( ncFile );
// load mesh data
std::vector<double> px = ncFile.readDoubleArr( "x", nPoints );
std::vector<double> py = ncFile.readDoubleArr( "y", nPoints );
std::vector<double> pz = readZCoords( ncFile );
// we may need to apply a shift to the X,Y coordinates
double xLLcorner = ncFile.getAttrDouble( NC_GLOBAL, "xllcorner" );
double yLLcorner = ncFile.getAttrDouble( NC_GLOBAL, "yllcorner" );
MDAL::Vertices vertices( nPoints );
Vertex *vertexPtr = vertices.data();
for ( size_t i = 0; i < nPoints; ++i, ++vertexPtr )
{
vertexPtr->x = px[i] + xLLcorner ;
vertexPtr->y = py[i] + yLLcorner ;
if ( !pz.empty() ) // missing both "z" and "elevation"
vertexPtr->z = pz[i];
}
return vertices;
}
MDAL::Faces MDAL::DriverSWW::readFaces( const NetCDFFile &ncFile ) const
{
// get dimensions
int nVolumesId, nVerticesId;
size_t nVolumes, nVertices;
ncFile.getDimension( "number_of_volumes", &nVolumes, &nVolumesId );
ncFile.getDimension( "number_of_vertices", &nVertices, &nVerticesId );
if ( nVertices != 3 )
throw MDAL_Status::Err_UnknownFormat;
std::vector<int> pvolumes = ncFile.readIntArr( "volumes", nVertices * nVolumes );
MDAL::Faces faces( nVolumes );
for ( size_t i = 0; i < nVolumes; ++i )
{
faces[i].resize( 3 );
faces[i][0] = static_cast<size_t>( pvolumes[3 * i + 0] );
faces[i][1] = static_cast<size_t>( pvolumes[3 * i + 1] );
faces[i][2] = static_cast<size_t>( pvolumes[3 * i + 2] );
}
return faces;
}
std::vector<double> MDAL::DriverSWW::readTimes( const NetCDFFile &ncFile ) const
{
size_t nTimesteps;
int nTimestepsId;
ncFile.getDimension( "number_of_timesteps", &nTimesteps, &nTimestepsId );
std::vector<double> times = ncFile.readDoubleArr( "time", nTimesteps );
return times;
}
void MDAL::DriverSWW::readDatasetGroups(
const NetCDFFile &ncFile,
MDAL::MemoryMesh *mesh,
const std::vector<double> &times
) const
{
std::set<std::string> parsedVariableNames; // already parsed arrays somewhere else
parsedVariableNames.insert( "x" );
parsedVariableNames.insert( "y" );
parsedVariableNames.insert( "z" );
parsedVariableNames.insert( "volumes" );
parsedVariableNames.insert( "time" );
std::vector<std::string> names = ncFile.readArrNames();
std::set<std::string> namesSet( names.begin(), names.end() );
// Add bed elevation group
parsedVariableNames.insert( "elevations" );
addBedElevation( ncFile, mesh, times );
for ( const std::string &name : names )
{
// skip already parsed variables
if ( parsedVariableNames.find( name ) == parsedVariableNames.cend() )
{
std::string xName, yName, groupName( name );
bool isVector = parseGroupName( groupName, xName, yName );
std::shared_ptr<MDAL::DatasetGroup> grp;
if ( isVector && ncFile.hasArr( xName ) && ncFile.hasArr( yName ) )
{
// vector dataset group
grp = readVectorGroup(
ncFile,
mesh,
times,
groupName,
xName,
yName );
parsedVariableNames.insert( xName );
parsedVariableNames.insert( yName );
}
else
{
// scalar dataset group
grp = readScalarGroup(
ncFile,
mesh,
times,
groupName,
name );
parsedVariableNames.insert( name );
}
if ( grp )
mesh->datasetGroups.push_back( grp );
}
}
}
bool MDAL::DriverSWW::parseGroupName( std::string &groupName,
std::string &xName,
std::string &yName ) const
{
bool isVector = false;
std::string baseName( groupName );
// X and Y variables
if ( groupName.size() > 1 )
{
if ( MDAL::startsWith( groupName, "x" ) )
{
baseName = groupName.substr( 1, groupName.size() - 1 );
xName = groupName;
yName = "y" + baseName;
isVector = true;
}
else if ( MDAL::startsWith( groupName, "y" ) )
{
baseName = groupName.substr( 1, groupName.size() - 1 );
xName = "x" + baseName;
yName = groupName;
isVector = true;
}
}
// Maximums
groupName = baseName;
if ( MDAL::endsWith( baseName, "_range" ) )
{
groupName = groupName.substr( 0, baseName.size() - 6 ) + "/Maximums";
}
return isVector;
}
std::shared_ptr<MDAL::DatasetGroup> MDAL::DriverSWW::readScalarGroup(
const NetCDFFile &ncFile,
MDAL::MemoryMesh *mesh,
const std::vector<double> &times,
const std::string groupName,
const std::string arrName
) const
{
size_t nPoints = getVertexCount( ncFile );
std::shared_ptr<MDAL::DatasetGroup> mds;
int varxid;
if ( nc_inq_varid( ncFile.handle(), arrName.c_str(), &varxid ) == NC_NOERR )
{
mds = std::make_shared<MDAL::DatasetGroup> (
name(),
mesh,
mFileName,
groupName );
mds->setIsOnVertices( true );
mds->setIsScalar( true );
int zDimsX = 0;
if ( nc_inq_varndims( ncFile.handle(), varxid, &zDimsX ) != NC_NOERR )
throw MDAL_Status::Err_UnknownFormat;
if ( zDimsX == 1 )
{
// TIME INDEPENDENT
std::shared_ptr<MDAL::MemoryDataset> o = std::make_shared<MDAL::MemoryDataset>( mds.get() );
o->setTime( 0.0 );
double *values = o->values();
std::vector<double> valuesX = ncFile.readDoubleArr( arrName, nPoints );
for ( size_t i = 0; i < nPoints; ++i )
{
values[i] = valuesX[i];
}
o->setStatistics( MDAL::calculateStatistics( o ) );
mds->datasets.push_back( o );
}
else
{
// TIME DEPENDENT
for ( size_t t = 0; t < times.size(); ++t )
{
std::shared_ptr<MDAL::MemoryDataset> mto = std::make_shared<MDAL::MemoryDataset>( mds.get() );
mto->setTime( static_cast<double>( times[t] ) / 3600. );
double *values = mto->values();
// fetching data for one timestep
size_t start[2], count[2];
const ptrdiff_t stride[2] = {1, 1};
start[0] = t;
start[1] = 0;
count[0] = 1;
count[1] = nPoints;
nc_get_vars_double( ncFile.handle(), varxid, start, count, stride, values );
mto->setStatistics( MDAL::calculateStatistics( mto ) );
mds->datasets.push_back( mto );
}
}
mds->setStatistics( MDAL::calculateStatistics( mds ) );
}
return mds;
}
std::shared_ptr<MDAL::DatasetGroup> MDAL::DriverSWW::readVectorGroup(
const NetCDFFile &ncFile,
MDAL::MemoryMesh *mesh,
const std::vector<double> &times,
const std::string groupName,
const std::string arrXName,
const std::string arrYName
) const
{
size_t nPoints = getVertexCount( ncFile );
std::shared_ptr<MDAL::DatasetGroup> mds;
int varxid, varyid;
if ( nc_inq_varid( ncFile.handle(), arrXName.c_str(), &varxid ) == NC_NOERR &&
nc_inq_varid( ncFile.handle(), arrYName.c_str(), &varyid ) == NC_NOERR )
{
mds = std::make_shared<MDAL::DatasetGroup> (
name(),
mesh,
mFileName,
groupName );
mds->setIsOnVertices( true );
mds->setIsScalar( false );
int zDimsX = 0;
int zDimsY = 0;
if ( nc_inq_varndims( ncFile.handle(), varxid, &zDimsX ) != NC_NOERR )
throw MDAL_Status::Err_UnknownFormat;
if ( nc_inq_varndims( ncFile.handle(), varyid, &zDimsY ) != NC_NOERR )
throw MDAL_Status::Err_UnknownFormat;
if ( zDimsX != zDimsY )
throw MDAL_Status::Err_UnknownFormat;
std::vector<double> valuesX( nPoints ), valuesY( nPoints );
if ( zDimsX == 1 )
{
// TIME INDEPENDENT
std::shared_ptr<MDAL::MemoryDataset> o = std::make_shared<MDAL::MemoryDataset>( mds.get() );
o->setTime( 0.0 );
double *values = o->values();
std::vector<double> valuesX = ncFile.readDoubleArr( arrXName, nPoints );
std::vector<double> valuesY = ncFile.readDoubleArr( arrYName, nPoints );
for ( size_t i = 0; i < nPoints; ++i )
{
values[2 * i] = valuesX[i];
values[2 * i + 1] = valuesY[i];
}
o->setStatistics( MDAL::calculateStatistics( o ) );
mds->datasets.push_back( o );
}
else
{
// TIME DEPENDENT
for ( size_t t = 0; t < times.size(); ++t )
{
std::shared_ptr<MDAL::MemoryDataset> mto = std::make_shared<MDAL::MemoryDataset>( mds.get() );
mto->setTime( static_cast<double>( times[t] ) / 3600. );
double *values = mto->values();
// fetching data for one timestep
size_t start[2], count[2];
const ptrdiff_t stride[2] = {1, 1};
start[0] = t;
start[1] = 0;
count[0] = 1;
count[1] = nPoints;
nc_get_vars_double( ncFile.handle(), varxid, start, count, stride, valuesX.data() );
nc_get_vars_double( ncFile.handle(), varyid, start, count, stride, valuesY.data() );
for ( size_t i = 0; i < nPoints; ++i )
{
values[2 * i] = static_cast<double>( valuesX[i] );
values[2 * i + 1] = static_cast<double>( valuesY[i] );
}
mto->setStatistics( MDAL::calculateStatistics( mto ) );
mds->datasets.push_back( mto );
}
}
mds->setStatistics( MDAL::calculateStatistics( mds ) );
}
return mds;
}
std::unique_ptr<MDAL::Mesh> MDAL::DriverSWW::load(
const std::string &resultsFile,
MDAL_Status *status )
{
mFileName = resultsFile;
if ( status ) *status = MDAL_Status::None;
int ncid;
int res;
NetCDFFile ncFile;
res = nc_open( mFileName.c_str(), NC_NOWRITE, &ncid );
if ( res != NC_NOERR )
try
{
MDAL::debug( nc_strerror( res ) );
nc_close( ncid );
if ( status ) *status = MDAL_Status::Err_UnknownFormat;
// Open file for reading
ncFile.openFile( mFileName );
// Read mesh
MDAL::Vertices vertices = readVertices( ncFile );
MDAL::Faces faces = readFaces( ncFile );
std::unique_ptr< MDAL::MemoryMesh > mesh(
new MemoryMesh(
name(),
vertices.size(),
faces.size(),
3, // triangles
computeExtent( vertices ),
mFileName
)
);
mesh->faces = faces;
mesh->vertices = vertices;
// Read times
std::vector<double> times = readTimes( ncFile );
// Create a dataset(s)
readDatasetGroups( ncFile, mesh.get(), times );
// Success!
return std::unique_ptr<Mesh>( mesh.release() );
}
catch ( MDAL_Status err )
{
if ( status ) *status = err;
return std::unique_ptr< MDAL::Mesh >();
}
// get dimensions
int nVolumesId, nVerticesId, nPointsId, nTimestepsId;
size_t nVolumes, nVertices, nPoints, nTimesteps;
if ( nc_inq_dimid( ncid, "number_of_volumes", &nVolumesId ) != NC_NOERR ||
nc_inq_dimid( ncid, "number_of_vertices", &nVerticesId ) != NC_NOERR ||
nc_inq_dimid( ncid, "number_of_points", &nPointsId ) != NC_NOERR ||
nc_inq_dimid( ncid, "number_of_timesteps", &nTimestepsId ) != NC_NOERR )
{
nc_close( ncid );
if ( status ) *status = MDAL_Status::Err_UnknownFormat;
return std::unique_ptr< MDAL::Mesh >();
}
if ( nc_inq_dimlen( ncid, nVolumesId, &nVolumes ) != NC_NOERR ||
nc_inq_dimlen( ncid, nVerticesId, &nVertices ) != NC_NOERR ||
nc_inq_dimlen( ncid, nPointsId, &nPoints ) != NC_NOERR ||
nc_inq_dimlen( ncid, nTimestepsId, &nTimesteps ) != NC_NOERR )
{
nc_close( ncid );
if ( status ) *status = MDAL_Status::Err_UnknownFormat;
return std::unique_ptr< MDAL::Mesh >();
}
if ( nVertices != 3 )
{
MDAL::debug( "Expecting triangular elements!" );
nc_close( ncid );
if ( status ) *status = MDAL_Status::Err_UnknownFormat;
return std::unique_ptr< MDAL::Mesh >();
}
int xid, yid, zid, volumesid, timeid, stageid;
if ( nc_inq_varid( ncid, "x", &xid ) != NC_NOERR ||
nc_inq_varid( ncid, "y", &yid ) != NC_NOERR ||
nc_inq_varid( ncid, "volumes", &volumesid ) != NC_NOERR ||
nc_inq_varid( ncid, "time", &timeid ) != NC_NOERR ||
nc_inq_varid( ncid, "stage", &stageid ) != NC_NOERR )
{
nc_close( ncid );
if ( status ) *status = MDAL_Status::Err_UnknownFormat;
return std::unique_ptr< MDAL::Mesh >();
}
// load mesh data
std::vector<float> px( nPoints ), py( nPoints ), pz( nPoints );
std::vector<int> pvolumes( nVertices * nVolumes );
if ( nc_get_var_float( ncid, xid, px.data() ) != NC_NOERR ||
nc_get_var_float( ncid, yid, py.data() ) != NC_NOERR ||
nc_get_var_int( ncid, volumesid, pvolumes.data() ) != NC_NOERR )
{
nc_close( ncid );
if ( status ) *status = MDAL_Status::Err_UnknownFormat;
return std::unique_ptr< MDAL::Mesh >();
}
// we may need to apply a shift to the X,Y coordinates
float xLLcorner = 0, yLLcorner = 0;
nc_get_att_float( ncid, NC_GLOBAL, "xllcorner", &xLLcorner );
nc_get_att_float( ncid, NC_GLOBAL, "yllcorner", &yLLcorner );
MDAL::Vertices nodes( nPoints );
Vertex *nodesPtr = nodes.data();
for ( size_t i = 0; i < nPoints; ++i, ++nodesPtr )
{
nodesPtr->x = static_cast<double>( px[i] + xLLcorner );
nodesPtr->y = static_cast<double>( py[i] + yLLcorner );
}
std::vector<float> times( nTimesteps );
nc_get_var_float( ncid, timeid, times.data() );
int zDims = 0;
if ( nc_inq_varid( ncid, "z", &zid ) == NC_NOERR &&
nc_get_var_float( ncid, zid, pz.data() ) == NC_NOERR )
{
// older SWW format: elevation is constant over time
zDims = 1;
}
else if ( nc_inq_varid( ncid, "elevation", &zid ) == NC_NOERR &&
nc_inq_varndims( ncid, zid, &zDims ) == NC_NOERR &&
( ( zDims == 1 && nc_get_var_float( ncid, zid, pz.data() ) == NC_NOERR ) || zDims == 2 ) )
{
// we're good
}
else
{
// neither "z" nor "elevation" are present -> something is going wrong
nc_close( ncid );
if ( status ) *status = MDAL_Status::Err_UnknownFormat;
return std::unique_ptr< MDAL::Mesh >();
}
MDAL::Faces elements( nVolumes );
for ( size_t i = 0; i < nVolumes; ++i )
{
elements[i].resize( 3 );
elements[i][0] = static_cast<size_t>( pvolumes[3 * i + 0] );
elements[i][1] = static_cast<size_t>( pvolumes[3 * i + 1] );
elements[i][2] = static_cast<size_t>( pvolumes[3 * i + 2] );
}
std::unique_ptr< MDAL::MemoryMesh > mesh(
new MemoryMesh(
nodes.size(),
elements.size(),
3, // triangles
computeExtent( nodes ),
mFileName
)
);
mesh->faces = elements;
mesh->vertices = nodes;
// Create a dataset for the bed elevation
std::shared_ptr<MDAL::DatasetGroup> bedDs = std::make_shared<MDAL::DatasetGroup> (
mesh.get(),
mFileName,
"Bed Elevation" );
bedDs->setIsOnVertices( true );
bedDs->setIsScalar( true );
// read bed elevations
std::vector<std::shared_ptr<MDAL::MemoryDataset>> elevationOutputs;
if ( zDims == 1 )
{
// either "z" or "elevation" with 1 dimension
std::shared_ptr<MDAL::MemoryDataset> o = std::make_shared<MDAL::MemoryDataset>( bedDs.get() );
o->setTime( 0.0 );
double *values = o->values();
for ( size_t i = 0; i < nPoints; ++i )
{
double z = static_cast<double>( pz[i] );
values[i] = z;
mesh->vertices[i].z = z;
}
o->setStatistics( MDAL::calculateStatistics( o ) );
bedDs->datasets.push_back( o );
elevationOutputs.push_back( o );
}
else if ( zDims == 2 )
{
// newer SWW format: elevation may change over time
for ( size_t t = 0; t < nTimesteps; ++t )
{
std::shared_ptr<MDAL::MemoryDataset> toe = std::make_shared<MDAL::MemoryDataset>( bedDs.get() );
toe->setTime( static_cast<double>( times[t] ) / 3600. );
double *elev = toe->values();
// fetching "elevation" data for one timestep
size_t start[2], count[2];
const ptrdiff_t stride[2] = {1, 1};
start[0] = t;
start[1] = 0;
count[0] = 1;
count[1] = nPoints;
std::vector<float> buffer( nPoints );
nc_get_vars_float( ncid, zid, start, count, stride, buffer.data() );
for ( size_t i = 0; i < nPoints; ++i )
{
double val = static_cast<double>( buffer[i] );
elev[i] = val;
}
toe->setStatistics( MDAL::calculateStatistics( toe ) );
bedDs->datasets.push_back( toe );
elevationOutputs.push_back( toe );
}
}
bedDs->setStatistics( MDAL::calculateStatistics( bedDs ) );
mesh->datasetGroups.push_back( bedDs );
// load results
std::shared_ptr<MDAL::DatasetGroup> dss = std::make_shared<MDAL::DatasetGroup> (
mesh.get(),
mFileName,
"Stage" );
dss->setIsOnVertices( true );
dss->setIsScalar( true );
std::shared_ptr<MDAL::DatasetGroup> dsd = std::make_shared<MDAL::DatasetGroup> (
mesh.get(),
mFileName,
"Depth" );
dsd->setIsOnVertices( true );
dsd->setIsScalar( true );
for ( size_t t = 0; t < nTimesteps; ++t )
{
const std::shared_ptr<MDAL::MemoryDataset> elevO = elevationOutputs.size() > 1 ? elevationOutputs[t] : elevationOutputs[0];
const double *elev = elevO->constValues();
std::shared_ptr<MDAL::MemoryDataset> tos = std::make_shared<MDAL::MemoryDataset>( dss.get() );
tos->setTime( static_cast<double>( times[t] ) / 3600. );
double *values = tos->values();
// fetching "stage" data for one timestep
size_t start[2], count[2];
const ptrdiff_t stride[2] = {1, 1};
start[0] = t;
start[1] = 0;
count[0] = 1;
count[1] = nPoints;
std::vector<float> buffer( nPoints );
nc_get_vars_float( ncid, stageid, start, count, stride, buffer.data() );
for ( size_t i = 0; i < nPoints; ++i )
{
double val = static_cast<double>( buffer[i] );
values[i] = val;
}
// derived data: depth = stage - elevation
std::shared_ptr<MDAL::MemoryDataset> tod = std::make_shared<MDAL::MemoryDataset>( dsd.get() );
tod->setTime( tos->time() );
double *depths = tod->values();
int *activeTos = tos->active();
int *activeTod = tod->active();
for ( size_t j = 0; j < nPoints; ++j )
depths[j] = values[j] - elev[j];
// determine which elements are active (wet)
for ( size_t elemidx = 0; elemidx < nVolumes; ++elemidx )
{
const Face &elem = mesh->faces[elemidx];
double v0 = depths[elem[0]];
double v1 = depths[elem[1]];
double v2 = depths[elem[2]];
activeTos[elemidx] = v0 > DEPTH_THRESHOLD && v1 > DEPTH_THRESHOLD && v2 > DEPTH_THRESHOLD;
activeTod[elemidx] = activeTos[elemidx];
}
tos->setStatistics( MDAL::calculateStatistics( tos ) );
dss->datasets.push_back( tos );
tod->setStatistics( MDAL::calculateStatistics( tod ) );
dsd->datasets.push_back( tod );
}
dss->setStatistics( MDAL::calculateStatistics( dss ) );
mesh->datasetGroups.push_back( dss );
dsd->setStatistics( MDAL::calculateStatistics( dsd ) );
mesh->datasetGroups.push_back( dsd );
int momentumxid, momentumyid;
if ( nc_inq_varid( ncid, "xmomentum", &momentumxid ) == NC_NOERR &&
nc_inq_varid( ncid, "ymomentum", &momentumyid ) == NC_NOERR )
{
std::shared_ptr<MDAL::DatasetGroup> mds = std::make_shared<MDAL::DatasetGroup> (
mesh.get(),
mFileName,
"Momentum" );
mds->setIsOnVertices( true );
mds->setIsScalar( false );
std::vector<float> valuesX( nPoints ), valuesY( nPoints );
for ( size_t t = 0; t < nTimesteps; ++t )
{
std::shared_ptr<MDAL::MemoryDataset> mto = std::make_shared<MDAL::MemoryDataset>( mds.get() );
mto->setTime( static_cast<double>( times[t] ) / 3600. );
double *values = mto->values();
std::shared_ptr<MDAL::MemoryDataset> mto0 = std::static_pointer_cast<MDAL::MemoryDataset>( dsd->datasets[t] );
memcpy( mto->active(), mto0->active(), mesh->facesCount() * sizeof( int ) );
// fetching "stage" data for one timestep
size_t start[2], count[2];
const ptrdiff_t stride[2] = {1, 1};
start[0] = t;
start[1] = 0;
count[0] = 1;
count[1] = nPoints;
nc_get_vars_float( ncid, momentumxid, start, count, stride, valuesX.data() );
nc_get_vars_float( ncid, momentumyid, start, count, stride, valuesY.data() );
for ( size_t i = 0; i < nPoints; ++i )
{
values[2 * i] = static_cast<double>( valuesX[i] );
values[2 * i + 1] = static_cast<double>( valuesY[i] );
}
mto->setStatistics( MDAL::calculateStatistics( mto ) );
mds->datasets.push_back( mto );
}
mds->setStatistics( MDAL::calculateStatistics( mds ) );
mesh->datasetGroups.push_back( mds );
}
nc_close( ncid );
return std::unique_ptr<Mesh>( mesh.release() );
}

View File

@ -7,15 +7,32 @@
#define MDAL_SWW_HPP
#include <string>
#include <memory>
#include <vector>
#include <map>
#include <utility>
#include "mdal_data_model.hpp"
#include "mdal_memory_data_model.hpp"
#include "mdal.h"
#include "mdal_driver.hpp"
#include "mdal_netcdf.hpp"
namespace MDAL
{
// AnuGA format with extension .SWW
/**
* AnuGA format with extension .SWW
*
* The format is based on NetCDF storage
*
* Bed Elevation can be static (== one bed elevation for all timesteps, stored
* in "z" variable or "elevation" variable)
* or dynamic (each timestep has its own elevation data, stored in "elevation"
* variable with multiple dimensions)
*
* Vector data are recognized by prefix "x" and "y" in the name
* Maximums data are recognized by suffix "_range" in the name
*/
class DriverSWW: public Driver
{
public:
@ -25,7 +42,43 @@ namespace MDAL
std::unique_ptr< Mesh > load( const std::string &resultsFile, MDAL_Status *status ) override;
bool canRead( const std::string &uri ) override;
private:
size_t getVertexCount( const NetCDFFile &ncFile ) const;
std::vector<double> readZCoords( const NetCDFFile &ncFile ) const;
MDAL::Vertices readVertices( const NetCDFFile &ncFile ) const;
MDAL::Faces readFaces( const NetCDFFile &ncFile ) const;
std::vector<double> readTimes( const NetCDFFile &ncFile ) const;
/**
* Finds all variables (arrays) in netcdf file and base on the name add it as
* vector or scalar dataset group
*/
void readDatasetGroups( const NetCDFFile &ncFile, MDAL::MemoryMesh *mesh, const std::vector<double> &times ) const;
bool parseGroupName( std::string &groupName, std::string &xName, std::string &yName ) const;
std::shared_ptr<MDAL::DatasetGroup> readScalarGroup(
const NetCDFFile &ncFile,
MDAL::MemoryMesh *mesh,
const std::vector<double> &times,
const std::string variableBaseName,
const std::string arrName
) const;
std::shared_ptr<MDAL::DatasetGroup> readVectorGroup(
const NetCDFFile &ncFile,
MDAL::MemoryMesh *mesh,
const std::vector<double> &times,
const std::string variableBaseName,
const std::string arrXName,
const std::string arrYName
) const;
void addBedElevation(
const NetCDFFile &ncFile,
MDAL::MemoryMesh *mesh,
const std::vector<double> &times
) const;
std::string mFileName;
};
} // namespace MDAL

View File

@ -89,7 +89,7 @@ MDAL::DriverXmdf::DriverXmdf()
: Driver( "XMDF",
"TUFLOW XMDF",
"*.xmdf",
DriverType::CanReadOnlyDatasets )
Capability::ReadDatasets )
{
}
@ -139,6 +139,7 @@ void MDAL::DriverXmdf::load( const std::string &datFile, MDAL::Mesh *mesh, MDAL
size_t vertexCount = mesh->verticesCount();
size_t faceCount = mesh->facesCount();
std::vector<std::string> rootGroups = file.groups();
if ( rootGroups.size() != 1 )
{
@ -147,44 +148,21 @@ void MDAL::DriverXmdf::load( const std::string &datFile, MDAL::Mesh *mesh, MDAL
return;
}
HdfGroup gMesh = file.group( rootGroups[0] );
// TODO: read Times group (e.g. time of peak velocity)
DatasetGroups groups; // DAT outputs data
if ( gMesh.pathExists( "Temporal" ) )
for ( const std::string &groupName : gMesh.groups() )
{
HdfGroup gTemporal = gMesh.group( "Temporal" );
if ( gTemporal.isValid() )
HdfGroup gGroup = gMesh.group( groupName );
if ( gGroup.isValid() )
{
addDatasetGroupsFromXmdfGroup( groups, gTemporal, vertexCount, faceCount );
}
}
if ( gMesh.pathExists( "Temporal" ) )
{
HdfGroup gMaximums = gMesh.group( "Maximums" );
if ( gMaximums.isValid() )
{
for ( const std::string &name : gMaximums.groups() )
if ( groupName == "Maximums" )
{
HdfGroup g = gMaximums.group( name );
std::shared_ptr<MDAL::DatasetGroup> maxGroup = readXmdfGroupAsDatasetGroup( g, name + "/Maximums", vertexCount, faceCount );
if ( !maxGroup || maxGroup->datasets.size() != 1 )
MDAL::debug( "Maximum dataset should have just one timestep!" );
else
groups.push_back( maxGroup );
addDatasetGroupsFromXmdfGroup( groups, gGroup, "/Maximums", vertexCount, faceCount );
}
else
{
addDatasetGroupsFromXmdfGroup( groups, gGroup, "", vertexCount, faceCount );
}
}
}
// res_to_res.exe (TUFLOW utiity tool)
if ( gMesh.pathExists( "Difference" ) )
{
HdfGroup gDifference = gMesh.group( "Difference" );
if ( gDifference.isValid() )
{
addDatasetGroupsFromXmdfGroup( groups, gDifference, vertexCount, faceCount );
}
}
@ -195,20 +173,26 @@ void MDAL::DriverXmdf::load( const std::string &datFile, MDAL::Mesh *mesh, MDAL
);
}
void MDAL::DriverXmdf::addDatasetGroupsFromXmdfGroup( DatasetGroups &groups, const HdfGroup &rootGroup, size_t vertexCount, size_t faceCount )
void MDAL::DriverXmdf::addDatasetGroupsFromXmdfGroup( DatasetGroups &groups,
const HdfGroup &rootGroup,
const std::string &nameSuffix,
size_t vertexCount,
size_t faceCount )
{
for ( const std::string &name : rootGroup.groups() )
for ( const std::string &groupName : rootGroup.groups() )
{
HdfGroup g = rootGroup.group( name );
std::shared_ptr<DatasetGroup> ds = readXmdfGroupAsDatasetGroup( g, name, vertexCount, faceCount );
HdfGroup g = rootGroup.group( groupName );
std::shared_ptr<DatasetGroup> ds = readXmdfGroupAsDatasetGroup( g, groupName + nameSuffix, vertexCount, faceCount );
if ( ds && ds->datasets.size() > 0 )
{
groups.push_back( ds );
}
}
}
std::shared_ptr<MDAL::DatasetGroup> MDAL::DriverXmdf::readXmdfGroupAsDatasetGroup(
const HdfGroup &rootGroup, const std::string &name, size_t vertexCount, size_t faceCount )
const HdfGroup &rootGroup, const std::string &groupName, size_t vertexCount, size_t faceCount )
{
std::shared_ptr<DatasetGroup> group;
std::vector<std::string> gDataNames = rootGroup.datasets();
@ -218,7 +202,7 @@ std::shared_ptr<MDAL::DatasetGroup> MDAL::DriverXmdf::readXmdfGroupAsDatasetGrou
!MDAL::contains( gDataNames, "Mins" ) ||
!MDAL::contains( gDataNames, "Maxs" ) )
{
MDAL::debug( "ignoring dataset " + name + " - not having required arrays" );
MDAL::debug( "ignoring dataset " + groupName + " - not having required arrays" );
return group;
}
@ -241,7 +225,7 @@ std::shared_ptr<MDAL::DatasetGroup> MDAL::DriverXmdf::readXmdfGroupAsDatasetGrou
dimMaxs.size() != 1
)
{
MDAL::debug( "ignoring dataset " + name + " - arrays not having correct dimension counts" );
MDAL::debug( "ignoring dataset " + groupName + " - arrays not having correct dimension counts" );
return group;
}
hsize_t nTimeSteps = dimTimes[0];
@ -251,12 +235,12 @@ std::shared_ptr<MDAL::DatasetGroup> MDAL::DriverXmdf::readXmdfGroupAsDatasetGrou
dimMins[0] != nTimeSteps ||
dimMaxs[0] != nTimeSteps )
{
MDAL::debug( "ignoring dataset " + name + " - arrays not having correct dimension sizes" );
MDAL::debug( "ignoring dataset " + groupName + " - arrays not having correct dimension sizes" );
return group;
}
if ( dimValues[1] != vertexCount || dimActive[1] != faceCount )
{
MDAL::debug( "ignoring dataset " + name + " - not aligned with the used mesh" );
MDAL::debug( "ignoring dataset " + groupName + " - not aligned with the used mesh" );
return group;
}
@ -266,9 +250,10 @@ std::shared_ptr<MDAL::DatasetGroup> MDAL::DriverXmdf::readXmdfGroupAsDatasetGrou
// all fine, set group and return
group = std::make_shared<MDAL::DatasetGroup>(
name(),
mMesh,
mDatFile,
name
groupName
);
group->setIsScalar( !isVector );
group->setIsOnVertices( true );

View File

@ -58,6 +58,26 @@ namespace MDAL
class DriverXmdf: public Driver
{
public:
/**
* Driver for XMDF Files
*
* Structure of the TUFLOW file. Groups are optional since it depends
* on tools which groups are created.
* - root
* - Temporal
* - Depth
* - Velocity
* - ..
* - Maximums
* - Depth
* - Velocity
* - ..
* - Difference (res_to_res.exe TUFLOW utility tool)
* - ..
* - Times (e.g. time of peak velocity)
* - ..
* - ...
*/
DriverXmdf();
~DriverXmdf( ) override = default;
DriverXmdf *create() override;
@ -70,13 +90,14 @@ namespace MDAL
std::string mDatFile;
std::shared_ptr<MDAL::DatasetGroup> readXmdfGroupAsDatasetGroup(
const HdfGroup &rootGroup,
const std::string &name,
const std::string &groupName,
size_t vertexCount,
size_t faceCount );
void addDatasetGroupsFromXmdfGroup(
DatasetGroups &groups,
const HdfGroup &rootGroup,
const std::string &nameSuffix,
size_t vertexCount,
size_t faceCount );
};

220
external/mdal/mdal.cpp vendored
View File

@ -12,6 +12,7 @@
#include "mdal.h"
#include "mdal_driver_manager.hpp"
#include "mdal_data_model.hpp"
#include "mdal_utils.hpp"
#define NODATA std::numeric_limits<double>::quiet_NaN()
@ -21,7 +22,7 @@ static MDAL_Status sLastStatus;
const char *MDAL_Version()
{
return "0.1.2";
return "0.1.4";
}
MDAL_Status MDAL_LastStatus()
@ -50,6 +51,12 @@ int MDAL_driverCount()
DriverH MDAL_driverFromIndex( int index )
{
if ( index < 0 )
{
sLastStatus = MDAL_Status::Err_MissingDriver;
return nullptr;
}
size_t idx = static_cast<size_t>( index );
std::shared_ptr<MDAL::Driver> driver = MDAL::DriverManager::instance().driver( idx );
return static_cast<DriverH>( driver.get() );
@ -71,7 +78,18 @@ bool MDAL_DR_meshLoadCapability( DriverH driver )
}
MDAL::Driver *d = static_cast< MDAL::Driver * >( driver );
return d->type() == MDAL::DriverType::CanReadMeshAndDatasets;
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 );
}
const char *MDAL_DR_longName( DriverH driver )
@ -262,6 +280,72 @@ DatasetGroupH MDAL_M_datasetGroup( MeshH mesh, int 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
///////////////////////////////////////////////////////////////////////////////////////
@ -506,6 +590,138 @@ void MDAL_G_minimumMaximum( DatasetGroupH group, double *min, double *max )
*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<MDAL::Driver> 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<MDAL::Driver> 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;
}
}
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

View File

@ -17,6 +17,11 @@ MDAL::Dataset::Dataset( MDAL::DatasetGroup *parent )
assert( mParent );
}
std::string MDAL::Dataset::driverName() const
{
return group()->driverName();
}
size_t MDAL::Dataset::valuesCount() const
{
if ( group()->isOnVertices() )
@ -69,20 +74,30 @@ void MDAL::Dataset::setIsValid( bool isValid )
mIsValid = isValid;
}
MDAL::DatasetGroup::DatasetGroup( MDAL::Mesh *parent,
MDAL::DatasetGroup::DatasetGroup( const std::string &driverName,
MDAL::Mesh *parent,
const std::string &uri,
const std::string &name )
: mParent( parent )
: mDriverName( driverName )
, mParent( parent )
, mUri( uri )
{
assert( mParent );
setName( name );
}
std::string MDAL::DatasetGroup::driverName() const
{
return mDriverName;
}
MDAL::DatasetGroup::~DatasetGroup() = default;
MDAL::DatasetGroup::DatasetGroup( MDAL::Mesh *parent, const std::string &uri )
: mParent( parent )
MDAL::DatasetGroup::DatasetGroup( const std::string &driverName,
MDAL::Mesh *parent,
const std::string &uri )
: mDriverName( driverName )
, mParent( parent )
, mUri( uri )
{
assert( mParent );
@ -145,6 +160,21 @@ MDAL::Mesh *MDAL::DatasetGroup::mesh() const
return mParent;
}
bool MDAL::DatasetGroup::isInEditMode() const
{
return mInEditMode;
}
void MDAL::DatasetGroup::startEditing()
{
mInEditMode = true;
}
void MDAL::DatasetGroup::stopEditing()
{
mInEditMode = false;
}
bool MDAL::DatasetGroup::isOnVertices() const
{
return mIsOnVertices;
@ -171,8 +201,15 @@ void MDAL::DatasetGroup::setIsScalar( bool isScalar )
mIsScalar = isScalar;
}
MDAL::Mesh::Mesh( size_t verticesCount, size_t facesCount, size_t faceVerticesMaximumCount, MDAL::BBox extent, const std::string &uri )
: mVerticesCount( verticesCount )
MDAL::Mesh::Mesh(
const std::string &driverName,
size_t verticesCount,
size_t facesCount,
size_t faceVerticesMaximumCount,
MDAL::BBox extent,
const std::string &uri )
: mDriverName( driverName )
, mVerticesCount( verticesCount )
, mFacesCount( facesCount )
, mFaceVerticesMaximumCount( faceVerticesMaximumCount )
, mExtent( extent )
@ -180,6 +217,11 @@ MDAL::Mesh::Mesh( size_t verticesCount, size_t facesCount, size_t faceVerticesMa
{
}
std::string MDAL::Mesh::driverName() const
{
return mDriverName;
}
MDAL::Mesh::~Mesh() = default;
void MDAL::Mesh::setSourceCrs( const std::string &str )

View File

@ -44,6 +44,8 @@ namespace MDAL
Dataset( DatasetGroup *parent );
virtual ~Dataset();
std::string driverName() const;
size_t valuesCount() const;
virtual size_t scalarData( size_t indexStart, size_t count, double *buffer ) = 0;
virtual size_t vectorData( size_t indexStart, size_t count, double *buffer ) = 0;
@ -73,15 +75,20 @@ namespace MDAL
class DatasetGroup
{
public:
DatasetGroup( Mesh *parent,
const std::string &uri );
DatasetGroup( const std::string &driverName,
Mesh *parent,
const std::string &uri
);
DatasetGroup( Mesh *parent,
DatasetGroup( const std::string &driverName,
Mesh *parent,
const std::string &uri,
const std::string &name );
~DatasetGroup();
std::string driverName() const;
std::string getMetadata( const std::string &key );
void setMetadata( const std::string &key, const std::string &val );
@ -104,7 +111,14 @@ namespace MDAL
Mesh *mesh() const;
bool isInEditMode() const;
void startEditing();
void stopEditing();
private:
bool mInEditMode = false;
const std::string mDriverName;
Mesh *mParent = nullptr;
bool mIsScalar = true;
bool mIsOnVertices = true;
@ -136,13 +150,16 @@ namespace MDAL
class Mesh
{
public:
Mesh( size_t verticesCount,
Mesh( const std::string &driverName,
size_t verticesCount,
size_t facesCount,
size_t faceVerticesMaximumCount,
BBox extent,
const std::string &uri );
virtual ~Mesh();
std::string driverName() const;
void setSourceCrs( const std::string &str );
void setSourceCrsFromWKT( const std::string &wkt );
void setSourceCrsFromEPSG( int code );
@ -165,6 +182,7 @@ namespace MDAL
size_t faceVerticesMaximumCount() const;
private:
const std::string mDriverName;
size_t mVerticesCount = 0;
size_t mFacesCount = 0;
size_t mFaceVerticesMaximumCount = 0; //typically 3 or 4, sometimes up to 9

View File

@ -41,7 +41,7 @@ std::unique_ptr<MDAL::Mesh> MDAL::DriverManager::load( const std::string &meshFi
for ( const auto &driver : mDrivers )
{
if ( ( driver->type() == DriverType::CanReadMeshAndDatasets ) &&
if ( ( driver->hasCapability( Capability::ReadMesh ) ) &&
driver->canRead( meshFile ) )
{
std::unique_ptr<Driver> drv( driver->create() );
@ -73,7 +73,7 @@ void MDAL::DriverManager::loadDatasets( Mesh *mesh, const std::string &datasetFi
for ( const auto &driver : mDrivers )
{
if ( ( driver->type() == DriverType::CanReadOnlyDatasets ) &&
if ( driver->hasCapability( Capability::ReadDatasets ) &&
driver->canRead( datasetFile ) )
{
std::unique_ptr<Driver> drv( driver->create() );
@ -93,7 +93,7 @@ size_t MDAL::DriverManager::driversCount() const
std::shared_ptr<MDAL::Driver> MDAL::DriverManager::driver( size_t index ) const
{
if ( mDrivers.size() < index )
if ( mDrivers.size() <= index )
{
return std::shared_ptr<MDAL::Driver>();
}

View File

@ -91,8 +91,18 @@ size_t MDAL::MemoryDataset::vectorData( size_t indexStart, size_t count, double
return copyValues;
}
MDAL::MemoryMesh::MemoryMesh( size_t verticesCount, size_t facesCount, size_t faceVerticesMaximumCount, MDAL::BBox extent, const std::string &uri )
: MDAL::Mesh( verticesCount, facesCount, faceVerticesMaximumCount, extent, uri )
MDAL::MemoryMesh::MemoryMesh( const std::string &driverName,
size_t verticesCount,
size_t facesCount,
size_t faceVerticesMaximumCount,
MDAL::BBox extent,
const std::string &uri )
: MDAL::Mesh( driverName,
verticesCount,
facesCount,
faceVerticesMaximumCount,
extent,
uri )
{
}

View File

@ -78,7 +78,8 @@ namespace MDAL
class MemoryMesh: public Mesh
{
public:
MemoryMesh( size_t verticesCount,
MemoryMesh( const std::string &driverName,
size_t verticesCount,
size_t facesCount,
size_t faceVerticesMaximumCount,
BBox extent,

View File

@ -24,6 +24,9 @@ bool MDAL::fileExists( const std::string &filename )
bool MDAL::startsWith( const std::string &str, const std::string &substr, ContainsBehaviour behaviour )
{
if ( str.size() < substr.size() )
return false;
if ( behaviour == ContainsBehaviour::CaseSensitive )
return str.rfind( substr, 0 ) == 0;
else
@ -32,6 +35,9 @@ bool MDAL::startsWith( const std::string &str, const std::string &substr, Contai
bool MDAL::endsWith( const std::string &str, const std::string &substr, ContainsBehaviour behaviour )
{
if ( str.size() < substr.size() )
return false;
if ( behaviour == ContainsBehaviour::CaseSensitive )
return str.rfind( substr ) == ( str.size() - substr.size() );
else
@ -182,6 +188,21 @@ std::string MDAL::join( const std::vector<std::string> parts, const std::string
return res.str();
}
std::string MDAL::leftJustified( const std::string &str, size_t width, char fill )
{
std::string ret( str );
if ( ret.size() > width )
{
ret = ret.substr( 0, width );
}
else
{
ret = ret + std::string( width - ret.size(), fill );
}
assert( ret.size() == width );
return ret;
}
std::string MDAL::toLower( const std::string &std )
{
std::string res( std );
@ -222,11 +243,22 @@ std::string MDAL::replace( const std::string &str, const std::string &substr, co
return res;
}
std::string MDAL::removeLastChar( const std::string &str )
// http://www.cplusplus.com/faq/sequences/strings/trim/
std::string MDAL::trim( const std::string &s, const std::string &delimiters )
{
std::string ret( str );
ret.pop_back();
return ret;
return ltrim( rtrim( s, delimiters ), delimiters );
}
// http://www.cplusplus.com/faq/sequences/strings/trim/
std::string MDAL::ltrim( const std::string &s, const std::string &delimiters )
{
return s.substr( s.find_first_not_of( delimiters ) );
}
// http://www.cplusplus.com/faq/sequences/strings/trim/
std::string MDAL::rtrim( const std::string &s, const std::string &delimiters )
{
return s.substr( 0, s.find_last_not_of( delimiters ) + 1 );
}
MDAL::BBox MDAL::computeExtent( const MDAL::Vertices &vertices )
@ -348,7 +380,12 @@ MDAL::Statistics _calculateStatistics( const std::vector<double> &values, size_t
return ret;
}
MDAL::Statistics MDAL::calculateStatistics( std::shared_ptr<DatasetGroup> grp )
MDAL::Statistics MDAL::calculateStatistics( std::shared_ptr<MDAL::DatasetGroup> grp )
{
return calculateStatistics( grp.get() );
}
MDAL::Statistics MDAL::calculateStatistics( DatasetGroup *grp )
{
Statistics ret;
if ( !grp )
@ -416,6 +453,7 @@ void MDAL::addBedElevationDatasetGroup( MDAL::Mesh *mesh, const Vertices &vertic
return;
std::shared_ptr<DatasetGroup> group = std::make_shared< DatasetGroup >(
mesh->driverName(),
mesh,
mesh->uri(),
"Bed Elevation"

View File

@ -47,7 +47,8 @@ namespace MDAL
bool contains( const std::string &str, const std::string &substr, ContainsBehaviour behaviour = CaseSensitive );
bool contains( const std::vector<std::string> &list, const std::string &str );
std::string replace( const std::string &str, const std::string &substr, const std::string &replacestr, ContainsBehaviour behaviour = CaseSensitive );
std::string removeLastChar( const std::string &str );
//! left justify and truncate, resulting string will always have width chars
std::string leftJustified( const std::string &str, size_t width, char fill = ' ' );
std::string toLower( const std::string &std );
@ -66,29 +67,20 @@ namespace MDAL
std::vector<std::string> split( const std::string &str, const std::string &delimiter, SplitBehaviour behaviour );
std::string join( const std::vector<std::string> parts, const std::string &delimiter );
// http://www.cplusplus.com/faq/sequences/strings/trim/
inline std::string rtrim(
//! Right trim
std::string rtrim(
const std::string &s,
const std::string &delimiters = " \f\n\r\t\v" )
{
return s.substr( 0, s.find_last_not_of( delimiters ) + 1 );
}
const std::string &delimiters = " \f\n\r\t\v" );
// http://www.cplusplus.com/faq/sequences/strings/trim/
inline std::string ltrim(
//! Left trim
std::string ltrim(
const std::string &s,
const std::string &delimiters = " \f\n\r\t\v" )
{
return s.substr( s.find_first_not_of( delimiters ) );
}
const std::string &delimiters = " \f\n\r\t\v" );
// http://www.cplusplus.com/faq/sequences/strings/trim/
inline std::string trim(
//! Right and left trim
std::string trim(
const std::string &s,
const std::string &delimiters = " \f\n\r\t\v" )
{
return ltrim( rtrim( s, delimiters ), delimiters );
}
const std::string &delimiters = " \f\n\r\t\v" );
// extent
BBox computeExtent( const Vertices &vertices );
@ -102,6 +94,7 @@ namespace MDAL
//! Calculates statistics for dataset group
Statistics calculateStatistics( std::shared_ptr<DatasetGroup> grp );
Statistics calculateStatistics( DatasetGroup *grp );
//! Calculates statistics for dataset
Statistics calculateStatistics( std::shared_ptr<Dataset> dataset );

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="900" height="600" viewBox="0 0 30 20">
<defs>
<path id="s" d="M0,-1 0.587785,0.809017 -0.951057,-0.309017H0.951057L-0.587785,0.809017z" fill="#ffde00"/>
</defs>
<rect width="30" height="20" fill="#de2910"/>
<use xlink:href="#s" transform="translate(5,5) scale(3)"/>
<use xlink:href="#s" transform="translate(10,2) rotate(23.036243)"/>
<use xlink:href="#s" transform="translate(12,4) rotate(45.869898)"/>
<use xlink:href="#s" transform="translate(12,7) rotate(69.945396)"/>
<use xlink:href="#s" transform="translate(10,9) rotate(20.659808)"/>
</svg>

Before

Width:  |  Height:  |  Size: 688 B

View File

@ -63,7 +63,6 @@
<file>flags/sr.svg</file>
<file>flags/te.svg</file>
<file>flags/tl.svg</file>
<file>flags/zh.svg</file>
<file>flags/zh-Hans.svg</file>
<file>flags/zh-Hant.svg</file>
<file>flags/ky.svg</file>
@ -379,6 +378,7 @@
<file>themes/default/mActionShowPinnedLabels.svg</file>
<file>themes/default/mActionShowPluginManager.svg</file>
<file>themes/default/mActionShowRasterCalculator.png</file>
<file>themes/default/mActionShowMeshCalculator.svg</file>
<file>themes/default/mActionShowSelectedLayers.svg</file>
<file>themes/default/mActionSimplify.svg</file>
<file>themes/default/mActionSplitFeatures.svg</file>
@ -742,6 +742,8 @@
<file>themes/default/mIconFolder24.svg</file>
<file>themes/default/mActionNewFolder.svg</file>
<file>themes/default/mIconFieldBool.svg</file>
<file>themes/default/mIconDataDefineColor.svg</file>
<file>themes/default/mIconDataDefineColorOn.svg</file>
</qresource>
<qresource prefix="/images/tips">
<file alias="symbol_levels.png">qgis_tips/symbol_levels.png</file>

View File

@ -0,0 +1 @@
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient id="a" x1="16.1" x2="10.9" y1="13" y2="9.09" gradientTransform="matrix(.476 0 0 .518 .336 -3.21)" gradientUnits="userSpaceOnUse"><stop stop-color="#aec7e2" offset="0"/><stop stop-color="#eee" offset="1"/></linearGradient><linearGradient id="b" x1="4.53" x2="4.46" y1="22.4" y2="25.1" gradientTransform="matrix(.719 0 0 2.45 .0312 -52.3)" gradientUnits="userSpaceOnUse"><stop stop-color="#eee" offset="0"/><stop stop-color="#aec7e2" offset="1"/></linearGradient></defs><path d="m4.5 9h1.5v2h-1.5z" fill="#cfcfcf"/><path d="m1 1v10h2.5v-10z" fill="url(#b)"/><path d="m4.5 1v7h5.5v-7z" fill="url(#a)"/><path d="m7 8.5h15" fill="none" stroke="#5b5b5c"/><path d="m7 13.5h15" fill="none" stroke="#5b5b5c"/><path d="m7 18.5h15" fill="none" stroke="#5b5b5c"/><circle cx="13" cy="8.5" r="1.5" fill="#f7aeae" fill-opacity=".996" fill-rule="evenodd" overflow="visible" stroke="#a20404"/><path d="m22.5 7.01v15" fill="none" stroke="#5b5b5c" stroke-linecap="round"/><path d="m6.5 7.01v15" fill="none" stroke="#5b5b5c" stroke-linecap="round"/><circle cx="15" cy="13.5" r="1.5" fill="#c5f7c5" fill-rule="evenodd" overflow="visible" stroke="#619361"/><circle cx="11" cy="13.5" r="1.5" fill="#c5f7c5" fill-rule="evenodd" overflow="visible" stroke="#619361"/><circle cx="11" cy="18.5" r="1.5" fill="#c2e0f4" fill-rule="evenodd" overflow="visible" stroke="#3f5e71"/><circle cx="15" cy="18.5" r="1.5" fill="#c2e0f4" fill-rule="evenodd" overflow="visible" stroke="#3f5e71"/><circle cx="19" cy="18.5" r="1.5" fill="#c2e0f4" fill-rule="evenodd" overflow="visible" stroke="#3f5e71"/><rect x="5" y="22" width="19" height="2" rx="0" ry="0" fill="#5b5b5c" stroke-width="0" style="paint-order:stroke markers fill"/><circle cx="19" cy="8.5" r="1.5" fill="#f7aeae" fill-opacity=".996" fill-rule="evenodd" overflow="visible" stroke="#a20404"/><path d="m10.5 8v-7.5h-10v11h5.5" fill="none" stroke="#2b3b4d"/><path d="m4 11v-10" stroke="#2b3b4d"/><path d="m1 8.5h5" stroke="#2b3b4d"/><path d="m4 8.5 6.5-8" stroke="#2b3b4d"/></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="4 4 24 24" width="24"><path d="M9.5 19.892c0 .836-.284 1.193-.631.792l-3.771-4.351a1.15 1.15 0 0 1 0-1.459l3.771-4.359c.347-.402.631-.045.631.792z" fill="#939598" stroke="#4f5052"/><path d="M9.341 8.199v15.156h12.514V8.199z" fill="none"/><path d="M9.5 8.5v15h12v-15z" fill="#fff" fill-opacity=".703" stroke="#878984" stroke-linecap="round" stroke-linejoin="round"/><path d="M12.954 11.868c-1.483 1.602-1.146-.264-.257-.906.921-.666 1.438-.649 1.431-.446-.008.238-.707.848-1.174 1.352zm-.498 5.16c-1.485 1.601-1.23.119-.34-.52.92-.663 1.437-.646 1.43-.443-.008.238-.626.462-1.09.963zm6.517 1.789c-1.432 1.598-1.322.08-.402-.509.702-.449.909-.06.402.509z" fill="#fff" opacity=".5"/><path d="M18.5 18v1.605c0 2.474-6 2.525-6-.18v-2.397c-.054-1.277.458-2.528 3-2.528v2c-.645.02-.995.748-1 1.212v.436c0 1.852 2 1.56 2 .185V18" fill="none" stroke="#2c2c2c" stroke-opacity=".706"/><path d="M13.5 14v-1.605c0-2.474 6-2.525 6 .18v2.397c.054 1.277-.458 2.528-3 2.528v-2c.645-.02.995-.748 1-1.212v-.436c0-1.852-2-1.56-2-.185V14" fill="none" stroke="#2c2c2c" stroke-opacity=".706"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="4 4 24 24" width="24"><path d="M9.5 19.892c0 .836-.284 1.193-.631.792l-3.771-4.351a1.15 1.15 0 0 1 0-1.459l3.771-4.359c.347-.402.631-.045.631.792z" fill="#939598" stroke="#4f5052"/><path d="M9.341 8.199v15.156h12.514V8.199z" fill="#fff"/><path d="M9.5 8.5v15h12v-15z" fill="#fbf091" stroke="#c4a000" stroke-linecap="round" stroke-linejoin="round"/><path d="M18.5 18v1.605c0 2.474-6 2.525-6-.18v-2.397c-.054-1.277.458-2.528 3-2.528v2c-.645.02-.995.748-1 1.212v.436c0 1.852 2 1.56 2 .185V18" fill="none" stroke="#2c2c2c" stroke-opacity=".706"/><path d="M13.5 14v-1.605c0-2.474 6-2.525 6 .18v2.397c.054 1.277-.458 2.528-3 2.528v-2c.645-.02.995-.748 1-1.212v-.436c0-1.852-2-1.56-2-.185V14" fill="none" stroke="#2c2c2c" stroke-opacity=".706"/></svg>

After

Width:  |  Height:  |  Size: 805 B

View File

@ -43,8 +43,8 @@ call "%PF86%\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %VCARCH%
path %path%;%PF86%\Microsoft Visual Studio 14.0\VC\bin
set GRASS7=
if exist %OSGEO4W_ROOT%\bin\grass72.bat set GRASS7=%OSGEO4W_ROOT%\bin\grass72.bat
if exist %OSGEO4W_ROOT%\bin\grass74.bat set GRASS7=%OSGEO4W_ROOT%\bin\grass74.bat
if exist %OSGEO4W_ROOT%\bin\grass76.bat set GRASS7=%OSGEO4W_ROOT%\bin\grass76.bat
if "%GRASS7%"=="" (echo GRASS7 not found & goto error)
for /f "usebackq tokens=1" %%a in (`%GRASS7% --config path`) do set GRASS_PREFIX=%%a

View File

@ -64,8 +64,8 @@ set CMAKE_OPT=^
:cmake
set GRASS7=
if exist %OSGEO4W_ROOT%\bin\grass72.bat set GRASS7=%OSGEO4W_ROOT%\bin\grass72.bat
if exist %OSGEO4W_ROOT%\bin\grass74.bat set GRASS7=%OSGEO4W_ROOT%\bin\grass74.bat
if exist %OSGEO4W_ROOT%\bin\grass76.bat set GRASS7=%OSGEO4W_ROOT%\bin\grass76.bat
if "%GRASS7%"=="" (echo GRASS7 not found & goto error)
for /f "usebackq tokens=1" %%a in (`%GRASS7% --config path`) do set GRASS7_PATH=%%a

View File

@ -1,6 +1,7 @@
// Include auto-generated SIP files
%Include auto_generated/qgs3dtypes.sip
%Include auto_generated/qgsphongmaterialsettings.sip
%Include auto_generated/qgsrulebased3drenderer.sip
%Include auto_generated/qgsvectorlayer3drenderer.sip
%Include auto_generated/symbols/qgsabstract3dsymbol.sip
%Include auto_generated/symbols/qgsline3dsymbol.sip

View File

@ -0,0 +1,280 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/3d/qgsrulebased3drenderer.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsRuleBased3DRendererMetadata : Qgs3DRendererAbstractMetadata
{
%Docstring
Metadata for rule-based 3D renderer to allow creation of its instances from XML
.. warning::
This is not considered stable API, and may change in future QGIS releases. It is
exposed to the Python bindings as a tech preview only.
.. versionadded:: 3.6
%End
%TypeHeaderCode
#include "qgsrulebased3drenderer.h"
%End
public:
QgsRuleBased3DRendererMetadata();
virtual QgsAbstract3DRenderer *createRenderer( QDomElement &elem, const QgsReadWriteContext &context ) /Factory/;
%Docstring
Creates an instance of a 3D renderer based on a DOM element with renderer configuration
%End
};
class QgsRuleBased3DRenderer : QgsAbstract3DRenderer
{
%Docstring
Rule-based 3D renderer.
Similar to rule-based 2D renderer and rule-based labeling, it allows specification of rules for 3D symbols.
.. warning::
This is not considered stable API, and may change in future QGIS releases. It is
exposed to the Python bindings as a tech preview only.
.. versionadded:: 3.6
%End
%TypeHeaderCode
#include "qgsrulebased3drenderer.h"
%End
public:
typedef QList<QgsRuleBased3DRenderer::Rule *> RuleList;
typedef QMap<const QgsRuleBased3DRenderer::Rule *, QgsFeature3DHandler *> RuleToHandlerMap;
class Rule
{
%Docstring
.. versionadded:: 3.6
%End
%TypeHeaderCode
#include "qgsrulebased3drenderer.h"
%End
public:
Rule( QgsAbstract3DSymbol *symbol /Transfer/, const QString &filterExp = QString(), const QString &description = QString(), bool elseRule = false );
%Docstring
takes ownership of symbol, symbol may be None
%End
~Rule();
enum RegisterResult
{
Filtered,
Inactive,
Registered
};
QgsAbstract3DSymbol *symbol() const;
%Docstring
Gets the labeling settings. May return a null pointer.
%End
QString filterExpression() const;
%Docstring
A filter that will check if this rule applies
:return: An expression
%End
QString description() const;
%Docstring
A human readable description for this rule
:return: Description
%End
bool active() const;
%Docstring
Returns if this rule is active
:return: True if the rule is active
%End
bool isElse() const;
%Docstring
Check if this rule is an ELSE rule
:return: True if this rule is an else rule
%End
QString ruleKey() const;
%Docstring
Unique rule identifier (for identification of rule within labeling, used as provider ID)
%End
void setSymbol( QgsAbstract3DSymbol *symbol /Transfer/ );
%Docstring
Sets new symbol (or NULL). Deletes old symbol if any.
%End
void setFilterExpression( const QString &filterExp );
%Docstring
Set the expression used to check if a given feature shall be rendered with this rule
:param filterExp: An expression
%End
void setDescription( const QString &description );
%Docstring
Set a human readable description for this rule
:param description: Description
%End
void setActive( bool state );
%Docstring
Sets if this rule is active
:param state: Determines if the rule should be activated or deactivated
%End
void setIsElse( bool iselse );
%Docstring
Sets if this rule is an ELSE rule
:param iselse: If true, this rule is an ELSE rule
%End
void setRuleKey( const QString &key );
%Docstring
Override the assigned rule key (should be used just internally by rule-based renderer)
%End
const QgsRuleBased3DRenderer::RuleList &children() const;
%Docstring
Returns all children rules of this rule
:return: A list of rules
%End
QgsRuleBased3DRenderer::RuleList descendants() const;
%Docstring
Returns all children, grand-children, grand-grand-children, grand-gra... you get it
:return: A list of descendant rules
%End
QgsRuleBased3DRenderer::Rule *parent();
%Docstring
The parent rule
:return: Parent rule
%End
void appendChild( QgsRuleBased3DRenderer::Rule *rule /Transfer/ );
%Docstring
add child rule, take ownership, sets this as parent
%End
void insertChild( int i, QgsRuleBased3DRenderer::Rule *rule /Transfer/ );
%Docstring
add child rule, take ownership, sets this as parent
%End
void removeChildAt( int i );
%Docstring
delete child rule
%End
const QgsRuleBased3DRenderer::Rule *findRuleByKey( const QString &key ) const;
%Docstring
Try to find a rule given its unique key
%End
QgsRuleBased3DRenderer::Rule *clone() const /Factory/;
%Docstring
clone this rule, return new instance
%End
static QgsRuleBased3DRenderer::Rule *create( const QDomElement &ruleElem, const QgsReadWriteContext &context ) /Factory/;
%Docstring
Create a rule from an XML definition
:param ruleElem: The XML rule element
:param context: reading context
:return: A new rule
%End
QDomElement save( QDomDocument &doc, const QgsReadWriteContext &context ) const;
%Docstring
store labeling info to XML element
%End
private:
Rule( const QgsRuleBased3DRenderer::Rule &rh );
};
QgsRuleBased3DRenderer( QgsRuleBased3DRenderer::Rule *root /Transfer/ );
%Docstring
Construct renderer with the given root rule (takes ownership)
%End
~QgsRuleBased3DRenderer();
void setLayer( QgsVectorLayer *layer );
%Docstring
Sets vector layer associated with the renderer
%End
QgsVectorLayer *layer() const;
%Docstring
Returns vector layer associated with the renderer
%End
QgsRuleBased3DRenderer::Rule *rootRule();
%Docstring
Returns pointer to the root rule
%End
virtual QString type() const;
virtual QgsRuleBased3DRenderer *clone() const /Factory/;
virtual void writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const;
virtual void readXml( const QDomElement &elem, const QgsReadWriteContext &context );
virtual void resolveReferences( const QgsProject &project );
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/3d/qgsrulebased3drenderer.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -274,6 +274,7 @@ INCLUDE_DIRECTORIES(BEFORE
${CMAKE_SOURCE_DIR}/src/analysis/processing
${CMAKE_SOURCE_DIR}/src/analysis/vector
${CMAKE_SOURCE_DIR}/src/analysis/vector/geometry_checker
${CMAKE_SOURCE_DIR}/src/analysis/mesh
${CMAKE_SOURCE_DIR}/src/analysis/raster
${CMAKE_SOURCE_DIR}/src/analysis/network
${CMAKE_SOURCE_DIR}/src/analysis/interpolation
@ -281,6 +282,7 @@ INCLUDE_DIRECTORIES(BEFORE
${CMAKE_BINARY_DIR}/src/analysis/processing
${CMAKE_BINARY_DIR}/src/analysis/vector
${CMAKE_BINARY_DIR}/src/analysis/mesh
${CMAKE_BINARY_DIR}/src/analysis/raster
${CMAKE_BINARY_DIR}/src/analysis/network
${CMAKE_BINARY_DIR}/src/analysis/interpolation

View File

@ -14,6 +14,7 @@
%Include auto_generated/raster/qgsrastermatrix.sip
%Include auto_generated/raster/qgsrastercalcnode.sip
%Include auto_generated/raster/qgstotalcurvaturefilter.sip
%Include auto_generated/mesh/qgsmeshcalculator.sip
%Include auto_generated/vector/qgsgeometrysnapper.sip
%Include auto_generated/vector/qgsgeometrysnappersinglesource.sip
%Include auto_generated/vector/qgszonalstatistics.sip

View File

@ -0,0 +1,109 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/analysis/mesh/qgsmeshcalculator.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsMeshCalculator
{
%Docstring
Performs mesh layer calculations.
Mesh calculator can do various mathematical operations
between dataset groups from a single mesh layer.
Resulting dataset group is added to the mesh layer.
Result can be filtered by extent or a vector layer mask
spatially and by selection of times.
Note: only dataset groups defined on vertices are
implemented and supported
.. versionadded:: 3.6
%End
%TypeHeaderCode
#include "qgsmeshcalculator.h"
%End
public:
enum Result
{
Success,
Canceled,
CreateOutputError,
InputLayerError,
ParserError,
InvalidDatasets,
EvaluateError,
MemoryError,
};
QgsMeshCalculator( const QString &formulaString,
const QString &outputFile,
const QgsRectangle &outputExtent,
double startTime,
double endTime,
QgsMeshLayer *layer );
%Docstring
Creates calculator with bounding box (rectangular) mask
:param formulaString: formula/expression to evaluate. Consists of dataset group names, operators and numbers
:param outputFile: file to store the resulting dataset group data
:param outputExtent: spatial filter defined by rectangle
:param startTime: time filter defining the starting dataset
:param endTime: time filter defining the ending dataset
:param layer: mesh layer with dataset groups references in formulaString
%End
QgsMeshCalculator( const QString &formulaString,
const QString &outputFile,
const QgsGeometry &outputMask,
double startTime,
double endTime,
QgsMeshLayer *layer );
%Docstring
Creates calculator with geometry mask
:param formulaString: formula/expression to evaluate. Consists of dataset group names, operators and numbers
:param outputFile: file to store the resulting dataset group data
:param outputMask: spatial filter defined by geometry
:param startTime: time filter defining the starting dataset
:param endTime: time filter defining the ending dataset
:param layer: mesh layer with dataset groups references in formulaString
%End
Result processCalculation( QgsFeedback *feedback = 0 );
%Docstring
Starts the calculation, writes new dataset group to file and adds it to the mesh layer
:param feedback: The optional feedback argument for progress reporting and cancelation support
:return: QgsMeshCalculator.Success in case of success
%End
static Result expression_valid( const QString &formulaString, QgsMeshLayer *layer );
%Docstring
Returns whether formula is valid for particular mesh layer
:param formulaString: formula/expression to evaluate. Consists of dataset group names, operators and numbers
:param layer: mesh layer with dataset groups references in formulaString
:return: QgsMeshCalculator.Success in case of success
%End
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/analysis/mesh/qgsmeshcalculator.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -148,6 +148,7 @@ class Editor(QsciScintilla):
self.SendScintilla(self.SCI_SETADDITIONALSELECTIONTYPING, 1)
self.SendScintilla(self.SCI_SETMULTIPASTE, 1)
self.SendScintilla(self.SCI_SETVIRTUALSPACEOPTIONS, self.SCVS_RECTANGULARSELECTION)
# self.setWrapMode(QsciScintilla.WrapCharacter)
self.setWhitespaceVisibility(QsciScintilla.WsVisibleAfterIndent)

View File

@ -37,6 +37,7 @@ from .additions.qgsgeometry import _geometryNonZero, mapping_geometry
from .additions.qgssettings import _qgssettings_enum_value, _qgssettings_set_enum_value, _qgssettings_flag_value
from .additions.qgstaskwrapper import QgsTaskWrapper
from .additions.readwritecontextentercategory import ReadWriteContextEnterCategory
from .additions.validitycheck import check
# Injections into classes
QgsFeature.__geo_interface__ = property(mapping_feature)

View File

@ -0,0 +1,95 @@
# -*- coding: utf-8 -*-
"""
***************************************************************************
validitycheck.py
---------------------
Date : January 2019
Copyright : (C) 2019 by Nyall Dawson
Email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
from qgis._core import (
QgsAbstractValidityCheck,
QgsApplication)
class CheckFactory:
"""
Constructs QgsAbstractValidityChecks using a decorator.
To use, Python based checks should use the decorator syntax:
.. highlight:: python
.. code-block:: python
@check.register(type=QgsAbstractValidityCheck.TypeLayoutCheck)
def my_layout_check(context, feedback):
results = ...
return results
"""
def __init__(self):
# unfortunately /Transfer/ annotation isn't working correct on validityCheckRegistry().addCheck(),
# so we manually need to store a reference to all checks we register
self.checks = []
def register(self, type, *args, **kwargs):
"""
Implements a decorator for registering Python based checks.
:param type: check type, e.g. QgsAbstractValidityCheck.TypeLayoutCheck
"""
def dec(f):
check = CheckWrapper(check_type=type, check_func=f)
self.checks.append(check)
QgsApplication.validityCheckRegistry().addCheck(check)
return dec
class CheckWrapper(QgsAbstractValidityCheck):
"""
Wrapper object used to create new validity checks from @check.
"""
def __init__(self, check_type, check_func):
"""
Initializer for CheckWrapper.
:param check_type: check type, e.g. QgsAbstractValidityCheck.TypeLayoutCheck
:param check_func: test function, should return a list of QgsValidityCheckResult results
"""
super().__init__()
self._check_type = check_type
self._results = []
self._check_func = check_func
def create(self):
return CheckWrapper(check_type=self._check_type, check_func=self._check_func)
def id(self):
return self._check_func.__name__
def checkType(self):
return self._check_type
def prepareCheck(self, context, feedback):
self._results = self._check_func(context, feedback)
if self._results is None:
self._results = []
return True
def runCheck(self, context, feedback):
return self._results
check = CheckFactory()

View File

@ -0,0 +1,2 @@
# The following has been generated automatically from src/core/qgsmaplayermodel.h
QgsMapLayerModel.ItemDataRole.baseClass = QgsMapLayerModel

View File

@ -188,6 +188,31 @@ Note that this method is 2D only and does not consider the z-value of the circle
.. seealso:: :py:func:`tangentToPoint`
.. versionadded:: 3.2
%End
int innerTangents( const QgsCircle &other,
QgsPointXY &line1P1 /Out/, QgsPointXY &line1P2 /Out/,
QgsPointXY &line2P1 /Out/, QgsPointXY &line2P2 /Out/ ) const;
%Docstring
Calculates the inner tangent points between this circle
and an ``other`` circle.
The inner tangent points correspond to the points at which the two lines
which are drawn so that they are tangential to both circles but on
different sides, touching the circles and crossing each other.
The first tangent line is described by the points
stored in ``line1P1`` and ``line1P2``,
and the second line is described by the points stored in ``line2P1``
and ``line2P2``.
Returns the number of tangents (either 0 or 2).
Note that this method is 2D only and does not consider the z-value of the circle.
.. seealso:: :py:func:`tangentToPoint`
.. versionadded:: 3.6
%End
virtual double area() const;

View File

@ -1515,22 +1515,96 @@ will be raised.
}
%End
QgsMultiPointXY asMultiPoint() const;
SIP_PYOBJECT asMultiPoint() const /TypeHint="QgsMultiPointXY"/;
%Docstring
Returns contents of the geometry as a multi point
if wkbType is WKBMultiPoint, otherwise an empty list
Returns the contents of the geometry as a multi-point.
Any z or m values present in the geometry will be discarded.
This method works only with multi-point geometry types. If the geometry
is not a multi-point type, a TypeError will be raised. If the geometry is null, a ValueError
will be raised.
%End
%MethodCode
const QgsWkbTypes::Type type = sipCpp->wkbType();
if ( sipCpp->isNull() )
{
PyErr_SetString( PyExc_ValueError, QStringLiteral( "Null geometry cannot be converted to a multipoint." ).toUtf8().constData() );
sipIsErr = 1;
}
else if ( QgsWkbTypes::geometryType( type ) != QgsWkbTypes::PointGeometry || !QgsWkbTypes::isMultiType( type ) )
{
PyErr_SetString( PyExc_TypeError, QStringLiteral( "%1 geometry cannot be converted to a multipoint. Only multipoint types are permitted." ).arg( QgsWkbTypes::displayString( type ) ).toUtf8().constData() );
sipIsErr = 1;
}
else
{
const sipMappedType *qvector_type = sipFindMappedType( "QVector< QgsPointXY >" );
sipRes = sipConvertFromNewType( new QgsPolylineXY( sipCpp->asMultiPoint() ), qvector_type, Py_None );
}
%End
QgsMultiPolylineXY asMultiPolyline() const;
SIP_PYOBJECT asMultiPolyline() const /TypeHint="QgsMultiPolylineXY"/;
%Docstring
Returns contents of the geometry as a multi linestring
if wkbType is WKBMultiLineString, otherwise an empty list
Returns the contents of the geometry as a multi-linestring.
Any z or m values present in the geometry will be discarded. If the geometry is a curved line type
(such as a MultiCurve), it will be automatically segmentized.
This method works only with multi-linestring (or multi-curve) geometry types. If the geometry
is not a multi-linestring type, a TypeError will be raised. If the geometry is null, a ValueError
will be raised.
%End
%MethodCode
const QgsWkbTypes::Type type = sipCpp->wkbType();
if ( sipCpp->isNull() )
{
PyErr_SetString( PyExc_ValueError, QStringLiteral( "Null geometry cannot be converted to a multilinestring." ).toUtf8().constData() );
sipIsErr = 1;
}
else if ( QgsWkbTypes::geometryType( type ) != QgsWkbTypes::LineGeometry || !QgsWkbTypes::isMultiType( type ) )
{
PyErr_SetString( PyExc_TypeError, QStringLiteral( "%1 geometry cannot be converted to a multilinestring. Only multi linestring or curves are permitted." ).arg( QgsWkbTypes::displayString( type ) ).toUtf8().constData() );
sipIsErr = 1;
}
else
{
const sipMappedType *qvector_type = sipFindMappedType( "QVector<QVector<QgsPointXY>>" );
sipRes = sipConvertFromNewType( new QgsMultiPolylineXY( sipCpp->asMultiPolyline() ), qvector_type, Py_None );
}
%End
QgsMultiPolygonXY asMultiPolygon() const;
SIP_PYOBJECT asMultiPolygon() const /TypeHint="QgsMultiPolygonXY"/;
%Docstring
Returns contents of the geometry as a multi polygon
if wkbType is WKBMultiPolygon, otherwise an empty list
Returns the contents of the geometry as a multi-polygon.
Any z or m values present in the geometry will be discarded. If the geometry is a curved polygon type
(such as a MultiSurface), it will be automatically segmentized.
This method works only with multi-polygon (or multi-curve polygon) geometry types. If the geometry
is not a multi-polygon type, a TypeError will be raised. If the geometry is null, a ValueError
will be raised.
%End
%MethodCode
const QgsWkbTypes::Type type = sipCpp->wkbType();
if ( sipCpp->isNull() )
{
PyErr_SetString( PyExc_ValueError, QStringLiteral( "Null geometry cannot be converted to a multipolygon." ).toUtf8().constData() );
sipIsErr = 1;
}
else if ( QgsWkbTypes::geometryType( type ) != QgsWkbTypes::PolygonGeometry || !QgsWkbTypes::isMultiType( type ) )
{
PyErr_SetString( PyExc_TypeError, QStringLiteral( "%1 geometry cannot be converted to a multipolygon. Only multi polygon or curves are permitted." ).arg( QgsWkbTypes::displayString( type ) ).toUtf8().constData() );
sipIsErr = 1;
}
else
{
const sipMappedType *qvector_type = sipFindMappedType( "QVector<QVector<QVector<QgsPointXY>>>" );
sipRes = sipConvertFromNewType( new QgsMultiPolygonXY( sipCpp->asMultiPolygon() ), qvector_type, Py_None );
}
%End
QVector<QgsGeometry> asGeometryCollection() const;

View File

@ -202,6 +202,29 @@ and ``line2P2``.
Returns the number of tangents (either 0 or 2).
.. versionadded:: 3.2
%End
static int circleCircleInnerTangents(
const QgsPointXY &center1, double radius1, const QgsPointXY &center2, double radius2,
QgsPointXY &line1P1 /Out/, QgsPointXY &line1P2 /Out/,
QgsPointXY &line2P1 /Out/, QgsPointXY &line2P2 /Out/ );
%Docstring
Calculates the inner tangent points for two circles, centered at \a
center1 and ``center2`` and with radii of ``radius1`` and ``radius2``
respectively.
The inner tangent points correspond to the points at which the two lines
which are drawn so that they are tangential to both circles and are
crossing each other.
The first tangent line is described by the points
stored in ``line1P1`` and ``line1P2``,
and the second line is described by the points stored in ``line2P1``
and ``line2P2``.
Returns the number of tangents (either 0 or 2).
.. versionadded:: 3.6
%End
static QgsPoint projectPointOnSegment( const QgsPoint &p, const QgsPoint &s1, const QgsPoint &s2 );

View File

@ -0,0 +1,201 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/geometry/qgsquadrilateral.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsQuadrilateral
{
%Docstring
Quadrilateral geometry type.
A quadrilateral is a polygon with four edges (or sides) and four vertices or corners.
This class allows the creation of simple quadrilateral (which does not self-intersect).
.. versionadded:: 3.6
%End
%TypeHeaderCode
#include "qgsquadrilateral.h"
%End
public:
QgsQuadrilateral();
QgsQuadrilateral( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3, const QgsPoint &p4 );
%Docstring
Construct a QgsQuadrilateral from four :py:class:`QgsPoint`.
:param p1: first point
:param p2: second point
:param p3: third point
:param p4: fourth point
.. seealso:: :py:func:`setPoints`
%End
explicit QgsQuadrilateral( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3, const QgsPointXY &p4 );
%Docstring
Construct a QgsQuadrilateral from four :py:class:`QgsPointXY`.
:param p1: first point
:param p2: second point
:param p3: third point
:param p4: fourth point
.. seealso:: :py:func:`setPoints`
%End
enum ConstructionOption
{
Distance,
Projected,
};
static QgsQuadrilateral rectangleFrom3Points( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3, ConstructionOption mode );
%Docstring
Construct a QgsQuadrilateral as a Rectangle from 3 points.
In the case where one of the points is of type PointZ. The other points
will also be of type Z, even if they are of type Point. In addition,
the z used will be the one of the first point with a Z.
This ensures consistency in point types and the ability to export to a
Polygon or LineString.
:param p1: first point
:param p2: second point
:param p3: third point
:param mode: Construction mode to construct the rectangle from 3 points
.. seealso:: ConstructionOption
%End
static QgsQuadrilateral rectangleFromExtent( const QgsPoint &p1, const QgsPoint &p2 );
%Docstring
Construct a QgsQuadrilateral as a rectangle from an extent, defined by
two opposite corner points.
Z is taken from point ``p1``.
:param p1: first point
:param p2: second point
%End
static QgsQuadrilateral squareFromDiagonal( const QgsPoint &p1, const QgsPoint &p2 );
%Docstring
Construct a QgsQuadrilateral as a square from a diagonal.
Z is taken from point ``p1``.
:param p1: first point
:param p2: second point
%End
static QgsQuadrilateral rectangleFromCenterPoint( const QgsPoint &center, const QgsPoint &point );
%Docstring
Construct a QgsQuadrilateral as a rectangle from center point ``center``
and another point ``point``.
Z is taken from ``center`` point.
:param center: center point
:param point: corner point
%End
static QgsQuadrilateral fromRectangle( const QgsRectangle &rectangle );
%Docstring
Construct a QgsQuadrilateral as a rectangle from a :py:class:`QgsRectangle`.
:param rectangle: rectangle
%End
bool equals( const QgsQuadrilateral &other, double epsilon = 4 * DBL_EPSILON ) const;
%Docstring
Compares two QgsQuadrilateral, allowing specification of the maximum allowable difference between points.
:param other: the QgsQuadrilateral to compare
:param epsilon: the maximum difference allowed / tolerance
%End
bool operator==( const QgsQuadrilateral &other ) const;
bool operator!=( const QgsQuadrilateral &other ) const;
bool isValid() const;
%Docstring
Convenient method to determine if a QgsQuadrilateral is valid.
A QgsQuadrilateral must be simple (not self-intersecting) and
cannot have collinear points.
%End
enum Point
{
Point1,
Point2,
Point3,
Point4,
};
bool setPoint( const QgsPoint &newPoint, Point index );
%Docstring
Sets the point ``newPoint`` at the ``index``.
Returns false if the QgsQuadrilateral is not valid.
.. seealso:: Point
%End
bool setPoints( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3, const QgsPoint &p4 );
%Docstring
Set all points
Returns false if the QgsQuadrilateral is not valid:
- The points do not have the same type
- The quadrilateral would have auto intersections
- The quadrilateral has double points
- The quadrilateral has collinear points
%End
QgsPointSequence points() const;
%Docstring
Returns a list including the vertices of the quadrilateral.
%End
QgsPolygon *toPolygon( bool force2D = false ) const /Factory/;
%Docstring
Returns the quadrilateral as a new polygon. Ownership is transferred to the caller.
%End
QgsLineString *toLineString( bool force2D = false ) const /Factory/;
%Docstring
Returns the quadrilateral as a new linestring. Ownership is transferred to the caller.
%End
QString toString( int pointPrecision = 17 ) const;
%Docstring
Returns a string representation of the quadrilateral.
Members will be truncated to the specified precision.
%End
double area() const;
%Docstring
Returns the area of the quadrilateral, or 0 if the quadrilateral is empty.
%End
double perimeter() const;
%Docstring
Returns the perimeter of the quadrilateral, or 0 if the quadrilateral is empty.
%End
SIP_PYOBJECT __repr__();
%MethodCode
QString str = QStringLiteral( "<QgsQuadrilateral: %1>" ).arg( sipCpp->toString() );
sipRes = PyUnicode_FromString( str.toUtf8().constData() );
%End
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/geometry/qgsquadrilateral.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -76,6 +76,7 @@ Default implementation does nothing. *
struct ItemContext
{
QgsRenderContext *context;
QPainter *painter;
QPointF point;
double labelXOffset;

View File

@ -488,6 +488,9 @@ Returns the legend's renderer settings object.
virtual void finalizeRestoreFromXml();
virtual QgsExpressionContext createExpressionContext() const;
public slots:

View File

@ -198,6 +198,8 @@ Sets the objects's property collection, used for data defined overrides.
:param collection: property collection. Existing properties will be replaced.
.. seealso:: :py:func:`dataDefinedProperties`
.. seealso:: DataDefinedProperty
%End

View File

@ -509,6 +509,30 @@ V3 ---- V4 ---- V6-----V8
%Docstring
Returns whether the faces are active for particular dataset
.. versionadded:: 3.6
%End
virtual bool persistDatasetGroup( const QString &path,
const QgsMeshDatasetGroupMetadata &meta,
const QVector<QgsMeshDataBlock> &datasetValues,
const QVector<QgsMeshDataBlock> &datasetActive,
const QVector<double> &times
) = 0;
%Docstring
Creates a new dataset group from a data and
persists it into a destination path
On success, the mesh's dataset group count is changed
:param path: destination path of the stored file
:param meta: new group's metadata
:param datasetValues: scalar/vector values for all datasets and all faces/vertices in the group
:param datasetActive: active flag values for all datasets in the group. Empty array represents can be used
when all faces are active
:param times: times in hours for all datasets in the group
:return: true on failure, false on success
.. versionadded:: 3.6
%End
};

View File

@ -130,6 +130,8 @@ Returns the provider type for this layer
QgsMeshRendererSettings rendererSettings() const;
%Docstring
Returns renderer settings

View File

@ -0,0 +1,59 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/mesh/qgsmeshlayerinterpolator.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
%ModuleHeaderCode
#include "qgsmeshlayerinterpolator.h"
%End
namespace QgsMeshUtils
{
QgsRasterBlock *exportRasterBlock(
const QgsMeshLayer &layer,
const QgsMeshDatasetIndex &datasetIndex,
const QgsCoordinateReferenceSystem &destinationCrs,
const QgsCoordinateTransformContext &transformContext,
double mapUnitsPerPixel,
const QgsRectangle &extent,
QgsRasterBlockFeedback *feedback = 0
) /Factory/;
%Docstring
Exports mesh layer's dataset values as raster block
The function always fetches native mesh and dataset data
from data provider and calculates triangular mesh
:param layer: mesh layer
:param datasetIndex: index from layer defining group and dataset (time) to export
:param destinationCrs: destination/map CRS. Used to create triangular mesh from native mesh
:param transformContext: Transform context to transform layer CRS to destination CRS
:param mapUnitsPerPixel: map units per pixel for block
:param extent: extent of block in destination CRS
:param feedback: optional raster feedback object for cancelation/preview
:return: raster block with Float.64 values. None on error
.. versionadded:: 3.6
%End
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/mesh/qgsmeshlayerinterpolator.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -133,6 +133,9 @@ Returns a double ``number``, rounded (as close as possible) to the specified num
double qgsPermissiveToDouble( QString string, bool &ok );
%Docstring
Converts a string to a double in a permissive way, e.g., allowing for incorrect

View File

@ -330,6 +330,8 @@ Sets the diagram's property collection, used for data defined overrides.
.. seealso:: :py:func:`dataDefinedProperties`
.. seealso:: Property
.. versionadded:: 3.0
%End

View File

@ -384,17 +384,17 @@ The ``interval`` parameter gives the maximum distance between points on the comp
This argument is always specified in meters. A shorter distance results in a denser line,
at the cost of extra computing time.
If the geodesic line crosses the international date line and ``breakLine`` is true, then
the line will be split into two parts, broken at the date line. In this case the function
will return two lines, corresponding to the portions at either side of the date line.
If the geodesic line crosses the antimeridian (+/- 180 degrees longitude) and ``breakLine`` is true, then
the line will be split into two parts, broken at the antimeridian. In this case the function
will return two lines, corresponding to the portions at either side of the antimeridian.
.. versionadded:: 3.6
%End
double latitudeGeodesicCrossesDateLine( const QgsPointXY &p1, const QgsPointXY &p2, double &fractionAlongLine /Out/ ) const;
double latitudeGeodesicCrossesAntimeridian( const QgsPointXY &p1, const QgsPointXY &p2, double &fractionAlongLine /Out/ ) const;
%Docstring
Calculates the latitude at which the geodesic line joining ``p1`` and ``p2`` crosses
the international date line (longitude +/- 180 degrees).
the antimeridian (longitude +/- 180 degrees).
The ellipsoid settings defined on this QgsDistanceArea object will be used during the calculations.
@ -404,8 +404,37 @@ will also be in this same CRS.
:param p1: Starting point, in ellipsoidCrs()
:param p2: Ending point, in ellipsoidCrs()
:return: - the latitude at which the geodesic crosses the date line
- fractionAlongLine: will be set to the fraction along the geodesic line joining ``p1`` to ``p2`` at which the date line crossing occurs.
:return: - the latitude at which the geodesic crosses the antimeridian
- fractionAlongLine: will be set to the fraction along the geodesic line joining ``p1`` to ``p2`` at which the antimeridian crossing occurs.
.. seealso:: :py:func:`splitGeometryAtAntimeridian`
.. versionadded:: 3.6
%End
QgsGeometry splitGeometryAtAntimeridian( const QgsGeometry &geometry ) const;
%Docstring
Splits a (Multi)LineString ``geometry`` at the antimeridian (longitude +/- 180 degrees).
The returned geometry will always be a multi-part geometry.
Whenever line segments in the input geometry cross the antimeridian, they will be
split into two segments, with the latitude of the breakpoint being determined using a geodesic
line connecting the points either side of this segment.
The ellipsoid settings defined on this QgsDistanceArea object will be used during the calculations.
``geometry`` must be in the sourceCrs() of this QgsDistanceArea object. The returned geometry
will also be in this same CRS.
If ``geometry`` contains M or Z values, these will be linearly interpolated for the new vertices
created at the antimeridian.
.. note::
Non-(Multi)LineString geometries will be returned unchanged.
.. seealso:: :py:func:`latitudeGeodesicCrossesAntimeridian`
.. versionadded:: 3.6
%End

View File

@ -341,6 +341,24 @@ Convenience function for setting a fields for the scope. Any existing
fields set by the scope will be overwritten.
:param fields: fields for scope
%End
void readXml( const QDomElement &element, const QgsReadWriteContext &context );
%Docstring
Reads scope variables from an XML element.
.. seealso:: :py:func:`writeXml`
.. versionadded:: 3.6
%End
bool writeXml( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const;
%Docstring
Writes scope variables to an XML ``element``.
.. seealso:: :py:func:`readXml`
.. versionadded:: 3.6
%End
};

View File

@ -34,7 +34,7 @@ Constructor for QgsLegendRenderer. The ownership of the legend model is not chan
and the model must exist for the lifetime of this renderer.
%End
QSizeF minimumSize();
QSizeF minimumSize( QgsRenderContext *renderContext = 0 );
%Docstring
Runs the layout algorithm and returns the minimum size required for the legend.

View File

@ -198,6 +198,17 @@ The ``scale`` value indicates the scale denominator, e.g. 1000.0 for a 1:1000 ma
void setDpi( int dpi );
QStringList evaluateItemText( const QString &text, const QgsExpressionContext &context ) const;
%Docstring
Returns the actual text to render for a legend item, split into separate lines.
The expression ``context`` argument is used to correctly evaluated expressions contained
within legend item text.
.. versionadded:: 3.6
%End
QStringList splitStringForWrapping( const QString &stringToSplt ) const;
%Docstring
Splits a string using the wrap char taking into account handling empty

View File

@ -10,6 +10,51 @@
class QgsNetworkRequestParameters
{
%Docstring
Encapsulates parameters and properties of a network request.
.. versionadded:: 3.6
%End
%TypeHeaderCode
#include "qgsnetworkaccessmanager.h"
%End
public:
QgsNetworkRequestParameters();
%Docstring
Default constructor.
%End
QgsNetworkRequestParameters( QNetworkAccessManager::Operation operation,
const QNetworkRequest &request );
%Docstring
Constructor for QgsNetworkRequestParameters, with the specified network
``operation`` and original ``request``.
%End
QNetworkAccessManager::Operation operation() const;
%Docstring
Returns the request operation, e.g. GET or POST.
%End
QNetworkRequest request() const;
%Docstring
Returns the network request.
This is the original network request sent to :py:class:`QgsNetworkAccessManager`, but with QGIS specific
configuration options such as proxy handling and SSL exceptions applied.
%End
QString originatingThreadId() const;
%Docstring
Returns a string identifying the thread which the request originated from.
%End
};
class QgsNetworkAccessManager : QNetworkAccessManager
{
%Docstring
@ -111,6 +156,18 @@ Returns whether the system proxy should be used
signals:
void requestAboutToBeCreated( QNetworkAccessManager::Operation, const QNetworkRequest &, QIODevice * );
void requestAboutToBeCreated( QgsNetworkRequestParameters request );
%Docstring
Emitted when a network request is about to be created.
This signal is propagated to the main thread QgsNetworkAccessManager instance, so it is necessary
only to connect to the main thread's signal in order to receive notifications about requests
created in any thread.
.. versionadded:: 3.6
%End
void requestCreated( QNetworkReply * );
void requestTimedOut( QNetworkReply * );

View File

@ -432,6 +432,8 @@ Sets the label's property collection, used for data defined overrides.
.. seealso:: :py:func:`dataDefinedProperties`
.. seealso:: Property
.. versionadded:: 3.0
%End

View File

@ -1003,6 +1003,15 @@ in the project. The removeMapLayer(), removeMapLayers() calls do not block remov
.. deprecated:: since QGIS 3.4 use QgsMapLayer.setFlags() instead
.. versionadded:: 3.2
%End
void setProjectColors( const QgsNamedColorList &colors );
%Docstring
Sets the ``colors`` for the project's color scheme (see QgsProjectColorScheme).
.. seealso:: :py:func:`projectColorsChanged`
.. versionadded:: 3.6
%End
void generateTsFile( const QString &locale );
@ -1230,6 +1239,15 @@ Emitted when the project's metadata is changed.
.. versionadded:: 3.2
%End
void projectColorsChanged();
%Docstring
Emitted whenever the project's color scheme has been changed.
.. seealso:: :py:func:`setProjectColors`
.. versionadded:: 3.6
%End
void layersWillBeRemoved( const QStringList &layerIds );
%Docstring

View File

@ -311,6 +311,13 @@ Returns true if preparation was successful.
%Docstring
Returns the set of any fields referenced by the property for a specified
expression context.
%End
bool isProjectColor() const;
%Docstring
Returns true if the property is set to a linked project color.
.. versionadded:: 3.6
%End
QVariant value( const QgsExpressionContext &context, const QVariant &defaultValue = QVariant(), bool *ok /Out/ = 0 ) const;

View File

@ -309,6 +309,21 @@ A grouped map of multiple QgsProperty objects, each referenced by a integer key
Properties within a collection are referenced by an integer key. This is done to avoid the cost of
string creation and comparisons which would be required by a string key. The intended use case is that
a context specific enum is cast to int and used for the key value.
Examples of such enums are :
.. seealso:: :py:func:`QgsLayoutObject.DataDefinedProperty`
.. seealso:: :py:func:`QgsSymbolLayer.Property`
.. seealso:: :py:func:`QgsPalLabeling.Property`
.. seealso:: :py:func:`QgsAbstract3DSymbol.Property`
.. seealso:: :py:func:`QgsDiagramLayerSettings.Property`
.. seealso:: :py:func:`QgsPalLayerSettings.Property`
.. seealso:: :py:func:`QgsWidgetWrapper.Property`
.. versionadded:: 3.0
%End

View File

@ -119,6 +119,19 @@ Will throw a QgsException if called on a vector with length of 0.
bool operator!=( QgsVector other ) const;
QString toString( int precision = 17 ) const;
%Docstring
Returns a string representation of the vector.
Members will be truncated to the specified ``precision``.
%End
SIP_PYOBJECT __repr__();
%MethodCode
QString str = QStringLiteral( "<QgsVector: %1>" ).arg( sipCpp->toString() );
sipRes = PyUnicode_FromString( str.toUtf8().constData() );
%End
};

View File

@ -89,7 +89,27 @@ Returns the length of the vector
Normalizes the current vector in place.
%End
double distance( const QgsVector3D &other ) const;
%Docstring
Returns the distance with the ``other`` :py:class:`QgsVector3`
%End
static QgsVector3D perpendicularPoint( const QgsVector3D &v1, const QgsVector3D &v2, const QgsVector3D &vp );
%Docstring
Returns the perpendicular point of vector ``vp`` from [``v1`` - ``v2``]
%End
QString toString( int precision = 17 ) const;
%Docstring
Returns a string representation of the 3D vector.
Members will be truncated to the specified ``precision``.
%End
SIP_PYOBJECT __repr__();
%MethodCode
QString str = QStringLiteral( "<QgsVector3D: %1>" ).arg( sipCpp->toString() );
sipRes = PyUnicode_FromString( str.toUtf8().constData() );
%End
};
/************************************************************************

View File

@ -153,20 +153,26 @@ returned value is undefined.
:param row: row index
:param column: column index
:return: value *
:return: value
.. seealso:: :py:func:`valueAndNoData`
%End
double value( qgssize index ) const;
%Docstring
Read a single value if type of block is numeric. If type is color,
Reads a single value if type of block is numeric. If type is color,
returned value is undefined.
:param index: data matrix index (long type in Python)
:return: value *
:return: value
.. seealso:: :py:func:`valueAndNoData`
%End
QRgb color( int row, int column ) const;
%Docstring
Read a single color
@ -188,12 +194,14 @@ Read a single value
bool isNoData( int row, int column ) const;
%Docstring
Check if value at position is no data
Checks if value at position is no data
:param row: row index
:param column: column index
:return: true if value is no data *
:return: true if value is no data
.. seealso:: :py:func:`valueAndNoData`
%End
bool isNoData( qgssize row, qgssize column ) const;
@ -203,7 +211,9 @@ Check if value at position is no data
:param row: row index
:param column: column index
:return: true if value is no data *
:return: true if value is no data
.. seealso:: :py:func:`valueAndNoData`
%End
bool isNoData( qgssize index ) const;
@ -212,7 +222,9 @@ Check if value at position is no data
:param index: data matrix index (long type in Python)
:return: true if value is no data *
:return: true if value is no data
.. seealso:: :py:func:`valueAndNoData`
%End
bool setValue( int row, int column, double value );
@ -441,6 +453,7 @@ Returns the height (number of rows) of the raster block.
/************************************************************************
* This file has been generated automatically from *
* *

View File

@ -33,6 +33,28 @@ Start reading of raster band. Raster data can then be retrieved by calling readN
:param nRows: number of rows
:param extent: area to read
:param feedback: optional raster feedback object for cancelation/preview. Added in QGIS 3.0.
%End
bool next( int bandNumber, int &columns /Out/, int &rows /Out/, int &topLeftColumn /Out/, int &topLeftRow /Out/, QgsRectangle &blockExtent /Out/ );
%Docstring
Fetches details of the next part of the raster data. This method does NOT actually fetch the raster
data itself, rather it calculates and iterates over the details of the raster alone.
It's useful for iterating over several layers using a target "reference" layer. E.g. summing
the pixels in n rasters whilst aligning the result to a reference layer which is not being summed.
Note that calling this method also advances the iterator, just like calling readNextRasterPart().
:param bandNumber: band to read
:param rows: number of rows on output device
:param topLeftColumn: top left column
:param topLeftRow: top left row
:param blockExtent: exact extent of returned raster block
:return: - false if the last part was already returned
- columns: number of columns on output device
.. versionadded:: 3.6
%End
bool readNextRasterPart( int bandNumber,

View File

@ -43,6 +43,8 @@ Create a new QgsArrowSymbolLayer
virtual QSet<QString> usedAttributes( const QgsRenderContext &context ) const;
virtual bool hasDataDefinedProperties() const;
double arrowWidth() const;
%Docstring

View File

@ -734,6 +734,8 @@ Returns the stroke width map unit scale.
virtual QSet<QString> usedAttributes( const QgsRenderContext &context ) const;
virtual bool hasDataDefinedProperties() const;
protected:
@ -1563,6 +1565,8 @@ Returns the map unit scale for the pattern's line offset.
virtual QSet<QString> usedAttributes( const QgsRenderContext &context ) const;
virtual bool hasDataDefinedProperties() const;
protected:
@ -1727,6 +1731,8 @@ Returns the units for the vertical displacement between rows in the pattern.
virtual QSet<QString> usedAttributes( const QgsRenderContext &context ) const;
virtual bool hasDataDefinedProperties() const;
virtual void setColor( const QColor &c );
virtual QColor color() const;
@ -1798,6 +1804,8 @@ class QgsCentroidFillSymbolLayer : QgsFillSymbolLayer
virtual QSet<QString> usedAttributes( const QgsRenderContext &context ) const;
virtual bool hasDataDefinedProperties() const;
void setPointOnSurface( bool pointOnSurface );
bool pointOnSurface() const;

View File

@ -70,6 +70,8 @@ Gets the expression to generate this geometry.
virtual QSet<QString> usedAttributes( const QgsRenderContext &context ) const;
virtual bool hasDataDefinedProperties() const;
virtual bool isCompatibleWithSymbol( QgsSymbol *symbol ) const;

View File

@ -378,6 +378,8 @@ Returns the units for the interval between markers.
virtual QSet<QString> usedAttributes( const QgsRenderContext &context ) const;
virtual bool hasDataDefinedProperties() const;
virtual void setDataDefinedProperty( QgsSymbolLayer::Property key, const QgsProperty &property );

View File

@ -505,6 +505,8 @@ Creates a new QgsFilledMarkerSymbolLayer.
virtual QSet<QString> usedAttributes( const QgsRenderContext &context ) const;
virtual bool hasDataDefinedProperties() const;
virtual void setColor( const QColor &c );
virtual QColor color() const;

View File

@ -459,6 +459,16 @@ Exports the style as a XML file
bool importXml( const QString &filename );
%Docstring
Imports the symbols and colorramps into the default style database from the given XML file
%End
static bool isXmlStyleFile( const QString &path );
%Docstring
Tests if the file at ``path`` is a QGIS style XML file.
This method samples only the first line in the file, so is safe to call on
large xml files.
.. versionadded:: 3.6
%End
signals:

View File

@ -300,6 +300,8 @@ will be overwritten.
.. seealso:: :py:func:`dataDefinedProperties`
.. seealso:: Property
.. versionadded:: 3.0
%End
@ -386,6 +388,8 @@ Returns a reference to the symbol layer's property collection, used for data def
.. seealso:: :py:func:`setDataDefinedProperties`
.. seealso:: Property
.. versionadded:: 3.0
%End
@ -399,6 +403,13 @@ Sets the symbol layer's property collection, used for data defined overrides.
.. seealso:: :py:func:`properties`
.. versionadded:: 3.0
%End
virtual bool hasDataDefinedProperties() const;
%Docstring
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
.. versionadded:: 3.4.5
%End
protected:

View File

@ -74,6 +74,8 @@ A symbol layer class for displaying displacement arrows based on point layer att
virtual QSet<QString> usedAttributes( const QgsRenderContext &context ) const;
virtual bool hasDataDefinedProperties() const;
void setXAttribute( const QString &attribute );
QString xAttribute() const;

View File

@ -41,8 +41,7 @@ result will be communicated to users, but not prevent them from proceeding.
};
class QgsAbstractValidityCheck : QObject
class QgsAbstractValidityCheck
{
%Docstring
Abstract base class for individual validity checks.
@ -77,6 +76,8 @@ Checks must be registered in the application's :py:class:`QgsValidityCheckRegist
TypeUserCheck,
};
virtual ~QgsAbstractValidityCheck();
virtual QgsAbstractValidityCheck *create() const = 0 /Factory/;
%Docstring
Creates a new instance of the check and returns it.
@ -126,9 +127,6 @@ The ``context`` argument gives the wider in which the check is being run.
};
/************************************************************************
* This file has been generated automatically from *
* *

View File

@ -236,6 +236,7 @@
%Include auto_generated/raster/qgssinglebandgrayrenderer.sip
%Include auto_generated/raster/qgssinglebandpseudocolorrenderer.sip
%Include auto_generated/raster/qgshillshaderenderer.sip
%Include auto_generated/mesh/qgsmeshlayerinterpolator.sip
%Include auto_generated/mesh/qgsmeshrenderersettings.sip
%Include auto_generated/scalebar/qgsdoubleboxscalebarrenderer.sip
%Include auto_generated/scalebar/qgsnumericscalebarrenderer.sip
@ -288,6 +289,7 @@
%Include auto_generated/geometry/qgsmultipolygon.sip
%Include auto_generated/geometry/qgsmultisurface.sip
%Include auto_generated/geometry/qgspolygon.sip
%Include auto_generated/geometry/qgsquadrilateral.sip
%Include auto_generated/geometry/qgsrectangle.sip
%Include auto_generated/geometry/qgsreferencedgeometry.sip
%Include auto_generated/geometry/qgsregularpolygon.sip

View File

@ -144,6 +144,8 @@ Returns a reference to the editor widget's property collection, used for data de
.. seealso:: :py:func:`setDataDefinedProperties`
.. seealso:: Property
.. versionadded:: 3.0
%End
@ -155,6 +157,8 @@ Sets the editor widget's property collection, used for data defined overrides.
.. seealso:: :py:func:`dataDefinedProperties`
.. seealso:: Property
.. versionadded:: 3.0
%End

View File

@ -303,6 +303,42 @@ that are shown in the button's drop-down menu.
swatch grids are hidden from the button's drop-down menu.
.. seealso:: :py:func:`setColorSchemeRegistry`
%End
void linkToProjectColor( const QString &name );
%Docstring
Sets the button to link to an existing project color, by color ``name``.
This changes the behavior of the button to a "linked" mode. Specifically,
the button will show the linked color and respond to changes in the project
color scheme by refreshing the displayed color automatically. Additionally,
the button's menu will show items specific to linked color mode, including
an option to "unlink" from the project color.
.. seealso:: :py:func:`linkedProjectColorName`
.. seealso:: :py:func:`unlink`
.. versionadded:: 3.6
%End
QString linkedProjectColorName() const;
%Docstring
Returns the linked project color name, if set.
.. seealso:: :py:func:`linkToProjectColor`
.. versionadded:: 3.6
%End
static QPixmap createMenuIcon( const QColor &color, bool showChecks = true );
%Docstring
Creates an icon for displaying a ``color`` in a drop-down menu.
If ``showChecks`` set to true, then a checkboard pattern will be shown behind
semi-transparent colors.
.. versionadded:: 3.6
%End
public slots:
@ -380,6 +416,17 @@ Sets color to null.
.. seealso:: :py:func:`setToNoColor`
.. versionadded:: 2.16
%End
void unlink();
%Docstring
Unlinks the button from a project color.
.. seealso:: :py:func:`unlinked`
.. seealso:: :py:func:`linkToProjectColor`
.. versionadded:: 3.6
%End
signals:
@ -401,6 +448,18 @@ Emitted when the button is clicked, if the button's behavior is set to SignalOnl
.. seealso:: :py:func:`setBehavior`
.. seealso:: :py:func:`behavior`
%End
void unlinked();
%Docstring
Emitted when the color is unlinked, e.g. when it was previously set to link
to a project color and is now no longer linked.
.. seealso:: :py:func:`unlink`
.. seealso:: :py:func:`linkToProjectColor`
.. versionadded:: 3.6
%End
protected:

View File

@ -39,6 +39,8 @@ Logs a ``message`` to the viewer.
virtual void reject();
virtual bool eventFilter( QObject *obj, QEvent *ev );
};

View File

@ -31,13 +31,14 @@ for added panels.
:param parent:
%End
void setMainPanel( QgsPanelWidget *panel );
void setMainPanel( QgsPanelWidget *panel /Transfer/ );
%Docstring
Adds the main panel widget to the stack and selects it for the user
The main widget can not be closed and only the showPanel signal is attached
Sets the main ``panel`` widget for the stack and selects it for the user.
The main widget cannot be closed and only the showPanel signal is attached
to handle children widget opening panels.
:param panel: The panel to set as the first widget in the stack.
Ownership of ``panel`` is transferred to the stack.
.. note::
@ -59,7 +60,7 @@ and doesn't display a back button.
.. seealso:: :py:func:`setMainPanel`
%End
QgsPanelWidget *takeMainPanel();
QgsPanelWidget *takeMainPanel() /TransferBack/;
%Docstring
Removes the main panel widget from the stack and transfers ownsership to the
caller.

View File

@ -40,7 +40,6 @@ Constructor for QgsPropertyOverrideButton.
:param layer: associated vector layer
%End
void init( int propertyKey,
const QgsProperty &property,
const QgsPropertiesDefinition &definitions,
@ -195,6 +194,17 @@ Register a sibling ``widget`` (line edit, text edit) that will receive the prope
%Docstring
Register an expression context generator class that will be used to retrieve
an expression context for the button when required.
%End
void registerLinkedWidget( QWidget *widget );
%Docstring
Registers a ``widget`` which is linked to this button. The meaning of linked widgets
depends on the property type, and the type of linked widget.
For color properties, linking a QgsColorButton allows the color button to correctly
reflect the status of the property when it's set to follow a project color.
.. versionadded:: 3.6
%End
void updateFieldLists();
@ -212,6 +222,12 @@ Updates list of fields.
Set whether the current property override definition is to be used
%End
void aboutToShowMenu();
void menuActionTriggered( QAction *action );
signals:
void changed();
@ -235,7 +251,6 @@ Emitted when creating a new auxiliary field
};
/************************************************************************
* This file has been generated automatically from *
* *

View File

@ -10,6 +10,7 @@
class QgsStyleManagerDialog : QDialog
{
%Docstring
@ -22,7 +23,8 @@ A dialog allowing users to customize and populate a QgsStyle.
%End
public:
QgsStyleManagerDialog( QgsStyle *style, QWidget *parent /TransferThis/ = 0, Qt::WindowFlags flags = Qt::WindowFlags() );
QgsStyleManagerDialog( QgsStyle *style, QWidget *parent /TransferThis/ = 0, Qt::WindowFlags flags = Qt::WindowFlags(),
bool readOnly = false );
%Docstring
Constructor for QgsStyleManagerDialog, with the specified ``parent`` widget and window ``flags``.
@ -35,10 +37,36 @@ The ``style`` object must last for the lifetime of the dialog.
QString RampType = QString() );
%Docstring
Opens the add color ramp dialog, returning the new color ramp's name if the ramp has been added.
%End
void setFavoritesGroupVisible( bool show );
%Docstring
Sets whether the favorites group should be shown. The default is to show the group.
.. versionadded:: 3.6
%End
void setSmartGroupsVisible( bool show );
%Docstring
Sets whether smart groups should be shown. The default is to show the groups.
.. versionadded:: 3.6
%End
void setBaseStyleName( const QString &name );
%Docstring
Sets the base ``name`` for the style, which is used by the dialog to reflect the
original style/XML file name.
``name`` should be stripped of any extensions and folder information, e.g. "transport_styles",
not "d:/stuff/transport_styles.xml".
.. versionadded:: 3.6
%End
public slots:
void activate();
%Docstring
Raises, unminimizes and activates this window
@ -47,69 +75,132 @@ Raises, unminimizes and activates this window
%End
void addItem();
%Docstring
Triggers the dialog for adding a new item, based on the currently
selected item type tab.
%End
void editItem();
%Docstring
Triggers the dialog for editing the current item.
%End
void removeItem();
%Docstring
Removes the current selected item.
%End
void exportItemsSVG();
%Docstring
Triggers the dialog to export selected items as SVG files.
.. seealso:: :py:func:`exportItemsPNG`
.. seealso:: :py:func:`exportSelectedItemsImages`
%End
void exportItemsPNG();
%Docstring
Triggers the dialog to export selected items as PNG files.
.. seealso:: :py:func:`exportItemsSVG`
.. seealso:: :py:func:`exportSelectedItemsImages`
%End
void exportSelectedItemsImages( const QString &dir, const QString &format, QSize size );
%Docstring
Triggers the dialog to export selected items as images of the specified ``format`` and ``size``.
.. seealso:: :py:func:`exportItemsSVG`
.. seealso:: :py:func:`exportItemsPNG`
%End
void exportItems();
%Docstring
Triggers the dialog to export items.
.. seealso:: :py:func:`importItems`
%End
void importItems();
%Docstring
Triggers the dialog to import items.
.. seealso:: :py:func:`exportItems`
%End
void populateList();
%Docstring
adds symbols of some type to list
Refreshes the list of items.
%End
void onFinished();
%Docstring
called when the dialog is going to be closed
Called when the dialog is going to be closed.
%End
void onClose();
%Docstring
Close the dialog
Closes the dialog
%End
void showHelp();
%Docstring
Open the associated help
Opens the associated help
%End
void itemChanged( QStandardItem *item );
void itemChanged( QStandardItem *item ) /Deprecated/;
%Docstring
.. deprecated:: in QGIS 3.6 - has no effect and will be removed in QGIS 4.0
%End
void groupChanged( const QModelIndex & );
void groupRenamed( QStandardItem * );
%Docstring
Trigerred when the current group (or tag) is changed.
%End
void groupRenamed( QStandardItem *item );
%Docstring
Triggered when a group ``item`` is renamed.
%End
int addTag();
%Docstring
add a tag
Triggers the dialog to add a new tag.
%End
int addSmartgroup();
%Docstring
add a smartgroup
Triggers the dialog to add a new smart group.
%End
void removeGroup();
%Docstring
remove a tag or smartgroup
Removes the selected tag or smartgroup.
%End
void tagSymbolsAction();
%Docstring
carry out symbol tagging using check boxes
Toggles the interactive item tagging mode.
%End
void editSmartgroupAction();
%Docstring
edit the selected smart group
Triggers the dialog for editing the selected smart group.
%End
void regrouped( QStandardItem * );
void regrouped( QStandardItem * ) /Deprecated/;
%Docstring
symbol changed from one group
.. deprecated:: in QGIS 3.6 - has no effect and will be removed in QGIS 4.0
%End
void filterSymbols( const QString & );
void filterSymbols( const QString &filter );
%Docstring
filter the symbols based on input search term
Sets the ``filter`` string to filter symbols by.
%End
void symbolSelected( const QModelIndex & );
@ -153,28 +244,36 @@ Remove all tags from selected symbols
protected:
void populateTypes();
void populateTypes() /Deprecated/;
%Docstring
populate combo box with known style items (symbols, color ramps)
Populate combo box with known style items (symbols, color ramps).
.. deprecated:: in QGIS 3.6 - has no effect and will be removed in QGIS 4.0
%End
void populateGroups();
%Docstring
populate the groups
%End
void setSymbolsChecked( const QStringList & );
void setSymbolsChecked( const QStringList & ) /Deprecated/;
%Docstring
to set symbols checked when in editing mode
.. deprecated:: in QGIS 3.6 - has no effect and will be removed in QGIS 4.0
%End
void populateSymbols( const QStringList &symbolNames, bool checkable = false );
void populateSymbols( const QStringList &symbolNames, bool checkable = false ) /Deprecated/;
%Docstring
populate list view with symbols of the current type with the given names
Populates the list view with symbols of the current type with the given names.
.. deprecated:: No longer required in QGIS 3.6, as the model is updated live. Has no effect and will be removed in QGIS 4.0
%End
void populateColorRamps( const QStringList &colorRamps, bool checkable = false );
void populateColorRamps( const QStringList &colorRamps, bool checkable = false ) /Deprecated/;
%Docstring
populate list view with color ramps
Populates the list view with color ramps of the current type with the given names.
.. deprecated:: No longer required in QGIS 3.6, as the model is updated live. Has no effect and will be removed in QGIS 4.0
%End
int currentItemType();
@ -192,8 +291,17 @@ add a new color ramp to style
bool editSymbol();
bool editColorRamp();
bool removeSymbol();
bool removeColorRamp();
bool removeSymbol() /Deprecated/;
%Docstring
.. deprecated:: in QGIS 3.6 - has no effect and will be removed in QGIS 4.0
%End
bool removeColorRamp() /Deprecated/;
%Docstring
.. deprecated:: in QGIS 3.6 - has no effect and will be removed in QGIS 4.0
%End
void enableSymbolInputs( bool );
%Docstring

View File

@ -465,6 +465,8 @@ class SpatiaLiteDBConnector(DBConnector):
self._execute(c, sql)
self._commit()
return True
def emptyTable(self, table):
""" delete all rows from table """
if self.isRasterTable(table):
@ -494,6 +496,7 @@ class SpatiaLiteDBConnector(DBConnector):
self._execute(c, sql)
self._commit()
return True
def moveTable(self, table, new_table, new_schema=None):
return self.renameTable(table, new_table)
@ -571,7 +574,16 @@ class SpatiaLiteDBConnector(DBConnector):
def addTableColumn(self, table, field_def):
""" add a column to table """
sql = u"ALTER TABLE %s ADD %s" % (self.quoteId(table), field_def)
self._execute_and_commit(sql)
self._execute(None, sql)
sql = u"SELECT InvalidateLayerStatistics(%s)" % (self.quoteId(table))
self._execute(None, sql)
sql = u"SELECT UpdateLayerStatistics(%s)" % (self.quoteId(table))
self._execute(None, sql)
self._commit()
return True
def deleteTableColumn(self, table, column):
""" delete column from a table """

View File

@ -39,6 +39,7 @@ from qgis.core import (QgsProcessingAlgorithm,
QgsProcessingParameterBoolean,
QgsProcessingParameterRasterDestination,
QgsProcessingParameterCrs,
QgsProcessingParameterString,
QgsProcessingOutputLayerDefinition,
QgsProcessingUtils)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
@ -57,6 +58,7 @@ class buildvrt(GdalAlgorithm):
ADD_ALPHA = 'ADD_ALPHA'
ASSIGN_CRS = 'ASSIGN_CRS'
RESAMPLING = 'RESAMPLING'
SRC_NODATA = 'SRC_NODATA'
RESOLUTION_OPTIONS = ['average', 'highest', 'lowest']
RESAMPLING_OPTIONS = ['nearest', 'bilinear', 'cubic', 'cubicspline', 'lanczos', 'average', 'mode']
@ -82,38 +84,45 @@ class buildvrt(GdalAlgorithm):
return 'vrt'
self.addParameter(QgsProcessingParameterMultipleLayers(self.INPUT,
QCoreApplication.translate("ParameterVrtDestination", 'Input layers'),
self.tr('Input layers'),
QgsProcessing.TypeRaster))
self.addParameter(QgsProcessingParameterEnum(self.RESOLUTION,
QCoreApplication.translate("ParameterVrtDestination", 'Resolution'),
self.tr('Resolution'),
options=self.RESOLUTION_OPTIONS,
defaultValue=0))
self.addParameter(QgsProcessingParameterBoolean(self.SEPARATE,
QCoreApplication.translate("ParameterVrtDestination", 'Place each input file into a separate band'),
self.tr('Place each input file into a separate band'),
defaultValue=True))
self.addParameter(QgsProcessingParameterBoolean(self.PROJ_DIFFERENCE,
QCoreApplication.translate("ParameterVrtDestination", 'Allow projection difference'),
self.tr('Allow projection difference'),
defaultValue=False))
add_alpha_param = QgsProcessingParameterBoolean(self.ADD_ALPHA,
QCoreApplication.translate("ParameterVrtDestination", 'Add alpha mask band to VRT when source raster has none'),
self.tr('Add alpha mask band to VRT when source raster has none'),
defaultValue=False)
add_alpha_param.setFlags(add_alpha_param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
self.addParameter(add_alpha_param)
assign_crs = QgsProcessingParameterCrs(self.ASSIGN_CRS,
QCoreApplication.translate("ParameterVrtDestination", 'Override projection for the output file'),
self.tr('Override projection for the output file'),
defaultValue=None, optional=True)
assign_crs.setFlags(assign_crs.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
self.addParameter(assign_crs)
resampling = QgsProcessingParameterEnum(self.RESAMPLING,
QCoreApplication.translate("ParameterVrtDestination", 'Resampling algorithm'),
self.tr('Resampling algorithm'),
options=self.RESAMPLING_OPTIONS,
defaultValue=0)
resampling.setFlags(resampling.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
self.addParameter(resampling)
src_nodata_param = QgsProcessingParameterString(self.SRC_NODATA,
self.tr('Nodata value(s) for input bands (space separated)'),
defaultValue=None,
optional=True)
src_nodata_param.setFlags(src_nodata_param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
self.addParameter(src_nodata_param)
self.addParameter(ParameterVrtDestination(self.OUTPUT, QCoreApplication.translate("ParameterVrtDestination", 'Virtual')))
def name(self):
@ -151,6 +160,10 @@ class buildvrt(GdalAlgorithm):
arguments.append('-r')
arguments.append(self.RESAMPLING_OPTIONS[self.parameterAsEnum(parameters, self.RESAMPLING, context)])
if self.SRC_NODATA in parameters and parameters[self.SRC_NODATA] not in (None, ''):
nodata = self.parameterAsString(parameters, self.SRC_NODATA, context)
arguments.append('-srcnodata "{}"'.format(nodata))
# Always write input files to a text file in case there are many of them and the
# length of the command will be longer then allowed in command prompt
list_file = GdalUtils.writeLayerParameterToTextFile(filename='buildvrtInputFiles.txt', alg=self, parameters=parameters, parameter_name=self.INPUT, context=context, executing=executing, quote=False)

View File

@ -127,7 +127,6 @@ class rasterize(GdalAlgorithm):
init_param = QgsProcessingParameterNumber(self.INIT,
self.tr('Pre-initialize the output image with value'),
type=QgsProcessingParameterNumber.Double,
defaultValue=0.0,
optional=True)
init_param.setFlags(init_param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
self.addParameter(init_param)
@ -181,8 +180,8 @@ class rasterize(GdalAlgorithm):
arguments.append(self.parameterAsDouble(parameters, self.WIDTH, context))
arguments.append(self.parameterAsDouble(parameters, self.HEIGHT, context))
initValue = self.parameterAsDouble(parameters, self.INIT, context)
if initValue:
if self.INIT in parameters and parameters[self.INIT] is not None:
initValue = self.parameterAsDouble(parameters, self.INIT, context)
arguments.append('-init')
arguments.append(initValue)

View File

@ -38,6 +38,7 @@ from qgis.core import (QgsRasterFileWriter,
QgsProcessingParameterEnum,
QgsProcessingParameterBoolean,
QgsProcessingParameterExtent,
QgsProcessingParameterString,
QgsProcessingParameterRasterDestination,
QgsProcessingUtils)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
@ -59,6 +60,7 @@ class warp(GdalAlgorithm):
TARGET_EXTENT = 'TARGET_EXTENT'
TARGET_EXTENT_CRS = 'TARGET_EXTENT_CRS'
MULTITHREADING = 'MULTITHREADING'
EXTRA = 'EXTRA'
OUTPUT = 'OUTPUT'
TYPES = ['Use input layer data type', 'Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64']
@ -139,6 +141,13 @@ class warp(GdalAlgorithm):
multithreading_param.setFlags(multithreading_param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
self.addParameter(multithreading_param)
extra_param = QgsProcessingParameterBoolean(self.EXTRA,
self.tr('Additional command-line parameters'),
defaultValue=None,
optional=True)
extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
self.addParameter(extra_param)
self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
self.tr('Reprojected')))
@ -228,6 +237,10 @@ class warp(GdalAlgorithm):
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))
if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
arguments.append(inLayer.source())
arguments.append(out)

View File

@ -132,8 +132,8 @@ class Grass7Utils:
Find GRASS binary path on the operating system.
Sets global variable Grass7Utils.command
"""
cmdList = ["grass74", "grass72", "grass71", "grass70", "grass",
"grass74.sh", "grass72.sh", "grass71.sh", "grass70.sh", "grass.sh"]
cmdList = ["grass76", "grass74", "grass72", "grass70", "grass",
"grass76.sh", "grass74.sh", "grass72.sh", "grass70.sh", "grass.sh"]
def searchFolder(folder):
"""
@ -544,7 +544,7 @@ class Grass7Utils:
return 'https://grass.osgeo.org/grass{}/manuals/'.format(version)
else:
# GRASS not available!
return 'https://grass.osgeo.org/grass72/manuals/'
return 'https://grass.osgeo.org/grass76/manuals/'
@staticmethod
def getSupportedOutputRasterExtensions():

View File

@ -84,18 +84,13 @@ qgis:createconstantrasterlayer: >
Given an input raster layer and a value, this algorithm generates a new layer with the same extent and cell size as the input one, and all cells with the specified value.
qgis:creategridlines: >
This algorithm creates a line vector layer with a grid covering a given extent.
This algorithm creates a vector layer with a grid covering a given extent. Elements in the grid can be points, lines or polygons.
The size of each element in the grid is defined using a horizontal and vertical spacing.
The size and/or placement of each element in the grid is defined using a horizontal and vertical spacing.
The CRS of the output layer must be defined. The grid extent and the spacing values must be expressed in the coordinates and units of this CRS.
qgis:creategridpolygon: >
This algorithm creates a polygon vector layer with a grid covering a given extent. The grid shape can be rectangles, diamond or hexagons.
The size of each element in the grid is defined using a horizontal and vertical spacing.
The CRS of the output layer must be defined. The grid extent and the spacing values must be expressed in the coordinates and units of this CRS.
The top-left point (minX, maxY) is used as the reference point. That means that, at that point, an element is guaranteed to be placed. Unless the width and height of the selected extent is a multiple of the selected spacing, that is not true for the other points that define that extent.
qgis:createpointsalonglines: >
This algorithm creates a points layer, with points distributed along the lines of an input vector layer. the distance between points (measured along the line) is defined as a parameter.

View File

@ -1,77 +0,0 @@
# -*- coding: utf-8 -*-
"""
***************************************************************************
DensifyGeometriesInterval.py by Anita Graser, Dec 2012
based on DensifyGeometries.py
---------------------
Date : October 2012
Copyright : (C) 2012 by Victor Olaya
Email : volayaf at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
__author__ = 'Anita Graser'
__date__ = 'Dec 2012'
__copyright__ = '(C) 2012, Anita Graser'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
from qgis.core import (QgsProcessingParameterDistance,
QgsProcessing)
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
class DensifyGeometriesInterval(QgisFeatureBasedAlgorithm):
INTERVAL = 'INTERVAL'
def tags(self):
return self.tr('add,vertex,vertices,points,nodes').split(',')
def group(self):
return self.tr('Vector geometry')
def groupId(self):
return 'vectorgeometry'
def __init__(self):
super().__init__()
self.interval = None
def initParameters(self, config=None):
self.addParameter(QgsProcessingParameterDistance(self.INTERVAL,
self.tr('Interval between vertices to add'),
1, 'INPUT', False, 0, 10000000))
def name(self):
return 'densifygeometriesgivenaninterval'
def displayName(self):
return self.tr('Densify by interval')
def outputName(self):
return self.tr('Densified')
def inputLayerTypes(self):
return [QgsProcessing.TypeVectorLine, QgsProcessing.TypeVectorPolygon]
def prepareAlgorithm(self, parameters, context, feedback):
self.interval = self.parameterAsDouble(parameters, self.INTERVAL, context)
return True
def processFeature(self, feature, context, feedback):
if feature.hasGeometry():
new_geometry = feature.geometry().densifyByDistance(float(self.interval))
feature.setGeometry(new_geometry)
return [feature]

View File

@ -129,7 +129,7 @@ class IdwInterpolation(QgisAlgorithm):
layerData = []
layers = []
for row in interpolationData.split(';'):
for row in interpolationData.split('::|::'):
v = row.split('::~::')
data = QgsInterpolator.LayerData()

Some files were not shown because too many files have changed in this diff Show More