44 mPointIndex =
nullptr;
51 const std::size_t size =
results.size();
53 for ( std::size_t i = 0; i < size; ++i, ++pointData )
58 geos::unique_ptr geosPoint( GEOSGeom_createPointFromXY_r( geosctxt, pointData->
distanceAlongCurve, pointData->
z ) );
60 GEOSSTRtree_insert_r( geosctxt, mPointIndex, geosPoint.get(), pointData );
67 return QStringLiteral(
"pointcloud" );
73 QMap< double, double > res;
76 res.insert( point.distanceAlongCurve, point.z );
88 res.append(
QgsPoint( point.x, point.y, point.z ) );
96 QVector< QgsGeometry > res;
107 QVector< QgsAbstractProfileResults::Feature > res;
108 res.reserve(
static_cast< int >(
results.size() ) );
133 f.
geometry =
QgsGeometry( std::make_unique< QgsPoint >( point.distanceAlongCurve, point.z ) );
150 { QStringLiteral(
"distance" ), point.distanceAlongCurve },
151 { QStringLiteral(
"elevation" ), point.z }
176 painter->setBrush( Qt::NoBrush );
177 painter->setPen( Qt::NoPen );
195 const QRectF visibleRegion( minDistance,
minZ, maxDistance - minDistance,
maxZ -
minZ );
196 QPainterPath clipPath;
197 clipPath.addPolygon( context.
worldTransform().map( visibleRegion ) );
198 painter->setClipPath( clipPath, Qt::ClipOperation::IntersectClip );
204 QPointF p = context.
worldTransform().map( QPointF( point.distanceAlongCurve, point.z ) );
207 color.setAlphaF( color.alphaF() * ( 1.0 - std::pow( point.distanceFromCurve /
tolerance, 0.5 ) ) );
212 painter->fillRect( QRectF( p.x() - penWidth * 0.5,
213 p.y() - penWidth * 0.5,
214 penWidth, penWidth ), color );
218 painter->setBrush( QBrush( color ) );
219 painter->setPen( Qt::NoPen );
220 painter->drawEllipse( QRectF( p.x() - penWidth * 0.5,
221 p.y() - penWidth * 0.5,
222 penWidth, penWidth ) );
230 QList< const QgsPointCloudLayerProfileResults::PointResult * > *
list;
248 GEOSCoordSequence *coord = GEOSCoordSeq_create_r( geosctxt, 2, 2 );
249 GEOSCoordSeq_setXY_r( geosctxt, coord, 0, minDistance, minElevation );
250 GEOSCoordSeq_setXY_r( geosctxt, coord, 1, maxDistance, maxElevation );
251 geos::unique_ptr searchDiagonal( GEOSGeom_createLineString_r( geosctxt, coord ) );
253 QList<const PointResult *> items;
255 callbackData.
list = &items;
256 GEOSSTRtree_query_r( geosctxt, mPointIndex, searchDiagonal.get(),
_GEOSQueryCallback, &callbackData );
260 double bestMatchDistance = std::numeric_limits< double >::max();
262 for (
const PointResult *candidate : std::as_const( items ) )
264 const double distance = std::sqrt( std::pow( candidate->distanceAlongCurve - point.
distance(), 2 )
266 if ( distance < bestMatchDistance )
268 bestMatchDistance = distance;
269 bestMatch = candidate;
290 std::unique_ptr< QgsCurve > substring( mProfileCurve->curveSubstring( distanceRange.
lower(), distanceRange.
upper() ) );
291 QgsGeos substringGeos( substring.get() );
293 if ( !searchGeometry )
299 searchGeometry->
transform( curveToLayerTransform );
307 const QgsDoubleRange providerElevationRange( ( elevationRange.
lower() - mZOffset ) / mZScale, ( elevationRange.
upper() - mZOffset ) / mZScale );
309 const QgsGeometry pointCloudSearchGeometry( std::move( searchGeometry ) );
310 const QVector<QVariantMap> pointAttributes = mLayer->dataProvider()->identify( mMaxErrorInLayerCoordinates, pointCloudSearchGeometry, providerElevationRange );
311 if ( pointAttributes.empty() )
328 mLayer = pcGenerator->mLayer;
329 mLayerId = pcGenerator->mId;
330 mCurveCrs = pcGenerator->mTargetCrs;
331 mProfileCurve.reset( pcGenerator->mProfileCurve->clone() );
332 mTolerance = pcGenerator->mTolerance;
334 mZOffset = pcGenerator->mZOffset;
335 mZScale = pcGenerator->mZScale;
344 , mIndex( layer->index() )
345 , mSubIndexes( layer->dataProvider()->subIndexes() )
346 , mLayerAttributes( layer->attributes() )
347 , mRenderer( qgis::down_cast<
QgsPointCloudLayerElevationProperties* >( layer->elevationProperties() )->respectLayerColors() && mLayer->renderer() ? mLayer->renderer()->clone() : nullptr )
357 , mProfileCurve( request.profileCurve() ? request.profileCurve()->clone() : nullptr )
358 , mTolerance( request.tolerance() )
359 , mSourceCrs( layer->crs3D() )
360 , mTargetCrs( request.
crs() )
361 , mTransformContext( request.transformContext() )
362 , mZOffset( layer->elevationProperties()->zOffset() )
363 , mZScale( layer->elevationProperties()->zScale() )
364 , mStepDistance( request.stepDistance() )
368 mScale = mIndex.
scale();
369 mOffset = mIndex.
offset();
387 mGatheredPoints.clear();
388 if ( !mLayer || !mProfileCurve || mFeedback->isCanceled() )
391 QVector<QgsPointCloudIndex> indexes;
392 if ( mIndex && mIndex.
isValid() )
393 indexes.append( mIndex );
396 const QgsRectangle profileCurveBbox = mProfileCurve->boundingBox();
397 for (
const QgsPointCloudSubIndex &subidx : mSubIndexes )
400 if ( index && index.
isValid() && subidx.polygonBounds().intersects( profileCurveBbox ) )
401 indexes.append( subidx.index() );
404 if ( indexes.empty() )
410 std::unique_ptr< QgsCurve > trimmedCurve;
412 if ( startDistanceOffset > 0 || endDistance < mProfileCurve->length() )
414 trimmedCurve.reset( mProfileCurve->curveSubstring( startDistanceOffset, endDistance ) );
415 sourceCurve = trimmedCurve.get();
419 sourceCurve = mProfileCurve.get();
423 QgsGeos originalCurveGeos( sourceCurve );
434 QgsDebugError( QStringLiteral(
"Error transforming profile line to layer CRS" ) );
438 if ( mFeedback->isCanceled() )
441 mSearchGeometryInLayerCrsGeometryEngine = std::make_unique< QgsGeos >( mSearchGeometryInLayerCrs.get() );
442 mSearchGeometryInLayerCrsGeometryEngine->prepareGeometry();
443 mMaxSearchExtentInLayerCrs = mSearchGeometryInLayerCrs->boundingBox();
446 if ( maximumErrorPixels < 0.0 )
448 QgsDebugError( QStringLiteral(
"Invalid maximum error in pixels" ) );
457 if ( toleranceInPixels / 4 < maximumErrorPixels )
458 maximumErrorPixels = toleranceInPixels / 4;
468 mPreparedRendererData = mRenderer->prepare();
469 if ( mPreparedRendererData )
471 const QSet< QString > rendererAttributes = mPreparedRendererData->usedAttributes();
472 for (
const QString &attribute : std::as_const( rendererAttributes ) )
474 if ( attributes.
indexOf( attribute ) >= 0 )
477 const int layerIndex = mLayerAttributes.
indexOf( attribute );
478 if ( layerIndex < 0 )
480 QgsMessageLog::logMessage( QObject::tr(
"Required attribute %1 not found in layer" ).arg( attribute ), QObject::tr(
"Point Cloud" ) );
484 attributes.
push_back( mLayerAttributes.
at( layerIndex ) );
490 mPreparedRendererData.reset();
495 mResults = std::make_unique< QgsPointCloudLayerProfileResults >();
496 mResults->copyPropertiesFromGenerator(
this );
497 mResults->mMaxErrorInLayerCoordinates = 0;
503 if ( mapUnitsPerPixel < 0.0 )
505 QgsDebugError( QStringLiteral(
"Invalid map units per pixel ratio" ) );
520 QgsDebugError( QStringLiteral(
"Could not transform node extent to curve CRS" ) );
521 rootNodeExtentInCurveCrs = rootNodeExtentLayerCoords;
524 const double rootErrorInMapCoordinates = rootNodeExtentInCurveCrs.
width() / pc.span();
525 if ( rootErrorInMapCoordinates < 0.0 )
527 QgsDebugError( QStringLiteral(
"Invalid root node error" ) );
531 double rootErrorPixels = rootErrorInMapCoordinates / mapUnitsPerPixel;
532 const QVector<QgsPointCloudNodeId> nodes = traverseTree( pc, pc.root(), maximumErrorPixels, rootErrorPixels, context.
elevationRange() );
534 const double rootErrorInLayerCoordinates = rootNodeExtentLayerCoords.
width() / pc.span();
535 const double maxErrorInMapCoordinates = maximumErrorPixels * mapUnitsPerPixel;
537 mResults->mMaxErrorInLayerCoordinates = std::max(
538 mResults->mMaxErrorInLayerCoordinates,
539 maxErrorInMapCoordinates * rootErrorInLayerCoordinates / rootErrorInMapCoordinates );
541 switch ( pc.accessType() )
555 if ( mFeedback->isCanceled() )
559 if ( mGatheredPoints.empty() )
569 const int size = mGatheredPoints.size();
570 mResults->results.resize( size );
572 for (
int i = 0; i < size; ++i, ++pointData, ++destData )
574 if ( mFeedback->isCanceled() )
577 *destData = *pointData;
579 if ( mOpacityByDistanceEffect )
582 mResults->minZ = std::min( destData->
z, mResults->minZ );
583 mResults->maxZ = std::max( destData->
z, mResults->maxZ );
585 mResults->finalize( mFeedback.get() );
592 return mResults.release();
597 return mFeedback.get();
602 QVector<QgsPointCloudNodeId> nodes;
604 if ( mFeedback->isCanceled() )
619 if ( !mSearchGeometryInLayerCrsGeometryEngine->intersects( nodeMapGeometry.
constGet() ) )
625 double childrenErrorPixels = nodeErrorPixels / 2.0;
626 if ( childrenErrorPixels < maxErrorPixels )
631 nodes += traverseTree( pc, nn, maxErrorPixels, childrenErrorPixels, zRange );
642 if ( mFeedback->isCanceled() )
645 std::unique_ptr<QgsPointCloudBlock> block( pc.
nodeData( n, request ) );
650 visitBlock( block.get(), zRange );
664 QVector<QgsPointCloudBlockRequest *> blockRequests;
668 for (
int i = 0; i < nodes.size(); ++i )
673 blockRequests.append( blockRequest );
675 [
this, &nodesDrawn, &loop, &blockRequests, &zRange, nStr, blockRequest ]()
677 blockRequests.removeOne( blockRequest );
680 if ( blockRequests.isEmpty() )
683 std::unique_ptr<QgsPointCloudBlock> block = blockRequest->
takeBlock();
685 blockRequest->deleteLater();
687 if ( mFeedback->isCanceled() )
694 QgsDebugError( QStringLiteral(
"Unable to load node %1, error: %2" ).arg( nStr, blockRequest->
errorStr() ) );
698 visitBlock( block.get(), zRange );
710 std::unique_ptr<QgsPointCloudBlock> block = blockRequest->
takeBlock();
712 blockRequest->deleteLater();
720 const char *ptr = block->
data();
728 int xOffset = 0, yOffset = 0, zOffset = 0;
733 bool useRenderer =
false;
734 if ( mPreparedRendererData )
736 useRenderer = mPreparedRendererData->prepareBlock( block );
741 for (
int i = 0; i < count; ++i )
743 if ( mFeedback->isCanceled() )
749 QgsPointCloudAttribute::getPointXYZ( ptr, i, recordSize, xOffset, xType, yOffset, yType, zOffset, zType, block->
scale(), block->
offset(), res.
x, res.
y, res.
z );
751 res.
z = res.
z * mZScale + mZOffset;
757 color = mPreparedRendererData->pointColor( block, i, res.
z );
758 if ( !color.isValid() )
761 res.
color = color.rgba();
765 res.
color = mPointColor.rgba();
768 if ( mSearchGeometryInLayerCrsGeometryEngine->contains( res.
x, res.
y ) )
782 mGatheredPoints.append( res );
@ RespectsMaximumErrorMapUnit
Generated profile respects the QgsProfileGenerationContext::maximumErrorMapUnits() property.
@ RespectsDistanceRange
Generated profile respects the QgsProfileGenerationContext::distanceRange() property.
@ Circle
Renders points as circles.
@ Square
Renders points as squares.
QFlags< ProfileGeneratorFlag > ProfileGeneratorFlags
@ Round
Use rounded joins.
@ Flat
Flat cap (in line with start/end of line)
@ Local
Local means the source is a local file on the machine.
@ Remote
Remote means it's loaded through a protocol like HTTP.
ProfileExportType
Types of export for elevation profiles.
@ Profile2D
Export profiles as 2D profile lines, with elevation stored in exported geometry Y dimension and dista...
@ Features3D
Export profiles as 3D features, with elevation values stored in exported geometry Z values.
@ DistanceVsElevationTable
Export profiles as a table of sampled distance vs elevation values.
@ Reverse
Reverse/inverse transform (from destination to source)
Abstract base class for objects which generate elevation profiles.
Abstract base class for storage of elevation profiles.
A 3-dimensional box composed of x, y, z coordinates.
double zMaximum() const
Returns the maximum z value.
QgsRectangle toRectangle() const
Converts the box to a 2D rectangle.
double zMinimum() const
Returns the minimum z value.
Contains information about the context in which a coordinate transform is executed.
Custom exception class for Coordinate Reference System related exceptions.
Abstract base class for curved geometry type.
QgsRange which stores a range of double values.
bool isInfinite() const
Returns true if the range consists of all possible values.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
bool isCanceled() const
Tells whether the operation has been canceled already.
void canceled()
Internal routines can connect to this signal if they use event loop.
A geometry is the spatial representation of a feature.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
static GEOSContextHandle_t get()
Returns a thread local instance of a GEOS context, safe for use in the current thread.
Does vector analysis using the GEOS library and handles import, export, and exception handling.
QgsAbstractGeometry * buffer(double distance, int segments, QString *errorMsg=nullptr) const override
double distance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculates the distance between this and geom.
void prepareGeometry() override
Prepares the geometry, so that subsequent calls to spatial relation methods are much faster.
double lineLocatePoint(const QgsPoint &point, QString *errorMsg=nullptr) const
Returns a distance representing the location along this linestring of the closest point on this lines...
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
Collection of point cloud attributes.
void push_back(const QgsPointCloudAttribute &attribute)
Adds extra attribute.
int pointRecordSize() const
Returns total size of record.
const QgsPointCloudAttribute & at(int index) const
Returns the attribute at the specified index.
const QgsPointCloudAttribute * find(const QString &attributeName, int &offset) const
Finds the attribute with the name.
int indexOf(const QString &name) const
Returns the index of the attribute with the specified name.
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.
DataType type() const
Returns the data type.
Base class for handling loading QgsPointCloudBlock asynchronously.
QString errorStr()
Returns the error message string of the request.
void finished()
Emitted when the request processing has finished.
std::unique_ptr< QgsPointCloudBlock > takeBlock()
Returns the requested block.
Base class for storing raw data from point cloud nodes.
QgsVector3D scale() const
Returns the custom scale of the block.
const char * data() const
Returns raw pointer to data.
QgsPointCloudAttributeCollection attributes() const
Returns the attributes that are stored in the data block, along with their size.
int pointCount() const
Returns number of points that are stored in the block.
QgsVector3D offset() const
Returns the custom offset of the block.
Smart pointer for QgsAbstractPointCloudIndex.
QgsVector3D offset() const
Returns offset of data from CRS.
QgsVector3D scale() const
Returns scale of data relative to CRS.
QgsPointCloudBlockRequest * asyncNodeData(const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request)
Returns a handle responsible for loading a node data block.
bool isValid() const
Returns whether index is loaded and valid.
std::unique_ptr< QgsPointCloudBlock > nodeData(const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request)
Returns node data block.
QgsPointCloudNode getNode(const QgsPointCloudNodeId &id) const
Returns object for a given node.
Point cloud layer specific subclass of QgsMapLayerElevationProperties.
Implementation of QgsAbstractProfileGenerator for point cloud layers.
Qgis::ProfileGeneratorFlags flags() const override
Returns flags which reflect how the profile generator operates.
QgsPointCloudLayerProfileGenerator(QgsPointCloudLayer *layer, const QgsProfileRequest &request)
Constructor for QgsPointCloudLayerProfileGenerator.
~QgsPointCloudLayerProfileGenerator() override
QString sourceId() const override
Returns a unique identifier representing the source of the profile.
QgsFeedback * feedback() const override
Access to feedback object of the generator (may be nullptr)
QgsAbstractProfileResults * takeResults() override
Takes results from the generator.
bool generateProfile(const QgsProfileGenerationContext &context=QgsProfileGenerationContext()) override
Generate the profile (based on data stored in the class).
Qgis::PointCloudSymbol pointSymbol
QgsProfileSnapResult snapPoint(const QgsProfilePoint &point, const QgsProfileSnapContext &context) override
Snaps a point to the generated elevation profile.
void finalize(QgsFeedback *feedback)
Finalizes results – should be called after last point is added.
QgsPointSequence sampledPoints() const override
Returns a list of sampled points, with their calculated elevation as the point z value.
QgsDoubleRange zRange() const override
Returns the range of the retrieved elevation values.
std::vector< PointResult > results
QMap< double, double > distanceToHeightMap() const override
Returns the map of distance (chainage) to height.
QVector< QgsGeometry > asGeometries() const override
Returns a list of geometries representing the calculated elevation results.
~QgsPointCloudLayerProfileResults() override
void copyPropertiesFromGenerator(const QgsAbstractProfileGenerator *generator) override
Copies properties from specified generator to the results object.
QVector< QgsProfileIdentifyResults > identify(const QgsProfilePoint &point, const QgsProfileIdentifyContext &context) override
Identify results visible at the specified profile point.
QString type() const override
Returns the unique string identifier for the results type.
bool opacityByDistanceEffect
QgsPointCloudLayerProfileResults()
void renderResults(QgsProfileRenderContext &context) override
Renders the results to the specified context.
QVector< QgsAbstractProfileResults::Feature > asFeatures(Qgis::ProfileExportType type, QgsFeedback *feedback=nullptr) const override
Returns a list of features representing the calculated elevation results.
Qgis::RenderUnit pointSizeUnit
Represents a map layer supporting display of point clouds.
Represents a indexed point cloud node's position in octree.
QString toString() const
Encode node to string.
Keeps metadata for indexed point cloud node.
qint64 pointCount() const
Returns number of points contained in node data.
QgsBox3D bounds() const
Returns node's bounding cube in CRS coords.
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.
Encapsulates the context in which an elevation profile is to be generated.
double mapUnitsPerDistancePixel() const
Returns the number of map units per pixel in the distance dimension.
QgsDoubleRange elevationRange() const
Returns the range of elevations to include in the generation.
double convertDistanceToPixels(double size, Qgis::RenderUnit unit) const
Converts a distance size from the specified units to pixels.
QgsDoubleRange distanceRange() const
Returns the range of distances to include in the generation.
Encapsulates the context of identifying profile results.
double maximumPointElevationDelta
Maximum allowed snapping delta for the elevation values when identifying a point.
double maximumPointDistanceDelta
Maximum allowed snapping delta for the distance values when identifying a point.
QgsProject * project
Associated project.
Stores identify results generated by a QgsAbstractProfileResults object.
Encapsulates a point on a distance-elevation profile.
double elevation() const
Returns the elevation of the point.
double distance() const
Returns the distance of the point.
Abstract base class for storage of elevation profiles.
const QTransform & worldTransform() const
Returns the transform from world coordinates to painter coordinates.
QgsDoubleRange elevationRange() const
Returns the range of elevations to include in the render.
QgsDoubleRange distanceRange() const
Returns the range of distances to include in the render.
QgsRenderContext & renderContext()
Returns a reference to the component QgsRenderContext.
Encapsulates properties and constraints relating to fetching elevation profiles from different source...
Encapsulates the context of snapping a profile point.
double maximumPointDistanceDelta
Maximum allowed snapping delta for the distance values when snapping to a point.
double maximumPointElevationDelta
Maximum allowed snapping delta for the elevation values when snapping to a point.
double displayRatioElevationVsDistance
Display ratio of elevation vs distance units.
Encapsulates results of snapping a profile point.
QgsProfilePoint snappedPoint
Snapped point.
QgsCoordinateTransformContext transformContext
bool overlaps(const QgsRange< T > &other) const
Returns true if this range overlaps another range.
bool contains(const QgsRange< T > &other) const
Returns true if this range contains another range.
T lower() const
Returns the lower bound of the range.
T upper() const
Returns the upper bound of the range.
A rectangle specified with double values.
bool intersects(const QgsRectangle &rect) const
Returns true when rectangle intersects with other rectangle.
double convertToPainterUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
QPainter * painter()
Returns the destination QPainter for the render operation.
Scoped object for saving and restoring a QPainter object's state.
QVector< QgsPoint > QgsPointSequence
#define QgsDebugError(str)
void _GEOSQueryCallback(void *item, void *userdata)
const QgsCoordinateReferenceSystem & crs
Encapsulates information about a feature exported from the profile results.
QString layerIdentifier
Identifier for grouping output features.
QVariantMap attributes
Exported attributes.
QgsGeometry geometry
Exported geometry.
double distanceAlongCurve
QList< const QgsPointCloudLayerProfileResults::PointResult * > * list