QGIS API Documentation 4.3.0-Master (9ff14a2eeba)
Loading...
Searching...
No Matches
qgspointcloudlayerexporter.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgspointcloudlayerexporter.cpp
3 ---------------------
4 begin : July 2022
5 copyright : (C) 2022 by Stefanos Natsis
6 email : uclaros at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19
20#include "qgsgeos.h"
23#include "qgsrectangle.h"
24#include "qgsvectorfilewriter.h"
25
26#include <QApplication>
27#include <QFileInfo>
28#include <QQueue>
29#include <QString>
30#include <QThread>
31
32#include "moc_qgspointcloudlayerexporter.cpp"
33
34using namespace Qt::StringLiterals;
35
36#ifdef HAVE_PDAL_QGIS
37#include <memory>
38#include <pdal/StageFactory.hpp>
39#include <pdal/io/BufferReader.hpp>
40#include <pdal/Dimension.hpp>
41#endif
42
44{
45 switch ( format )
46 {
48 return u"GPKG"_s;
50 return u"DXF"_s;
52 return u"ESRI Shapefile"_s;
54 return u"CSV"_s;
57 break;
58 }
59 return QString();
60}
61
63 : mLayerAttributeCollection( layer->attributes() )
64 , mIndex( layer->index() )
65 , mSourceCrs( QgsCoordinateReferenceSystem( layer->crs() ) )
66 , mTargetCrs( QgsCoordinateReferenceSystem( layer->crs() ) )
67{
68 bool ok;
69 mPointRecordFormat = layer->dataProvider()->originalMetadata().value( u"dataformat_id"_s ).toInt( &ok );
70 if ( !ok )
71 mPointRecordFormat = 3;
72
74}
75
78
80{
81 if ( supportedFormats().contains( format ) )
82 {
83 mFormat = format;
84 return true;
85 }
86 return false;
87}
88
90{
91 mFilterGeometryEngine = std::make_unique<QgsGeos>( geometry );
92 mFilterGeometryEngine->prepareGeometry();
93}
94
95void QgsPointCloudLayerExporter::setFilterGeometry( QgsMapLayer *layer, bool selectedFeaturesOnly )
96{
97 QgsVectorLayer *vlayer = dynamic_cast< QgsVectorLayer * >( layer );
98 if ( !vlayer )
99 return;
100
101 QVector< QgsGeometry > allGeometries;
103 const QgsFeatureRequest request = QgsFeatureRequest( mExtent ).setNoAttributes();
104 if ( selectedFeaturesOnly )
105 fit = vlayer->getSelectedFeatures( request );
106 else
107 fit = vlayer->getFeatures( request );
108
109 QgsCoordinateTransform transform( vlayer->crs(), mSourceCrs, mTransformContext );
110
111 QgsFeature f;
112 while ( fit.nextFeature( f ) )
113 {
114 if ( f.hasGeometry() )
115 {
116 allGeometries.append( f.geometry() );
117 }
118 }
119 QgsGeometry unaryUnion = QgsGeometry::unaryUnion( allGeometries );
120 try
121 {
122 unaryUnion.transform( transform );
123 }
124 catch ( const QgsCsException &cse )
125 {
126 QgsDebugError( u"Error transforming union of filter layer: %1"_s.arg( cse.what() ) );
127 QgsDebugError( u"FilterGeometry will be ignored."_s );
128 return;
129 }
130 setFilterGeometry( unaryUnion.constGet() );
131}
132
133void QgsPointCloudLayerExporter::setAttributes( const QStringList &attributeList )
134{
135 mRequestedAttributes.clear();
136
137 const QVector<QgsPointCloudAttribute> allAttributes = mLayerAttributeCollection.attributes();
138 for ( const QgsPointCloudAttribute &attribute : allAttributes )
139 {
140 // Don't add x, y, z or duplicate attributes
141 if ( attribute.name().compare( 'X'_L1, Qt::CaseInsensitive )
142 && attribute.name().compare( 'Y'_L1, Qt::CaseInsensitive )
143 && attribute.name().compare( 'Z'_L1, Qt::CaseInsensitive )
144 && attributeList.contains( attribute.name() )
145 && !mRequestedAttributes.contains( attribute.name() ) )
146 {
147 mRequestedAttributes.append( attribute.name() );
148 }
149 }
150}
151
153{
154 QStringList allAttributeNames;
155 const QVector<QgsPointCloudAttribute> allAttributes = mLayerAttributeCollection.attributes();
156 for ( const QgsPointCloudAttribute &attribute : allAttributes )
157 {
158 allAttributeNames.append( attribute.name() );
159 }
160 setAttributes( allAttributeNames );
161}
162
163const QgsPointCloudAttributeCollection QgsPointCloudLayerExporter::requestedAttributeCollection()
164{
165 const QVector<QgsPointCloudAttribute> allAttributes = mLayerAttributeCollection.attributes();
166 QgsPointCloudAttributeCollection requestAttributes;
167 for ( const QgsPointCloudAttribute &attribute : allAttributes )
168 {
169 // For this collection we also need x, y, z apart from the requested attributes
170 if ( attribute.name().compare( 'X'_L1, Qt::CaseInsensitive )
171 || attribute.name().compare( 'Y'_L1, Qt::CaseInsensitive )
172 || attribute.name().compare( 'Z'_L1, Qt::CaseInsensitive )
173 || mRequestedAttributes.contains( attribute.name(), Qt::CaseInsensitive ) )
174 {
175 requestAttributes.push_back( attribute );
176 }
177 }
178 return requestAttributes;
179}
180
181QgsFields QgsPointCloudLayerExporter::outputFields()
182{
183 const QVector<QgsPointCloudAttribute> attributes = mLayerAttributeCollection.attributes();
184
185 QgsFields fields;
186 for ( const QgsPointCloudAttribute &attribute : attributes )
187 {
188 if ( mRequestedAttributes.contains( attribute.name(), Qt::CaseInsensitive ) )
189 fields.append( QgsField( attribute.name(), attribute.variantType(), attribute.displayType() ) );
190 }
191 return fields;
192}
193
195{
196 mMemoryLayer.reset();
197
198
199 if ( mFormat == ExportFormat::Memory )
200 {
201#ifdef QGISDEBUG
202 if ( QApplication::instance()->thread() != QThread::currentThread() )
203 {
204 QgsDebugMsgLevel( u"prepareExport() should better be called from the main thread!"_s, 2 );
205 }
206#endif
207
208 mMemoryLayer.reset( QgsMemoryProviderUtils::createMemoryLayer( mName, outputFields(), Qgis::WkbType::PointZ, mTargetCrs ) );
209 }
210}
211
213{
214 mTransform = QgsCoordinateTransform( mSourceCrs, mTargetCrs, mTransformContext );
215 if ( mExtent.isFinite() )
216 {
217 try
218 {
219 mExtent = mTransform.transformBoundingBox( mExtent, Qgis::TransformDirection::Reverse );
220 }
221 catch ( const QgsCsException &cse )
222 {
223 QgsDebugError( u"Error transforming extent: %1"_s.arg( cse.what() ) );
224 }
225 }
226
227 QStringList layerCreationOptions;
228
229 switch ( mFormat )
230 {
232 {
233 if ( !mMemoryLayer )
235
236 ExporterMemory exp( this );
237 exp.run();
238 break;
239 }
240
242 {
243#ifdef HAVE_PDAL_QGIS
245 // PDAL may throw exceptions
246 try
247 {
248 ExporterPdal exp( this );
249 exp.run();
250 }
251 catch ( std::runtime_error &e )
252 {
253 setLastError( QString::fromLatin1( e.what() ) );
254 QgsDebugError( u"PDAL has thrown an exception: {}"_s.arg( e.what() ) );
255 }
256#endif
257 break;
258 }
259
261 layerCreationOptions << u"GEOMETRY=AS_XYZ"_s << u"SEPARATOR=COMMA"_s; // just in case ogr changes the default lco
262 [[fallthrough]];
266 {
267 const QString ogrDriver = getOgrDriverName( mFormat );
269 saveOptions.layerName = mName;
270 saveOptions.driverName = ogrDriver;
273 saveOptions.layerOptions << layerCreationOptions;
275 saveOptions.actionOnExistingFile = mActionOnExistingFile;
276 saveOptions.feedback = mFeedback;
277 mVectorSink.reset( QgsVectorFileWriter::create( mFilename, outputFields(), Qgis::WkbType::PointZ, mTargetCrs, QgsCoordinateTransformContext(), saveOptions ) );
278 ExporterVector exp( this );
279 exp.run();
280 return;
281 }
282 }
283}
284
286{
287 switch ( mFormat )
288 {
290 {
291 return mMemoryLayer.release();
292 }
293
295 {
296 const QFileInfo fileInfo( mFilename );
297 return new QgsPointCloudLayer( mFilename, fileInfo.completeBaseName(), u"pdal"_s );
298 }
299
301 {
302 QString uri( mFilename );
303 uri += "|layername=" + mName;
304 return new QgsVectorLayer( uri, mName, u"ogr"_s );
305 }
306
310 {
311 const QFileInfo fileInfo( mFilename );
312 return new QgsVectorLayer( mFilename, fileInfo.completeBaseName(), u"ogr"_s );
313 }
314 }
316}
317
318//
319// ExporterBase
320//
321
322void QgsPointCloudLayerExporter::ExporterBase::run()
323{
325 geometryFilterRectangle( -std::numeric_limits<double>::infinity(), -std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity(), false );
326 if ( mParent->mFilterGeometryEngine )
327 {
328 const QgsAbstractGeometry *envelope = mParent->mFilterGeometryEngine->envelope();
329 if ( envelope )
330 geometryFilterRectangle = envelope->boundingBox();
331 }
332
333 QVector<QgsPointCloudNodeId> nodes;
334 qint64 pointCount = 0;
335 QQueue<QgsPointCloudNodeId> queue;
336 queue.push_back( mParent->mIndex.root() );
337 while ( !queue.empty() )
338 {
339 QgsPointCloudNode node = mParent->mIndex.getNode( queue.front() );
340 queue.pop_front();
341 const QgsBox3D nodeBounds = node.bounds();
342 if ( mParent->mExtent.intersects( nodeBounds.toRectangle() )
343 && mParent->mZRange.overlaps( { nodeBounds.zMinimum(), nodeBounds.zMaximum() } )
344 && geometryFilterRectangle.intersects( nodeBounds.toRectangle() ) )
345 {
346 pointCount += node.pointCount();
347 nodes.push_back( node.id() );
348 }
349 for ( QgsPointCloudNodeId child : node.children() )
350 {
351 queue.push_back( child );
352 }
353 }
354
355 const qint64 pointsToExport = mParent->mPointsLimit > 0 ? std::min( mParent->mPointsLimit, pointCount ) : pointCount;
356 QgsPointCloudRequest request;
357 request.setAttributes( mParent->requestedAttributeCollection() );
358 std::unique_ptr<QgsPointCloudBlock> block = nullptr;
359 qint64 pointsExported = 0;
360 for ( QgsPointCloudNodeId node : nodes )
361 {
362 block = mParent->mIndex.nodeData( node, request );
363 const QgsPointCloudAttributeCollection attributesCollection = block->attributes();
364 const char *ptr = block->data();
365 int count = block->pointCount();
366 int recordSize = attributesCollection.pointRecordSize();
367 const QgsVector3D scale = block->scale();
368 const QgsVector3D offset = block->offset();
369 int xOffset = 0, yOffset = 0, zOffset = 0;
370 const QgsPointCloudAttribute::DataType xType = attributesCollection.find( u"X"_s, xOffset )->type();
371 const QgsPointCloudAttribute::DataType yType = attributesCollection.find( u"Y"_s, yOffset )->type();
372 const QgsPointCloudAttribute::DataType zType = attributesCollection.find( u"Z"_s, zOffset )->type();
373 for ( int i = 0; i < count; ++i )
374 {
375 if ( mParent->mFeedback && i % 1000 == 0 )
376 {
377 if ( pointsToExport > 0 )
378 {
379 mParent->mFeedback->setProgress( 100 * static_cast< float >( pointsExported ) / pointsToExport );
380 }
381 if ( mParent->mFeedback->isCanceled() )
382 {
383 mParent->setLastError( QObject::tr( "Canceled by user" ) );
384 return;
385 }
386 }
387
388 if ( pointsExported >= pointsToExport )
389 break;
390
391 double x, y, z;
392 QgsPointCloudAttribute::getPointXYZ( ptr, i, recordSize, xOffset, xType, yOffset, yType, zOffset, zType, scale, offset, x, y, z );
393 if ( !mParent->mZRange.contains( z ) || !mParent->mExtent.contains( x, y ) || ( mParent->mFilterGeometryEngine && !mParent->mFilterGeometryEngine->contains( x, y ) ) )
394 {
395 continue;
396 }
397
398 try
399 {
400 mParent->mTransform.transformInPlace( x, y, z );
401 const QVariantMap attributeMap = QgsPointCloudAttribute::getAttributeMap( ptr, i * recordSize, attributesCollection );
402 handlePoint( x, y, z, attributeMap, pointsExported );
403 ++pointsExported;
404 }
405 catch ( const QgsCsException &cse )
406 {
407 QgsDebugError( u"Error transforming point: %1"_s.arg( cse.what() ) );
408 }
409 }
410 handleNode();
411 }
412 handleAll();
413}
414
415//
416// ExporterMemory
417//
418
419QgsPointCloudLayerExporter::ExporterMemory::ExporterMemory( QgsPointCloudLayerExporter *exp )
420{
421 mParent = exp;
422}
423
424QgsPointCloudLayerExporter::ExporterMemory::~ExporterMemory()
425{
426 mParent->mMemoryLayer->moveToThread( QApplication::instance()->thread() );
427}
428
429void QgsPointCloudLayerExporter::ExporterMemory::handlePoint( double x, double y, double z, const QVariantMap &map, const qint64 pointNumber )
430{
431 Q_UNUSED( pointNumber )
432
433 QgsFeature feature;
434 feature.setGeometry( QgsGeometry( new QgsPoint( x, y, z ) ) );
435 QgsAttributes featureAttributes;
436 for ( const QString &attribute : std::as_const( mParent->mRequestedAttributes ) )
437 {
438 const double val = map[attribute].toDouble();
439 featureAttributes.append( val );
440 }
441 feature.setAttributes( featureAttributes );
442 mFeatures.append( feature );
443}
444
445void QgsPointCloudLayerExporter::ExporterMemory::handleNode()
446{
447 QgsVectorLayer *vl = qgis::down_cast<QgsVectorLayer *>( mParent->mMemoryLayer.get() );
448 if ( vl )
449 {
450 if ( !vl->dataProvider()->addFeatures( mFeatures ) )
451 {
452 mParent->setLastError( vl->dataProvider()->lastError() );
453 }
454 }
455 mFeatures.clear();
456}
457
458void QgsPointCloudLayerExporter::ExporterMemory::handleAll()
459{}
460
461//
462// ExporterVector
463//
464
465QgsPointCloudLayerExporter::ExporterVector::ExporterVector( QgsPointCloudLayerExporter *exp )
466{
467 mParent = exp;
468}
469
470QgsPointCloudLayerExporter::ExporterVector::~ExporterVector()
471{
472 mParent->mVectorSink.reset();
473}
474
475void QgsPointCloudLayerExporter::ExporterVector::handlePoint( double x, double y, double z, const QVariantMap &map, const qint64 pointNumber )
476{
477 Q_UNUSED( pointNumber )
478
479 QgsFeature feature;
480 feature.setGeometry( QgsGeometry( new QgsPoint( x, y, z ) ) );
481 QgsAttributes featureAttributes;
482 for ( const QString &attribute : std::as_const( mParent->mRequestedAttributes ) )
483 {
484 const double val = map[attribute].toDouble();
485 featureAttributes.append( val );
486 }
487 feature.setAttributes( featureAttributes );
488 mFeatures.append( feature );
489}
490
491void QgsPointCloudLayerExporter::ExporterVector::handleNode()
492{
493 if ( !mParent->mVectorSink->addFeatures( mFeatures ) )
494 {
495 mParent->setLastError( mParent->mVectorSink->lastError() );
496 }
497 mFeatures.clear();
498}
499
500void QgsPointCloudLayerExporter::ExporterVector::handleAll()
501{}
502
503//
504// ExporterPdal
505//
506
507#ifdef HAVE_PDAL_QGIS
508
509QgsPointCloudLayerExporter::ExporterPdal::ExporterPdal( QgsPointCloudLayerExporter *exp )
510 : mPointFormat( exp->mPointRecordFormat )
511{
512 mParent = exp;
513
514 mOptions.add( "filename", mParent->mFilename.toStdString() );
515 mOptions.add( "a_srs", mParent->mTargetCrs.toWkt().toStdString() );
516 mOptions.add( "minor_version", u"4"_s.toStdString() ); // delault to LAZ 1.4 to properly handle pdrf >= 6
517 mOptions.add( "format", QString::number( mPointFormat ).toStdString() );
518 if ( mParent->mTransform.isShortCircuited() )
519 {
520 mOptions.add( "offset_x", QString::number( mParent->mIndex.offset().x() ).toStdString() );
521 mOptions.add( "offset_y", QString::number( mParent->mIndex.offset().y() ).toStdString() );
522 mOptions.add( "offset_z", QString::number( mParent->mIndex.offset().z() ).toStdString() );
523 mOptions.add( "scale_x", QString::number( mParent->mIndex.scale().x() ).toStdString() );
524 mOptions.add( "scale_y", QString::number( mParent->mIndex.scale().y() ).toStdString() );
525 mOptions.add( "scale_z", QString::number( mParent->mIndex.scale().z() ).toStdString() );
526 }
527
528 mTable.layout()->registerDim( pdal::Dimension::Id::X );
529 mTable.layout()->registerDim( pdal::Dimension::Id::Y );
530 mTable.layout()->registerDim( pdal::Dimension::Id::Z );
531
532 mTable.layout()->registerDim( pdal::Dimension::Id::Classification );
533 mTable.layout()->registerDim( pdal::Dimension::Id::Intensity );
534 mTable.layout()->registerDim( pdal::Dimension::Id::ReturnNumber );
535 mTable.layout()->registerDim( pdal::Dimension::Id::NumberOfReturns );
536 mTable.layout()->registerDim( pdal::Dimension::Id::ScanDirectionFlag );
537 mTable.layout()->registerDim( pdal::Dimension::Id::EdgeOfFlightLine );
538 mTable.layout()->registerDim( pdal::Dimension::Id::ScanAngleRank );
539 mTable.layout()->registerDim( pdal::Dimension::Id::UserData );
540 mTable.layout()->registerDim( pdal::Dimension::Id::PointSourceId );
541
542 if ( mPointFormat == 6 || mPointFormat == 7 || mPointFormat == 8 || mPointFormat == 9 || mPointFormat == 10 )
543 {
544 mTable.layout()->registerDim( pdal::Dimension::Id::ScanChannel );
545 mTable.layout()->registerDim( pdal::Dimension::Id::ClassFlags );
546 }
547
548 if ( mPointFormat != 0 && mPointFormat != 2 )
549 {
550 mTable.layout()->registerDim( pdal::Dimension::Id::GpsTime );
551 }
552
553 if ( mPointFormat == 2 || mPointFormat == 3 || mPointFormat == 5 || mPointFormat == 7 || mPointFormat == 8 || mPointFormat == 10 )
554 {
555 mTable.layout()->registerDim( pdal::Dimension::Id::Red );
556 mTable.layout()->registerDim( pdal::Dimension::Id::Green );
557 mTable.layout()->registerDim( pdal::Dimension::Id::Blue );
558 }
559
560 if ( mPointFormat == 8 || mPointFormat == 10 )
561 {
562 mTable.layout()->registerDim( pdal::Dimension::Id::Infrared );
563 }
564
565 mView = std::make_shared<pdal::PointView>( mTable );
566}
567
568void QgsPointCloudLayerExporter::ExporterPdal::handlePoint( double x, double y, double z, const QVariantMap &map, const qint64 pointNumber )
569{
570 mView->setField( pdal::Dimension::Id::X, pointNumber, x );
571 mView->setField( pdal::Dimension::Id::Y, pointNumber, y );
572 mView->setField( pdal::Dimension::Id::Z, pointNumber, z );
573
574
575 mView->setField( pdal::Dimension::Id::Classification, pointNumber, map[u"Classification"_s].toInt() );
576 mView->setField( pdal::Dimension::Id::Intensity, pointNumber, map[u"Intensity"_s].toInt() );
577 mView->setField( pdal::Dimension::Id::ReturnNumber, pointNumber, map[u"ReturnNumber"_s].toInt() );
578 mView->setField( pdal::Dimension::Id::NumberOfReturns, pointNumber, map[u"NumberOfReturns"_s].toInt() );
579 mView->setField( pdal::Dimension::Id::ScanDirectionFlag, pointNumber, map[u"ScanDirectionFlag"_s].toInt() );
580 mView->setField( pdal::Dimension::Id::EdgeOfFlightLine, pointNumber, map[u"EdgeOfFlightLine"_s].toInt() );
581 mView->setField( pdal::Dimension::Id::ScanAngleRank, pointNumber, map[u"ScanAngleRank"_s].toFloat() );
582 mView->setField( pdal::Dimension::Id::UserData, pointNumber, map[u"UserData"_s].toInt() );
583 mView->setField( pdal::Dimension::Id::PointSourceId, pointNumber, map[u"PointSourceId"_s].toInt() );
584
585 if ( mPointFormat == 6 || mPointFormat == 7 || mPointFormat == 8 || mPointFormat == 9 || mPointFormat == 10 )
586 {
587 mView->setField( pdal::Dimension::Id::ScanChannel, pointNumber, map[u"ScannerChannel"_s].toInt() );
588 const int classificationFlags = ( map[u"Synthetic"_s].toInt() & 0x01 ) << 0
589 | ( map[u"KeyPoint"_s].toInt() & 0x01 ) << 1
590 | ( map[u"Withheld"_s].toInt() & 0x01 ) << 2
591 | ( map[u"Overlap"_s].toInt() & 0x01 ) << 3;
592 mView->setField( pdal::Dimension::Id::ClassFlags, pointNumber, classificationFlags );
593 }
594
595 if ( mPointFormat != 0 && mPointFormat != 2 )
596 {
597 mView->setField( pdal::Dimension::Id::GpsTime, pointNumber, map[u"GpsTime"_s].toDouble() );
598 }
599
600 if ( mPointFormat == 2 || mPointFormat == 3 || mPointFormat == 5 || mPointFormat == 7 || mPointFormat == 8 || mPointFormat == 10 )
601 {
602 mView->setField( pdal::Dimension::Id::Red, pointNumber, map[u"Red"_s].toInt() );
603 mView->setField( pdal::Dimension::Id::Green, pointNumber, map[u"Green"_s].toInt() );
604 mView->setField( pdal::Dimension::Id::Blue, pointNumber, map[u"Blue"_s].toInt() );
605 }
606
607 if ( mPointFormat == 8 || mPointFormat == 10 )
608 {
609 mView->setField( pdal::Dimension::Id::Infrared, pointNumber, map[u"Infrared"_s].toInt() );
610 }
611}
612
613void QgsPointCloudLayerExporter::ExporterPdal::handleNode()
614{}
615
616void QgsPointCloudLayerExporter::ExporterPdal::handleAll()
617{
618 pdal::BufferReader reader;
619 reader.addView( mView );
620
621 pdal::StageFactory factory;
622
623 pdal::Stage *writer = factory.createStage( "writers.las" );
624
625 writer->setInput( reader );
626 writer->setOptions( mOptions );
627 writer->prepare( mTable );
628 writer->execute( mTable );
629}
630#endif
631
632//
633// QgsPointCloudLayerExporterTask
634//
635
637 : QgsTask( tr( "Exporting point cloud" ), QgsTask::CanCancel )
638 , mExp( exporter )
639 , mOwnedFeedback( new QgsFeedback() )
640{}
641
643{
644 mOwnedFeedback->cancel();
646}
647
649{
650 if ( !mExp )
651 return false;
652
653 connect( mOwnedFeedback.get(), &QgsFeedback::progressChanged, this, &QgsPointCloudLayerExporterTask::setProgress );
654 mExp->setFeedback( mOwnedFeedback.get() );
655
656 mExp->doExport();
657
658 return true;
659}
660
662{
663 Q_UNUSED( result )
664
665 emit exportComplete();
666 delete mExp;
667}
@ PointZ
PointZ.
Definition qgis.h:313
@ NoSymbology
Export only data.
Definition qgis.h:6208
@ Reverse
Reverse/inverse transform (from destination to source).
Definition qgis.h:2847
Abstract base class for all geometries.
virtual QgsRectangle boundingBox() const
Returns the minimal bounding box for the geometry.
QgsRectangle toRectangle() const
Converts the box to a 2D rectangle.
Definition qgsbox3d.h:388
Represents a coordinate reference system (CRS).
Contains information about the context in which a coordinate transform is executed.
Handles coordinate transforms between two coordinate systems.
Custom exception class for Coordinate Reference System related exceptions.
QString what() const
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
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...
Definition qgsfeature.h:60
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
QgsGeometry geometry
Definition qgsfeature.h:66
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.
Definition qgsfeedback.h:44
void progressChanged(double progress)
Emitted when the feedback object reports a progress change.
Container of fields for a vector layer.
Definition qgsfields.h:46
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
Definition qgsfields.cpp:75
A geometry is the spatial representation of a feature.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
static QgsGeometry unaryUnion(const QVector< QgsGeometry > &geometries, const QgsGeometryParameters &parameters=QgsGeometryParameters(), QgsFeedback *feedback=nullptr)
Compute the unary union on a list of geometries.
Base class for all map layer types.
Definition qgsmaplayer.h:83
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:90
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.
A 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.
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.
QgsMapLayer * takeExportedLayer()
Gets a pointer to the exported layer.
QgsCoordinateReferenceSystem crs() const
Gets the crs for the exported file.
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.
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.
QList< QgsPointCloudNodeId > children() const
Returns IDs of child nodes.
qint64 pointCount() const
Returns number of points contained in node data.
QgsPointCloudNodeId id() const
Returns node's ID (unique in index).
QgsBox3D bounds() const
Returns node's bounding cube in CRS coords.
void setAttributes(const QgsPointCloudAttributeCollection &attributes)
Set attributes filter in the request.
A rectangle specified with double values.
virtual void cancel()
Notifies the task that it should terminate.
QgsTask(const QString &description=QString(), QgsTask::Flags flags=AllFlags)
Constructor for QgsTask.
@ CanCancel
Task can be canceled.
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 QgsVectorFileWriter::writeAsVectorFormat().
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 dataset.
QgsFeatureIterator getSelectedFeatures(QgsFeatureRequest request=QgsFeatureRequest()) const
Returns an iterator of the selected features.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const final
Queries the layer for features specified in request.
QgsVectorDataProvider * dataProvider() final
Returns the layer's data provider, it may be nullptr.
#define BUILTIN_UNREACHABLE
Definition qgis.h:8035
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:80
#define QgsDebugError(str)
Definition qgslogger.h:71