50using namespace Qt::StringLiterals;
63 QVector<QgsGeometry> res;
67 for (
const Feature &feature : it.value() )
69 res.append( feature.geometry );
81 return asIndividualFeatures(
type, feedback );
96 return snapPointToIndividualFeatures( point, context );
107 auto visitFeature = [&ids](
QgsFeatureId featureId ) { ids << featureId; };
109 visitFeaturesInRange( distanceRange, elevationRange, visitFeature );
113 QVector< QVariantMap> idsList;
114 for (
auto it = ids.constBegin(); it != ids.constEnd(); ++it )
115 idsList.append( QVariantMap( { { u
"id"_s, *it } } ) );
122 QHash< QgsFeatureId, QVariantMap >
features;
123 auto visitFeature = [&
features](
QgsFeatureId featureId,
double delta,
double distance,
double elevation ) {
124 auto it =
features.find( featureId );
127 features[featureId] = QVariantMap( { { u
"id"_s, featureId }, { u
"delta"_s, delta }, { u
"distance"_s, distance }, { u
"elevation"_s, elevation } } );
131 const double currentDelta = it.value().value( u
"delta"_s ).toDouble();
132 if ( delta < currentDelta )
134 *it = QVariantMap( { { u
"id"_s, featureId }, { u
"delta"_s, delta }, { u
"distance"_s, distance }, { u
"elevation"_s, elevation } } );
141 QVector< QVariantMap> attributes;
143 attributes.append( *it );
145 QVector<QgsProfileIdentifyResults> res;
147 if ( !attributes.empty() )
153 res.reserve( surfaceResults.size() );
166 double bestSnapDistance = std::numeric_limits< double >::max();
168 auto visitFeature = [&bestSnapDistance, &res](
QgsFeatureId,
double delta,
double distance,
double elevation ) {
169 if ( distance < bestSnapDistance )
171 bestSnapDistance = delta;
181void QgsVectorLayerProfileResults::visitFeaturesAtPoint(
183 double maximumPointDistanceDelta,
184 double maximumPointElevationDelta,
185 double maximumSurfaceElevationDelta,
186 const std::function<
void(
QgsFeatureId,
double delta,
double distance,
double elevation ) > &visitor,
196 for (
const Feature &feature : it.value() )
198 const QgsRectangle featureBounds = feature.crossSectionGeometry.boundingBox();
199 if ( ( featureBounds.
xMinimum() - maximumPointDistanceDelta <= point.
distance() ) && ( featureBounds.
xMaximum() + maximumPointDistanceDelta >= point.
distance() ) )
201 switch ( feature.crossSectionGeometry.type() )
205 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
209 const double snapDistanceDelta = std::fabs( point.
distance() - candidatePoint->x() );
210 if ( snapDistanceDelta > maximumPointDistanceDelta )
213 const double snapHeightDelta = std::fabs( point.
elevation() - candidatePoint->y() );
214 if ( snapHeightDelta > maximumPointElevationDelta )
217 const double snapDistance = candidatePoint->distance( targetPoint );
218 visitor( feature.featureId, snapDistance, candidatePoint->x(), candidatePoint->y() );
226 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
233 if ( lineString->numPoints() == 2 &&
qgsDoubleNear( lineString->pointN( 0 ).x(), lineString->pointN( 1 ).x() ) )
235 const double snapDistanceDelta = std::fabs( point.
distance() - lineString->pointN( 0 ).x() );
236 if ( snapDistanceDelta > maximumPointDistanceDelta )
239 const double snapHeightDelta = std::fabs( point.
elevation() - lineString->pointN( 0 ).y() );
240 if ( snapHeightDelta <= maximumPointElevationDelta )
242 const double snapDistanceP1 = lineString->pointN( 0 ).distance( targetPoint );
243 visitor( feature.featureId, snapDistanceP1, lineString->pointN( 0 ).x(), lineString->pointN( 0 ).y() );
246 const double snapHeightDelta2 = std::fabs( point.
elevation() - lineString->pointN( 1 ).y() );
247 if ( snapHeightDelta2 <= maximumPointElevationDelta )
249 const double snapDistanceP2 = lineString->pointN( 1 ).distance( targetPoint );
250 visitor( feature.featureId, snapDistanceP2, lineString->pointN( 1 ).x(), lineString->pointN( 1 ).y() );
255 double elevation1 = lineString->pointN( 0 ).y();
256 double elevation2 = lineString->pointN( 1 ).y();
257 if ( elevation1 > elevation2 )
258 std::swap( elevation1, elevation2 );
262 const double snapDistance = std::fabs( lineString->pointN( 0 ).x() - point.
distance() );
263 visitor( feature.featureId, snapDistance, lineString->pointN( 0 ).x(), point.
elevation() );
270 const QgsRectangle partBounds = ( *partIt )->boundingBox();
277 QgsGeos cutLineGeos( cutLine.constGet() );
279 const QgsGeometry points( cutLineGeos.intersection( line ) );
281 for (
auto vertexIt = points.vertices_begin(); vertexIt != points.vertices_end(); ++vertexIt )
283 const double snapHeightDelta = std::fabs( point.
elevation() - ( *vertexIt ).y() );
284 if ( snapHeightDelta > maximumSurfaceElevationDelta )
287 const double snapDistance = ( *vertexIt ).distance( targetPoint );
288 visitor( feature.featureId, snapDistance, ( *vertexIt ).x(), ( *vertexIt ).y() );
305 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
309 const QgsRectangle partBounds = ( *partIt )->boundingBox();
316 QgsGeos cutLineGeos( cutLine.constGet() );
318 const QgsGeometry points( cutLineGeos.intersection( exterior ) );
319 for (
auto vertexIt = points.vertices_begin(); vertexIt != points.vertices_end(); ++vertexIt )
321 const double snapHeightDelta = std::fabs( point.
elevation() - ( *vertexIt ).y() );
322 if ( snapHeightDelta > maximumSurfaceElevationDelta )
325 const double snapDistance = ( *vertexIt ).distance( targetPoint );
326 visitor( feature.featureId, snapDistance, ( *vertexIt ).x(), ( *vertexIt ).y() );
344 const QgsRectangle profileRange( distanceRange.
lower(), elevationRange.
lower(), distanceRange.
upper(), elevationRange.
upper() );
346 QgsGeos profileRangeGeos( profileRangeGeometry.
constGet() );
347 profileRangeGeos.prepareGeometry();
351 for (
const Feature &feature : it.value() )
353 if ( feature.crossSectionGeometry.boundingBoxIntersects( profileRange ) )
355 switch ( feature.crossSectionGeometry.type() )
359 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
363 if ( profileRange.contains( candidatePoint->x(), candidatePoint->y() ) )
365 visitor( feature.featureId );
375 if ( profileRangeGeos.intersects( feature.crossSectionGeometry.constGet() ) )
377 visitor( feature.featureId );
397 renderResultsAsIndividualFeatures( context );
402 renderMarkersOverContinuousSurfacePlot( context );
415 painter->setBrush( Qt::NoBrush );
416 painter->setPen( Qt::NoPen );
423 const QRectF visibleRegion( minDistance,
minZ, maxDistance - minDistance,
maxZ -
minZ );
424 QPainterPath clipPath;
425 clipPath.addPolygon( context.
worldTransform().map( visibleRegion ) );
426 painter->setClipPath( clipPath, Qt::ClipOperation::IntersectClip );
428 const QgsRectangle clipPathRect( clipPath.boundingRect() );
431 if ( profileFeature.crossSectionGeometry.isEmpty() )
434 QgsGeometry transformed = profileFeature.crossSectionGeometry;
441 switch ( transformed.
type() )
447 markerSymbol->renderPoint( QPointF( point->x(), point->y() ),
nullptr, context.
renderContext() );
451 const int numGeometries = multipoint->numGeometries();
452 for (
int i = 0; i < numGeometries; ++i )
454 markerSymbol->renderPoint( QPointF( multipoint->pointN( i )->x(), multipoint->pointN( i )->y() ),
nullptr, context.
renderContext() );
464 lineSymbol->renderPolyline( line->asQPolygonF(),
nullptr, context.
renderContext() );
468 const int numGeometries = multiLinestring->numGeometries();
469 for (
int i = 0; i < numGeometries; ++i )
471 lineSymbol->renderPolyline( multiLinestring->lineStringN( i )->asQPolygonF(),
nullptr, context.
renderContext() );
481 if (
const QgsCurve *exterior = polygon->exteriorRing() )
482 fillSymbol->renderPolygon( exterior->asQPolygonF(),
nullptr,
nullptr, context.
renderContext() );
486 const int numGeometries = multiPolygon->numGeometries();
487 for (
int i = 0; i < numGeometries; ++i )
489 fillSymbol->renderPolygon( multiPolygon->polygonN( i )->exteriorRing()->asQPolygonF(),
nullptr,
nullptr, context.
renderContext() );
501 QgsFeatureRequest req;
506 std::unique_ptr< QgsFeatureRenderer > renderer(
mLayer->renderer()->clone() );
511 QSet<QString> attributes = renderer->usedAttributes( context.
renderContext() );
513 std::unique_ptr< QgsMarkerSymbol > marker(
mMarkerSymbol->clone() );
514 std::unique_ptr< QgsLineSymbol > line(
mLineSymbol->clone() );
515 std::unique_ptr< QgsFillSymbol > fill(
mFillSymbol->clone() );
516 attributes.unite( marker->usedAttributes( context.
renderContext() ) );
517 attributes.unite( line->usedAttributes( context.
renderContext() ) );
518 attributes.unite( fill->usedAttributes( context.
renderContext() ) );
523 QgsFeatureIterator it =
mLayer->getFeatures( req );
527 QgsSymbol *rendererSymbol = renderer->symbolForFeature( feature, context.
renderContext() );
528 if ( !rendererSymbol )
531 marker->setColor( rendererSymbol->
color() );
532 marker->setOpacity( rendererSymbol->
opacity() );
533 line->setColor( rendererSymbol->
color() );
534 line->setOpacity( rendererSymbol->
opacity() );
535 fill->setColor( rendererSymbol->
color() );
536 fill->setOpacity( rendererSymbol->
opacity() );
542 const QVector< Feature > profileFeatures =
features.value( feature.
id() );
543 for (
const Feature &profileFeature : profileFeatures )
562 QSet<QString> attributes;
573 QgsFeatureIterator it =
mLayer->getFeatures( req );
577 const QVector< Feature > profileFeatures =
features.value( feature.
id() );
578 for (
const Feature &profileFeature : profileFeatures )
595 const QgsScopedQPainterState painterState( painter );
597 painter->setBrush( Qt::NoBrush );
598 painter->setPen( Qt::NoPen );
605 const QRectF visibleRegion( minDistance,
minZ, maxDistance - minDistance,
maxZ -
minZ );
606 QPainterPath clipPath;
607 clipPath.addPolygon( context.
worldTransform().map( visibleRegion ) );
608 painter->setClipPath( clipPath, Qt::ClipOperation::IntersectClip );
614 QHash< QgsFeatureId, QgsFeature > surfaceFeatures;
617 QgsFeatureRequest request;
621 QgsFeatureIterator featIt =
mLayer->getFeatures( request );
624 surfaceFeatures.insert( feature.
id(), feature );
630 if ( std::isnan( pointIt.value() ) )
643 QVector<QgsAbstractProfileResults::Feature> res;
650 for (
const Feature &feature : it.value() )
655 QgsAbstractProfileResults::Feature outFeature;
657 outFeature.
attributes = { { u
"id"_s, feature.featureId } };
665 outFeature.
geometry = feature.crossSectionGeometry;
682 mId = vlGenerator->mId;
685 mMarkerSymbol.reset( vlGenerator->mProfileMarkerSymbol->clone() );
697 , mProfileCurve( request.profileCurve() ? request.profileCurve()->clone() : nullptr )
698 , mTerrainProvider( request.terrainProvider() ? request.terrainProvider()->clone() : nullptr )
699 , mTolerance( request.tolerance() )
700 , mSourceCrs( layer->crs3D() )
701 , mTargetCrs( request.crs() )
702 , mTransformContext( request.transformContext() )
703 , mExtent( layer->extent() )
705 , mOffset( layer->elevationProperties()->zOffset() )
706 , mScale( layer->elevationProperties()->zScale() )
714 , mExpressionContext( request.expressionContext() )
715 , mFields( layer->fields() )
716 , mDataDefinedProperties( layer->elevationProperties()->dataDefinedProperties() )
717 , mWkbType( layer->wkbType() )
723 if ( mTerrainProvider )
724 mTerrainProvider->prepare();
728 mProfileCurve->dropZValue();
751 if ( !mProfileCurve || mFeedback->isCanceled() )
760 std::unique_ptr< QgsCurve > origCurve = std::move( mProfileCurve );
761 std::unique_ptr< QgsVectorLayerProfileResults > totalResults;
762 double distanceProcessed = 0;
764 QVector<QgsLineString *> disjointParts = profileLine->splitToDisjointXYParts();
765 for (
int i = 0; i < disjointParts.size(); i++ )
767 mProfileCurve.reset( disjointParts[i] );
768 if ( !generateProfileInner() )
770 mProfileCurve = std::move( origCurve );
773 for (
int j = i + 1; j < disjointParts.size(); j++ )
774 delete disjointParts[j];
781 totalResults = std::move( mResults );
785 totalResults->mRawPoints.append( mResults->mRawPoints );
786 totalResults->minZ = std::min( totalResults->minZ, mResults->minZ );
787 totalResults->maxZ = std::max( totalResults->maxZ, mResults->maxZ );
788 for (
auto it = mResults->mDistanceToHeightMap.constKeyValueBegin(); it != mResults->mDistanceToHeightMap.constKeyValueEnd(); ++it )
790 totalResults->mDistanceToHeightMap[it->first + distanceProcessed] = it->second;
792 for (
auto it = mResults->mDistanceToFeatureId.constKeyValueBegin(); it != mResults->mDistanceToFeatureId.constKeyValueEnd(); ++it )
794 totalResults->mDistanceToFeatureId[it->first + distanceProcessed] = it->second;
796 for (
auto it = mResults->features.constKeyValueBegin(); it != mResults->features.constKeyValueEnd(); ++it )
801 totalResults->features[it->first].push_back( feature );
806 distanceProcessed += mProfileCurve->length();
809 mProfileCurve = std::move( origCurve );
810 mResults = std::move( totalResults );
814 return generateProfileInner();
822 if ( mTerrainProvider )
823 mTargetToTerrainProviderTransform =
QgsCoordinateTransform( mTargetCrs, mTerrainProvider->crs(), mTransformContext );
829 catch ( QgsCsException & )
831 QgsDebugError( u
"Error transforming profile line to vector CRS"_s );
835 const QgsRectangle profileCurveBoundingBox = mTransformedCurve->boundingBox();
836 if ( !profileCurveBoundingBox.
intersects( mExtent ) )
839 if ( mFeedback->isCanceled() )
842 mResults = std::make_unique< QgsVectorLayerProfileResults >();
843 mResults->mLayer = mLayer;
844 mResults->copyPropertiesFromGenerator(
this );
846 mProfileCurveEngine = std::make_unique<QgsGeos>( mProfileCurve.get() );
847 mProfileCurveEngine->prepareGeometry();
849 if ( tolerance() == 0.0 )
851 mProfileBufferedCurve = std::unique_ptr<QgsAbstractGeometry>( mProfileCurve->clone() );
858 mProfileBufferedCurveEngine = std::make_unique<QgsGeos>( mProfileBufferedCurve.get() );
859 mProfileBufferedCurveEngine->prepareGeometry();
861 mDataDefinedProperties.prepare( mExpressionContext );
863 if ( mFeedback->isCanceled() )
869 if ( !generateProfileForPoints() )
874 if ( !generateProfileForLines() )
879 if ( !generateProfileForPolygons() )
893 return mResults.release();
898 return mFeedback.get();
901bool QgsVectorLayerProfileGenerator::generateProfileForPoints()
916 while ( !mFeedback->isCanceled() && it.
nextFeature( feature ) )
923 if ( mProfileBufferedCurveEngine->intersects( *it ) )
929 return !mFeedback->isCanceled();
932void QgsVectorLayerProfileGenerator::processIntersectionPoint(
const QgsPoint *point,
const QgsFeature &feature )
937 const double height = featureZToHeight( point->
x(), point->
y(), point->
z(), offset );
938 mResults->mRawPoints.append( QgsPoint( point->
x(), point->
y(), height ) );
939 mResults->minZ = std::min( mResults->minZ, height );
940 mResults->maxZ = std::max( mResults->maxZ, height );
942 const double distanceAlongProfileCurve = mProfileCurveEngine->lineLocatePoint( *point, &error );
943 mResults->mDistanceToHeightMap.insert( distanceAlongProfileCurve, height );
944 mResults->mDistanceToFeatureId.insert( distanceAlongProfileCurve, feature.
id() );
946 QgsVectorLayerProfileResults::Feature resultFeature;
948 if ( mExtrusionEnabled )
952 resultFeature.
geometry = QgsGeometry(
new QgsLineString( QgsPoint( point->
x(), point->
y(), height ), QgsPoint( point->
x(), point->
y(), height + extrusion ) ) );
953 resultFeature.
crossSectionGeometry = QgsGeometry(
new QgsLineString( QgsPoint( distanceAlongProfileCurve, height ), QgsPoint( distanceAlongProfileCurve, height + extrusion ) ) );
954 mResults->minZ = std::min( mResults->minZ, height + extrusion );
955 mResults->maxZ = std::max( mResults->maxZ, height + extrusion );
959 resultFeature.
geometry = QgsGeometry(
new QgsPoint( point->
x(), point->
y(), height ) );
960 resultFeature.
crossSectionGeometry = QgsGeometry(
new QgsPoint( distanceAlongProfileCurve, height ) );
963 mResults->features[resultFeature.
featureId].append( resultFeature );
966void QgsVectorLayerProfileGenerator::processIntersectionCurve(
const QgsLineString *intersectionCurve,
const QgsFeature &feature )
970 QgsVectorLayerProfileResults::Feature resultFeature;
972 double maxDistanceAlongProfileCurve = std::numeric_limits<double>::lowest();
977 const int numPoints = intersectionCurve->
numPoints();
978 QVector< double > newX( numPoints );
979 QVector< double > newY( numPoints );
980 QVector< double > newZ( numPoints );
981 QVector< double > newDistance( numPoints );
983 const double *inX = intersectionCurve->
xData();
984 const double *inY = intersectionCurve->
yData();
985 const double *inZ = intersectionCurve->
is3D() ? intersectionCurve->
zData() :
nullptr;
986 double *outX = newX.data();
987 double *outY = newY.data();
988 double *outZ = newZ.data();
989 double *outDistance = newDistance.data();
991 QVector< double > extrudedZ;
992 double *extZOut =
nullptr;
993 if ( mExtrusionEnabled )
995 extrudedZ.resize( numPoints );
996 extZOut = extrudedZ.data();
999 for (
int i = 0; !mFeedback->isCanceled() && i < numPoints; ++i )
1001 QgsPoint intersectionPoint( *inX, *inY, ( inZ ? *inZ : std::numeric_limits<double>::quiet_NaN() ) );
1003 const double height = featureZToHeight( intersectionPoint.x(), intersectionPoint.y(), intersectionPoint.z(), offset );
1004 const double distanceAlongProfileCurve = mProfileCurveEngine->lineLocatePoint( intersectionPoint, &error );
1006 maxDistanceAlongProfileCurve = std::max( maxDistanceAlongProfileCurve, distanceAlongProfileCurve );
1008 mResults->mRawPoints.append( QgsPoint( intersectionPoint.x(), intersectionPoint.y(), height ) );
1009 mResults->minZ = std::min( mResults->minZ, height );
1010 mResults->maxZ = std::max( mResults->maxZ, height );
1012 mResults->mDistanceToHeightMap.insert( distanceAlongProfileCurve, height );
1013 mResults->mDistanceToFeatureId.insert( distanceAlongProfileCurve, feature.
id() );
1014 *outDistance++ = distanceAlongProfileCurve;
1016 *outX++ = intersectionPoint.x();
1017 *outY++ = intersectionPoint.y();
1020 *extZOut++ = height + extrusion;
1022 if ( mExtrusionEnabled )
1024 mResults->minZ = std::min( mResults->minZ, height + extrusion );
1025 mResults->maxZ = std::max( mResults->maxZ, height + extrusion );
1033 mResults->mDistanceToHeightMap.insert( maxDistanceAlongProfileCurve +
Qgis::DEFAULT_SEGMENT_EPSILON, std::numeric_limits<double>::quiet_NaN() );
1035 if ( mFeedback->isCanceled() )
1039 if ( mExtrusionEnabled )
1041 auto ring = std::make_unique< QgsLineString >( newX, newY, newZ );
1042 auto extrudedRing = std::make_unique< QgsLineString >( newX, newY, extrudedZ );
1043 std::unique_ptr< QgsLineString > reversedExtrusion( extrudedRing->reversed() );
1044 ring->append( reversedExtrusion.get() );
1046 resultFeature.
geometry = QgsGeometry(
new QgsPolygon( ring.release() ) );
1048 auto distanceVHeightRing = std::make_unique< QgsLineString >( newDistance, newZ );
1049 auto extrudedDistanceVHeightRing = std::make_unique< QgsLineString >( newDistance, extrudedZ );
1050 std::unique_ptr< QgsLineString > reversedDistanceVHeightExtrusion( extrudedDistanceVHeightRing->reversed() );
1051 distanceVHeightRing->append( reversedDistanceVHeightExtrusion.get() );
1052 distanceVHeightRing->close();
1053 resultFeature.
crossSectionGeometry = QgsGeometry(
new QgsPolygon( distanceVHeightRing.release() ) );
1057 resultFeature.
geometry = QgsGeometry(
new QgsLineString( newX, newY, newZ ) );
1061 mResults->features[resultFeature.
featureId].append( resultFeature );
1064bool QgsVectorLayerProfileGenerator::generateProfileForLines()
1067 QgsFeatureRequest request;
1069 if ( tolerance() > 0 )
1071 request.
setDistanceWithin( QgsGeometry( mProfileCurve->clone() ), tolerance() );
1077 request.
setSubsetOfAttributes( mDataDefinedProperties.referencedFields( mExpressionContext ), mFields );
1080 auto processCurve = [
this](
const QgsFeature &feature,
const QgsCurve *featGeomPart ) {
1082 std::unique_ptr< QgsAbstractGeometry > intersection( mProfileBufferedCurveEngine->intersection( featGeomPart, &error ) );
1083 if ( !intersection )
1086 if ( mFeedback->isCanceled() )
1091 if ( intersection->isEmpty() )
1093 intersection.reset( featGeomPart->clone() );
1094 for (
auto it = intersection->const_parts_begin(); !mFeedback->isCanceled() && it != intersection->const_parts_end(); ++it )
1097 processIntersectionCurve( intersectionCurve, feature );
1102 QgsGeos featGeomPartGeos( featGeomPart );
1103 featGeomPartGeos.prepareGeometry();
1105 for (
auto it = intersection->const_parts_begin(); !mFeedback->isCanceled() && it != intersection->const_parts_end(); ++it )
1111 const double distance = featGeomPartGeos.lineLocatePoint( *intersectionPoint, &error );
1112 std::unique_ptr< QgsPoint > interpolatedPoint( featGeomPart->interpolatePoint( distance ) );
1114 processIntersectionPoint( interpolatedPoint.get(), feature );
1120 auto lineInterpolated = std::make_unique<QgsLineString>();
1121 for (
int i = 0; i < intersectionCurve->
numPoints(); ++i )
1123 const QgsPoint pt = intersectionCurve->
pointN( i );
1126 const double distance = featGeomPartGeos.lineLocatePoint( pt, &err );
1128 std::unique_ptr<QgsPoint> pointWithInterpolatedZM( featGeomPart->interpolatePoint( distance ) );
1129 lineInterpolated->addVertex( *pointWithInterpolatedZM );
1132 processIntersectionCurve( lineInterpolated.get(), feature );
1138 QgsFeatureIterator it = mSource->getFeatures( request );
1139 while ( !mFeedback->isCanceled() && it.
nextFeature( feature ) )
1141 mExpressionContext.setFeature( feature );
1143 const QgsGeometry g = feature.
geometry();
1146 if ( mProfileBufferedCurveEngine->intersects( *it ) )
1153 return !mFeedback->isCanceled();
1156QgsPoint QgsVectorLayerProfileGenerator::interpolatePointOnTriangle(
const QgsPolygon *triangle,
double x,
double y )
const
1158 QgsPoint p1, p2, p3;
1163 const double z = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, p1.
z(), p2.
z(), p3.
z(), QgsPointXY( x, y ) );
1164 return QgsPoint( x, y, z );
1167void QgsVectorLayerProfileGenerator::processTriangleIntersectForPoint(
1168 const QgsPolygon *triangle,
const QgsPoint *p, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts,
const QgsFeatureId featureId
1171 const QgsPoint interpolatedPoint = interpolatePointOnTriangle( triangle, p->
x(), p->
y() );
1172 mResults->mRawPoints.append( interpolatedPoint );
1173 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() );
1174 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() );
1177 const double distance = mProfileCurveEngine->lineLocatePoint( *p, &lastError );
1178 mResults->mDistanceToHeightMap.insert( distance, interpolatedPoint.
z() );
1179 mResults->mDistanceToFeatureId.insert( distance, featureId );
1181 if ( mExtrusionEnabled )
1185 transformedParts.append( QgsGeometry(
new QgsLineString( interpolatedPoint, QgsPoint( interpolatedPoint.
x(), interpolatedPoint.
y(), interpolatedPoint.
z() + extrusion ) ) ) );
1186 crossSectionParts.append( QgsGeometry(
new QgsLineString( QgsPoint( distance, interpolatedPoint.
z() ), QgsPoint( distance, interpolatedPoint.
z() + extrusion ) ) ) );
1187 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() + extrusion );
1188 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() + extrusion );
1192 transformedParts.append( QgsGeometry(
new QgsPoint( interpolatedPoint ) ) );
1193 crossSectionParts.append( QgsGeometry(
new QgsPoint( distance, interpolatedPoint.
z() ) ) );
1197void QgsVectorLayerProfileGenerator::processTriangleIntersectForLine(
1198 const QgsPolygon *triangle,
const QgsLineString *intersectionLine, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts,
const QgsFeatureId featureId
1204 int numPoints = intersectionLine->
numPoints();
1205 QVector< double > newX( numPoints );
1206 QVector< double > newY( numPoints );
1207 QVector< double > newZ( numPoints );
1208 QVector< double > newDistance( numPoints );
1210 const double *inX = intersectionLine->
xData();
1211 const double *inY = intersectionLine->
yData();
1212 const double *inZ = intersectionLine->
is3D() ? intersectionLine->
zData() :
nullptr;
1213 double *outX = newX.data();
1214 double *outY = newY.data();
1215 double *outZ = newZ.data();
1216 double *outDistance = newDistance.data();
1218 double minDistanceAlongProfileCurve = std::numeric_limits< double >::max();
1219 double maxDistanceAlongProfileCurve = std::numeric_limits< double >::lowest();
1220 QVector< double > extrudedZ;
1221 double *extZOut =
nullptr;
1222 double extrusion = 0;
1224 if ( mExtrusionEnabled )
1226 extrudedZ.resize( numPoints );
1227 extZOut = extrudedZ.data();
1233 QVector< QPair< double, double > > segmentDistanceToHeight;
1234 segmentDistanceToHeight.reserve( numPoints );
1235 for (
int i = 0; !mFeedback->isCanceled() && i < numPoints; ++i )
1239 double z = inZ ? *inZ++ : 0;
1241 QgsPoint interpolatedPoint( x, y, z );
1247 interpolatedPoint = interpolatePointOnTriangle( triangle, x, y );
1249 double tempOutZ = std::isnan( interpolatedPoint.
z() ) ? 0.0 : interpolatedPoint.
z();
1252 if ( mExtrusionEnabled )
1253 *extZOut++ = tempOutZ + extrusion;
1255 mResults->mRawPoints.append( interpolatedPoint );
1256 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() );
1257 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() );
1258 if ( mExtrusionEnabled )
1260 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() + extrusion );
1261 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() + extrusion );
1264 const double distance = mProfileCurveEngine->lineLocatePoint( interpolatedPoint, &lastError );
1265 *outDistance++ = distance;
1267 segmentDistanceToHeight.append( { distance, interpolatedPoint.
z() } );
1268 minDistanceAlongProfileCurve = std::min( distance, minDistanceAlongProfileCurve );
1269 maxDistanceAlongProfileCurve = std::max( distance, maxDistanceAlongProfileCurve );
1272 if ( numPoints > 0 )
1277 for (
const QPair< double, double > &point : std::as_const( segmentDistanceToHeight ) )
1279 double distance = point.first;
1289 mResults->mDistanceToHeightMap.insert( distance, point.second );
1290 mResults->mDistanceToFeatureId.insert( distance, featureId );
1296 mSurfaceIntervals.append( { minDistanceAlongProfileCurve, maxDistanceAlongProfileCurve } );
1299 if ( mFeedback->isCanceled() )
1302 if ( mExtrusionEnabled )
1304 auto ring = std::make_unique< QgsLineString >( newX, newY, newZ );
1305 auto extrudedRing = std::make_unique< QgsLineString >( newX, newY, extrudedZ );
1306 std::unique_ptr< QgsLineString > reversedExtrusion( extrudedRing->reversed() );
1307 ring->append( reversedExtrusion.get() );
1309 transformedParts.append( QgsGeometry(
new QgsPolygon( ring.release() ) ) );
1311 auto distanceVHeightRing = std::make_unique< QgsLineString >( newDistance, newZ );
1312 auto extrudedDistanceVHeightRing = std::make_unique< QgsLineString >( newDistance, extrudedZ );
1313 std::unique_ptr< QgsLineString > reversedDistanceVHeightExtrusion( extrudedDistanceVHeightRing->reversed() );
1314 distanceVHeightRing->append( reversedDistanceVHeightExtrusion.get() );
1315 distanceVHeightRing->close();
1316 crossSectionParts.append( QgsGeometry(
new QgsPolygon( distanceVHeightRing.release() ) ) );
1320 transformedParts.append( QgsGeometry(
new QgsLineString( newX, newY, newZ ) ) );
1321 crossSectionParts.append( QgsGeometry(
new QgsLineString( newDistance, newZ ) ) );
1325void QgsVectorLayerProfileGenerator::processTriangleIntersectForPolygon(
1326 const QgsPolygon *sourcePolygon,
const QgsPolygon *intersectionPolygon, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts,
const QgsFeatureId featureId
1329 bool oldExtrusion = mExtrusionEnabled;
1362 mExtrusionEnabled =
false;
1363 if ( mProfileBufferedCurveEngine->contains( sourcePolygon ) )
1365 if (
const QgsCurve *exterior = sourcePolygon->
exteriorRing() )
1368 processTriangleIntersectForLine( sourcePolygon, exteriorLine, transformedParts, crossSectionParts, featureId );
1373 processTriangleIntersectForLine( sourcePolygon, interiorLine, transformedParts, crossSectionParts, featureId );
1379 if (
const QgsCurve *exterior = intersectionPolygon->
exteriorRing() )
1383 processTriangleIntersectForLine( sourcePolygon, exteriorLine, transformedParts, crossSectionParts, featureId );
1384 delete exteriorLine;
1389 if ( mProfileBufferedCurveEngine->contains( interiorLine ) )
1391 processTriangleIntersectForLine( sourcePolygon, interiorLine, transformedParts, crossSectionParts, featureId );
1396 newInteriorLine->deleteVertex( QgsVertexId( 0, 0, interiorLine->
numPoints() - 1 ) );
1397 processTriangleIntersectForLine( sourcePolygon, newInteriorLine.get(), transformedParts, crossSectionParts, featureId );
1402 mExtrusionEnabled = oldExtrusion;
1405bool QgsVectorLayerProfileGenerator::generateProfileForPolygons()
1408 QgsFeatureRequest request;
1410 if ( tolerance() > 0 )
1412 request.
setDistanceWithin( QgsGeometry( mProfileCurve->clone() ), tolerance() );
1418 request.
setSubsetOfAttributes( mDataDefinedProperties.referencedFields( mExpressionContext ), mFields );
1421 std::function< void(
const QgsPolygon *triangle,
const QgsAbstractGeometry *intersect, QVector< QgsGeometry > &, QVector< QgsGeometry > &,
const QgsFeatureId ) > processTriangleLineIntersect;
1422 processTriangleLineIntersect =
1423 [
this](
const QgsPolygon *triangle,
const QgsAbstractGeometry *intersection, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts,
const QgsFeatureId featureId ) {
1424 for (
auto it = intersection->const_parts_begin(); !mFeedback->isCanceled() && it != intersection->const_parts_end(); ++it )
1432 processTriangleIntersectForPoint( triangle, p, transformedParts, crossSectionParts, featureId );
1439 processTriangleIntersectForLine( triangle, intersectionLine, transformedParts, crossSectionParts, featureId );
1446 processTriangleIntersectForPolygon( triangle, poly, transformedParts, crossSectionParts, featureId );
1457 auto triangleIsCollinearInXYPlane = [](
const QgsPolygon *polygon ) ->
bool {
1462 auto processPolygon =
1464 &processTriangleLineIntersect,
1465 &triangleIsCollinearInXYPlane](
const QgsCurvePolygon *polygon, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts,
double offset,
bool &wasCollinear,
const QgsFeatureId featureId ) {
1466 std::unique_ptr< QgsPolygon > clampedPolygon;
1469 clampedPolygon.reset( p->
clone() );
1475 clampAltitudes( clampedPolygon.get(), offset );
1477 if ( mFeedback->isCanceled() )
1480 if ( tolerance() > 0.0 )
1483 if ( mProfileBufferedCurveEngine->intersects( clampedPolygon.get(), &error ) )
1485 std::unique_ptr< QgsAbstractGeometry > intersection;
1486 intersection.reset( mProfileBufferedCurveEngine->intersection( clampedPolygon.get(), &error ) );
1487 if ( error.isEmpty() )
1489 processTriangleLineIntersect( clampedPolygon.get(), intersection.get(), transformedParts, crossSectionParts, featureId );
1498 QVector< double > newX( numPoints );
1499 QVector< double > newY( numPoints );
1500 QVector< double > newZ( numPoints );
1501 double *outX = newX.data();
1502 double *outY = newY.data();
1503 double *outZ = newZ.data();
1505 const double *inX = ring->
xData();
1506 const double *inY = ring->
yData();
1507 const double *inZ = ring->
zData();
1508 for (
int i = 0; !mFeedback->isCanceled() && i < ring->numPoints() - 1; ++i )
1510 *outX++ = inX[i] + i * 1.0e-9;
1511 *outY++ = inY[i] + i * 1.0e-9;
1514 std::unique_ptr< QgsPolygon > shiftedPoly;
1515 shiftedPoly = std::make_unique<QgsPolygon>(
new QgsLineString( newX, newY, newZ ) );
1517 intersection.reset( mProfileBufferedCurveEngine->intersection( shiftedPoly.get(), &error ) );
1519 processTriangleLineIntersect( clampedPolygon.get(), intersection.get(), transformedParts, crossSectionParts, featureId );
1523 QgsDebugMsgLevel( u
"processPolygon after shift bad geom! error: %1"_s.arg( error ), 0 );
1531 QgsGeometry tessellation;
1532 if ( clampedPolygon->numInteriorRings() == 0 && clampedPolygon->exteriorRing() && clampedPolygon->exteriorRing()->numPoints() == 4 && clampedPolygon->exteriorRing()->isClosed() )
1535 auto multiPolygon = std::make_unique< QgsMultiPolygon >();
1536 multiPolygon->addGeometry( clampedPolygon.release() );
1537 tessellation = QgsGeometry( std::move( multiPolygon ) );
1541 const QgsRectangle bounds = clampedPolygon->boundingBox();
1547 if ( mFeedback->isCanceled() )
1555 for (
int i = 0; !mFeedback->isCanceled() && i < numTriangles; ++i )
1559 if ( triangleIsCollinearInXYPlane( triangle ) )
1561 wasCollinear =
true;
1567 for (
int curveSegmentIndex = 0; curveSegmentIndex < mProfileCurve->numPoints() - 1; ++curveSegmentIndex )
1569 const QgsPoint p1 = ls->pointN( curveSegmentIndex );
1570 const QgsPoint p2 = ls->pointN( curveSegmentIndex + 1 );
1572 QgsPoint intersectionPoint;
1573 bool intersectionFound =
false;
1574 double minZ = std::numeric_limits< double >::max();
1575 double maxZ = std::numeric_limits< double >::lowest();
1577 for (
auto vertexPair : std::array<std::pair<int, int>, 3> { { { 0, 1 }, { 1, 2 }, { 2, 0 } } } )
1579 bool isIntersection =
false;
1580 QgsPoint edgeIntersectionPoint;
1583 if ( !edgeIntersectionPoint.
isEmpty() && !intersectionFound )
1585 intersectionPoint = edgeIntersectionPoint;
1586 intersectionFound =
true;
1591 ring->
xAt( vertexPair.first ), ring->
yAt( vertexPair.first ), ring->
xAt( vertexPair.second ), ring->
yAt( vertexPair.second ), edgeIntersectionPoint.
x(), edgeIntersectionPoint.
y()
1593 double intersectionZ = ring->
zAt( vertexPair.first ) + ( ring->
zAt( vertexPair.second ) - ring->
zAt( vertexPair.first ) ) * fraction;
1594 minZ = std::min( minZ, intersectionZ );
1595 maxZ = std::max( maxZ, intersectionZ );
1599 if ( intersectionFound )
1602 mResults->mRawPoints.append( intersectionPoint );
1603 mResults->minZ = std::min( mResults->minZ, minZ );
1604 mResults->maxZ = std::max( mResults->maxZ, maxZ );
1606 const double distance = mProfileCurveEngine->lineLocatePoint( intersectionPoint, &lastError );
1608 crossSectionParts.append( QgsGeometry(
new QgsLineString( QVector< double > { distance, distance }, QVector< double > { minZ, maxZ } ) ) );
1610 mResults->mDistanceToHeightMap.insert( distance, minZ );
1611 mResults->mDistanceToHeightMap.insert( distance, maxZ );
1612 mResults->mDistanceToFeatureId.insert( distance, featureId );
1619 QgsDebugError( u
"Collinear triangles with curved profile lines are not supported yet"_s );
1625 if ( mProfileBufferedCurveEngine->intersects( triangle, &error ) )
1627 std::unique_ptr< QgsAbstractGeometry > intersection( mProfileBufferedCurveEngine->intersection( triangle, &error ) );
1628 processTriangleLineIntersect( triangle, intersection.get(), transformedParts, crossSectionParts, featureId );
1637 QgsFeatureIterator it = mSource->getFeatures( request );
1638 while ( !mFeedback->isCanceled() && it.
nextFeature( feature ) )
1640 if ( !mProfileBufferedCurveEngine->intersects( feature.
geometry().
constGet() ) )
1643 mExpressionContext.setFeature( feature );
1646 const QgsGeometry g = feature.
geometry();
1647 QVector< QgsGeometry > transformedParts;
1648 QVector< QgsGeometry > crossSectionParts;
1649 bool wasCollinear =
false;
1654 if ( mProfileBufferedCurveEngine->intersects( *it ) )
1658 processPolygon( curvePolygon, transformedParts, crossSectionParts, offset, wasCollinear, feature.
id() );
1662 for (
int i = 0; i < polySurface->numPatches(); ++i )
1664 const QgsPolygon *polygon = polySurface->patchN( i );
1665 if ( mProfileBufferedCurveEngine->intersects( polygon ) )
1667 processPolygon( polygon, transformedParts, crossSectionParts, offset, wasCollinear, feature.
id() );
1673 QgsDebugError( u
"Unhandled Geometry type: %1"_s.arg( ( *it )->wktTypeStr() ) );
1678 if ( mFeedback->isCanceled() )
1682 QgsVectorLayerProfileResults::Feature resultFeature;
1685 if ( !crossSectionParts.empty() )
1687 if ( !wasCollinear )
1689 QgsGeometry unioned = QgsGeometry::unaryUnion( crossSectionParts );
1690 if ( unioned.isEmpty() )
1692 resultFeature.crossSectionGeometry = QgsGeometry::collectGeometry( crossSectionParts );
1696 if ( unioned.type() == Qgis::GeometryType::Line )
1698 unioned = unioned.mergeLines();
1700 resultFeature.crossSectionGeometry = unioned;
1705 resultFeature.crossSectionGeometry = QgsGeometry::collectGeometry( crossSectionParts );
1708 mResults->features[resultFeature.
featureId].append( resultFeature );
1711 insertSurfaceSeparators();
1715double QgsVectorLayerProfileGenerator::tolerance()
const
1717 return mCustomToleranceEnabled ? mCustomTolerance : mTolerance;
1720double QgsVectorLayerProfileGenerator::terrainHeight(
double x,
double y )
const
1722 if ( !mTerrainProvider )
1723 return std::numeric_limits<double>::quiet_NaN();
1729 mTargetToTerrainProviderTransform.transformInPlace( x, y, dummyZ );
1731 catch ( QgsCsException & )
1733 return std::numeric_limits<double>::quiet_NaN();
1736 return mTerrainProvider->heightAt( x, y );
1739double QgsVectorLayerProfileGenerator::featureZToHeight(
double x,
double y,
double z,
double offset )
const
1741 switch ( mClamping )
1749 const double terrainZ = terrainHeight( x, y );
1750 if ( !std::isnan( terrainZ ) )
1752 switch ( mClamping )
1755 if ( std::isnan( z ) )
1773 return ( std::isnan( z ) ? 0 : z ) * mScale + offset;
1776void QgsVectorLayerProfileGenerator::clampAltitudes(
QgsLineString *lineString,
const QgsPoint ¢roid,
double offset )
const
1780 if ( mFeedback->isCanceled() )
1783 double terrainZ = 0;
1784 switch ( mClamping )
1793 pt.
setX( lineString->
xAt( i ) );
1794 pt.
setY( lineString->
yAt( i ) );
1798 pt.
set( centroid.
x(), centroid.
y() );
1802 terrainZ = terrainHeight( pt.
x(), pt.
y() );
1812 switch ( mClamping )
1816 geomZ = lineString->
zAt( i );
1823 const double z = ( terrainZ + ( std::isnan( geomZ ) ? 0 : geomZ ) ) * mScale + offset;
1824 lineString->
setZAt( i, z );
1828bool QgsVectorLayerProfileGenerator::clampAltitudes(
QgsPolygon *polygon,
double offset )
const
1830 if ( !polygon->
is3D() )
1844 QgsCurve *curve =
const_cast<QgsCurve *
>( polygon->
exteriorRing() );
1849 clampAltitudes( lineString, centroid, offset );
1853 if ( mFeedback->isCanceled() )
1856 QgsCurve *curve =
const_cast<QgsCurve *
>( polygon->
interiorRing( i ) );
1861 clampAltitudes( lineString, centroid, offset );
1866void QgsVectorLayerProfileGenerator::insertSurfaceSeparators()
1869 if ( mSurfaceIntervals.size() <= 1 )
1871 mSurfaceIntervals.clear();
1875 std::sort( mSurfaceIntervals.begin(), mSurfaceIntervals.end() );
1876 double currentEnd = mSurfaceIntervals[0].second;
1877 for (
auto intervalIt = mSurfaceIntervals.cbegin() + 1; intervalIt != mSurfaceIntervals.cend(); ++intervalIt )
1879 const double newStart = intervalIt->first;
1884 currentEnd = std::max( currentEnd, intervalIt->second );
1887 mSurfaceIntervals.clear();
@ Relative
Elevation is relative to terrain height (final elevation = terrain elevation + feature elevation).
@ Terrain
Elevation is clamped to terrain (final elevation = terrain elevation).
@ Absolute
Elevation is taken directly from feature and is independent of terrain height (final elevation = feat...
VertexType
Types of vertex.
@ Round
Use rounded joins.
@ Centroid
Clamp just centroid of feature.
@ Vertex
Clamp every vertex of feature.
@ Flat
Flat cap (in line with start/end of line).
static const double DEFAULT_SEGMENT_EPSILON
Default snapping tolerance for segments.
@ ContinuousSurface
The features should be treated as representing values on a continuous surface (eg contour lines).
@ IndividualFeatures
Treat each feature as an individual object (eg buildings).
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).
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
virtual bool deleteVertex(QgsVertexId position)
Deletes a vertex within the geometry.
virtual QgsPoint centroid() const
Returns the centroid of the geometry.
Abstract base class for objects which generate elevation profiles.
Abstract base class for storage of elevation profiles.
std::unique_ptr< QgsCurve > mProfileCurve
std::unique_ptr< QgsLineSymbol > mLineSymbol
QgsAbstractProfileSurfaceGenerator(const QgsProfileRequest &request)
Constructor for QgsAbstractProfileSurfaceGenerator.
Qgis::ProfileSurfaceSymbology mSymbology
std::unique_ptr< QgsFillSymbol > mFillSymbol
std::unique_ptr< QgsFillSymbol > mFillSymbol
QMap< double, double > mDistanceToHeightMap
std::unique_ptr< QgsLineSymbol > mLineSymbol
void renderResults(QgsProfileRenderContext &context) override
Renders the results to the specified context.
void copyPropertiesFromGenerator(const QgsAbstractProfileGenerator *generator) override
Copies properties from specified generator to the results object.
QVector< QgsAbstractProfileResults::Feature > asFeatures(Qgis::ProfileExportType type, QgsFeedback *feedback=nullptr) const override
Returns a list of features representing the calculated elevation results.
QVector< QgsProfileIdentifyResults > identify(const QgsProfilePoint &point, const QgsProfileIdentifyContext &context) override
Identify results visible at the specified profile point.
QgsProfileSnapResult snapPoint(const QgsProfilePoint &point, const QgsProfileSnapContext &context) override
Snaps a point to the generated elevation profile.
int numInteriorRings() const
Returns the number of interior rings contained with the curve polygon.
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
const QgsCurve * interiorRing(int i) const
Retrieves an interior ring from the curve polygon.
virtual int numPoints() const =0
Returns the number of points in the curve.
virtual bool pointAt(int node, QgsPoint &point, Qgis::VertexType &type) const =0
Returns the point and vertex type of a point within the curve.
QgsRange which stores a range of double values.
RAII class to pop scope from an expression context on destruction.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
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 & setCoordinateTransform(const QgsCoordinateTransform &transform)
Sets the coordinate transform which will be used to transform the feature's geometries.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets the feature IDs that should be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature's geometries.
void setFeedback(QgsFeedback *feedback)
Attach a feedback object that can be queried regularly by the iterator to check if it should be cance...
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
QgsFeatureRequest & setDistanceWithin(const QgsGeometry &geometry, double distance)
Sets a reference geometry and a maximum distance from this geometry to retrieve features within.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
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.
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
static double pointFractionAlongLine(double x1, double y1, double x2, double y2, double px, double py)
Given the line (x1, y1) to (x2, y2) and a point (px, py) returns the fraction of the line length at w...
static bool pointsAreCollinear(double x1, double y1, double x2, double y2, double x3, double y3, double epsilon)
Given the points (x1, y1), (x2, y2) and (x3, y3) returns true if these points can be considered colli...
static bool segmentIntersection(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q1, const QgsPoint &q2, QgsPoint &intersectionPoint, bool &isIntersection, double tolerance=1e-8, bool acceptImproperIntersection=false)
Compute the intersection between two segments.
A geometry is the spatial representation of a feature.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
QgsAbstractGeometry::const_part_iterator const_parts_begin() const
Returns STL-style const iterator pointing to the first part of the geometry.
Q_INVOKABLE bool boundingBoxIntersects(const QgsRectangle &rectangle) const
Returns true if the bounding box of this geometry intersects with a rectangle.
static QgsGeometry collectGeometry(const QVector< QgsGeometry > &geometries)
Creates a new multipart geometry from a list of QgsGeometry objects.
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 fromPointXY(const QgsPointXY &point)
Creates a new geometry from a QgsPointXY object.
QgsAbstractGeometry::const_part_iterator const_parts_end() const
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry.
Qgis::GeometryOperationResult translate(double dx, double dy, double dz=0.0, double dm=0.0)
Translates this geometry by dx, dy, dz and dm.
Line string geometry type, with support for z-dimension and m-values.
A line symbol type, for rendering LineString and MultiLineString geometries.
@ ExtrusionHeight
Extrusion height.
A marker symbol type, for rendering Point and MultiPoint geometries.
void setY(double y)
Sets the y value of the point.
void set(double x, double y)
Sets the x and y value of the point.
void setX(double x)
Sets the x value of the point.
Point geometry type, with support for z-dimension and m-values.
QgsPoint * clone() const override
Clones the geometry by performing a deep copy.
bool isEmpty() const override
Returns true if the geometry is empty.
Encapsulates the context in which an elevation profile is to be generated.
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.
double maximumSurfaceElevationDelta
Maximum allowed snapping delta for the elevation values when identifying a continuous elevation surfa...
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 maximumSurfaceElevationDelta
Maximum allowed snapping delta for the elevation values when snapping to a continuous elevation surfa...
double maximumPointElevationDelta
Maximum allowed snapping delta for the elevation values when snapping to a point.
Encapsulates results of snapping a profile point.
QgsProfilePoint snappedPoint
Snapped point.
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext(), bool ignoreContext=false) const final
Returns the set of any fields referenced by the active properties from the collection.
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.
QPainter * painter()
Returns the destination QPainter for the render operation.
QgsExpressionContext & expressionContext()
Gets the expression context.
Scoped object for saving and restoring a QPainter object's state.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
void setZAt(int index, double z)
Sets the z-coordinate of the specified node in the simple curve.
int numPoints() const override
Returns the number of points in the curve.
int nCoordinates() const override
Returns the number of nodes contained in the geometry.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
const double * yData() const
Returns a const pointer to the y vertex data.
double zAt(int index) const override
Returns the z-coordinate of the specified node in the simple curve.
QgsPoint pointN(int i) const
Returns the specified point from inside the simple curve.
const double * xData() const
Returns a const pointer to the x vertex data.
const double * zData() const
Returns a const pointer to the z vertex data, or nullptr if the simple curve does not have z values.
qreal opacity() const
Returns the opacity for the symbol.
QColor color() const
Returns the symbol's color.
Qgis::SymbolType type() const
Returns the symbol's type.
std::unique_ptr< QgsMultiPolygon > asMultiPolygon() const
Returns the triangulation as a multipolygon geometry.
void setBounds(const QgsRectangle &bounds)
Sets scaling and the bounds of the input geometry coordinates.
void addPolygon(const QgsPolygon &polygon, float extrusionHeight)
Tessellates a triangle and adds its vertex entries to the output data array.
Vector layer specific subclass of QgsMapLayerElevationProperties.
Partial snapshot of vector layer's state (only the members necessary for access to features).
Implementation of QgsAbstractProfileGenerator for vector layers.
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).
QString sourceId() const override
Returns a unique identifier representing the source of the profile.
QString type() const override
Returns the unique string identifier for the results type.
~QgsVectorLayerProfileGenerator() override
QgsFeedback * feedback() const override
Access to feedback object of the generator (may be nullptr).
QgsVectorLayerProfileGenerator(QgsVectorLayer *layer, const QgsProfileRequest &request)
Constructor for QgsVectorLayerProfileGenerator.
QVector< QgsProfileIdentifyResults > identify(const QgsProfilePoint &point, const QgsProfileIdentifyContext &context) override
Identify results visible at the specified profile point.
Qgis::VectorProfileType profileType
std::unique_ptr< QgsMarkerSymbol > mMarkerSymbol
bool respectLayerSymbology
bool mShowMarkerSymbolInSurfacePlots
QVector< QgsGeometry > asGeometries() const override
Returns a list of geometries representing the calculated elevation results.
QPointer< QgsVectorLayer > mLayer
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.
QgsProfileSnapResult snapPoint(const QgsProfilePoint &point, const QgsProfileSnapContext &context) override
Snaps a point to the generated elevation profile.
QString type() const override
Returns the unique string identifier for the results type.
QHash< QgsFeatureId, QVector< Feature > > features
QMap< double, QgsFeatureId > mDistanceToFeatureId
void copyPropertiesFromGenerator(const QgsAbstractProfileGenerator *generator) override
Copies properties from specified generator to the results object.
Represents a vector layer which manages a vector based dataset.
QgsMapLayerElevationProperties * elevationProperties() override
Returns the layer's elevation properties.
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
#define BUILTIN_UNREACHABLE
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
T qgsgeometry_cast(QgsAbstractGeometry *geom)
QSet< QgsFeatureId > QgsFeatureIds
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)
QString layerIdentifier
Identifier for grouping output features.
QVariantMap attributes
Exported attributes.
QgsGeometry geometry
Exported geometry.
QgsGeometry crossSectionGeometry
Cross section distance vs height geometry for feature.
QgsFeatureId featureId
Original feature ID.
QgsGeometry geometry
Feature's geometry with any terrain height adjustment and extrusion applied.