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