QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
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 << u"SEPARATOR=COMMA"_s; // just in case ogr changes the default lco
266 [[fallthrough]];
270 {
271 const QString ogrDriver = getOgrDriverName( mFormat );
273 saveOptions.layerName = mName;
274 saveOptions.driverName = ogrDriver;
277 saveOptions.layerOptions << layerCreationOptions;
279 saveOptions.actionOnExistingFile = mActionOnExistingFile;
280 saveOptions.feedback = mFeedback;
281 mVectorSink = QgsVectorFileWriter::create( mFilename, outputFields(), Qgis::WkbType::PointZ, mTargetCrs, QgsCoordinateTransformContext(), saveOptions );
282 ExporterVector exp( this );
283 exp.run();
284 return;
285 }
286 }
287}
288
290{
291 switch ( mFormat )
292 {
294 {
295 QgsMapLayer *retVal = mMemoryLayer;
296 mMemoryLayer = nullptr;
297 return retVal;
298 }
299
301 {
302 const QFileInfo fileInfo( mFilename );
303 return new QgsPointCloudLayer( mFilename, fileInfo.completeBaseName(), u"pdal"_s );
304 }
305
307 {
308 QString uri( mFilename );
309 uri += "|layername=" + mName;
310 return new QgsVectorLayer( uri, mName, u"ogr"_s );
311 }
312
316 {
317 const QFileInfo fileInfo( mFilename );
318 return new QgsVectorLayer( mFilename, fileInfo.completeBaseName(), u"ogr"_s );
319 }
320 }
322}
323
324//
325// ExporterBase
326//
327
328void QgsPointCloudLayerExporter::ExporterBase::run()
329{
331 geometryFilterRectangle( -std::numeric_limits<double>::infinity(), -std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity(), false );
332 if ( mParent->mFilterGeometryEngine )
333 {
334 const QgsAbstractGeometry *envelope = mParent->mFilterGeometryEngine->envelope();
335 if ( envelope )
336 geometryFilterRectangle = envelope->boundingBox();
337 }
338
339 QVector<QgsPointCloudNodeId> nodes;
340 qint64 pointCount = 0;
341 QQueue<QgsPointCloudNodeId> queue;
342 queue.push_back( mParent->mIndex.root() );
343 while ( !queue.empty() )
344 {
345 QgsPointCloudNode node = mParent->mIndex.getNode( queue.front() );
346 queue.pop_front();
347 const QgsBox3D nodeBounds = node.bounds();
348 if ( mParent->mExtent.intersects( nodeBounds.toRectangle() )
349 && mParent->mZRange.overlaps( { nodeBounds.zMinimum(), nodeBounds.zMaximum() } )
350 && geometryFilterRectangle.intersects( nodeBounds.toRectangle() ) )
351 {
352 pointCount += node.pointCount();
353 nodes.push_back( node.id() );
354 }
355 for ( const QgsPointCloudNodeId &child : node.children() )
356 {
357 queue.push_back( child );
358 }
359 }
360
361 const qint64 pointsToExport = mParent->mPointsLimit > 0 ? std::min( mParent->mPointsLimit, pointCount ) : pointCount;
362 QgsPointCloudRequest request;
363 request.setAttributes( mParent->requestedAttributeCollection() );
364 std::unique_ptr<QgsPointCloudBlock> block = nullptr;
365 qint64 pointsExported = 0;
366 for ( const QgsPointCloudNodeId &node : nodes )
367 {
368 block = mParent->mIndex.nodeData( node, request );
369 const QgsPointCloudAttributeCollection attributesCollection = block->attributes();
370 const char *ptr = block->data();
371 int count = block->pointCount();
372 int recordSize = attributesCollection.pointRecordSize();
373 const QgsVector3D scale = block->scale();
374 const QgsVector3D offset = block->offset();
375 int xOffset = 0, yOffset = 0, zOffset = 0;
376 const QgsPointCloudAttribute::DataType xType = attributesCollection.find( u"X"_s, xOffset )->type();
377 const QgsPointCloudAttribute::DataType yType = attributesCollection.find( u"Y"_s, yOffset )->type();
378 const QgsPointCloudAttribute::DataType zType = attributesCollection.find( u"Z"_s, zOffset )->type();
379 for ( int i = 0; i < count; ++i )
380 {
381 if ( mParent->mFeedback && i % 1000 == 0 )
382 {
383 if ( pointsToExport > 0 )
384 {
385 mParent->mFeedback->setProgress( 100 * static_cast< float >( pointsExported ) / pointsToExport );
386 }
387 if ( mParent->mFeedback->isCanceled() )
388 {
389 mParent->setLastError( QObject::tr( "Canceled by user" ) );
390 return;
391 }
392 }
393
394 if ( pointsExported >= pointsToExport )
395 break;
396
397 double x, y, z;
398 QgsPointCloudAttribute::getPointXYZ( ptr, i, recordSize, xOffset, xType, yOffset, yType, zOffset, zType, scale, offset, x, y, z );
399 if ( !mParent->mZRange.contains( z ) || !mParent->mExtent.contains( x, y ) || ( mParent->mFilterGeometryEngine && !mParent->mFilterGeometryEngine->contains( x, y ) ) )
400 {
401 continue;
402 }
403
404 try
405 {
406 mParent->mTransform->transformInPlace( x, y, z );
407 const QVariantMap attributeMap = QgsPointCloudAttribute::getAttributeMap( ptr, i * recordSize, attributesCollection );
408 handlePoint( x, y, z, attributeMap, pointsExported );
409 ++pointsExported;
410 }
411 catch ( const QgsCsException &cse )
412 {
413 QgsDebugError( u"Error transforming point: %1"_s.arg( cse.what() ) );
414 }
415 }
416 handleNode();
417 }
418 handleAll();
419}
420
421//
422// ExporterMemory
423//
424
425QgsPointCloudLayerExporter::ExporterMemory::ExporterMemory( QgsPointCloudLayerExporter *exp )
426{
427 mParent = exp;
428}
429
430QgsPointCloudLayerExporter::ExporterMemory::~ExporterMemory()
431{
432 mParent->mMemoryLayer->moveToThread( QApplication::instance()->thread() );
433}
434
435void QgsPointCloudLayerExporter::ExporterMemory::handlePoint( double x, double y, double z, const QVariantMap &map, const qint64 pointNumber )
436{
437 Q_UNUSED( pointNumber )
438
439 QgsFeature feature;
440 feature.setGeometry( QgsGeometry( new QgsPoint( x, y, z ) ) );
441 QgsAttributes featureAttributes;
442 for ( const QString &attribute : std::as_const( mParent->mRequestedAttributes ) )
443 {
444 const double val = map[attribute].toDouble();
445 featureAttributes.append( val );
446 }
447 feature.setAttributes( featureAttributes );
448 mFeatures.append( feature );
449}
450
451void QgsPointCloudLayerExporter::ExporterMemory::handleNode()
452{
453 QgsVectorLayer *vl = qgis::down_cast<QgsVectorLayer *>( mParent->mMemoryLayer );
454 if ( vl )
455 {
456 if ( !vl->dataProvider()->addFeatures( mFeatures ) )
457 {
458 mParent->setLastError( vl->dataProvider()->lastError() );
459 }
460 }
461 mFeatures.clear();
462}
463
464void QgsPointCloudLayerExporter::ExporterMemory::handleAll()
465{}
466
467//
468// ExporterVector
469//
470
471QgsPointCloudLayerExporter::ExporterVector::ExporterVector( QgsPointCloudLayerExporter *exp )
472{
473 mParent = exp;
474}
475
476QgsPointCloudLayerExporter::ExporterVector::~ExporterVector()
477{
478 delete mParent->mVectorSink;
479 mParent->mVectorSink = nullptr;
480}
481
482void QgsPointCloudLayerExporter::ExporterVector::handlePoint( double x, double y, double z, const QVariantMap &map, const qint64 pointNumber )
483{
484 Q_UNUSED( pointNumber )
485
486 QgsFeature feature;
487 feature.setGeometry( QgsGeometry( new QgsPoint( x, y, z ) ) );
488 QgsAttributes featureAttributes;
489 for ( const QString &attribute : std::as_const( mParent->mRequestedAttributes ) )
490 {
491 const double val = map[attribute].toDouble();
492 featureAttributes.append( val );
493 }
494 feature.setAttributes( featureAttributes );
495 mFeatures.append( feature );
496}
497
498void QgsPointCloudLayerExporter::ExporterVector::handleNode()
499{
500 if ( !mParent->mVectorSink->addFeatures( mFeatures ) )
501 {
502 mParent->setLastError( mParent->mVectorSink->lastError() );
503 }
504 mFeatures.clear();
505}
506
507void QgsPointCloudLayerExporter::ExporterVector::handleAll()
508{}
509
510//
511// ExporterPdal
512//
513
514#ifdef HAVE_PDAL_QGIS
515
516QgsPointCloudLayerExporter::ExporterPdal::ExporterPdal( QgsPointCloudLayerExporter *exp )
517 : mPointFormat( exp->mPointRecordFormat )
518{
519 mParent = exp;
520
521 mOptions.add( "filename", mParent->mFilename.toStdString() );
522 mOptions.add( "a_srs", mParent->mTargetCrs.toWkt().toStdString() );
523 mOptions.add( "minor_version", u"4"_s.toStdString() ); // delault to LAZ 1.4 to properly handle pdrf >= 6
524 mOptions.add( "format", QString::number( mPointFormat ).toStdString() );
525 if ( mParent->mTransform->isShortCircuited() )
526 {
527 mOptions.add( "offset_x", QString::number( mParent->mIndex.offset().x() ).toStdString() );
528 mOptions.add( "offset_y", QString::number( mParent->mIndex.offset().y() ).toStdString() );
529 mOptions.add( "offset_z", QString::number( mParent->mIndex.offset().z() ).toStdString() );
530 mOptions.add( "scale_x", QString::number( mParent->mIndex.scale().x() ).toStdString() );
531 mOptions.add( "scale_y", QString::number( mParent->mIndex.scale().y() ).toStdString() );
532 mOptions.add( "scale_z", QString::number( mParent->mIndex.scale().z() ).toStdString() );
533 }
534
535 mTable.layout()->registerDim( pdal::Dimension::Id::X );
536 mTable.layout()->registerDim( pdal::Dimension::Id::Y );
537 mTable.layout()->registerDim( pdal::Dimension::Id::Z );
538
539 mTable.layout()->registerDim( pdal::Dimension::Id::Classification );
540 mTable.layout()->registerDim( pdal::Dimension::Id::Intensity );
541 mTable.layout()->registerDim( pdal::Dimension::Id::ReturnNumber );
542 mTable.layout()->registerDim( pdal::Dimension::Id::NumberOfReturns );
543 mTable.layout()->registerDim( pdal::Dimension::Id::ScanDirectionFlag );
544 mTable.layout()->registerDim( pdal::Dimension::Id::EdgeOfFlightLine );
545 mTable.layout()->registerDim( pdal::Dimension::Id::ScanAngleRank );
546 mTable.layout()->registerDim( pdal::Dimension::Id::UserData );
547 mTable.layout()->registerDim( pdal::Dimension::Id::PointSourceId );
548
549 if ( mPointFormat == 6 || mPointFormat == 7 || mPointFormat == 8 || mPointFormat == 9 || mPointFormat == 10 )
550 {
551 mTable.layout()->registerDim( pdal::Dimension::Id::ScanChannel );
552 mTable.layout()->registerDim( pdal::Dimension::Id::ClassFlags );
553 }
554
555 if ( mPointFormat != 0 && mPointFormat != 2 )
556 {
557 mTable.layout()->registerDim( pdal::Dimension::Id::GpsTime );
558 }
559
560 if ( mPointFormat == 2 || mPointFormat == 3 || mPointFormat == 5 || mPointFormat == 7 || mPointFormat == 8 || mPointFormat == 10 )
561 {
562 mTable.layout()->registerDim( pdal::Dimension::Id::Red );
563 mTable.layout()->registerDim( pdal::Dimension::Id::Green );
564 mTable.layout()->registerDim( pdal::Dimension::Id::Blue );
565 }
566
567 if ( mPointFormat == 8 || mPointFormat == 10 )
568 {
569 mTable.layout()->registerDim( pdal::Dimension::Id::Infrared );
570 }
571
572 mView = std::make_shared<pdal::PointView>( mTable );
573}
574
575void QgsPointCloudLayerExporter::ExporterPdal::handlePoint( double x, double y, double z, const QVariantMap &map, const qint64 pointNumber )
576{
577 mView->setField( pdal::Dimension::Id::X, pointNumber, x );
578 mView->setField( pdal::Dimension::Id::Y, pointNumber, y );
579 mView->setField( pdal::Dimension::Id::Z, pointNumber, z );
580
581
582 mView->setField( pdal::Dimension::Id::Classification, pointNumber, map[u"Classification"_s].toInt() );
583 mView->setField( pdal::Dimension::Id::Intensity, pointNumber, map[u"Intensity"_s].toInt() );
584 mView->setField( pdal::Dimension::Id::ReturnNumber, pointNumber, map[u"ReturnNumber"_s].toInt() );
585 mView->setField( pdal::Dimension::Id::NumberOfReturns, pointNumber, map[u"NumberOfReturns"_s].toInt() );
586 mView->setField( pdal::Dimension::Id::ScanDirectionFlag, pointNumber, map[u"ScanDirectionFlag"_s].toInt() );
587 mView->setField( pdal::Dimension::Id::EdgeOfFlightLine, pointNumber, map[u"EdgeOfFlightLine"_s].toInt() );
588 mView->setField( pdal::Dimension::Id::ScanAngleRank, pointNumber, map[u"ScanAngleRank"_s].toFloat() );
589 mView->setField( pdal::Dimension::Id::UserData, pointNumber, map[u"UserData"_s].toInt() );
590 mView->setField( pdal::Dimension::Id::PointSourceId, pointNumber, map[u"PointSourceId"_s].toInt() );
591
592 if ( mPointFormat == 6 || mPointFormat == 7 || mPointFormat == 8 || mPointFormat == 9 || mPointFormat == 10 )
593 {
594 mView->setField( pdal::Dimension::Id::ScanChannel, pointNumber, map[u"ScannerChannel"_s].toInt() );
595 const int classificationFlags = ( map[u"Synthetic"_s].toInt() & 0x01 ) << 0
596 | ( map[u"KeyPoint"_s].toInt() & 0x01 ) << 1
597 | ( map[u"Withheld"_s].toInt() & 0x01 ) << 2
598 | ( map[u"Overlap"_s].toInt() & 0x01 ) << 3;
599 mView->setField( pdal::Dimension::Id::ClassFlags, pointNumber, classificationFlags );
600 }
601
602 if ( mPointFormat != 0 && mPointFormat != 2 )
603 {
604 mView->setField( pdal::Dimension::Id::GpsTime, pointNumber, map[u"GpsTime"_s].toDouble() );
605 }
606
607 if ( mPointFormat == 2 || mPointFormat == 3 || mPointFormat == 5 || mPointFormat == 7 || mPointFormat == 8 || mPointFormat == 10 )
608 {
609 mView->setField( pdal::Dimension::Id::Red, pointNumber, map[u"Red"_s].toInt() );
610 mView->setField( pdal::Dimension::Id::Green, pointNumber, map[u"Green"_s].toInt() );
611 mView->setField( pdal::Dimension::Id::Blue, pointNumber, map[u"Blue"_s].toInt() );
612 }
613
614 if ( mPointFormat == 8 || mPointFormat == 10 )
615 {
616 mView->setField( pdal::Dimension::Id::Infrared, pointNumber, map[u"Infrared"_s].toInt() );
617 }
618}
619
620void QgsPointCloudLayerExporter::ExporterPdal::handleNode()
621{}
622
623void QgsPointCloudLayerExporter::ExporterPdal::handleAll()
624{
625 pdal::BufferReader reader;
626 reader.addView( mView );
627
628 pdal::StageFactory factory;
629
630 pdal::Stage *writer = factory.createStage( "writers.las" );
631
632 writer->setInput( reader );
633 writer->setOptions( mOptions );
634 writer->prepare( mTable );
635 writer->execute( mTable );
636}
637#endif
638
639//
640// QgsPointCloudLayerExporterTask
641//
642
644 : QgsTask( tr( "Exporting point cloud" ), QgsTask::CanCancel )
645 , mExp( exporter )
646 , mOwnedFeedback( new QgsFeedback() )
647{}
648
650{
651 mOwnedFeedback->cancel();
653}
654
656{
657 if ( !mExp )
658 return false;
659
660 connect( mOwnedFeedback.get(), &QgsFeedback::progressChanged, this, &QgsPointCloudLayerExporterTask::setProgress );
661 mExp->setFeedback( mOwnedFeedback.get() );
662
663 mExp->doExport();
664
665 return true;
666}
667
669{
670 Q_UNUSED( result )
671
672 emit exportComplete();
673 delete mExp;
674}
@ PointZ
PointZ.
Definition qgis.h:313
@ NoSymbology
Export only data.
Definition qgis.h:5914
@ Reverse
Reverse/inverse transform (from destination to source).
Definition qgis.h:2766
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: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: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())
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:7540
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63
#define QgsDebugError(str)
Definition qgslogger.h:59