Skip to content

Commit

Permalink
Use a QgsFeatureSink instead of path to shapefile in QgsTinInterpolator
Browse files Browse the repository at this point in the history
Instead of just forcing writing the triangulation to a shapefile (boo!)
change the parameter to use a QgsFeatureSink, so that anything
which implements the QgsFeatureSink interface can be used for
storing the triangulation.
  • Loading branch information
nyalldawson committed Aug 29, 2017
1 parent d5e63bc commit 9ca57bd
Show file tree
Hide file tree
Showing 11 changed files with 116 additions and 61 deletions.
1 change: 1 addition & 0 deletions doc/api_break.dox
Expand Up @@ -2338,6 +2338,7 @@ QgsTINInterpolator {#qgis_api_break_3_0_QgsTINInterpolator}
------------------

- The constructor takes a QgsFeedback argument instead of using a QProgressDialog.
- setExportTriangulationToFile() and setTriangulationFilePath() were removed. Use setTriangulationSink() instead.

QgsTolerance {#qgis_api_break_3_0_QgsTolerance}
------------
Expand Down
22 changes: 20 additions & 2 deletions python/analysis/interpolation/qgstininterpolator.sip
Expand Up @@ -45,8 +45,26 @@ class QgsTINInterpolator: QgsInterpolator
:rtype: int
%End

void setExportTriangulationToFile( bool e );
void setTriangulationFilePath( const QString &filepath );
static QgsFields triangulationFields();
%Docstring
Returns the fields output by features when saving the triangulation.
These fields should be used when creating
a suitable feature sink for setTriangulationSink()
.. seealso:: setTriangulationSink()
.. versionadded:: 3.0
:rtype: QgsFields
%End

void setTriangulationSink( QgsFeatureSink *sink );
%Docstring
Sets the optional ``sink`` for saving the triangulation features.

The sink must be setup to accept LineString features, with fields matching
those returned by triangulationFields().

.. seealso:: triangulationFields()
.. versionadded:: 3.0
%End

};

Expand Down
32 changes: 19 additions & 13 deletions python/plugins/processing/algs/qgis/TinInterpolation.py
Expand Up @@ -30,13 +30,16 @@
from qgis.PyQt.QtGui import QIcon

from qgis.core import (QgsProcessingUtils,
QgsProcessing,
QgsProcessingParameterDefinition,
QgsProcessingParameterEnum,
QgsProcessingParameterNumber,
QgsProcessingParameterExtent,
QgsProcessingParameterRasterDestination,
QgsProcessingParameterFileDestination,
QgsProcessingException)
QgsWkbTypes,
QgsProcessingParameterFeatureSink,
QgsProcessingException,
QgsCoordinateReferenceSystem)
from qgis.analysis import (QgsInterpolator,
QgsTINInterpolator,
QgsGridFileWriter)
Expand Down Expand Up @@ -85,7 +88,6 @@ def dataToString(data):


class TinInterpolation(QgisAlgorithm):

INTERPOLATION_DATA = 'INTERPOLATION_DATA'
METHOD = 'METHOD'
COLUMNS = 'COLUMNS'
Expand All @@ -94,7 +96,7 @@ class TinInterpolation(QgisAlgorithm):
CELLSIZE_Y = 'CELLSIZE_Y'
EXTENT = 'EXTENT'
OUTPUT = 'OUTPUT'
TRIANGULATION_FILE = 'TRIANGULATION_FILE'
TRIANGULATION = 'TRIANGULATION'

def icon(self):
return QIcon(os.path.join(pluginPath, 'images', 'interpolation.png'))
Expand Down Expand Up @@ -134,10 +136,10 @@ def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
self.tr('Interpolated')))

triangulation_file_param = QgsProcessingParameterFileDestination(self.TRIANGULATION_FILE,
self.tr('Triangulation'),
self.tr('SHP files (*.shp)'),
optional=True)
triangulation_file_param = QgsProcessingParameterFeatureSink(self.TRIANGULATION,
self.tr('Triangulation'),
type=QgsProcessing.TypeVectorLine,
optional=True)
triangulation_file_param.setCreateByDefault(False)
self.addParameter(triangulation_file_param)

Expand All @@ -156,7 +158,6 @@ def processAlgorithm(self, parameters, context, feedback):
cellsizeY = self.parameterAsDouble(parameters, self.CELLSIZE_Y, context)
bbox = self.parameterAsExtent(parameters, self.EXTENT, context)
output = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
triangulation = self.parameterAsFileOutput(parameters, self.TRIANGULATION_FILE, context)

if interpolationData is None:
raise QgsProcessingException(
Expand All @@ -168,6 +169,7 @@ def processAlgorithm(self, parameters, context, feedback):

layerData = []
layers = []
crs = QgsCoordinateReferenceSystem()
for row in interpolationData.split(';'):
v = row.split(',')
data = QgsInterpolator.LayerData()
Expand All @@ -176,6 +178,8 @@ def processAlgorithm(self, parameters, context, feedback):
layer = QgsProcessingUtils.mapLayerFromString(v[0], context)
data.vectorLayer = layer
layers.append(layer)
if not crs.isValid():
crs = layer.crs()

data.zCoordInterpolation = bool(v[1])
data.interpolationAttribute = int(v[2])
Expand All @@ -192,10 +196,12 @@ def processAlgorithm(self, parameters, context, feedback):
else:
interpolationMethod = QgsTINInterpolator.CloughTocher

(triangulation_sink, triangulation_dest_id) = self.parameterAsSink(parameters, self.TRIANGULATION, context,
QgsTINInterpolator.triangulationFields(), QgsWkbTypes.LineString, crs)

interpolator = QgsTINInterpolator(layerData, interpolationMethod, feedback)
if triangulation is not None and triangulation != '':
interpolator.setExportTriangulationToFile(True)
interpolator.setTriangulationFilePath(triangulation)
if triangulation_sink is not None:
interpolator.setTriangulationSink(triangulation_sink)

writer = QgsGridFileWriter(interpolator,
output,
Expand All @@ -206,4 +212,4 @@ def processAlgorithm(self, parameters, context, feedback):
cellsizeY)

writer.writeFile(feedback)
return {self.OUTPUT: output}
return {self.OUTPUT: output, self.TRIANGULATION: triangulation_dest_id}
32 changes: 7 additions & 25 deletions src/analysis/interpolation/DualEdgeTriangulation.cpp
Expand Up @@ -3081,30 +3081,9 @@ QList<int> *DualEdgeTriangulation::getPointsAroundEdge( double x, double y )
}
}

bool DualEdgeTriangulation::saveAsShapefile( const QString &fileName ) const
bool DualEdgeTriangulation::saveTriangulation( QgsFeatureSink *sink, QgsFeedback *feedback ) const
{
QString shapeFileName = fileName;

QgsFields fields;
fields.append( QgsField( QStringLiteral( "type" ), QVariant::String, QStringLiteral( "String" ) ) );

// add the extension if not present
if ( shapeFileName.indexOf( QLatin1String( ".shp" ) ) == -1 )
{
shapeFileName += QLatin1String( ".shp" );
}

//delete already existing files
if ( QFile::exists( shapeFileName ) )
{
if ( !QgsVectorFileWriter::deleteShapeFile( shapeFileName ) )
{
return false;
}
}

QgsVectorFileWriter writer( shapeFileName, QStringLiteral( "Utf-8" ), fields, QgsWkbTypes::LineString );
if ( writer.hasError() != QgsVectorFileWriter::NoError )
if ( !sink )
{
return false;
}
Expand All @@ -3123,6 +3102,9 @@ bool DualEdgeTriangulation::saveAsShapefile( const QString &fileName ) const

for ( int i = 0; i < mHalfEdge.size(); ++i )
{
if ( feedback && feedback->isCanceled() )
break;

HalfEdge *currentEdge = mHalfEdge[i];
if ( currentEdge->getPoint() != -1 && mHalfEdge[currentEdge->getDual()]->getPoint() != -1 && !alreadyVisitedEdges[currentEdge->getDual()] )
{
Expand Down Expand Up @@ -3152,14 +3134,14 @@ bool DualEdgeTriangulation::saveAsShapefile( const QString &fileName ) const
}
edgeLineFeature.setAttribute( 0, attributeString );

writer.addFeature( edgeLineFeature );
sink->addFeature( edgeLineFeature, QgsFeatureSink::FastInsert );
}
alreadyVisitedEdges[i] = true;
}

delete [] alreadyVisitedEdges;

return true;
return !feedback || !feedback->isCanceled();
}

double DualEdgeTriangulation::swapMinAngle( int edge ) const
Expand Down
4 changes: 1 addition & 3 deletions src/analysis/interpolation/DualEdgeTriangulation.h
Expand Up @@ -103,9 +103,7 @@ class ANALYSIS_EXPORT DualEdgeTriangulation: public Triangulation
//! Returns a value list with the numbers of the four points, which would be affected by an edge swap. This function is e.g. needed by NormVecDecorator to know the points, for which the normals have to be recalculated. The returned ValueList has to be deleted by the code which calls the method
virtual QList<int> *getPointsAroundEdge( double x, double y ) override;

/** Saves the triangulation as a (line) shapefile
\returns true in case of success*/
virtual bool saveAsShapefile( const QString &fileName ) const override;
virtual bool saveTriangulation( QgsFeatureSink *sink, QgsFeedback *feedback = nullptr ) const override;

protected:
//! X-coordinate of the upper right corner of the bounding box
Expand Down
6 changes: 3 additions & 3 deletions src/analysis/interpolation/NormVecDecorator.cpp
Expand Up @@ -17,6 +17,7 @@
#include "NormVecDecorator.h"
#include "qgsfeedback.h"
#include "qgslogger.h"
#include "qgsfields.h"
#include <QApplication>

NormVecDecorator::~NormVecDecorator()
Expand Down Expand Up @@ -590,13 +591,12 @@ bool NormVecDecorator::swapEdge( double x, double y )
}
}

bool NormVecDecorator::saveAsShapefile( const QString &fileName ) const
bool NormVecDecorator::saveTriangulation( QgsFeatureSink *sink, QgsFeedback *feedback ) const
{
if ( !mTIN )
{
return false;
}
return mTIN->saveAsShapefile( fileName );
return mTIN->saveTriangulation( sink, feedback );
}


4 changes: 1 addition & 3 deletions src/analysis/interpolation/NormVecDecorator.h
Expand Up @@ -68,9 +68,7 @@ class ANALYSIS_EXPORT NormVecDecorator: public TriDecorator
//! Swaps the edge which is closest to the point with x and y coordinates (if this is possible) and forces recalculation of the concerned normals (if alreadyestimated is true)
virtual bool swapEdge( double x, double y ) override;

/** Saves the triangulation as a (line) shapefile
\returns true in case of success*/
virtual bool saveAsShapefile( const QString &fileName ) const override;
virtual bool saveTriangulation( QgsFeatureSink *sink, QgsFeedback *feedback = nullptr ) const override;

protected:
//! Is true, if the normals already have been estimated
Expand Down
8 changes: 7 additions & 1 deletion src/analysis/interpolation/Triangulation.cpp
Expand Up @@ -13,5 +13,11 @@
* *
***************************************************************************/
#include "Triangulation.h"
#include "qgsfields.h"

//empty file (abstract class)
QgsFields Triangulation::triangulationFields()
{
QgsFields fields;
fields.append( QgsField( QStringLiteral( "type" ), QVariant::String, QStringLiteral( "String" ) ) );
return fields;
}
23 changes: 21 additions & 2 deletions src/analysis/interpolation/Triangulation.h
Expand Up @@ -23,7 +23,10 @@
#include "TriangleInterpolator.h"
#include "qgis_analysis.h"

class QgsFeatureSink;
class Line3D;
class QgsFields;
class QgsFeedback;

#define SIP_NO_FILE

Expand Down Expand Up @@ -152,10 +155,26 @@ class ANALYSIS_EXPORT Triangulation
virtual bool swapEdge( double x, double y ) = 0;

/**
* Saves the triangulation as a (line) shapefile
* Returns the fields output by features when calling
* saveTriangulation(). These fields should be used when creating
* a suitable feature sink for saveTriangulation()
* \see saveTriangulation()
* \since QGIS 3.0
*/
static QgsFields triangulationFields();

/**
* Saves the triangulation features to a feature \a sink.
*
* The sink must be setup to accept LineString features, with fields matching
* those returned by triangulationFields().
*
* \returns true in case of success
*
* \see triangulationFields()
* \since QGIS 3.0
*/
virtual bool saveAsShapefile( const QString &fileName ) const = 0;
virtual bool saveTriangulation( QgsFeatureSink *sink, QgsFeedback *feedback = nullptr ) const = 0;
};

#ifndef SIP_RUN
Expand Down
15 changes: 12 additions & 3 deletions src/analysis/interpolation/qgstininterpolator.cpp
Expand Up @@ -35,7 +35,6 @@ QgsTINInterpolator::QgsTINInterpolator( const QList<LayerData> &inputData, TINIn
, mTriangleInterpolator( nullptr )
, mIsInitialized( false )
, mFeedback( feedback )
, mExportTriangulationToFile( false )
, mInterpolation( interpolation )
{
}
Expand Down Expand Up @@ -67,6 +66,16 @@ int QgsTINInterpolator::interpolatePoint( double x, double y, double &result )
return 0;
}

QgsFields QgsTINInterpolator::triangulationFields()
{
return Triangulation::triangulationFields();
}

void QgsTINInterpolator::setTriangulationSink( QgsFeatureSink *sink )
{
mTriangulationSink = sink;
}

void QgsTINInterpolator::initialize()
{
DualEdgeTriangulation *dualEdgeTriangulation = new DualEdgeTriangulation( 100000, nullptr );
Expand Down Expand Up @@ -143,9 +152,9 @@ void QgsTINInterpolator::initialize()
mIsInitialized = true;

//debug
if ( mExportTriangulationToFile )
if ( mTriangulationSink )
{
dualEdgeTriangulation->saveAsShapefile( mTriangulationFilePath );
dualEdgeTriangulation->saveTriangulation( mTriangulationSink, mFeedback );
}
}

Expand Down
30 changes: 24 additions & 6 deletions src/analysis/interpolation/qgstininterpolator.h
Expand Up @@ -22,10 +22,12 @@
#include <QString>
#include "qgis_analysis.h"

class QgsFeatureSink;
class Triangulation;
class TriangleInterpolator;
class QgsFeature;
class QgsFeedback;
class QgsFields;

/** \ingroup analysis
* Interpolation in a triangular irregular network*/
Expand Down Expand Up @@ -54,18 +56,34 @@ class ANALYSIS_EXPORT QgsTINInterpolator: public QgsInterpolator
\returns 0 in case of success*/
int interpolatePoint( double x, double y, double &result ) override;

void setExportTriangulationToFile( bool e ) {mExportTriangulationToFile = e;}
void setTriangulationFilePath( const QString &filepath ) {mTriangulationFilePath = filepath;}
/**
* Returns the fields output by features when saving the triangulation.
* These fields should be used when creating
* a suitable feature sink for setTriangulationSink()
* \see setTriangulationSink()
* \since QGIS 3.0
*/
static QgsFields triangulationFields();

/**
* Sets the optional \a sink for saving the triangulation features.
*
* The sink must be setup to accept LineString features, with fields matching
* those returned by triangulationFields().
*
* \see triangulationFields()
* \since QGIS 3.0
*/
void setTriangulationSink( QgsFeatureSink *sink );

private:
Triangulation *mTriangulation = nullptr;
TriangleInterpolator *mTriangleInterpolator = nullptr;
bool mIsInitialized;
QgsFeedback *mFeedback = nullptr;
//! If true: export triangulation to shapefile after initialization
bool mExportTriangulationToFile;
//! File path to export the triangulation
QString mTriangulationFilePath;

//! Feature sink for triangulation
QgsFeatureSink *mTriangulationSink = nullptr;
//! Type of interpolation
TINInterpolation mInterpolation;

Expand Down

0 comments on commit 9ca57bd

Please sign in to comment.