49using namespace Qt::StringLiterals;
62 QVector<QgsGeometry> res;
66 for (
const Feature &feature : it.value() )
68 res.append( feature.geometry );
80 return asIndividualFeatures(
type, feedback );
95 return snapPointToIndividualFeatures( point, context );
106 auto visitFeature = [&ids](
QgsFeatureId featureId ) { ids << featureId; };
108 visitFeaturesInRange( distanceRange, elevationRange, visitFeature );
112 QVector< QVariantMap> idsList;
113 for (
auto it = ids.constBegin(); it != ids.constEnd(); ++it )
114 idsList.append( QVariantMap( { { u
"id"_s, *it } } ) );
121 QHash< QgsFeatureId, QVariantMap >
features;
122 auto visitFeature = [&
features](
QgsFeatureId featureId,
double delta,
double distance,
double elevation ) {
123 auto it =
features.find( featureId );
126 features[featureId] = QVariantMap( { { u
"id"_s, featureId }, { u
"delta"_s, delta }, { u
"distance"_s, distance }, { u
"elevation"_s, elevation } } );
130 const double currentDelta = it.value().value( u
"delta"_s ).toDouble();
131 if ( delta < currentDelta )
133 *it = QVariantMap( { { u
"id"_s, featureId }, { u
"delta"_s, delta }, { u
"distance"_s, distance }, { u
"elevation"_s, elevation } } );
140 QVector< QVariantMap> attributes;
142 attributes.append( *it );
144 QVector<QgsProfileIdentifyResults> res;
146 if ( !attributes.empty() )
152 res.reserve( surfaceResults.size() );
165 double bestSnapDistance = std::numeric_limits< double >::max();
167 auto visitFeature = [&bestSnapDistance, &res](
QgsFeatureId,
double delta,
double distance,
double elevation ) {
168 if ( distance < bestSnapDistance )
170 bestSnapDistance = delta;
180void QgsVectorLayerProfileResults::visitFeaturesAtPoint(
182 double maximumPointDistanceDelta,
183 double maximumPointElevationDelta,
184 double maximumSurfaceElevationDelta,
185 const std::function<
void(
QgsFeatureId,
double delta,
double distance,
double elevation ) > &visitor,
195 for (
const Feature &feature : it.value() )
197 const QgsRectangle featureBounds = feature.crossSectionGeometry.boundingBox();
198 if ( ( featureBounds.
xMinimum() - maximumPointDistanceDelta <= point.
distance() ) && ( featureBounds.
xMaximum() + maximumPointDistanceDelta >= point.
distance() ) )
200 switch ( feature.crossSectionGeometry.type() )
204 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
208 const double snapDistanceDelta = std::fabs( point.
distance() - candidatePoint->x() );
209 if ( snapDistanceDelta > maximumPointDistanceDelta )
212 const double snapHeightDelta = std::fabs( point.
elevation() - candidatePoint->y() );
213 if ( snapHeightDelta > maximumPointElevationDelta )
216 const double snapDistance = candidatePoint->distance( targetPoint );
217 visitor( feature.featureId, snapDistance, candidatePoint->x(), candidatePoint->y() );
225 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
232 if ( lineString->numPoints() == 2 &&
qgsDoubleNear( lineString->pointN( 0 ).x(), lineString->pointN( 1 ).x() ) )
234 const double snapDistanceDelta = std::fabs( point.
distance() - lineString->pointN( 0 ).x() );
235 if ( snapDistanceDelta > maximumPointDistanceDelta )
238 const double snapHeightDelta = std::fabs( point.
elevation() - lineString->pointN( 0 ).y() );
239 if ( snapHeightDelta <= maximumPointElevationDelta )
241 const double snapDistanceP1 = lineString->pointN( 0 ).distance( targetPoint );
242 visitor( feature.featureId, snapDistanceP1, lineString->pointN( 0 ).x(), lineString->pointN( 0 ).y() );
245 const double snapHeightDelta2 = std::fabs( point.
elevation() - lineString->pointN( 1 ).y() );
246 if ( snapHeightDelta2 <= maximumPointElevationDelta )
248 const double snapDistanceP2 = lineString->pointN( 1 ).distance( targetPoint );
249 visitor( feature.featureId, snapDistanceP2, lineString->pointN( 1 ).x(), lineString->pointN( 1 ).y() );
254 double elevation1 = lineString->pointN( 0 ).y();
255 double elevation2 = lineString->pointN( 1 ).y();
256 if ( elevation1 > elevation2 )
257 std::swap( elevation1, elevation2 );
261 const double snapDistance = std::fabs( lineString->pointN( 0 ).x() - point.
distance() );
262 visitor( feature.featureId, snapDistance, lineString->pointN( 0 ).x(), point.
elevation() );
269 const QgsRectangle partBounds = ( *partIt )->boundingBox();
276 QgsGeos cutLineGeos( cutLine.constGet() );
278 const QgsGeometry points( cutLineGeos.intersection( line ) );
280 for (
auto vertexIt = points.vertices_begin(); vertexIt != points.vertices_end(); ++vertexIt )
282 const double snapHeightDelta = std::fabs( point.
elevation() - ( *vertexIt ).y() );
283 if ( snapHeightDelta > maximumSurfaceElevationDelta )
286 const double snapDistance = ( *vertexIt ).distance( targetPoint );
287 visitor( feature.featureId, snapDistance, ( *vertexIt ).x(), ( *vertexIt ).y() );
304 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
308 const QgsRectangle partBounds = ( *partIt )->boundingBox();
315 QgsGeos cutLineGeos( cutLine.constGet() );
317 const QgsGeometry points( cutLineGeos.intersection( exterior ) );
318 for (
auto vertexIt = points.vertices_begin(); vertexIt != points.vertices_end(); ++vertexIt )
320 const double snapHeightDelta = std::fabs( point.
elevation() - ( *vertexIt ).y() );
321 if ( snapHeightDelta > maximumSurfaceElevationDelta )
324 const double snapDistance = ( *vertexIt ).distance( targetPoint );
325 visitor( feature.featureId, snapDistance, ( *vertexIt ).x(), ( *vertexIt ).y() );
343 const QgsRectangle profileRange( distanceRange.
lower(), elevationRange.
lower(), distanceRange.
upper(), elevationRange.
upper() );
345 QgsGeos profileRangeGeos( profileRangeGeometry.
constGet() );
346 profileRangeGeos.prepareGeometry();
350 for (
const Feature &feature : it.value() )
352 if ( feature.crossSectionGeometry.boundingBoxIntersects( profileRange ) )
354 switch ( feature.crossSectionGeometry.type() )
358 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
362 if ( profileRange.contains( candidatePoint->x(), candidatePoint->y() ) )
364 visitor( feature.featureId );
374 if ( profileRangeGeos.intersects( feature.crossSectionGeometry.constGet() ) )
376 visitor( feature.featureId );
396 renderResultsAsIndividualFeatures( context );
401 renderMarkersOverContinuousSurfacePlot( context );
414 painter->setBrush( Qt::NoBrush );
415 painter->setPen( Qt::NoPen );
422 const QRectF visibleRegion( minDistance,
minZ, maxDistance - minDistance,
maxZ -
minZ );
423 QPainterPath clipPath;
424 clipPath.addPolygon( context.
worldTransform().map( visibleRegion ) );
425 painter->setClipPath( clipPath, Qt::ClipOperation::IntersectClip );
427 const QgsRectangle clipPathRect( clipPath.boundingRect() );
430 if ( profileFeature.crossSectionGeometry.isEmpty() )
433 QgsGeometry transformed = profileFeature.crossSectionGeometry;
440 switch ( transformed.
type() )
446 markerSymbol->renderPoint( QPointF( point->x(), point->y() ),
nullptr, context.
renderContext() );
450 const int numGeometries = multipoint->numGeometries();
451 for (
int i = 0; i < numGeometries; ++i )
453 markerSymbol->renderPoint( QPointF( multipoint->pointN( i )->x(), multipoint->pointN( i )->y() ),
nullptr, context.
renderContext() );
463 lineSymbol->renderPolyline( line->asQPolygonF(),
nullptr, context.
renderContext() );
467 const int numGeometries = multiLinestring->numGeometries();
468 for (
int i = 0; i < numGeometries; ++i )
470 lineSymbol->renderPolyline( multiLinestring->lineStringN( i )->asQPolygonF(),
nullptr, context.
renderContext() );
480 if (
const QgsCurve *exterior = polygon->exteriorRing() )
481 fillSymbol->renderPolygon( exterior->asQPolygonF(),
nullptr,
nullptr, context.
renderContext() );
485 const int numGeometries = multiPolygon->numGeometries();
486 for (
int i = 0; i < numGeometries; ++i )
488 fillSymbol->renderPolygon( multiPolygon->polygonN( i )->exteriorRing()->asQPolygonF(),
nullptr,
nullptr, context.
renderContext() );
500 QgsFeatureRequest req;
505 std::unique_ptr< QgsFeatureRenderer > renderer(
mLayer->renderer()->clone() );
510 QSet<QString> attributes = renderer->usedAttributes( context.
renderContext() );
512 std::unique_ptr< QgsMarkerSymbol > marker(
mMarkerSymbol->clone() );
513 std::unique_ptr< QgsLineSymbol > line(
mLineSymbol->clone() );
514 std::unique_ptr< QgsFillSymbol > fill(
mFillSymbol->clone() );
515 attributes.unite( marker->usedAttributes( context.
renderContext() ) );
516 attributes.unite( line->usedAttributes( context.
renderContext() ) );
517 attributes.unite( fill->usedAttributes( context.
renderContext() ) );
522 QgsFeatureIterator it =
mLayer->getFeatures( req );
526 QgsSymbol *rendererSymbol = renderer->symbolForFeature( feature, context.
renderContext() );
527 if ( !rendererSymbol )
530 marker->setColor( rendererSymbol->
color() );
531 marker->setOpacity( rendererSymbol->
opacity() );
532 line->setColor( rendererSymbol->
color() );
533 line->setOpacity( rendererSymbol->
opacity() );
534 fill->setColor( rendererSymbol->
color() );
535 fill->setOpacity( rendererSymbol->
opacity() );
541 const QVector< Feature > profileFeatures =
features.value( feature.
id() );
542 for (
const Feature &profileFeature : profileFeatures )
561 QSet<QString> attributes;
572 QgsFeatureIterator it =
mLayer->getFeatures( req );
576 const QVector< Feature > profileFeatures =
features.value( feature.
id() );
577 for (
const Feature &profileFeature : profileFeatures )
594 const QgsScopedQPainterState painterState( painter );
596 painter->setBrush( Qt::NoBrush );
597 painter->setPen( Qt::NoPen );
604 const QRectF visibleRegion( minDistance,
minZ, maxDistance - minDistance,
maxZ -
minZ );
605 QPainterPath clipPath;
606 clipPath.addPolygon( context.
worldTransform().map( visibleRegion ) );
607 painter->setClipPath( clipPath, Qt::ClipOperation::IntersectClip );
613 QHash< QgsFeatureId, QgsFeature > surfaceFeatures;
616 QgsFeatureRequest request;
620 QgsFeatureIterator featIt =
mLayer->getFeatures( request );
623 surfaceFeatures.insert( feature.
id(), feature );
629 if ( std::isnan( pointIt.value() ) )
642 QVector<QgsAbstractProfileResults::Feature> res;
649 for (
const Feature &feature : it.value() )
654 QgsAbstractProfileResults::Feature outFeature;
656 outFeature.
attributes = { { u
"id"_s, feature.featureId } };
664 outFeature.
geometry = feature.crossSectionGeometry;
681 mId = vlGenerator->mId;
684 mMarkerSymbol.reset( vlGenerator->mProfileMarkerSymbol->clone() );
696 , mProfileCurve( request.profileCurve() ? request.profileCurve()->clone() : nullptr )
697 , mTerrainProvider( request.terrainProvider() ? request.terrainProvider()->clone() : nullptr )
698 , mTolerance( request.tolerance() )
699 , mSourceCrs( layer->crs3D() )
700 , mTargetCrs( request.crs() )
701 , mTransformContext( request.transformContext() )
702 , mExtent( layer->extent() )
704 , mOffset( layer->elevationProperties()->zOffset() )
705 , mScale( layer->elevationProperties()->zScale() )
713 , mExpressionContext( request.expressionContext() )
714 , mFields( layer->fields() )
715 , mDataDefinedProperties( layer->elevationProperties()->dataDefinedProperties() )
716 , mWkbType( layer->wkbType() )
722 if ( mTerrainProvider )
723 mTerrainProvider->prepare();
727 mProfileCurve->dropZValue();
750 if ( !mProfileCurve || mFeedback->isCanceled() )
759 std::unique_ptr< QgsCurve > origCurve = std::move( mProfileCurve );
760 std::unique_ptr< QgsVectorLayerProfileResults > totalResults;
761 double distanceProcessed = 0;
763 QVector<QgsLineString *> disjointParts = profileLine->splitToDisjointXYParts();
764 for (
int i = 0; i < disjointParts.size(); i++ )
766 mProfileCurve.reset( disjointParts[i] );
767 if ( !generateProfileInner() )
769 mProfileCurve = std::move( origCurve );
772 for (
int j = i + 1; j < disjointParts.size(); j++ )
773 delete disjointParts[j];
780 totalResults = std::move( mResults );
784 totalResults->mRawPoints.append( mResults->mRawPoints );
785 totalResults->minZ = std::min( totalResults->minZ, mResults->minZ );
786 totalResults->maxZ = std::max( totalResults->maxZ, mResults->maxZ );
787 for (
auto it = mResults->mDistanceToHeightMap.constKeyValueBegin(); it != mResults->mDistanceToHeightMap.constKeyValueEnd(); ++it )
789 totalResults->mDistanceToHeightMap[it->first + distanceProcessed] = it->second;
791 for (
auto it = mResults->mDistanceToFeatureId.constKeyValueBegin(); it != mResults->mDistanceToFeatureId.constKeyValueEnd(); ++it )
793 totalResults->mDistanceToFeatureId[it->first + distanceProcessed] = it->second;
795 for (
auto it = mResults->features.constKeyValueBegin(); it != mResults->features.constKeyValueEnd(); ++it )
800 totalResults->features[it->first].push_back( feature );
805 distanceProcessed += mProfileCurve->length();
808 mProfileCurve = std::move( origCurve );
809 mResults = std::move( totalResults );
813 return generateProfileInner();
821 if ( mTerrainProvider )
822 mTargetToTerrainProviderTransform =
QgsCoordinateTransform( mTargetCrs, mTerrainProvider->crs(), mTransformContext );
828 catch ( QgsCsException & )
830 QgsDebugError( u
"Error transforming profile line to vector CRS"_s );
834 const QgsRectangle profileCurveBoundingBox = mTransformedCurve->boundingBox();
835 if ( !profileCurveBoundingBox.
intersects( mExtent ) )
838 if ( mFeedback->isCanceled() )
841 mResults = std::make_unique< QgsVectorLayerProfileResults >();
842 mResults->mLayer = mLayer;
843 mResults->copyPropertiesFromGenerator(
this );
845 mProfileCurveEngine = std::make_unique<QgsGeos>( mProfileCurve.get() );
846 mProfileCurveEngine->prepareGeometry();
848 if ( tolerance() == 0.0 )
850 mProfileBufferedCurve = std::unique_ptr<QgsAbstractGeometry>( mProfileCurve->clone() );
857 mProfileBufferedCurveEngine = std::make_unique<QgsGeos>( mProfileBufferedCurve.get() );
858 mProfileBufferedCurveEngine->prepareGeometry();
860 mDataDefinedProperties.prepare( mExpressionContext );
862 if ( mFeedback->isCanceled() )
868 if ( !generateProfileForPoints() )
873 if ( !generateProfileForLines() )
878 if ( !generateProfileForPolygons() )
892 return mResults.release();
897 return mFeedback.get();
900bool QgsVectorLayerProfileGenerator::generateProfileForPoints()
915 while ( !mFeedback->isCanceled() && it.
nextFeature( feature ) )
922 if ( mProfileBufferedCurveEngine->intersects( *it ) )
928 return !mFeedback->isCanceled();
931void QgsVectorLayerProfileGenerator::processIntersectionPoint(
const QgsPoint *point,
const QgsFeature &feature )
936 const double height = featureZToHeight( point->
x(), point->
y(), point->
z(), offset );
937 mResults->mRawPoints.append( QgsPoint( point->
x(), point->
y(), height ) );
938 mResults->minZ = std::min( mResults->minZ, height );
939 mResults->maxZ = std::max( mResults->maxZ, height );
941 const double distanceAlongProfileCurve = mProfileCurveEngine->lineLocatePoint( *point, &error );
942 mResults->mDistanceToHeightMap.insert( distanceAlongProfileCurve, height );
943 mResults->mDistanceToFeatureId.insert( distanceAlongProfileCurve, feature.
id() );
945 QgsVectorLayerProfileResults::Feature resultFeature;
947 if ( mExtrusionEnabled )
951 resultFeature.
geometry = QgsGeometry(
new QgsLineString( QgsPoint( point->
x(), point->
y(), height ), QgsPoint( point->
x(), point->
y(), height + extrusion ) ) );
952 resultFeature.
crossSectionGeometry = QgsGeometry(
new QgsLineString( QgsPoint( distanceAlongProfileCurve, height ), QgsPoint( distanceAlongProfileCurve, height + extrusion ) ) );
953 mResults->minZ = std::min( mResults->minZ, height + extrusion );
954 mResults->maxZ = std::max( mResults->maxZ, height + extrusion );
958 resultFeature.
geometry = QgsGeometry(
new QgsPoint( point->
x(), point->
y(), height ) );
959 resultFeature.
crossSectionGeometry = QgsGeometry(
new QgsPoint( distanceAlongProfileCurve, height ) );
962 mResults->features[resultFeature.
featureId].append( resultFeature );
965void QgsVectorLayerProfileGenerator::processIntersectionCurve(
const QgsLineString *intersectionCurve,
const QgsFeature &feature )
969 QgsVectorLayerProfileResults::Feature resultFeature;
971 double maxDistanceAlongProfileCurve = std::numeric_limits<double>::lowest();
976 const int numPoints = intersectionCurve->
numPoints();
977 QVector< double > newX( numPoints );
978 QVector< double > newY( numPoints );
979 QVector< double > newZ( numPoints );
980 QVector< double > newDistance( numPoints );
982 const double *inX = intersectionCurve->
xData();
983 const double *inY = intersectionCurve->
yData();
984 const double *inZ = intersectionCurve->
is3D() ? intersectionCurve->
zData() :
nullptr;
985 double *outX = newX.data();
986 double *outY = newY.data();
987 double *outZ = newZ.data();
988 double *outDistance = newDistance.data();
990 QVector< double > extrudedZ;
991 double *extZOut =
nullptr;
992 if ( mExtrusionEnabled )
994 extrudedZ.resize( numPoints );
995 extZOut = extrudedZ.data();
998 for (
int i = 0; !mFeedback->isCanceled() && i < numPoints; ++i )
1000 QgsPoint intersectionPoint( *inX, *inY, ( inZ ? *inZ : std::numeric_limits<double>::quiet_NaN() ) );
1002 const double height = featureZToHeight( intersectionPoint.x(), intersectionPoint.y(), intersectionPoint.z(), offset );
1003 const double distanceAlongProfileCurve = mProfileCurveEngine->lineLocatePoint( intersectionPoint, &error );
1005 maxDistanceAlongProfileCurve = std::max( maxDistanceAlongProfileCurve, distanceAlongProfileCurve );
1007 mResults->mRawPoints.append( QgsPoint( intersectionPoint.x(), intersectionPoint.y(), height ) );
1008 mResults->minZ = std::min( mResults->minZ, height );
1009 mResults->maxZ = std::max( mResults->maxZ, height );
1011 mResults->mDistanceToHeightMap.insert( distanceAlongProfileCurve, height );
1012 mResults->mDistanceToFeatureId.insert( distanceAlongProfileCurve, feature.
id() );
1013 *outDistance++ = distanceAlongProfileCurve;
1015 *outX++ = intersectionPoint.x();
1016 *outY++ = intersectionPoint.y();
1019 *extZOut++ = height + extrusion;
1021 if ( mExtrusionEnabled )
1023 mResults->minZ = std::min( mResults->minZ, height + extrusion );
1024 mResults->maxZ = std::max( mResults->maxZ, height + extrusion );
1032 mResults->mDistanceToHeightMap.insert( maxDistanceAlongProfileCurve + 0.000001, std::numeric_limits<double>::quiet_NaN() );
1034 if ( mFeedback->isCanceled() )
1038 if ( mExtrusionEnabled )
1040 auto ring = std::make_unique< QgsLineString >( newX, newY, newZ );
1041 auto extrudedRing = std::make_unique< QgsLineString >( newX, newY, extrudedZ );
1042 std::unique_ptr< QgsLineString > reversedExtrusion( extrudedRing->reversed() );
1043 ring->append( reversedExtrusion.get() );
1045 resultFeature.
geometry = QgsGeometry(
new QgsPolygon( ring.release() ) );
1047 auto distanceVHeightRing = std::make_unique< QgsLineString >( newDistance, newZ );
1048 auto extrudedDistanceVHeightRing = std::make_unique< QgsLineString >( newDistance, extrudedZ );
1049 std::unique_ptr< QgsLineString > reversedDistanceVHeightExtrusion( extrudedDistanceVHeightRing->reversed() );
1050 distanceVHeightRing->append( reversedDistanceVHeightExtrusion.get() );
1051 distanceVHeightRing->close();
1052 resultFeature.
crossSectionGeometry = QgsGeometry(
new QgsPolygon( distanceVHeightRing.release() ) );
1056 resultFeature.
geometry = QgsGeometry(
new QgsLineString( newX, newY, newZ ) );
1060 mResults->features[resultFeature.
featureId].append( resultFeature );
1063bool QgsVectorLayerProfileGenerator::generateProfileForLines()
1066 QgsFeatureRequest request;
1068 if ( tolerance() > 0 )
1070 request.
setDistanceWithin( QgsGeometry( mProfileCurve->clone() ), tolerance() );
1076 request.
setSubsetOfAttributes( mDataDefinedProperties.referencedFields( mExpressionContext ), mFields );
1079 auto processCurve = [
this](
const QgsFeature &feature,
const QgsCurve *featGeomPart ) {
1081 std::unique_ptr< QgsAbstractGeometry > intersection( mProfileBufferedCurveEngine->intersection( featGeomPart, &error ) );
1082 if ( !intersection )
1085 if ( mFeedback->isCanceled() )
1090 if ( intersection->isEmpty() )
1092 intersection.reset( featGeomPart->clone() );
1093 for (
auto it = intersection->const_parts_begin(); !mFeedback->isCanceled() && it != intersection->const_parts_end(); ++it )
1096 processIntersectionCurve( intersectionCurve, feature );
1101 QgsGeos featGeomPartGeos( featGeomPart );
1102 featGeomPartGeos.prepareGeometry();
1104 for (
auto it = intersection->const_parts_begin(); !mFeedback->isCanceled() && it != intersection->const_parts_end(); ++it )
1110 const double distance = featGeomPartGeos.lineLocatePoint( *intersectionPoint, &error );
1111 std::unique_ptr< QgsPoint > interpolatedPoint( featGeomPart->interpolatePoint( distance ) );
1113 processIntersectionPoint( interpolatedPoint.get(), feature );
1119 auto lineInterpolated = std::make_unique<QgsLineString>();
1120 for (
int i = 0; i < intersectionCurve->
numPoints(); ++i )
1122 const QgsPoint pt = intersectionCurve->
pointN( i );
1125 const double distance = featGeomPartGeos.lineLocatePoint( pt, &err );
1127 std::unique_ptr<QgsPoint> pointWithInterpolatedZM( featGeomPart->interpolatePoint( distance ) );
1128 lineInterpolated->addVertex( *pointWithInterpolatedZM );
1131 processIntersectionCurve( lineInterpolated.get(), feature );
1137 QgsFeatureIterator it = mSource->getFeatures( request );
1138 while ( !mFeedback->isCanceled() && it.
nextFeature( feature ) )
1140 mExpressionContext.setFeature( feature );
1142 const QgsGeometry g = feature.
geometry();
1145 if ( mProfileBufferedCurveEngine->intersects( *it ) )
1152 return !mFeedback->isCanceled();
1155QgsPoint QgsVectorLayerProfileGenerator::interpolatePointOnTriangle(
const QgsPolygon *triangle,
double x,
double y )
const
1157 QgsPoint p1, p2, p3;
1162 const double z = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, p1.
z(), p2.
z(), p3.
z(), QgsPointXY( x, y ) );
1163 return QgsPoint( x, y, z );
1166void QgsVectorLayerProfileGenerator::processTriangleIntersectForPoint(
1167 const QgsPolygon *triangle,
const QgsPoint *p, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts,
const QgsFeatureId featureId
1170 const QgsPoint interpolatedPoint = interpolatePointOnTriangle( triangle, p->
x(), p->
y() );
1171 mResults->mRawPoints.append( interpolatedPoint );
1172 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() );
1173 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() );
1176 const double distance = mProfileCurveEngine->lineLocatePoint( *p, &lastError );
1177 mResults->mDistanceToHeightMap.insert( distance, interpolatedPoint.
z() );
1178 mResults->mDistanceToFeatureId.insert( distance, featureId );
1180 if ( mExtrusionEnabled )
1184 transformedParts.append( QgsGeometry(
new QgsLineString( interpolatedPoint, QgsPoint( interpolatedPoint.
x(), interpolatedPoint.
y(), interpolatedPoint.
z() + extrusion ) ) ) );
1185 crossSectionParts.append( QgsGeometry(
new QgsLineString( QgsPoint( distance, interpolatedPoint.
z() ), QgsPoint( distance, interpolatedPoint.
z() + extrusion ) ) ) );
1186 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() + extrusion );
1187 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() + extrusion );
1191 transformedParts.append( QgsGeometry(
new QgsPoint( interpolatedPoint ) ) );
1192 crossSectionParts.append( QgsGeometry(
new QgsPoint( distance, interpolatedPoint.
z() ) ) );
1196void QgsVectorLayerProfileGenerator::processTriangleIntersectForLine(
1197 const QgsPolygon *triangle,
const QgsLineString *intersectionLine, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts,
const QgsFeatureId featureId
1203 int numPoints = intersectionLine->
numPoints();
1204 QVector< double > newX( numPoints );
1205 QVector< double > newY( numPoints );
1206 QVector< double > newZ( numPoints );
1207 QVector< double > newDistance( numPoints );
1209 const double *inX = intersectionLine->
xData();
1210 const double *inY = intersectionLine->
yData();
1211 const double *inZ = intersectionLine->
is3D() ? intersectionLine->
zData() :
nullptr;
1212 double *outX = newX.data();
1213 double *outY = newY.data();
1214 double *outZ = newZ.data();
1215 double *outDistance = newDistance.data();
1217 double lastDistanceAlongProfileCurve = 0.0;
1218 QVector< double > extrudedZ;
1219 double *extZOut =
nullptr;
1220 double extrusion = 0;
1222 if ( mExtrusionEnabled )
1224 extrudedZ.resize( numPoints );
1225 extZOut = extrudedZ.data();
1231 for (
int i = 0; !mFeedback->isCanceled() && i < numPoints; ++i )
1235 double z = inZ ? *inZ++ : 0;
1237 QgsPoint interpolatedPoint( x, y, z );
1243 interpolatedPoint = interpolatePointOnTriangle( triangle, x, y );
1245 double tempOutZ = std::isnan( interpolatedPoint.
z() ) ? 0.0 : interpolatedPoint.
z();
1248 if ( mExtrusionEnabled )
1249 *extZOut++ = tempOutZ + extrusion;
1251 mResults->mRawPoints.append( interpolatedPoint );
1252 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() );
1253 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() );
1254 if ( mExtrusionEnabled )
1256 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() + extrusion );
1257 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() + extrusion );
1260 const double distance = mProfileCurveEngine->lineLocatePoint( interpolatedPoint, &lastError );
1261 *outDistance++ = distance;
1263 mResults->mDistanceToHeightMap.insert( distance, interpolatedPoint.
z() );
1264 mResults->mDistanceToFeatureId.insert( distance, featureId );
1265 lastDistanceAlongProfileCurve = distance;
1269 mResults->mDistanceToHeightMap.insert( lastDistanceAlongProfileCurve + 0.000001, std::numeric_limits<double>::quiet_NaN() );
1271 if ( mFeedback->isCanceled() )
1274 if ( mExtrusionEnabled )
1276 auto ring = std::make_unique< QgsLineString >( newX, newY, newZ );
1277 auto extrudedRing = std::make_unique< QgsLineString >( newX, newY, extrudedZ );
1278 std::unique_ptr< QgsLineString > reversedExtrusion( extrudedRing->reversed() );
1279 ring->append( reversedExtrusion.get() );
1281 transformedParts.append( QgsGeometry(
new QgsPolygon( ring.release() ) ) );
1283 auto distanceVHeightRing = std::make_unique< QgsLineString >( newDistance, newZ );
1284 auto extrudedDistanceVHeightRing = std::make_unique< QgsLineString >( newDistance, extrudedZ );
1285 std::unique_ptr< QgsLineString > reversedDistanceVHeightExtrusion( extrudedDistanceVHeightRing->reversed() );
1286 distanceVHeightRing->append( reversedDistanceVHeightExtrusion.get() );
1287 distanceVHeightRing->close();
1288 crossSectionParts.append( QgsGeometry(
new QgsPolygon( distanceVHeightRing.release() ) ) );
1292 transformedParts.append( QgsGeometry(
new QgsLineString( newX, newY, newZ ) ) );
1293 crossSectionParts.append( QgsGeometry(
new QgsLineString( newDistance, newZ ) ) );
1297void QgsVectorLayerProfileGenerator::processTriangleIntersectForPolygon(
1298 const QgsPolygon *sourcePolygon,
const QgsPolygon *intersectionPolygon, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts,
const QgsFeatureId featureId
1301 bool oldExtrusion = mExtrusionEnabled;
1334 mExtrusionEnabled =
false;
1335 if ( mProfileBufferedCurveEngine->contains( sourcePolygon ) )
1337 if (
const QgsCurve *exterior = sourcePolygon->
exteriorRing() )
1340 processTriangleIntersectForLine( sourcePolygon, exteriorLine, transformedParts, crossSectionParts, featureId );
1345 processTriangleIntersectForLine( sourcePolygon, interiorLine, transformedParts, crossSectionParts, featureId );
1351 if (
const QgsCurve *exterior = intersectionPolygon->
exteriorRing() )
1355 processTriangleIntersectForLine( sourcePolygon, exteriorLine, transformedParts, crossSectionParts, featureId );
1356 delete exteriorLine;
1361 if ( mProfileBufferedCurveEngine->contains( interiorLine ) )
1363 processTriangleIntersectForLine( sourcePolygon, interiorLine, transformedParts, crossSectionParts, featureId );
1368 newInteriorLine->deleteVertex( QgsVertexId( 0, 0, interiorLine->
numPoints() - 1 ) );
1369 processTriangleIntersectForLine( sourcePolygon, newInteriorLine.get(), transformedParts, crossSectionParts, featureId );
1374 mExtrusionEnabled = oldExtrusion;
1377bool QgsVectorLayerProfileGenerator::generateProfileForPolygons()
1380 QgsFeatureRequest request;
1382 if ( tolerance() > 0 )
1384 request.
setDistanceWithin( QgsGeometry( mProfileCurve->clone() ), tolerance() );
1390 request.
setSubsetOfAttributes( mDataDefinedProperties.referencedFields( mExpressionContext ), mFields );
1393 std::function< void(
const QgsPolygon *triangle,
const QgsAbstractGeometry *intersect, QVector< QgsGeometry > &, QVector< QgsGeometry > &,
const QgsFeatureId ) > processTriangleLineIntersect;
1394 processTriangleLineIntersect =
1395 [
this](
const QgsPolygon *triangle,
const QgsAbstractGeometry *intersection, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts,
const QgsFeatureId featureId ) {
1396 for (
auto it = intersection->const_parts_begin(); !mFeedback->isCanceled() && it != intersection->const_parts_end(); ++it )
1404 processTriangleIntersectForPoint( triangle, p, transformedParts, crossSectionParts, featureId );
1411 processTriangleIntersectForLine( triangle, intersectionLine, transformedParts, crossSectionParts, featureId );
1418 processTriangleIntersectForPolygon( triangle, poly, transformedParts, crossSectionParts, featureId );
1429 auto triangleIsCollinearInXYPlane = [](
const QgsPolygon *polygon ) ->
bool {
1434 auto processPolygon =
1436 &processTriangleLineIntersect,
1437 &triangleIsCollinearInXYPlane](
const QgsCurvePolygon *polygon, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts,
double offset,
bool &wasCollinear,
const QgsFeatureId featureId ) {
1438 std::unique_ptr< QgsPolygon > clampedPolygon;
1441 clampedPolygon.reset( p->
clone() );
1447 clampAltitudes( clampedPolygon.get(), offset );
1449 if ( mFeedback->isCanceled() )
1452 if ( tolerance() > 0.0 )
1455 if ( mProfileBufferedCurveEngine->intersects( clampedPolygon.get(), &error ) )
1457 std::unique_ptr< QgsAbstractGeometry > intersection;
1458 intersection.reset( mProfileBufferedCurveEngine->intersection( clampedPolygon.get(), &error ) );
1459 if ( error.isEmpty() )
1461 processTriangleLineIntersect( clampedPolygon.get(), intersection.get(), transformedParts, crossSectionParts, featureId );
1470 QVector< double > newX( numPoints );
1471 QVector< double > newY( numPoints );
1472 QVector< double > newZ( numPoints );
1473 double *outX = newX.data();
1474 double *outY = newY.data();
1475 double *outZ = newZ.data();
1477 const double *inX = ring->
xData();
1478 const double *inY = ring->
yData();
1479 const double *inZ = ring->
zData();
1480 for (
int i = 0; !mFeedback->isCanceled() && i < ring->numPoints() - 1; ++i )
1482 *outX++ = inX[i] + i * 1.0e-9;
1483 *outY++ = inY[i] + i * 1.0e-9;
1486 std::unique_ptr< QgsPolygon > shiftedPoly;
1487 shiftedPoly = std::make_unique<QgsPolygon>(
new QgsLineString( newX, newY, newZ ) );
1489 intersection.reset( mProfileBufferedCurveEngine->intersection( shiftedPoly.get(), &error ) );
1491 processTriangleLineIntersect( clampedPolygon.get(), intersection.get(), transformedParts, crossSectionParts, featureId );
1495 QgsDebugMsgLevel( u
"processPolygon after shift bad geom! error: %1"_s.arg( error ), 0 );
1503 QgsGeometry tessellation;
1504 if ( clampedPolygon->numInteriorRings() == 0 && clampedPolygon->exteriorRing() && clampedPolygon->exteriorRing()->numPoints() == 4 && clampedPolygon->exteriorRing()->isClosed() )
1507 auto multiPolygon = std::make_unique< QgsMultiPolygon >();
1508 multiPolygon->addGeometry( clampedPolygon.release() );
1509 tessellation = QgsGeometry( std::move( multiPolygon ) );
1513 const QgsRectangle bounds = clampedPolygon->boundingBox();
1519 if ( mFeedback->isCanceled() )
1527 for (
int i = 0; !mFeedback->isCanceled() && i < numTriangles; ++i )
1531 if ( triangleIsCollinearInXYPlane( triangle ) )
1533 wasCollinear =
true;
1539 for (
int curveSegmentIndex = 0; curveSegmentIndex < mProfileCurve->numPoints() - 1; ++curveSegmentIndex )
1541 const QgsPoint p1 = ls->pointN( curveSegmentIndex );
1542 const QgsPoint p2 = ls->pointN( curveSegmentIndex + 1 );
1544 QgsPoint intersectionPoint;
1545 bool intersectionFound =
false;
1546 double minZ = std::numeric_limits< double >::max();
1547 double maxZ = std::numeric_limits< double >::lowest();
1549 for (
auto vertexPair : std::array<std::pair<int, int>, 3> { { { 0, 1 }, { 1, 2 }, { 2, 0 } } } )
1551 bool isIntersection =
false;
1552 QgsPoint edgeIntersectionPoint;
1555 if ( !edgeIntersectionPoint.
isEmpty() && !intersectionFound )
1557 intersectionPoint = edgeIntersectionPoint;
1558 intersectionFound =
true;
1563 ring->
xAt( vertexPair.first ), ring->
yAt( vertexPair.first ), ring->
xAt( vertexPair.second ), ring->
yAt( vertexPair.second ), edgeIntersectionPoint.
x(), edgeIntersectionPoint.
y()
1565 double intersectionZ = ring->
zAt( vertexPair.first ) + ( ring->
zAt( vertexPair.second ) - ring->
zAt( vertexPair.first ) ) * fraction;
1566 minZ = std::min( minZ, intersectionZ );
1567 maxZ = std::max( maxZ, intersectionZ );
1571 if ( intersectionFound )
1574 mResults->mRawPoints.append( intersectionPoint );
1575 mResults->minZ = std::min( mResults->minZ, minZ );
1576 mResults->maxZ = std::max( mResults->maxZ, maxZ );
1578 const double distance = mProfileCurveEngine->lineLocatePoint( intersectionPoint, &lastError );
1580 crossSectionParts.append( QgsGeometry(
new QgsLineString( QVector< double > { distance, distance }, QVector< double > { minZ, maxZ } ) ) );
1582 mResults->mDistanceToHeightMap.insert( distance, minZ );
1583 mResults->mDistanceToHeightMap.insert( distance, maxZ );
1584 mResults->mDistanceToFeatureId.insert( distance, featureId );
1591 QgsDebugError( u
"Collinear triangles with curved profile lines are not supported yet"_s );
1597 if ( mProfileBufferedCurveEngine->intersects( triangle, &error ) )
1599 std::unique_ptr< QgsAbstractGeometry > intersection( mProfileBufferedCurveEngine->intersection( triangle, &error ) );
1600 processTriangleLineIntersect( triangle, intersection.get(), transformedParts, crossSectionParts, featureId );
1609 QgsFeatureIterator it = mSource->getFeatures( request );
1610 while ( !mFeedback->isCanceled() && it.
nextFeature( feature ) )
1612 if ( !mProfileBufferedCurveEngine->intersects( feature.
geometry().
constGet() ) )
1615 mExpressionContext.setFeature( feature );
1618 const QgsGeometry g = feature.
geometry();
1619 QVector< QgsGeometry > transformedParts;
1620 QVector< QgsGeometry > crossSectionParts;
1621 bool wasCollinear =
false;
1626 if ( mProfileBufferedCurveEngine->intersects( *it ) )
1630 processPolygon( curvePolygon, transformedParts, crossSectionParts, offset, wasCollinear, feature.
id() );
1634 for (
int i = 0; i < polySurface->numPatches(); ++i )
1636 const QgsPolygon *polygon = polySurface->patchN( i );
1637 if ( mProfileBufferedCurveEngine->intersects( polygon ) )
1639 processPolygon( polygon, transformedParts, crossSectionParts, offset, wasCollinear, feature.
id() );
1645 QgsDebugError( u
"Unhandled Geometry type: %1"_s.arg( ( *it )->wktTypeStr() ) );
1650 if ( mFeedback->isCanceled() )
1654 QgsVectorLayerProfileResults::Feature resultFeature;
1657 if ( !crossSectionParts.empty() )
1659 if ( !wasCollinear )
1661 QgsGeometry unioned = QgsGeometry::unaryUnion( crossSectionParts );
1662 if ( unioned.isEmpty() )
1664 resultFeature.crossSectionGeometry = QgsGeometry::collectGeometry( crossSectionParts );
1668 if ( unioned.type() == Qgis::GeometryType::Line )
1670 unioned = unioned.mergeLines();
1672 resultFeature.crossSectionGeometry = unioned;
1677 resultFeature.crossSectionGeometry = QgsGeometry::collectGeometry( crossSectionParts );
1680 mResults->features[resultFeature.
featureId].append( resultFeature );
1685double QgsVectorLayerProfileGenerator::tolerance()
const
1687 return mCustomToleranceEnabled ? mCustomTolerance : mTolerance;
1690double QgsVectorLayerProfileGenerator::terrainHeight(
double x,
double y )
const
1692 if ( !mTerrainProvider )
1693 return std::numeric_limits<double>::quiet_NaN();
1699 mTargetToTerrainProviderTransform.transformInPlace( x, y, dummyZ );
1701 catch ( QgsCsException & )
1703 return std::numeric_limits<double>::quiet_NaN();
1706 return mTerrainProvider->heightAt( x, y );
1709double QgsVectorLayerProfileGenerator::featureZToHeight(
double x,
double y,
double z,
double offset )
const
1711 switch ( mClamping )
1719 const double terrainZ = terrainHeight( x, y );
1720 if ( !std::isnan( terrainZ ) )
1722 switch ( mClamping )
1725 if ( std::isnan( z ) )
1743 return ( std::isnan( z ) ? 0 : z ) * mScale + offset;
1746void QgsVectorLayerProfileGenerator::clampAltitudes(
QgsLineString *lineString,
const QgsPoint ¢roid,
double offset )
const
1750 if ( mFeedback->isCanceled() )
1753 double terrainZ = 0;
1754 switch ( mClamping )
1763 pt.
setX( lineString->
xAt( i ) );
1764 pt.
setY( lineString->
yAt( i ) );
1768 pt.
set( centroid.
x(), centroid.
y() );
1772 terrainZ = terrainHeight( pt.
x(), pt.
y() );
1782 switch ( mClamping )
1786 geomZ = lineString->
zAt( i );
1793 const double z = ( terrainZ + ( std::isnan( geomZ ) ? 0 : geomZ ) ) * mScale + offset;
1794 lineString->
setZAt( i, z );
1798bool QgsVectorLayerProfileGenerator::clampAltitudes(
QgsPolygon *polygon,
double offset )
const
1800 if ( !polygon->
is3D() )
1814 QgsCurve *curve =
const_cast<QgsCurve *
>( polygon->
exteriorRing() );
1819 clampAltitudes( lineString, centroid, offset );
1823 if ( mFeedback->isCanceled() )
1826 QgsCurve *curve =
const_cast<QgsCurve *
>( polygon->
interiorRing( i ) );
1831 clampAltitudes( lineString, centroid, offset );
@ 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).
@ 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.