20#include <QApplication> 
   30#include <pdal/StageFactory.hpp> 
   31#include <pdal/io/BufferReader.hpp> 
   32#include <pdal/Dimension.hpp> 
   40      return QStringLiteral( 
"GPKG" );
 
   42      return QStringLiteral( 
"DXF" );
 
   44      return QStringLiteral( 
"ESRI Shapefile" );
 
   46      return QStringLiteral( 
"CSV" );
 
   55  : mLayerAttributeCollection( layer->attributes() )
 
   56  , mIndex( layer->dataProvider()->index()->clone().release() )
 
   63    mPointRecordFormat = 3;
 
   87  mFilterGeometryEngine.reset( 
new QgsGeos( geometry ) );
 
   88  mFilterGeometryEngine->prepareGeometry();
 
   97  QVector< QgsGeometry > allGeometries;
 
  100  if ( selectedFeaturesOnly )
 
  112      allGeometries.append( f.
geometry() );
 
  122    QgsDebugError( QStringLiteral( 
"Error transforming union of filter layer: %1" ).arg( cse.
what() ) );
 
  123    QgsDebugError( QStringLiteral( 
"FilterGeometry will be ignored." ) );
 
  131  mRequestedAttributes.clear();
 
  133  const QVector<QgsPointCloudAttribute> allAttributes = mLayerAttributeCollection.
attributes();
 
  137    if ( attribute.name().compare( QLatin1String( 
"X" ), Qt::CaseInsensitive ) &&
 
  138         attribute.name().compare( QLatin1String( 
"Y" ), Qt::CaseInsensitive ) &&
 
  139         attribute.name().compare( QLatin1String( 
"Z" ), Qt::CaseInsensitive ) &&
 
  140         attributeList.contains( attribute.name() ) &&
 
  141         ! mRequestedAttributes.contains( attribute.name() ) )
 
  143      mRequestedAttributes.append( attribute.name() );
 
  150  QStringList allAttributeNames;
 
  151  const QVector<QgsPointCloudAttribute> allAttributes = mLayerAttributeCollection.
attributes();
 
  154    allAttributeNames.append( attribute.name() );
 
  161  const QVector<QgsPointCloudAttribute> allAttributes = mLayerAttributeCollection.
attributes();
 
  166    if ( attribute.name().compare( QLatin1String( 
"X" ), Qt::CaseInsensitive ) ||
 
  167         attribute.name().compare( QLatin1String( 
"Y" ), Qt::CaseInsensitive ) ||
 
  168         attribute.name().compare( QLatin1String( 
"Z" ), Qt::CaseInsensitive ) ||
 
  169         mRequestedAttributes.contains( attribute.name(), Qt::CaseInsensitive ) )
 
  171      requestAttributes.
push_back( attribute );
 
  174  return requestAttributes;
 
  177QgsFields QgsPointCloudLayerExporter::outputFields()
 
  184    if ( mRequestedAttributes.contains( attribute.name(), Qt::CaseInsensitive ) )
 
  185      fields.
append( 
QgsField( attribute.name(), attribute.variantType(), attribute.displayType() ) );
 
  193  mMemoryLayer = 
nullptr;
 
  197    if ( QApplication::instance()->thread() != QThread::currentThread() )
 
  198      QgsDebugMsgLevel( QStringLiteral( 
"prepareExport() should better be called from the main thread!" ), 2 );
 
  215      QgsDebugError( QStringLiteral( 
"Error transforming extent: %1" ).arg( cse.
what() ) );
 
  219  QStringList layerCreationOptions;
 
  228      ExporterMemory exp( 
this );
 
  240        ExporterPdal exp( 
this );
 
  243      catch ( std::runtime_error &e )
 
  245        setLastError( QString::fromLatin1( e.what() ) );
 
  246        QgsDebugError( QStringLiteral( 
"PDAL has thrown an exception: {}" ).arg( e.what() ) );
 
  253      layerCreationOptions << QStringLiteral( 
"GEOMETRY=AS_XYZ" )
 
  254                           << QStringLiteral( 
"SEPARATOR=COMMA" ); 
 
  271      ExporterVector exp( 
this );
 
  285      mMemoryLayer = 
nullptr;
 
  291      const QFileInfo fileInfo( mFilename );
 
  292      return new QgsPointCloudLayer( mFilename, fileInfo.completeBaseName(), QStringLiteral( 
"pdal" ) );
 
  297      QString uri( mFilename );
 
  298      uri += 
"|layername=" + mName;
 
  306      const QFileInfo fileInfo( mFilename );
 
  307      return new QgsVectorLayer( mFilename, fileInfo.completeBaseName(), QStringLiteral( 
"ogr" ) );
 
  317void QgsPointCloudLayerExporter::ExporterBase::run()
 
  319  QgsRectangle geometryFilterRectangle( -std::numeric_limits<double>::infinity(),
 
  320                                        -std::numeric_limits<double>::infinity(),
 
  321                                        std::numeric_limits<double>::infinity(),
 
  322                                        std::numeric_limits<double>::infinity(),
 
  324  if ( mParent->mFilterGeometryEngine )
 
  331  QVector<IndexedPointCloudNode> nodes;
 
  332  qint64 pointCount = 0;
 
  333  QQueue<IndexedPointCloudNode> queue;
 
  334  queue.push_back( mParent->mIndex->root() );
 
  335  while ( !queue.empty() )
 
  339    const QgsRectangle nodeExtent = mParent->mIndex->nodeMapExtent( node );
 
  340    if ( mParent->mExtent.intersects( nodeExtent ) &&
 
  341         mParent->mZRange.overlaps( mParent->mIndex->nodeZRange( node ) ) &&
 
  342         geometryFilterRectangle.intersects( nodeExtent ) )
 
  344      pointCount += mParent->mIndex->nodePointCount( node );
 
  345      nodes.push_back( node );
 
  349      queue.push_back( child );
 
  353  const qint64 pointsToExport = mParent->mPointsLimit > 0 ? std::min( mParent->mPointsLimit, pointCount ) : pointCount;
 
  355  request.
setAttributes( mParent->requestedAttributeCollection() );
 
  356  std::unique_ptr<QgsPointCloudBlock> block = 
nullptr;
 
  357  qint64 pointsExported = 0;
 
  360    block.reset( mParent->mIndex->nodeData( node, request ) );
 
  362    const char *ptr = block->data();
 
  363    int count = block->pointCount();
 
  367    int xOffset = 0, yOffset = 0, zOffset = 0;
 
  371    for ( 
int i = 0; i < count; ++i )
 
  374      if ( mParent->mFeedback &&
 
  377        mParent->mFeedback->setProgress( 100 * 
static_cast< float >( pointsExported ) / pointsToExport );
 
  378        if ( mParent->mFeedback->isCanceled() )
 
  380          mParent->setLastError( QObject::tr( 
"Canceled by user" ) );
 
  385      if ( pointsExported >= pointsToExport )
 
  395      if ( ! mParent->mZRange.contains( z ) ||
 
  396           ! mParent->mExtent.contains( x, y ) ||
 
  397           ( mParent->mFilterGeometryEngine && ! mParent->mFilterGeometryEngine->contains( x, y ) ) )
 
  404        mParent->mTransform->transformInPlace( x, y, z );
 
  406        handlePoint( x, y, z, attributeMap, pointsExported );
 
  411        QgsDebugError( QStringLiteral( 
"Error transforming point: %1" ).arg( cse.
what() ) );
 
  428QgsPointCloudLayerExporter::ExporterMemory::~ExporterMemory()
 
  430  mParent->mMemoryLayer->moveToThread( QApplication::instance()->thread() );
 
  433void QgsPointCloudLayerExporter::ExporterMemory::handlePoint( 
double x, 
double y, 
double z, 
const QVariantMap &map, 
const qint64 pointNumber )
 
  435  Q_UNUSED( pointNumber )
 
  440  for ( 
const QString &attribute : std::as_const( mParent->mRequestedAttributes ) )
 
  442    const double val = map[ attribute ].toDouble();
 
  443    featureAttributes.append( val );
 
  446  mFeatures.append( feature );
 
  449void QgsPointCloudLayerExporter::ExporterMemory::handleNode()
 
  451  QgsVectorLayer *vl = qgis::down_cast<QgsVectorLayer *>( mParent->mMemoryLayer );
 
  462void QgsPointCloudLayerExporter::ExporterMemory::handleAll()
 
  476QgsPointCloudLayerExporter::ExporterVector::~ExporterVector()
 
  478  delete mParent->mVectorSink;
 
  479  mParent->mVectorSink = 
nullptr;
 
  482void QgsPointCloudLayerExporter::ExporterVector::handlePoint( 
double x, 
double y, 
double z, 
const QVariantMap &map, 
const qint64 pointNumber )
 
  484  Q_UNUSED( pointNumber )
 
  489  for ( 
const QString &attribute : std::as_const( mParent->mRequestedAttributes ) )
 
  491    const double val = map[ attribute ].toDouble();
 
  492    featureAttributes.append( val );
 
  495  mFeatures.append( feature );
 
  498void QgsPointCloudLayerExporter::ExporterVector::handleNode()
 
  500  if ( ! mParent->mVectorSink->addFeatures( mFeatures ) )
 
  502    mParent->setLastError( mParent->mVectorSink->lastError() );
 
  507void QgsPointCloudLayerExporter::ExporterVector::handleAll()
 
  519  : mPointFormat( exp->mPointRecordFormat )
 
  523  mOptions.add( 
"filename", mParent->mFilename.toStdString() );
 
  524  mOptions.add( 
"a_srs", mParent->mTargetCrs.toWkt().toStdString() );
 
  525  mOptions.add( 
"minor_version", QStringLiteral( 
"4" ).toStdString() ); 
 
  526  mOptions.add( 
"format", QString::number( mPointFormat ).toStdString() );
 
  527  if ( mParent->mTransform->isShortCircuited() )
 
  529    mOptions.add( 
"offset_x", QString::number( mParent->mIndex->offset().x() ).toStdString() );
 
  530    mOptions.add( 
"offset_y", QString::number( mParent->mIndex->offset().y() ).toStdString() );
 
  531    mOptions.add( 
"offset_z", QString::number( mParent->mIndex->offset().z() ).toStdString() );
 
  532    mOptions.add( 
"scale_x", QString::number( mParent->mIndex->scale().x() ).toStdString() );
 
  533    mOptions.add( 
"scale_y", QString::number( mParent->mIndex->scale().y() ).toStdString() );
 
  534    mOptions.add( 
"scale_z", QString::number( mParent->mIndex->scale().z() ).toStdString() );
 
  537  mTable.layout()->registerDim( pdal::Dimension::Id::X );
 
  538  mTable.layout()->registerDim( pdal::Dimension::Id::Y );
 
  539  mTable.layout()->registerDim( pdal::Dimension::Id::Z );
 
  541  mTable.layout()->registerDim( pdal::Dimension::Id::Classification );
 
  542  mTable.layout()->registerDim( pdal::Dimension::Id::Intensity );
 
  543  mTable.layout()->registerDim( pdal::Dimension::Id::ReturnNumber );
 
  544  mTable.layout()->registerDim( pdal::Dimension::Id::NumberOfReturns );
 
  545  mTable.layout()->registerDim( pdal::Dimension::Id::ScanDirectionFlag );
 
  546  mTable.layout()->registerDim( pdal::Dimension::Id::EdgeOfFlightLine );
 
  547  mTable.layout()->registerDim( pdal::Dimension::Id::ScanAngleRank );
 
  548  mTable.layout()->registerDim( pdal::Dimension::Id::UserData );
 
  549  mTable.layout()->registerDim( pdal::Dimension::Id::PointSourceId );
 
  551  if ( mPointFormat == 6 || mPointFormat == 7 || mPointFormat == 8 || mPointFormat == 9 || mPointFormat == 10 )
 
  553    mTable.layout()->registerDim( pdal::Dimension::Id::ScanChannel );
 
  554    mTable.layout()->registerDim( pdal::Dimension::Id::ClassFlags );
 
  557  if ( mPointFormat != 0 && mPointFormat != 2 )
 
  559    mTable.layout()->registerDim( pdal::Dimension::Id::GpsTime );
 
  562  if ( mPointFormat == 2 || mPointFormat == 3 || mPointFormat == 5 || mPointFormat == 7 || mPointFormat == 8 || mPointFormat == 10 )
 
  564    mTable.layout()->registerDim( pdal::Dimension::Id::Red );
 
  565    mTable.layout()->registerDim( pdal::Dimension::Id::Green );
 
  566    mTable.layout()->registerDim( pdal::Dimension::Id::Blue );
 
  569  if ( mPointFormat == 8 || mPointFormat == 10 )
 
  571    mTable.layout()->registerDim( pdal::Dimension::Id::Infrared );
 
  574  mView.reset( 
new pdal::PointView( mTable ) );
 
  577void QgsPointCloudLayerExporter::ExporterPdal::handlePoint( 
double x, 
double y, 
double z, 
const QVariantMap &map, 
const qint64 pointNumber )
 
  579  mView->setField( pdal::Dimension::Id::X, pointNumber, x );
 
  580  mView->setField( pdal::Dimension::Id::Y, pointNumber, y );
 
  581  mView->setField( pdal::Dimension::Id::Z, pointNumber, z );
 
  584  mView->setField( pdal::Dimension::Id::Classification, pointNumber, map[ QStringLiteral( 
"Classification" ) ].toInt() );
 
  585  mView->setField( pdal::Dimension::Id::Intensity, pointNumber, map[ QStringLiteral( 
"Intensity" ) ].toInt() );
 
  586  mView->setField( pdal::Dimension::Id::ReturnNumber, pointNumber, map[ QStringLiteral( 
"ReturnNumber" ) ].toInt() );
 
  587  mView->setField( pdal::Dimension::Id::NumberOfReturns, pointNumber, map[ QStringLiteral( 
"NumberOfReturns" ) ].toInt() );
 
  588  mView->setField( pdal::Dimension::Id::ScanDirectionFlag, pointNumber, map[ QStringLiteral( 
"ScanDirectionFlag" ) ].toInt() );
 
  589  mView->setField( pdal::Dimension::Id::EdgeOfFlightLine, pointNumber, map[ QStringLiteral( 
"EdgeOfFlightLine" ) ].toInt() );
 
  590  mView->setField( pdal::Dimension::Id::ScanAngleRank, pointNumber, map[ QStringLiteral( 
"ScanAngleRank" ) ].toInt() );
 
  591  mView->setField( pdal::Dimension::Id::UserData, pointNumber, map[ QStringLiteral( 
"UserData" ) ].toInt() );
 
  592  mView->setField( pdal::Dimension::Id::PointSourceId, pointNumber, map[ QStringLiteral( 
"PointSourceId" ) ].toInt() );
 
  594  if ( mPointFormat == 6 || mPointFormat == 7 || mPointFormat == 8 || mPointFormat == 9 || mPointFormat == 10 )
 
  596    mView->setField( pdal::Dimension::Id::ScanChannel, pointNumber, map[ QStringLiteral( 
"ScannerChannel" ) ].toInt() );
 
  597    mView->setField( pdal::Dimension::Id::ClassFlags, pointNumber, map[ QStringLiteral( 
"ClassificationFlags" ) ].toInt() );
 
  600  if ( mPointFormat != 0 && mPointFormat != 2 )
 
  602    mView->setField( pdal::Dimension::Id::GpsTime, pointNumber, map[ QStringLiteral( 
"GpsTime" ) ].toDouble() );
 
  605  if ( mPointFormat == 2 || mPointFormat == 3 || mPointFormat == 5 || mPointFormat == 7 || mPointFormat == 8 || mPointFormat == 10 )
 
  607    mView->setField( pdal::Dimension::Id::Red, pointNumber, map[ QStringLiteral( 
"Red" ) ].toInt() );
 
  608    mView->setField( pdal::Dimension::Id::Green, pointNumber, map[ QStringLiteral( 
"Green" ) ].toInt() );
 
  609    mView->setField( pdal::Dimension::Id::Blue, pointNumber, map[ QStringLiteral( 
"Blue" ) ].toInt() );
 
  612  if ( mPointFormat == 8 || mPointFormat == 10 )
 
  614    mView->setField( pdal::Dimension::Id::Infrared, pointNumber, map[ QStringLiteral( 
"Infrared" ) ].toInt() );
 
  618void QgsPointCloudLayerExporter::ExporterPdal::handleNode()
 
  623void QgsPointCloudLayerExporter::ExporterPdal::handleAll()
 
  625  pdal::BufferReader reader;
 
  626  reader.addView( mView );
 
  628  pdal::StageFactory factory;
 
  630  pdal::Stage *writer = factory.createStage( 
"writers.las" );
 
  632  writer->setInput( reader );
 
  633  writer->setOptions( mOptions );
 
  634  writer->prepare( mTable );
 
  635  writer->execute( mTable );
 
  652  mOwnedFeedback->cancel();
 
Represents a indexed point cloud node in octree.
 
@ NoSymbology
Export only data.
 
Abstract base class for all geometries.
 
virtual QgsRectangle boundingBox() const =0
Returns the minimal bounding box for the geometry.
 
This class represents a coordinate reference system (CRS).
 
Contains information about the context in which a coordinate transform is executed.
 
Custom exception class for Coordinate Reference System related exceptions.
 
Wrapper for iterator of features from vector data provider or vector layer.
 
bool nextFeature(QgsFeature &f)
 
This class wraps a request for features to a vector layer (or directly its vector data provider).
 
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
 
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
 
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
 
bool hasGeometry() const
Returns true if the feature has an associated geometry.
 
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
 
Base class for feedback objects to be used for cancellation of something running in a worker thread.
 
void progressChanged(double progress)
Emitted when the feedback object reports a progress change.
 
Encapsulate a field in an attribute table or data source.
 
Container of fields for a vector layer.
 
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
 
A geometry is the spatial representation of a feature.
 
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
 
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
 
static QgsGeometry unaryUnion(const QVector< QgsGeometry > &geometries, const QgsGeometryParameters ¶meters=QgsGeometryParameters())
Compute the unary union on a list of geometries.
 
Does vector analysis using the geos library and handles import, export, exception handling*.
 
Base class for all map layer types.
 
QgsCoordinateReferenceSystem crs
 
static QgsVectorLayer * createMemoryLayer(const QString &name, const QgsFields &fields, Qgis::WkbType geometryType=Qgis::WkbType::NoGeometry, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem(), bool loadDefaultStyle=true) SIP_FACTORY
Creates a new memory layer using the specified parameters.
 
Collection of point cloud attributes.
 
void push_back(const QgsPointCloudAttribute &attribute)
Adds extra attribute.
 
int pointRecordSize() const
Returns total size of record.
 
const QgsPointCloudAttribute * find(const QString &attributeName, int &offset) const
Finds the attribute with the name.
 
QVector< QgsPointCloudAttribute > attributes() const
Returns all attributes.
 
Attribute for point cloud data pair of name and size in bytes.
 
DataType
Systems of unit measurement.
 
static void getPointXYZ(const char *ptr, int i, std::size_t pointRecordSize, int xOffset, QgsPointCloudAttribute::DataType xType, int yOffset, QgsPointCloudAttribute::DataType yType, int zOffset, QgsPointCloudAttribute::DataType zType, const QgsVector3D &indexScale, const QgsVector3D &indexOffset, double &x, double &y, double &z)
Retrieves the x, y, z values for the point at index i.
 
static QVariantMap getAttributeMap(const char *data, std::size_t recordOffset, const QgsPointCloudAttributeCollection &attributeCollection)
Retrieves all the attributes of a point.
 
DataType type() const
Returns the data type.
 
virtual QVariantMap originalMetadata() const
Returns a representation of the original metadata included in a point cloud dataset.
 
void cancel() override
Notifies the task that it should terminate.
 
QgsPointCloudLayerExporterTask(QgsPointCloudLayerExporter *exporter)
Constructor for QgsPointCloudLayerExporterTask.
 
void exportComplete()
Emitted when exporting the layer is successfully completed.
 
void finished(bool result) override
If the task is managed by a QgsTaskManager, this will be called after the task has finished (whether ...
 
bool run() override
Performs the task's operation.
 
Handles exporting point cloud layers to memory layers, OGR supported files and PDAL supported files.
 
void setFeedback(QgsFeedback *feedback)
Sets a QgsFeedback object to allow cancellation / progress reporting.
 
QgsMapLayer * takeExportedLayer()
Gets a pointer to the exported layer.
 
ExportFormat format() const
Returns the format for the exported file or layer.
 
void setAttributes(const QStringList &attributes)
Sets the list of point cloud attributes that will be exported.
 
ExportFormat
Supported export formats for point clouds.
 
@ Csv
Comma separated values.
 
@ Las
LAS/LAZ point cloud.
 
~QgsPointCloudLayerExporter()
 
void setAllAttributes()
Sets that all attributes will be exported.
 
bool setFormat(const ExportFormat format)
Sets the format for the exported file.
 
static QString getOgrDriverName(ExportFormat format)
Gets the OGR driver name for the specified format.
 
QStringList attributes() const
Gets the list of point cloud attributes that will be exported.
 
QgsPointCloudLayerExporter(QgsPointCloudLayer *layer)
Constructor for QgsPointCloudLayerExporter, associated with the specified layer.
 
void prepareExport()
Creates the QgsVectorLayer for exporting to a memory layer, if necessary.
 
static QList< ExportFormat > supportedFormats()
Gets a list of the supported export formats.
 
void setFilterGeometry(const QgsAbstractGeometry *geometry)
Sets a spatial filter for points to be exported based on geom in the point cloud's CRS.
 
void doExport()
Performs the actual exporting operation.
 
Represents a map layer supporting display of point clouds.
 
QgsPointCloudDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
 
Point cloud data request.
 
void setAttributes(const QgsPointCloudAttributeCollection &attributes)
Set attributes filter in the request.
 
Point geometry type, with support for z-dimension and m-values.
 
A rectangle specified with double values.
 
bool isFinite() const
Returns true if the rectangle has finite boundaries.
 
Abstract base class for long running background tasks.
 
virtual void cancel()
Notifies the task that it should terminate.
 
void setProgress(double progress)
Sets the task's current progress.
 
QString lastError() const override
Returns the most recent error encountered by the sink, e.g.
 
bool addFeatures(QgsFeatureList &flist, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a list of features to the sink.
 
Options to pass to writeAsVectorFormat()
 
QString driverName
OGR driver to use.
 
QString layerName
Layer name. If let empty, it will be derived from the filename.
 
QStringList layerOptions
List of OGR layer creation options.
 
Qgis::FeatureSymbologyExport symbologyExport
Symbology to export.
 
QgsVectorFileWriter::ActionOnExistingFile actionOnExistingFile
Action on existing file.
 
QStringList datasourceOptions
List of OGR data source creation options.
 
QgsFeedback * feedback
Optional feedback object allowing cancellation of layer save.
 
static QStringList defaultLayerOptions(const QString &driverName)
Returns a list of the default layer options for a specified driver.
 
static QgsVectorFileWriter * create(const QString &fileName, const QgsFields &fields, Qgis::WkbType geometryType, const QgsCoordinateReferenceSystem &srs, const QgsCoordinateTransformContext &transformContext, const QgsVectorFileWriter::SaveVectorOptions &options, QgsFeatureSink::SinkFlags sinkFlags=QgsFeatureSink::SinkFlags(), QString *newFilename=nullptr, QString *newLayer=nullptr)
Create a new vector file writer.
 
static QStringList defaultDatasetOptions(const QString &driverName)
Returns a list of the default dataset options for a specified driver.
 
Represents a vector layer which manages a vector based data sets.
 
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
 
QgsFeatureIterator getSelectedFeatures(QgsFeatureRequest request=QgsFeatureRequest()) const
Returns an iterator of the selected features.
 
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
 
#define BUILTIN_UNREACHABLE
 
#define QgsDebugMsgLevel(str, level)
 
#define QgsDebugError(str)
 
const QgsCoordinateReferenceSystem & crs