QGIS API Documentation 3.99.0-Master (d270888f95f)
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
77{
78 delete mMemoryLayer;
79 delete mVectorSink;
80 delete mTransform;
81}
82
84{
85 if ( supportedFormats().contains( format ) )
86 {
87 mFormat = format;
88 return true;
89 }
90 return false;
91}
92
94{
95 mFilterGeometryEngine = std::make_unique<QgsGeos>( geometry );
96 mFilterGeometryEngine->prepareGeometry();
97}
98
99void QgsPointCloudLayerExporter::setFilterGeometry( QgsMapLayer *layer, bool selectedFeaturesOnly )
100{
101 QgsVectorLayer *vlayer = dynamic_cast< QgsVectorLayer * >( layer );
102 if ( !vlayer )
103 return;
104
105 QVector< QgsGeometry > allGeometries;
107 const QgsFeatureRequest request = QgsFeatureRequest( mExtent ).setNoAttributes();
108 if ( selectedFeaturesOnly )
109 fit = vlayer->getSelectedFeatures( request );
110 else
111 fit = vlayer->getFeatures( request );
112
113 QgsCoordinateTransform transform( vlayer->crs(), mSourceCrs, mTransformContext );
114
115 QgsFeature f;
116 while ( fit.nextFeature( f ) )
117 {
118 if ( f.hasGeometry() )
119 {
120 allGeometries.append( f.geometry() );
121 }
122 }
123 QgsGeometry unaryUnion = QgsGeometry::unaryUnion( allGeometries );
124 try
125 {
126 unaryUnion.transform( transform );
127 }
128 catch ( const QgsCsException &cse )
129 {
130 QgsDebugError( u"Error transforming union of filter layer: %1"_s.arg( cse.what() ) );
131 QgsDebugError( u"FilterGeometry will be ignored."_s );
132 return;
133 }
134 setFilterGeometry( unaryUnion.constGet() );
135}
136
137void QgsPointCloudLayerExporter::setAttributes( const QStringList &attributeList )
138{
139 mRequestedAttributes.clear();
140
141 const QVector<QgsPointCloudAttribute> allAttributes = mLayerAttributeCollection.attributes();
142 for ( const QgsPointCloudAttribute &attribute : allAttributes )
143 {
144 // Don't add x, y, z or duplicate attributes
145 if ( attribute.name().compare( 'X'_L1, Qt::CaseInsensitive ) &&
146 attribute.name().compare( 'Y'_L1, Qt::CaseInsensitive ) &&
147 attribute.name().compare( 'Z'_L1, Qt::CaseInsensitive ) &&
148 attributeList.contains( attribute.name() ) &&
149 ! mRequestedAttributes.contains( attribute.name() ) )
150 {
151 mRequestedAttributes.append( attribute.name() );
152 }
153 }
154}
155
157{
158 QStringList allAttributeNames;
159 const QVector<QgsPointCloudAttribute> allAttributes = mLayerAttributeCollection.attributes();
160 for ( const QgsPointCloudAttribute &attribute : allAttributes )
161 {
162 allAttributeNames.append( attribute.name() );
163 }
164 setAttributes( allAttributeNames );
165}
166
167const QgsPointCloudAttributeCollection QgsPointCloudLayerExporter::requestedAttributeCollection()
168{
169 const QVector<QgsPointCloudAttribute> allAttributes = mLayerAttributeCollection.attributes();
170 QgsPointCloudAttributeCollection requestAttributes;
171 for ( const QgsPointCloudAttribute &attribute : allAttributes )
172 {
173 // For this collection we also need x, y, z apart from the requested attributes
174 if ( attribute.name().compare( 'X'_L1, Qt::CaseInsensitive ) ||
175 attribute.name().compare( 'Y'_L1, Qt::CaseInsensitive ) ||
176 attribute.name().compare( 'Z'_L1, Qt::CaseInsensitive ) ||
177 mRequestedAttributes.contains( attribute.name(), Qt::CaseInsensitive ) )
178 {
179 requestAttributes.push_back( attribute );
180 }
181 }
182 return requestAttributes;
183}
184
185QgsFields QgsPointCloudLayerExporter::outputFields()
186{
187 const QVector<QgsPointCloudAttribute> attributes = mLayerAttributeCollection.attributes();
188
189 QgsFields fields;
190 for ( const QgsPointCloudAttribute &attribute : attributes )
191 {
192 if ( mRequestedAttributes.contains( attribute.name(), Qt::CaseInsensitive ) )
193 fields.append( QgsField( attribute.name(), attribute.variantType(), attribute.displayType() ) );
194 }
195 return fields;
196}
197
199{
200 delete mMemoryLayer;
201 mMemoryLayer = nullptr;
202
203 if ( mFormat == ExportFormat::Memory )
204 {
205#ifdef QGISDEBUG
206 if ( QApplication::instance()->thread() != QThread::currentThread() )
207 {
208 QgsDebugMsgLevel( u"prepareExport() should better be called from the main thread!"_s, 2 );
209 }
210#endif
211
212 mMemoryLayer = QgsMemoryProviderUtils::createMemoryLayer( mName, outputFields(), Qgis::WkbType::PointZ, mTargetCrs );
213 }
214}
215
217{
218 mTransform = new QgsCoordinateTransform( mSourceCrs, mTargetCrs, mTransformContext );
219 if ( mExtent.isFinite() )
220 {
221 try
222 {
223 mExtent = mTransform->transformBoundingBox( mExtent, Qgis::TransformDirection::Reverse );
224 }
225 catch ( const QgsCsException &cse )
226 {
227 QgsDebugError( u"Error transforming extent: %1"_s.arg( cse.what() ) );
228 }
229 }
230
231 QStringList layerCreationOptions;
232
233 switch ( mFormat )
234 {
236 {
237 if ( !mMemoryLayer )
239
240 ExporterMemory exp( this );
241 exp.run();
242 break;
243 }
244
246 {
247#ifdef HAVE_PDAL_QGIS
249 // PDAL may throw exceptions
250 try
251 {
252 ExporterPdal exp( this );
253 exp.run();
254 }
255 catch ( std::runtime_error &e )
256 {
257 setLastError( QString::fromLatin1( e.what() ) );
258 QgsDebugError( u"PDAL has thrown an exception: {}"_s.arg( e.what() ) );
259 }
260#endif
261 break;
262 }
263
265 layerCreationOptions << u"GEOMETRY=AS_XYZ"_s
266 << u"SEPARATOR=COMMA"_s; // just in case ogr changes the default lco
267 [[fallthrough]];
271 {
272 const QString ogrDriver = getOgrDriverName( mFormat );
274 saveOptions.layerName = mName;
275 saveOptions.driverName = ogrDriver;
278 saveOptions.layerOptions << layerCreationOptions;
280 saveOptions.actionOnExistingFile = mActionOnExistingFile;
281 saveOptions.feedback = mFeedback;
282 mVectorSink = QgsVectorFileWriter::create( mFilename, outputFields(), Qgis::WkbType::PointZ, mTargetCrs, QgsCoordinateTransformContext(), saveOptions );
283 ExporterVector exp( this );
284 exp.run();
285 return;
286 }
287 }
288}
289
291{
292 switch ( mFormat )
293 {
295 {
296 QgsMapLayer *retVal = mMemoryLayer;
297 mMemoryLayer = nullptr;
298 return retVal;
299 }
300
302 {
303 const QFileInfo fileInfo( mFilename );
304 return new QgsPointCloudLayer( mFilename, fileInfo.completeBaseName(), u"pdal"_s );
305 }
306
308 {
309 QString uri( mFilename );
310 uri += "|layername=" + mName;
311 return new QgsVectorLayer( uri, mName, u"ogr"_s );
312 }
313
317 {
318 const QFileInfo fileInfo( mFilename );
319 return new QgsVectorLayer( mFilename, fileInfo.completeBaseName(), u"ogr"_s );
320 }
321 }
323}
324
325//
326// ExporterBase
327//
328
329void QgsPointCloudLayerExporter::ExporterBase::run()
330{
331 QgsRectangle geometryFilterRectangle( -std::numeric_limits<double>::infinity(),
332 -std::numeric_limits<double>::infinity(),
333 std::numeric_limits<double>::infinity(),
334 std::numeric_limits<double>::infinity(),
335 false );
336 if ( mParent->mFilterGeometryEngine )
337 {
338 const QgsAbstractGeometry *envelope = mParent->mFilterGeometryEngine->envelope();
339 if ( envelope )
340 geometryFilterRectangle = envelope->boundingBox();
341 }
342
343 QVector<QgsPointCloudNodeId> nodes;
344 qint64 pointCount = 0;
345 QQueue<QgsPointCloudNodeId> queue;
346 queue.push_back( mParent->mIndex.root() );
347 while ( !queue.empty() )
348 {
349 QgsPointCloudNode node = mParent->mIndex.getNode( queue.front() );
350 queue.pop_front();
351 const QgsBox3D nodeBounds = node.bounds();
352 if ( mParent->mExtent.intersects( nodeBounds.toRectangle() ) &&
353 mParent->mZRange.overlaps( { nodeBounds.zMinimum(), nodeBounds.zMaximum() } ) &&
354 geometryFilterRectangle.intersects( nodeBounds.toRectangle() ) )
355 {
356 pointCount += node.pointCount();
357 nodes.push_back( node.id() );
358 }
359 for ( const QgsPointCloudNodeId &child : node.children() )
360 {
361 queue.push_back( child );
362 }
363 }
364
365 const qint64 pointsToExport = mParent->mPointsLimit > 0 ? std::min( mParent->mPointsLimit, pointCount ) : pointCount;
366 QgsPointCloudRequest request;
367 request.setAttributes( mParent->requestedAttributeCollection() );
368 std::unique_ptr<QgsPointCloudBlock> block = nullptr;
369 qint64 pointsExported = 0;
370 for ( const QgsPointCloudNodeId &node : nodes )
371 {
372 block = mParent->mIndex.nodeData( node, request );
373 const QgsPointCloudAttributeCollection attributesCollection = block->attributes();
374 const char *ptr = block->data();
375 int count = block->pointCount();
376 int recordSize = attributesCollection.pointRecordSize();
377 const QgsVector3D scale = block->scale();
378 const QgsVector3D offset = block->offset();
379 int xOffset = 0, yOffset = 0, zOffset = 0;
380 const QgsPointCloudAttribute::DataType xType = attributesCollection.find( u"X"_s, xOffset )->type();
381 const QgsPointCloudAttribute::DataType yType = attributesCollection.find( u"Y"_s, yOffset )->type();
382 const QgsPointCloudAttribute::DataType zType = attributesCollection.find( u"Z"_s, zOffset )->type();
383 for ( int i = 0; i < count; ++i )
384 {
385
386 if ( mParent->mFeedback &&
387 i % 1000 == 0 )
388 {
389 if ( pointsToExport > 0 )
390 {
391 mParent->mFeedback->setProgress( 100 * static_cast< float >( pointsExported ) / pointsToExport );
392 }
393 if ( mParent->mFeedback->isCanceled() )
394 {
395 mParent->setLastError( QObject::tr( "Canceled by user" ) );
396 return;
397 }
398 }
399
400 if ( pointsExported >= pointsToExport )
401 break;
402
403 double x, y, z;
404 QgsPointCloudAttribute::getPointXYZ( ptr, i, recordSize,
405 xOffset, xType,
406 yOffset, yType,
407 zOffset, zType,
408 scale, offset,
409 x, y, z );
410 if ( ! mParent->mZRange.contains( z ) ||
411 ! mParent->mExtent.contains( x, y ) ||
412 ( mParent->mFilterGeometryEngine && ! mParent->mFilterGeometryEngine->contains( x, y ) ) )
413 {
414 continue;
415 }
416
417 try
418 {
419 mParent->mTransform->transformInPlace( x, y, z );
420 const QVariantMap attributeMap = QgsPointCloudAttribute::getAttributeMap( ptr, i * recordSize, attributesCollection );
421 handlePoint( x, y, z, attributeMap, pointsExported );
422 ++pointsExported;
423 }
424 catch ( const QgsCsException &cse )
425 {
426 QgsDebugError( u"Error transforming point: %1"_s.arg( cse.what() ) );
427 }
428 }
429 handleNode();
430 }
431 handleAll();
432}
433
434//
435// ExporterMemory
436//
437
438QgsPointCloudLayerExporter::ExporterMemory::ExporterMemory( QgsPointCloudLayerExporter *exp )
439{
440 mParent = exp;
441}
442
443QgsPointCloudLayerExporter::ExporterMemory::~ExporterMemory()
444{
445 mParent->mMemoryLayer->moveToThread( QApplication::instance()->thread() );
446}
447
448void QgsPointCloudLayerExporter::ExporterMemory::handlePoint( double x, double y, double z, const QVariantMap &map, const qint64 pointNumber )
449{
450 Q_UNUSED( pointNumber )
451
452 QgsFeature feature;
453 feature.setGeometry( QgsGeometry( new QgsPoint( x, y, z ) ) );
454 QgsAttributes featureAttributes;
455 for ( const QString &attribute : std::as_const( mParent->mRequestedAttributes ) )
456 {
457 const double val = map[ attribute ].toDouble();
458 featureAttributes.append( val );
459 }
460 feature.setAttributes( featureAttributes );
461 mFeatures.append( feature );
462}
463
464void QgsPointCloudLayerExporter::ExporterMemory::handleNode()
465{
466 QgsVectorLayer *vl = qgis::down_cast<QgsVectorLayer *>( mParent->mMemoryLayer );
467 if ( vl )
468 {
469 if ( ! vl->dataProvider()->addFeatures( mFeatures ) )
470 {
471 mParent->setLastError( vl->dataProvider()->lastError() );
472 }
473 }
474 mFeatures.clear();
475}
476
477void QgsPointCloudLayerExporter::ExporterMemory::handleAll()
478{
479
480}
481
482//
483// ExporterVector
484//
485
486QgsPointCloudLayerExporter::ExporterVector::ExporterVector( QgsPointCloudLayerExporter *exp )
487{
488 mParent = exp;
489}
490
491QgsPointCloudLayerExporter::ExporterVector::~ExporterVector()
492{
493 delete mParent->mVectorSink;
494 mParent->mVectorSink = nullptr;
495}
496
497void QgsPointCloudLayerExporter::ExporterVector::handlePoint( double x, double y, double z, const QVariantMap &map, const qint64 pointNumber )
498{
499 Q_UNUSED( pointNumber )
500
501 QgsFeature feature;
502 feature.setGeometry( QgsGeometry( new QgsPoint( x, y, z ) ) );
503 QgsAttributes featureAttributes;
504 for ( const QString &attribute : std::as_const( mParent->mRequestedAttributes ) )
505 {
506 const double val = map[ attribute ].toDouble();
507 featureAttributes.append( val );
508 }
509 feature.setAttributes( featureAttributes );
510 mFeatures.append( feature );
511}
512
513void QgsPointCloudLayerExporter::ExporterVector::handleNode()
514{
515 if ( ! mParent->mVectorSink->addFeatures( mFeatures ) )
516 {
517 mParent->setLastError( mParent->mVectorSink->lastError() );
518 }
519 mFeatures.clear();
520}
521
522void QgsPointCloudLayerExporter::ExporterVector::handleAll()
523{
524
525}
526
527//
528// ExporterPdal
529//
530
531#ifdef HAVE_PDAL_QGIS
532
533QgsPointCloudLayerExporter::ExporterPdal::ExporterPdal( QgsPointCloudLayerExporter *exp )
534 : mPointFormat( exp->mPointRecordFormat )
535{
536 mParent = exp;
537
538 mOptions.add( "filename", mParent->mFilename.toStdString() );
539 mOptions.add( "a_srs", mParent->mTargetCrs.toWkt().toStdString() );
540 mOptions.add( "minor_version", u"4"_s.toStdString() ); // delault to LAZ 1.4 to properly handle pdrf >= 6
541 mOptions.add( "format", QString::number( mPointFormat ).toStdString() );
542 if ( mParent->mTransform->isShortCircuited() )
543 {
544 mOptions.add( "offset_x", QString::number( mParent->mIndex.offset().x() ).toStdString() );
545 mOptions.add( "offset_y", QString::number( mParent->mIndex.offset().y() ).toStdString() );
546 mOptions.add( "offset_z", QString::number( mParent->mIndex.offset().z() ).toStdString() );
547 mOptions.add( "scale_x", QString::number( mParent->mIndex.scale().x() ).toStdString() );
548 mOptions.add( "scale_y", QString::number( mParent->mIndex.scale().y() ).toStdString() );
549 mOptions.add( "scale_z", QString::number( mParent->mIndex.scale().z() ).toStdString() );
550 }
551
552 mTable.layout()->registerDim( pdal::Dimension::Id::X );
553 mTable.layout()->registerDim( pdal::Dimension::Id::Y );
554 mTable.layout()->registerDim( pdal::Dimension::Id::Z );
555
556 mTable.layout()->registerDim( pdal::Dimension::Id::Classification );
557 mTable.layout()->registerDim( pdal::Dimension::Id::Intensity );
558 mTable.layout()->registerDim( pdal::Dimension::Id::ReturnNumber );
559 mTable.layout()->registerDim( pdal::Dimension::Id::NumberOfReturns );
560 mTable.layout()->registerDim( pdal::Dimension::Id::ScanDirectionFlag );
561 mTable.layout()->registerDim( pdal::Dimension::Id::EdgeOfFlightLine );
562 mTable.layout()->registerDim( pdal::Dimension::Id::ScanAngleRank );
563 mTable.layout()->registerDim( pdal::Dimension::Id::UserData );
564 mTable.layout()->registerDim( pdal::Dimension::Id::PointSourceId );
565
566 if ( mPointFormat == 6 || mPointFormat == 7 || mPointFormat == 8 || mPointFormat == 9 || mPointFormat == 10 )
567 {
568 mTable.layout()->registerDim( pdal::Dimension::Id::ScanChannel );
569 mTable.layout()->registerDim( pdal::Dimension::Id::ClassFlags );
570 }
571
572 if ( mPointFormat != 0 && mPointFormat != 2 )
573 {
574 mTable.layout()->registerDim( pdal::Dimension::Id::GpsTime );
575 }
576
577 if ( mPointFormat == 2 || mPointFormat == 3 || mPointFormat == 5 || mPointFormat == 7 || mPointFormat == 8 || mPointFormat == 10 )
578 {
579 mTable.layout()->registerDim( pdal::Dimension::Id::Red );
580 mTable.layout()->registerDim( pdal::Dimension::Id::Green );
581 mTable.layout()->registerDim( pdal::Dimension::Id::Blue );
582 }
583
584 if ( mPointFormat == 8 || mPointFormat == 10 )
585 {
586 mTable.layout()->registerDim( pdal::Dimension::Id::Infrared );
587 }
588
589 mView = std::make_shared<pdal::PointView>( mTable );
590}
591
592void QgsPointCloudLayerExporter::ExporterPdal::handlePoint( double x, double y, double z, const QVariantMap &map, const qint64 pointNumber )
593{
594 mView->setField( pdal::Dimension::Id::X, pointNumber, x );
595 mView->setField( pdal::Dimension::Id::Y, pointNumber, y );
596 mView->setField( pdal::Dimension::Id::Z, pointNumber, z );
597
598
599 mView->setField( pdal::Dimension::Id::Classification, pointNumber, map[ u"Classification"_s ].toInt() );
600 mView->setField( pdal::Dimension::Id::Intensity, pointNumber, map[ u"Intensity"_s ].toInt() );
601 mView->setField( pdal::Dimension::Id::ReturnNumber, pointNumber, map[ u"ReturnNumber"_s ].toInt() );
602 mView->setField( pdal::Dimension::Id::NumberOfReturns, pointNumber, map[ u"NumberOfReturns"_s ].toInt() );
603 mView->setField( pdal::Dimension::Id::ScanDirectionFlag, pointNumber, map[ u"ScanDirectionFlag"_s ].toInt() );
604 mView->setField( pdal::Dimension::Id::EdgeOfFlightLine, pointNumber, map[ u"EdgeOfFlightLine"_s ].toInt() );
605 mView->setField( pdal::Dimension::Id::ScanAngleRank, pointNumber, map[ u"ScanAngleRank"_s ].toFloat() );
606 mView->setField( pdal::Dimension::Id::UserData, pointNumber, map[ u"UserData"_s ].toInt() );
607 mView->setField( pdal::Dimension::Id::PointSourceId, pointNumber, map[ u"PointSourceId"_s ].toInt() );
608
609 if ( mPointFormat == 6 || mPointFormat == 7 || mPointFormat == 8 || mPointFormat == 9 || mPointFormat == 10 )
610 {
611 mView->setField( pdal::Dimension::Id::ScanChannel, pointNumber, map[ u"ScannerChannel"_s ].toInt() );
612 const int classificationFlags = ( map[ u"Synthetic"_s ].toInt() & 0x01 ) << 0 |
613 ( map[ u"KeyPoint"_s ].toInt() & 0x01 ) << 1 |
614 ( map[ u"Withheld"_s ].toInt() & 0x01 ) << 2 |
615 ( map[ u"Overlap"_s ].toInt() & 0x01 ) << 3;
616 mView->setField( pdal::Dimension::Id::ClassFlags, pointNumber, classificationFlags );
617 }
618
619 if ( mPointFormat != 0 && mPointFormat != 2 )
620 {
621 mView->setField( pdal::Dimension::Id::GpsTime, pointNumber, map[ u"GpsTime"_s ].toDouble() );
622 }
623
624 if ( mPointFormat == 2 || mPointFormat == 3 || mPointFormat == 5 || mPointFormat == 7 || mPointFormat == 8 || mPointFormat == 10 )
625 {
626 mView->setField( pdal::Dimension::Id::Red, pointNumber, map[ u"Red"_s ].toInt() );
627 mView->setField( pdal::Dimension::Id::Green, pointNumber, map[ u"Green"_s ].toInt() );
628 mView->setField( pdal::Dimension::Id::Blue, pointNumber, map[ u"Blue"_s ].toInt() );
629 }
630
631 if ( mPointFormat == 8 || mPointFormat == 10 )
632 {
633 mView->setField( pdal::Dimension::Id::Infrared, pointNumber, map[ u"Infrared"_s ].toInt() );
634 }
635}
636
637void QgsPointCloudLayerExporter::ExporterPdal::handleNode()
638{
639
640}
641
642void QgsPointCloudLayerExporter::ExporterPdal::handleAll()
643{
644 pdal::BufferReader reader;
645 reader.addView( mView );
646
647 pdal::StageFactory factory;
648
649 pdal::Stage *writer = factory.createStage( "writers.las" );
650
651 writer->setInput( reader );
652 writer->setOptions( mOptions );
653 writer->prepare( mTable );
654 writer->execute( mTable );
655}
656#endif
657
658//
659// QgsPointCloudLayerExporterTask
660//
661
663 : QgsTask( tr( "Exporting point cloud" ), QgsTask::CanCancel )
664 , mExp( exporter )
665 , mOwnedFeedback( new QgsFeedback() )
666{
667}
668
670{
671 mOwnedFeedback->cancel();
673}
674
676{
677 if ( !mExp )
678 return false;
679
680 connect( mOwnedFeedback.get(), &QgsFeedback::progressChanged, this, &QgsPointCloudLayerExporterTask::setProgress );
681 mExp->setFeedback( mOwnedFeedback.get() );
682
683 mExp->doExport();
684
685 return true;
686}
687
689{
690 Q_UNUSED( result )
691
692 emit exportComplete();
693 delete mExp;
694}
@ PointZ
PointZ.
Definition qgis.h:299
@ NoSymbology
Export only data.
Definition qgis.h:5824
@ Reverse
Reverse/inverse transform (from destination to source).
Definition qgis.h:2731
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:381
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:71
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:76
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())
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:7489
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63
#define QgsDebugError(str)
Definition qgslogger.h:59