Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
More flexible API for interpolation
E.g. adds API support for interpolating by m value
  • Loading branch information
nyalldawson committed Nov 2, 2017
1 parent 73306f1 commit e91ee5b
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 51 deletions.
2 changes: 1 addition & 1 deletion doc/api_break.dox
Expand Up @@ -1490,7 +1490,7 @@ QgsInterpolator {#qgis_api_break_3_0_QgsInterpolator}

- The InputType enum was renamed to SourceType and the enum values were renamed.
- LayerData.vectorLayer was renamed to LayerData.source
- LayerData.zCoordInterpolation was renamed to LayerData.useZValue
- LayerData.zCoordInterpolation was renamed to LayerData.valueSource and now takes a QgsInterpolator.ValueSource enum value.
- LayerData.mInputType was renamed to LayerData.sourceType


Expand Down
11 changes: 9 additions & 2 deletions python/analysis/interpolation/qgsinterpolator.sip
Expand Up @@ -58,6 +58,13 @@ class QgsInterpolator
SourceBreakLines,
};

enum ValueSource
{
ValueAttribute,
ValueZ,
ValueM,
};

enum Result
{
Success,
Expand All @@ -72,9 +79,9 @@ class QgsInterpolator
%Docstring
Feature source
%End
bool useZValue;
ValueSource valueSource;
%Docstring
True if feature geometry z values should be used for interpolation
Source for feature values to interpolate
%End
int interpolationAttribute;
%Docstring
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/qgis/IdwInterpolation.py
Expand Up @@ -159,7 +159,7 @@ def processAlgorithm(self, parameters, context, feedback):
data.source = layer
layers.append(layer)

data.useZValue = bool(v[1])
data.valueSource = int(v[1])
data.interpolationAttribute = int(v[2])
if v[3] == '0':
data.sourceType = QgsInterpolator.SourcePoints
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/qgis/TinInterpolation.py
Expand Up @@ -181,7 +181,7 @@ def processAlgorithm(self, parameters, context, feedback):
if not crs.isValid():
crs = layer.sourceCrs()

data.useZValue = bool(v[1])
data.valueSource = int(v[1])
data.interpolationAttribute = int(v[2])
if v[3] == '0':
data.sourceType = QgsInterpolator.SourcePoints
Expand Down
Expand Up @@ -136,11 +136,11 @@ def value(self):
continue

interpolationAttribute = item.text(1)
interpolationSource = QgsInterpolator.ValueAttribute
if interpolationAttribute == 'Z_COORD':
zCoord = True
interpolationSource = QgsInterpolator.ValueZ
fieldIndex = -1
else:
zCoord = False
fieldIndex = layer.fields().indexFromName(interpolationAttribute)

comboBox = self.layersTree.itemWidget(self.layersTree.topLevelItem(i), 2)
Expand All @@ -152,10 +152,10 @@ def value(self):
else:
inputType = QgsInterpolator.SourceBreakLines

layers += '{},{},{:d},{:d};'.format(layer.source(),
zCoord,
fieldIndex,
inputType)
layers += '{},{:d},{:d},{:d};'.format(layer.source(),
interpolationSource,
fieldIndex,
inputType)
return layers[:-1]


Expand Down
78 changes: 58 additions & 20 deletions src/analysis/interpolation/qgsinterpolator.cpp
Expand Up @@ -53,9 +53,15 @@ QgsInterpolator::Result QgsInterpolator::cacheBaseData( QgsFeedback *feedback )
}

QgsAttributeList attList;
if ( !layer.useZValue )
switch ( layer.valueSource )
{
attList.push_back( layer.interpolationAttribute );
case ValueAttribute:
attList.push_back( layer.interpolationAttribute );
break;

case ValueZ:
case ValueM:
break;
}

double attributeValue = 0.0;
Expand All @@ -75,21 +81,29 @@ QgsInterpolator::Result QgsInterpolator::cacheBaseData( QgsFeedback *feedback )
if ( feedback )
feedback->setProgress( progress );

if ( !layer.useZValue )
switch ( layer.valueSource )
{
QVariant attributeVariant = feature.attribute( layer.interpolationAttribute );
if ( !attributeVariant.isValid() ) //attribute not found, something must be wrong (e.g. NULL value)
{
continue;
}
attributeValue = attributeVariant.toDouble( &attributeConversionOk );
if ( !attributeConversionOk || std::isnan( attributeValue ) ) //don't consider vertices with attributes like 'nan' for the interpolation
case ValueAttribute:
{
continue;
QVariant attributeVariant = feature.attribute( layer.interpolationAttribute );
if ( !attributeVariant.isValid() ) //attribute not found, something must be wrong (e.g. NULL value)
{
continue;
}
attributeValue = attributeVariant.toDouble( &attributeConversionOk );
if ( !attributeConversionOk || std::isnan( attributeValue ) ) //don't consider vertices with attributes like 'nan' for the interpolation
{
continue;
}
break;
}

case ValueZ:
case ValueM:
break;
}

if ( !addVerticesToCache( feature.geometry(), layer.useZValue, attributeValue ) )
if ( !addVerticesToCache( feature.geometry(), layer.valueSource, attributeValue ) )
return FeatureGeometryError;
}
layerCount++;
Expand All @@ -98,21 +112,45 @@ QgsInterpolator::Result QgsInterpolator::cacheBaseData( QgsFeedback *feedback )
return Success;
}

bool QgsInterpolator::addVerticesToCache( const QgsGeometry &geom, bool zCoord, double attributeValue )
bool QgsInterpolator::addVerticesToCache( const QgsGeometry &geom, ValueSource source, double attributeValue )
{
if ( !geom || geom.isEmpty() )
return true; // nothing to do

bool hasZ = geom.constGet()->is3D();
//validate source
switch ( source )
{
case ValueAttribute:
break;

case ValueM:
if ( !geom.constGet()->isMeasure() )
return false;
else
break;

case ValueZ:
if ( !geom.constGet()->is3D() )
return false;
else
break;
}

for ( auto point = geom.vertices_begin(); point != geom.vertices_end(); ++point )
{
if ( hasZ && zCoord )
{
mCachedBaseData.push_back( QgsInterpolatorVertexData( ( *point ).x(), ( *point ).y(), ( *point ).z() ) );
}
else
switch ( source )
{
mCachedBaseData.push_back( QgsInterpolatorVertexData( ( *point ).x(), ( *point ).y(), attributeValue ) );
case ValueM:
mCachedBaseData.push_back( QgsInterpolatorVertexData( ( *point ).x(), ( *point ).y(), ( *point ).m() ) );
break;

case ValueZ:
mCachedBaseData.push_back( QgsInterpolatorVertexData( ( *point ).x(), ( *point ).y(), ( *point ).z() ) );
break;

case ValueAttribute:
mCachedBaseData.push_back( QgsInterpolatorVertexData( ( *point ).x(), ( *point ).y(), attributeValue ) );
break;
}
}
mDataIsCached = true;
Expand Down
18 changes: 13 additions & 5 deletions src/analysis/interpolation/qgsinterpolator.h
Expand Up @@ -72,6 +72,14 @@ class ANALYSIS_EXPORT QgsInterpolator
SourceBreakLines, //!< Break lines
};

//! Source for interpolated values from features
enum ValueSource
{
ValueAttribute, //!< Take value from feature's attribute
ValueZ, //!< Use feature's geometry Z values for interpolation
ValueM, //!< Use feature's geometry M values for interpolation
};

//! Result of an interpolation operation
enum Result
{
Expand All @@ -86,8 +94,8 @@ class ANALYSIS_EXPORT QgsInterpolator
{
//! Feature source
QgsFeatureSource *source = nullptr;
//! True if feature geometry z values should be used for interpolation
bool useZValue = false;
//! Source for feature values to interpolate
ValueSource valueSource = ValueAttribute;
//! Index of feature attribute to use for interpolation
int interpolationAttribute = -1;
//! Source type
Expand Down Expand Up @@ -138,11 +146,11 @@ class ANALYSIS_EXPORT QgsInterpolator
/**
* Helper method that adds the vertices of a geometry to the mCachedBaseData
* \param geom the geometry
* \param zCoord true if the z-coordinate of the geometry is to be interpolated
* \param attributeValue the attribute value for interpolation (if not interpolated from z-coordinate)
* \param source source for values to interpolate from the feature
* \param attributeValue the attribute value for interpolation (if interpolating from attribute value)
*\returns 0 in case of success
*/
bool addVerticesToCache( const QgsGeometry &geom, bool zCoord, double attributeValue );
bool addVerticesToCache( const QgsGeometry &geom, ValueSource source, double attributeValue );
};

#endif
29 changes: 15 additions & 14 deletions src/analysis/interpolation/qgstininterpolator.cpp
Expand Up @@ -93,7 +93,7 @@ void QgsTINInterpolator::initialize()
int nProcessedFeatures = 0;
if ( mFeedback )
{
Q_FOREACH ( const LayerData &layer, mLayerData )
for ( const LayerData &layer : qgis::as_const( mLayerData ) )
{
if ( layer.source )
{
Expand All @@ -103,14 +103,20 @@ void QgsTINInterpolator::initialize()
}

QgsFeature f;
Q_FOREACH ( const LayerData &layer, mLayerData )
for ( const LayerData &layer : qgis::as_const( mLayerData ) )
{
if ( layer.source )
{
QgsAttributeList attList;
if ( !layer.useZValue )
switch ( layer.valueSource )
{
attList.push_back( layer.interpolationAttribute );
case QgsInterpolator::ValueAttribute:
attList.push_back( layer.interpolationAttribute );
break;

case QgsInterpolator::ValueM:
case QgsInterpolator::ValueZ:
break;
}

QgsFeatureIterator fit = layer.source->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( attList ) );
Expand All @@ -126,7 +132,7 @@ void QgsTINInterpolator::initialize()
if ( nFeatures > 0 )
mFeedback->setProgress( 100.0 * static_cast< double >( nProcessedFeatures ) / nFeatures );
}
insertData( &f, layer.useZValue, layer.interpolationAttribute, layer.sourceType );
insertData( f, layer.valueSource, layer.interpolationAttribute, layer.sourceType );
++nProcessedFeatures;
}
}
Expand Down Expand Up @@ -157,16 +163,11 @@ void QgsTINInterpolator::initialize()
}
}

int QgsTINInterpolator::insertData( QgsFeature *f, bool zCoord, int attr, SourceType type )
int QgsTINInterpolator::insertData( const QgsFeature &f, bool zCoord, int attr, SourceType type )
{
if ( !f )
{
return 1;
}

QgsGeometry g = f->geometry();
QgsGeometry g = f.geometry();
{
if ( g.isNull() )
if ( g.isNull() || g.isEmpty() )
{
return 2;
}
Expand All @@ -177,7 +178,7 @@ int QgsTINInterpolator::insertData( QgsFeature *f, bool zCoord, int attr, Source
bool attributeConversionOk = false;
if ( !zCoord )
{
QVariant attributeVariant = f->attribute( attr );
QVariant attributeVariant = f.attribute( attr );
if ( !attributeVariant.isValid() ) //attribute not found, something must be wrong (e.g. NULL value)
{
return 3;
Expand Down
2 changes: 1 addition & 1 deletion src/analysis/interpolation/qgstininterpolator.h
Expand Up @@ -93,7 +93,7 @@ class ANALYSIS_EXPORT QgsTINInterpolator: public QgsInterpolator
\param attr interpolation attribute index (if zCoord is false)
\param type point/structure line, break line
\returns 0 in case of success, -1 if the feature could not be inserted because of numerical problems*/
int insertData( QgsFeature *f, bool zCoord, int attr, SourceType type );
int insertData( const QgsFeature &f, bool zCoord, int attr, SourceType type );
};

#endif

0 comments on commit e91ee5b

Please sign in to comment.