47using namespace Qt::StringLiterals;
60 QVector<QgsGeometry> res;
64 for (
const Feature &feature : it.value() )
66 res.append( feature.geometry );
78 return asIndividualFeatures(
type, feedback );
93 return snapPointToIndividualFeatures( point, context );
104 auto visitFeature = [&ids](
QgsFeatureId featureId ) { ids << featureId; };
106 visitFeaturesInRange( distanceRange, elevationRange, visitFeature );
110 QVector< QVariantMap> idsList;
111 for (
auto it = ids.constBegin(); it != ids.constEnd(); ++it )
112 idsList.append( QVariantMap( { { u
"id"_s, *it } } ) );
119 QHash< QgsFeatureId, QVariantMap >
features;
120 auto visitFeature = [&
features](
QgsFeatureId featureId,
double delta,
double distance,
double elevation ) {
121 auto it =
features.find( featureId );
124 features[featureId] = QVariantMap( { { u
"id"_s, featureId }, { u
"delta"_s, delta }, { u
"distance"_s, distance }, { u
"elevation"_s, elevation } } );
128 const double currentDelta = it.value().value( u
"delta"_s ).toDouble();
129 if ( delta < currentDelta )
131 *it = QVariantMap( { { u
"id"_s, featureId }, { u
"delta"_s, delta }, { u
"distance"_s, distance }, { u
"elevation"_s, elevation } } );
138 QVector< QVariantMap> attributes;
140 attributes.append( *it );
142 QVector<QgsProfileIdentifyResults> res;
144 if ( !attributes.empty() )
150 res.reserve( surfaceResults.size() );
163 double bestSnapDistance = std::numeric_limits< double >::max();
165 auto visitFeature = [&bestSnapDistance, &res](
QgsFeatureId,
double delta,
double distance,
double elevation ) {
166 if ( distance < bestSnapDistance )
168 bestSnapDistance = delta;
178void QgsVectorLayerProfileResults::visitFeaturesAtPoint(
180 double maximumPointDistanceDelta,
181 double maximumPointElevationDelta,
182 double maximumSurfaceElevationDelta,
183 const std::function<
void(
QgsFeatureId,
double delta,
double distance,
double elevation ) > &visitor,
193 for (
const Feature &feature : it.value() )
195 const QgsRectangle featureBounds = feature.crossSectionGeometry.boundingBox();
196 if ( ( featureBounds.
xMinimum() - maximumPointDistanceDelta <= point.
distance() ) && ( featureBounds.
xMaximum() + maximumPointDistanceDelta >= point.
distance() ) )
198 switch ( feature.crossSectionGeometry.type() )
202 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
206 const double snapDistanceDelta = std::fabs( point.
distance() - candidatePoint->x() );
207 if ( snapDistanceDelta > maximumPointDistanceDelta )
210 const double snapHeightDelta = std::fabs( point.
elevation() - candidatePoint->y() );
211 if ( snapHeightDelta > maximumPointElevationDelta )
214 const double snapDistance = candidatePoint->distance( targetPoint );
215 visitor( feature.featureId, snapDistance, candidatePoint->x(), candidatePoint->y() );
223 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
230 if ( lineString->numPoints() == 2 &&
qgsDoubleNear( lineString->pointN( 0 ).x(), lineString->pointN( 1 ).x() ) )
232 const double snapDistanceDelta = std::fabs( point.
distance() - lineString->pointN( 0 ).x() );
233 if ( snapDistanceDelta > maximumPointDistanceDelta )
236 const double snapHeightDelta = std::fabs( point.
elevation() - lineString->pointN( 0 ).y() );
237 if ( snapHeightDelta <= maximumPointElevationDelta )
239 const double snapDistanceP1 = lineString->pointN( 0 ).distance( targetPoint );
240 visitor( feature.featureId, snapDistanceP1, lineString->pointN( 0 ).x(), lineString->pointN( 0 ).y() );
243 const double snapHeightDelta2 = std::fabs( point.
elevation() - lineString->pointN( 1 ).y() );
244 if ( snapHeightDelta2 <= maximumPointElevationDelta )
246 const double snapDistanceP2 = lineString->pointN( 1 ).distance( targetPoint );
247 visitor( feature.featureId, snapDistanceP2, lineString->pointN( 1 ).x(), lineString->pointN( 1 ).y() );
252 double elevation1 = lineString->pointN( 0 ).y();
253 double elevation2 = lineString->pointN( 1 ).y();
254 if ( elevation1 > elevation2 )
255 std::swap( elevation1, elevation2 );
259 const double snapDistance = std::fabs( lineString->pointN( 0 ).x() - point.
distance() );
260 visitor( feature.featureId, snapDistance, lineString->pointN( 0 ).x(), point.
elevation() );
267 const QgsRectangle partBounds = ( *partIt )->boundingBox();
274 QgsGeos cutLineGeos( cutLine.constGet() );
276 const QgsGeometry points( cutLineGeos.intersection( line ) );
278 for (
auto vertexIt = points.vertices_begin(); vertexIt != points.vertices_end(); ++vertexIt )
280 const double snapHeightDelta = std::fabs( point.
elevation() - ( *vertexIt ).y() );
281 if ( snapHeightDelta > maximumSurfaceElevationDelta )
284 const double snapDistance = ( *vertexIt ).distance( targetPoint );
285 visitor( feature.featureId, snapDistance, ( *vertexIt ).x(), ( *vertexIt ).y() );
302 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
306 const QgsRectangle partBounds = ( *partIt )->boundingBox();
313 QgsGeos cutLineGeos( cutLine.constGet() );
315 const QgsGeometry points( cutLineGeos.intersection( exterior ) );
316 for (
auto vertexIt = points.vertices_begin(); vertexIt != points.vertices_end(); ++vertexIt )
318 const double snapHeightDelta = std::fabs( point.
elevation() - ( *vertexIt ).y() );
319 if ( snapHeightDelta > maximumSurfaceElevationDelta )
322 const double snapDistance = ( *vertexIt ).distance( targetPoint );
323 visitor( feature.featureId, snapDistance, ( *vertexIt ).x(), ( *vertexIt ).y() );
341 const QgsRectangle profileRange( distanceRange.
lower(), elevationRange.
lower(), distanceRange.
upper(), elevationRange.
upper() );
343 QgsGeos profileRangeGeos( profileRangeGeometry.
constGet() );
344 profileRangeGeos.prepareGeometry();
348 for (
const Feature &feature : it.value() )
350 if ( feature.crossSectionGeometry.boundingBoxIntersects( profileRange ) )
352 switch ( feature.crossSectionGeometry.type() )
356 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
360 if ( profileRange.contains( candidatePoint->x(), candidatePoint->y() ) )
362 visitor( feature.featureId );
372 if ( profileRangeGeos.intersects( feature.crossSectionGeometry.constGet() ) )
374 visitor( feature.featureId );
394 renderResultsAsIndividualFeatures( context );
399 renderMarkersOverContinuousSurfacePlot( context );
412 painter->setBrush( Qt::NoBrush );
413 painter->setPen( Qt::NoPen );
420 const QRectF visibleRegion( minDistance,
minZ, maxDistance - minDistance,
maxZ -
minZ );
421 QPainterPath clipPath;
422 clipPath.addPolygon( context.
worldTransform().map( visibleRegion ) );
423 painter->setClipPath( clipPath, Qt::ClipOperation::IntersectClip );
425 const QgsRectangle clipPathRect( clipPath.boundingRect() );
428 if ( profileFeature.crossSectionGeometry.isEmpty() )
431 QgsGeometry transformed = profileFeature.crossSectionGeometry;
438 switch ( transformed.
type() )
444 markerSymbol->renderPoint( QPointF( point->x(), point->y() ),
nullptr, context.
renderContext() );
448 const int numGeometries = multipoint->numGeometries();
449 for (
int i = 0; i < numGeometries; ++i )
451 markerSymbol->renderPoint( QPointF( multipoint->pointN( i )->x(), multipoint->pointN( i )->y() ),
nullptr, context.
renderContext() );
461 lineSymbol->renderPolyline( line->asQPolygonF(),
nullptr, context.
renderContext() );
465 const int numGeometries = multiLinestring->numGeometries();
466 for (
int i = 0; i < numGeometries; ++i )
468 lineSymbol->renderPolyline( multiLinestring->lineStringN( i )->asQPolygonF(),
nullptr, context.
renderContext() );
478 if (
const QgsCurve *exterior = polygon->exteriorRing() )
479 fillSymbol->renderPolygon( exterior->asQPolygonF(),
nullptr,
nullptr, context.
renderContext() );
483 const int numGeometries = multiPolygon->numGeometries();
484 for (
int i = 0; i < numGeometries; ++i )
486 fillSymbol->renderPolygon( multiPolygon->polygonN( i )->exteriorRing()->asQPolygonF(),
nullptr,
nullptr, context.
renderContext() );
498 QgsFeatureRequest req;
503 std::unique_ptr< QgsFeatureRenderer > renderer(
mLayer->renderer()->clone() );
508 QSet<QString> attributes = renderer->usedAttributes( context.
renderContext() );
510 std::unique_ptr< QgsMarkerSymbol > marker(
mMarkerSymbol->clone() );
511 std::unique_ptr< QgsLineSymbol > line(
mLineSymbol->clone() );
512 std::unique_ptr< QgsFillSymbol > fill(
mFillSymbol->clone() );
513 attributes.unite( marker->usedAttributes( context.
renderContext() ) );
514 attributes.unite( line->usedAttributes( context.
renderContext() ) );
515 attributes.unite( fill->usedAttributes( context.
renderContext() ) );
520 QgsFeatureIterator it =
mLayer->getFeatures( req );
524 QgsSymbol *rendererSymbol = renderer->symbolForFeature( feature, context.
renderContext() );
525 if ( !rendererSymbol )
528 marker->setColor( rendererSymbol->
color() );
529 marker->setOpacity( rendererSymbol->
opacity() );
530 line->setColor( rendererSymbol->
color() );
531 line->setOpacity( rendererSymbol->
opacity() );
532 fill->setColor( rendererSymbol->
color() );
533 fill->setOpacity( rendererSymbol->
opacity() );
539 const QVector< Feature > profileFeatures =
features.value( feature.
id() );
540 for (
const Feature &profileFeature : profileFeatures )
559 QSet<QString> attributes;
570 QgsFeatureIterator it =
mLayer->getFeatures( req );
574 const QVector< Feature > profileFeatures =
features.value( feature.
id() );
575 for (
const Feature &profileFeature : profileFeatures )
592 const QgsScopedQPainterState painterState( painter );
594 painter->setBrush( Qt::NoBrush );
595 painter->setPen( Qt::NoPen );
602 const QRectF visibleRegion( minDistance,
minZ, maxDistance - minDistance,
maxZ -
minZ );
603 QPainterPath clipPath;
604 clipPath.addPolygon( context.
worldTransform().map( visibleRegion ) );
605 painter->setClipPath( clipPath, Qt::ClipOperation::IntersectClip );
611 if ( std::isnan( pointIt.value() ) )
621 QVector<QgsAbstractProfileResults::Feature> res;
628 for (
const Feature &feature : it.value() )
633 QgsAbstractProfileResults::Feature outFeature;
635 outFeature.
attributes = { { u
"id"_s, feature.featureId } };
643 outFeature.
geometry = feature.crossSectionGeometry;
660 mId = vlGenerator->mId;
663 mMarkerSymbol.reset( vlGenerator->mProfileMarkerSymbol->clone() );
675 , mProfileCurve( request.profileCurve() ? request.profileCurve()->clone() : nullptr )
676 , mTerrainProvider( request.terrainProvider() ? request.terrainProvider()->clone() : nullptr )
677 , mTolerance( request.tolerance() )
678 , mSourceCrs( layer->crs3D() )
679 , mTargetCrs( request.crs() )
680 , mTransformContext( request.transformContext() )
681 , mExtent( layer->extent() )
683 , mOffset( layer->elevationProperties()->zOffset() )
684 , mScale( layer->elevationProperties()->zScale() )
692 , mExpressionContext( request.expressionContext() )
693 , mFields( layer->fields() )
694 , mDataDefinedProperties( layer->elevationProperties()->dataDefinedProperties() )
695 , mWkbType( layer->wkbType() )
701 if ( mTerrainProvider )
702 mTerrainProvider->prepare();
706 mProfileCurve->dropZValue();
729 if ( !mProfileCurve || mFeedback->isCanceled() )
738 std::unique_ptr< QgsCurve > origCurve = std::move( mProfileCurve );
739 std::unique_ptr< QgsVectorLayerProfileResults > totalResults;
740 double distanceProcessed = 0;
742 QVector<QgsLineString *> disjointParts = profileLine->splitToDisjointXYParts();
743 for (
int i = 0; i < disjointParts.size(); i++ )
745 mProfileCurve.reset( disjointParts[i] );
746 if ( !generateProfileInner() )
748 mProfileCurve = std::move( origCurve );
751 for (
int j = i + 1; j < disjointParts.size(); j++ )
752 delete disjointParts[j];
759 totalResults = std::move( mResults );
763 totalResults->mRawPoints.append( mResults->mRawPoints );
764 totalResults->minZ = std::min( totalResults->minZ, mResults->minZ );
765 totalResults->maxZ = std::max( totalResults->maxZ, mResults->maxZ );
766 for (
auto it = mResults->mDistanceToHeightMap.constKeyValueBegin(); it != mResults->mDistanceToHeightMap.constKeyValueEnd(); ++it )
768 totalResults->mDistanceToHeightMap[it->first + distanceProcessed] = it->second;
770 for (
auto it = mResults->features.constKeyValueBegin(); it != mResults->features.constKeyValueEnd(); ++it )
775 totalResults->features[it->first].push_back( feature );
780 distanceProcessed += mProfileCurve->length();
783 mProfileCurve = std::move( origCurve );
784 mResults = std::move( totalResults );
788 return generateProfileInner();
796 if ( mTerrainProvider )
797 mTargetToTerrainProviderTransform =
QgsCoordinateTransform( mTargetCrs, mTerrainProvider->crs(), mTransformContext );
803 catch ( QgsCsException & )
805 QgsDebugError( u
"Error transforming profile line to vector CRS"_s );
809 const QgsRectangle profileCurveBoundingBox = mTransformedCurve->boundingBox();
810 if ( !profileCurveBoundingBox.
intersects( mExtent ) )
813 if ( mFeedback->isCanceled() )
816 mResults = std::make_unique< QgsVectorLayerProfileResults >();
817 mResults->mLayer = mLayer;
818 mResults->copyPropertiesFromGenerator(
this );
820 mProfileCurveEngine = std::make_unique<QgsGeos>( mProfileCurve.get() );
821 mProfileCurveEngine->prepareGeometry();
823 if ( tolerance() == 0.0 )
825 mProfileBufferedCurve = std::unique_ptr<QgsAbstractGeometry>( mProfileCurve->clone() );
832 mProfileBufferedCurveEngine = std::make_unique<QgsGeos>( mProfileBufferedCurve.get() );
833 mProfileBufferedCurveEngine->prepareGeometry();
835 mDataDefinedProperties.prepare( mExpressionContext );
837 if ( mFeedback->isCanceled() )
843 if ( !generateProfileForPoints() )
848 if ( !generateProfileForLines() )
853 if ( !generateProfileForPolygons() )
867 return mResults.release();
872 return mFeedback.get();
875bool QgsVectorLayerProfileGenerator::generateProfileForPoints()
890 while ( !mFeedback->isCanceled() && it.
nextFeature( feature ) )
897 if ( mProfileBufferedCurveEngine->intersects( *it ) )
903 return !mFeedback->isCanceled();
906void QgsVectorLayerProfileGenerator::processIntersectionPoint(
const QgsPoint *point,
const QgsFeature &feature )
911 const double height = featureZToHeight( point->
x(), point->
y(), point->
z(), offset );
912 mResults->mRawPoints.append( QgsPoint( point->
x(), point->
y(), height ) );
913 mResults->minZ = std::min( mResults->minZ, height );
914 mResults->maxZ = std::max( mResults->maxZ, height );
916 const double distanceAlongProfileCurve = mProfileCurveEngine->lineLocatePoint( *point, &error );
917 mResults->mDistanceToHeightMap.insert( distanceAlongProfileCurve, height );
919 QgsVectorLayerProfileResults::Feature resultFeature;
921 if ( mExtrusionEnabled )
925 resultFeature.
geometry = QgsGeometry(
new QgsLineString( QgsPoint( point->
x(), point->
y(), height ), QgsPoint( point->
x(), point->
y(), height + extrusion ) ) );
926 resultFeature.
crossSectionGeometry = QgsGeometry(
new QgsLineString( QgsPoint( distanceAlongProfileCurve, height ), QgsPoint( distanceAlongProfileCurve, height + extrusion ) ) );
927 mResults->minZ = std::min( mResults->minZ, height + extrusion );
928 mResults->maxZ = std::max( mResults->maxZ, height + extrusion );
932 resultFeature.
geometry = QgsGeometry(
new QgsPoint( point->
x(), point->
y(), height ) );
933 resultFeature.
crossSectionGeometry = QgsGeometry(
new QgsPoint( distanceAlongProfileCurve, height ) );
936 mResults->features[resultFeature.
featureId].append( resultFeature );
939void QgsVectorLayerProfileGenerator::processIntersectionCurve(
const QgsLineString *intersectionCurve,
const QgsFeature &feature )
943 QgsVectorLayerProfileResults::Feature resultFeature;
945 double maxDistanceAlongProfileCurve = std::numeric_limits<double>::lowest();
950 const int numPoints = intersectionCurve->
numPoints();
951 QVector< double > newX( numPoints );
952 QVector< double > newY( numPoints );
953 QVector< double > newZ( numPoints );
954 QVector< double > newDistance( numPoints );
956 const double *inX = intersectionCurve->
xData();
957 const double *inY = intersectionCurve->
yData();
958 const double *inZ = intersectionCurve->
is3D() ? intersectionCurve->
zData() :
nullptr;
959 double *outX = newX.data();
960 double *outY = newY.data();
961 double *outZ = newZ.data();
962 double *outDistance = newDistance.data();
964 QVector< double > extrudedZ;
965 double *extZOut =
nullptr;
966 if ( mExtrusionEnabled )
968 extrudedZ.resize( numPoints );
969 extZOut = extrudedZ.data();
972 for (
int i = 0; !mFeedback->isCanceled() && i < numPoints; ++i )
974 QgsPoint intersectionPoint( *inX, *inY, ( inZ ? *inZ : std::numeric_limits<double>::quiet_NaN() ) );
976 const double height = featureZToHeight( intersectionPoint.x(), intersectionPoint.y(), intersectionPoint.z(), offset );
977 const double distanceAlongProfileCurve = mProfileCurveEngine->lineLocatePoint( intersectionPoint, &error );
979 maxDistanceAlongProfileCurve = std::max( maxDistanceAlongProfileCurve, distanceAlongProfileCurve );
981 mResults->mRawPoints.append( QgsPoint( intersectionPoint.x(), intersectionPoint.y(), height ) );
982 mResults->minZ = std::min( mResults->minZ, height );
983 mResults->maxZ = std::max( mResults->maxZ, height );
985 mResults->mDistanceToHeightMap.insert( distanceAlongProfileCurve, height );
986 *outDistance++ = distanceAlongProfileCurve;
988 *outX++ = intersectionPoint.x();
989 *outY++ = intersectionPoint.y();
992 *extZOut++ = height + extrusion;
994 if ( mExtrusionEnabled )
996 mResults->minZ = std::min( mResults->minZ, height + extrusion );
997 mResults->maxZ = std::max( mResults->maxZ, height + extrusion );
1005 mResults->mDistanceToHeightMap.insert( maxDistanceAlongProfileCurve + 0.000001, std::numeric_limits<double>::quiet_NaN() );
1007 if ( mFeedback->isCanceled() )
1011 if ( mExtrusionEnabled )
1013 auto ring = std::make_unique< QgsLineString >( newX, newY, newZ );
1014 auto extrudedRing = std::make_unique< QgsLineString >( newX, newY, extrudedZ );
1015 std::unique_ptr< QgsLineString > reversedExtrusion( extrudedRing->reversed() );
1016 ring->append( reversedExtrusion.get() );
1018 resultFeature.
geometry = QgsGeometry(
new QgsPolygon( ring.release() ) );
1020 auto distanceVHeightRing = std::make_unique< QgsLineString >( newDistance, newZ );
1021 auto extrudedDistanceVHeightRing = std::make_unique< QgsLineString >( newDistance, extrudedZ );
1022 std::unique_ptr< QgsLineString > reversedDistanceVHeightExtrusion( extrudedDistanceVHeightRing->reversed() );
1023 distanceVHeightRing->append( reversedDistanceVHeightExtrusion.get() );
1024 distanceVHeightRing->close();
1025 resultFeature.
crossSectionGeometry = QgsGeometry(
new QgsPolygon( distanceVHeightRing.release() ) );
1029 resultFeature.
geometry = QgsGeometry(
new QgsLineString( newX, newY, newZ ) );
1033 mResults->features[resultFeature.
featureId].append( resultFeature );
1036bool QgsVectorLayerProfileGenerator::generateProfileForLines()
1039 QgsFeatureRequest request;
1041 if ( tolerance() > 0 )
1043 request.
setDistanceWithin( QgsGeometry( mProfileCurve->clone() ), tolerance() );
1049 request.
setSubsetOfAttributes( mDataDefinedProperties.referencedFields( mExpressionContext ), mFields );
1052 auto processCurve = [
this](
const QgsFeature &feature,
const QgsCurve *featGeomPart ) {
1054 std::unique_ptr< QgsAbstractGeometry > intersection( mProfileBufferedCurveEngine->intersection( featGeomPart, &error ) );
1055 if ( !intersection )
1058 if ( mFeedback->isCanceled() )
1063 if ( intersection->isEmpty() )
1065 intersection.reset( featGeomPart->clone() );
1066 for (
auto it = intersection->const_parts_begin(); !mFeedback->isCanceled() && it != intersection->const_parts_end(); ++it )
1069 processIntersectionCurve( intersectionCurve, feature );
1074 QgsGeos featGeomPartGeos( featGeomPart );
1075 featGeomPartGeos.prepareGeometry();
1077 for (
auto it = intersection->const_parts_begin(); !mFeedback->isCanceled() && it != intersection->const_parts_end(); ++it )
1083 const double distance = featGeomPartGeos.lineLocatePoint( *intersectionPoint, &error );
1084 std::unique_ptr< QgsPoint > interpolatedPoint( featGeomPart->interpolatePoint( distance ) );
1086 processIntersectionPoint( interpolatedPoint.get(), feature );
1092 auto lineInterpolated = std::make_unique<QgsLineString>();
1093 for (
int i = 0; i < intersectionCurve->
numPoints(); ++i )
1095 const QgsPoint pt = intersectionCurve->
pointN( i );
1098 const double distance = featGeomPartGeos.lineLocatePoint( pt, &err );
1100 std::unique_ptr<QgsPoint> pointWithInterpolatedZM( featGeomPart->interpolatePoint( distance ) );
1101 lineInterpolated->addVertex( *pointWithInterpolatedZM );
1104 processIntersectionCurve( lineInterpolated.get(), feature );
1110 QgsFeatureIterator it = mSource->getFeatures( request );
1111 while ( !mFeedback->isCanceled() && it.
nextFeature( feature ) )
1113 mExpressionContext.setFeature( feature );
1115 const QgsGeometry g = feature.
geometry();
1118 if ( mProfileBufferedCurveEngine->intersects( *it ) )
1125 return !mFeedback->isCanceled();
1128QgsPoint QgsVectorLayerProfileGenerator::interpolatePointOnTriangle(
const QgsPolygon *triangle,
double x,
double y )
const
1130 QgsPoint p1, p2, p3;
1135 const double z = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, p1.
z(), p2.
z(), p3.
z(), QgsPointXY( x, y ) );
1136 return QgsPoint( x, y, z );
1139void QgsVectorLayerProfileGenerator::processTriangleIntersectForPoint(
const QgsPolygon *triangle,
const QgsPoint *p, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts )
1141 const QgsPoint interpolatedPoint = interpolatePointOnTriangle( triangle, p->
x(), p->
y() );
1142 mResults->mRawPoints.append( interpolatedPoint );
1143 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() );
1144 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() );
1147 const double distance = mProfileCurveEngine->lineLocatePoint( *p, &lastError );
1148 mResults->mDistanceToHeightMap.insert( distance, interpolatedPoint.
z() );
1150 if ( mExtrusionEnabled )
1154 transformedParts.append( QgsGeometry(
new QgsLineString( interpolatedPoint, QgsPoint( interpolatedPoint.
x(), interpolatedPoint.
y(), interpolatedPoint.
z() + extrusion ) ) ) );
1155 crossSectionParts.append( QgsGeometry(
new QgsLineString( QgsPoint( distance, interpolatedPoint.
z() ), QgsPoint( distance, interpolatedPoint.
z() + extrusion ) ) ) );
1156 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() + extrusion );
1157 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() + extrusion );
1161 transformedParts.append( QgsGeometry(
new QgsPoint( interpolatedPoint ) ) );
1162 crossSectionParts.append( QgsGeometry(
new QgsPoint( distance, interpolatedPoint.
z() ) ) );
1166void QgsVectorLayerProfileGenerator::processTriangleIntersectForLine(
1167 const QgsPolygon *triangle,
const QgsLineString *intersectionLine, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts
1173 int numPoints = intersectionLine->
numPoints();
1174 QVector< double > newX( numPoints );
1175 QVector< double > newY( numPoints );
1176 QVector< double > newZ( numPoints );
1177 QVector< double > newDistance( numPoints );
1179 const double *inX = intersectionLine->
xData();
1180 const double *inY = intersectionLine->
yData();
1181 const double *inZ = intersectionLine->
is3D() ? intersectionLine->
zData() :
nullptr;
1182 double *outX = newX.data();
1183 double *outY = newY.data();
1184 double *outZ = newZ.data();
1185 double *outDistance = newDistance.data();
1187 double lastDistanceAlongProfileCurve = 0.0;
1188 QVector< double > extrudedZ;
1189 double *extZOut =
nullptr;
1190 double extrusion = 0;
1192 if ( mExtrusionEnabled )
1194 extrudedZ.resize( numPoints );
1195 extZOut = extrudedZ.data();
1201 for (
int i = 0; !mFeedback->isCanceled() && i < numPoints; ++i )
1205 double z = inZ ? *inZ++ : 0;
1207 QgsPoint interpolatedPoint( x, y, z );
1213 interpolatedPoint = interpolatePointOnTriangle( triangle, x, y );
1215 double tempOutZ = std::isnan( interpolatedPoint.
z() ) ? 0.0 : interpolatedPoint.
z();
1218 if ( mExtrusionEnabled )
1219 *extZOut++ = tempOutZ + extrusion;
1221 mResults->mRawPoints.append( interpolatedPoint );
1222 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() );
1223 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() );
1224 if ( mExtrusionEnabled )
1226 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() + extrusion );
1227 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() + extrusion );
1230 const double distance = mProfileCurveEngine->lineLocatePoint( interpolatedPoint, &lastError );
1231 *outDistance++ = distance;
1233 mResults->mDistanceToHeightMap.insert( distance, interpolatedPoint.
z() );
1234 lastDistanceAlongProfileCurve = distance;
1238 mResults->mDistanceToHeightMap.insert( lastDistanceAlongProfileCurve + 0.000001, std::numeric_limits<double>::quiet_NaN() );
1240 if ( mFeedback->isCanceled() )
1243 if ( mExtrusionEnabled )
1245 auto ring = std::make_unique< QgsLineString >( newX, newY, newZ );
1246 auto extrudedRing = std::make_unique< QgsLineString >( newX, newY, extrudedZ );
1247 std::unique_ptr< QgsLineString > reversedExtrusion( extrudedRing->reversed() );
1248 ring->append( reversedExtrusion.get() );
1250 transformedParts.append( QgsGeometry(
new QgsPolygon( ring.release() ) ) );
1252 auto distanceVHeightRing = std::make_unique< QgsLineString >( newDistance, newZ );
1253 auto extrudedDistanceVHeightRing = std::make_unique< QgsLineString >( newDistance, extrudedZ );
1254 std::unique_ptr< QgsLineString > reversedDistanceVHeightExtrusion( extrudedDistanceVHeightRing->reversed() );
1255 distanceVHeightRing->append( reversedDistanceVHeightExtrusion.get() );
1256 distanceVHeightRing->close();
1257 crossSectionParts.append( QgsGeometry(
new QgsPolygon( distanceVHeightRing.release() ) ) );
1261 transformedParts.append( QgsGeometry(
new QgsLineString( newX, newY, newZ ) ) );
1262 crossSectionParts.append( QgsGeometry(
new QgsLineString( newDistance, newZ ) ) );
1266void QgsVectorLayerProfileGenerator::processTriangleIntersectForPolygon(
1267 const QgsPolygon *sourcePolygon,
const QgsPolygon *intersectionPolygon, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts
1270 bool oldExtrusion = mExtrusionEnabled;
1303 mExtrusionEnabled =
false;
1304 if ( mProfileBufferedCurveEngine->contains( sourcePolygon ) )
1306 if (
const QgsCurve *exterior = sourcePolygon->
exteriorRing() )
1309 processTriangleIntersectForLine( sourcePolygon, exteriorLine, transformedParts, crossSectionParts );
1314 processTriangleIntersectForLine( sourcePolygon, interiorLine, transformedParts, crossSectionParts );
1320 if (
const QgsCurve *exterior = intersectionPolygon->
exteriorRing() )
1324 processTriangleIntersectForLine( sourcePolygon, exteriorLine, transformedParts, crossSectionParts );
1325 delete exteriorLine;
1330 if ( mProfileBufferedCurveEngine->contains( interiorLine ) )
1332 processTriangleIntersectForLine( sourcePolygon, interiorLine, transformedParts, crossSectionParts );
1337 newInteriorLine->deleteVertex( QgsVertexId( 0, 0, interiorLine->
numPoints() - 1 ) );
1338 processTriangleIntersectForLine( sourcePolygon, newInteriorLine.get(), transformedParts, crossSectionParts );
1343 mExtrusionEnabled = oldExtrusion;
1346bool QgsVectorLayerProfileGenerator::generateProfileForPolygons()
1349 QgsFeatureRequest request;
1351 if ( tolerance() > 0 )
1353 request.
setDistanceWithin( QgsGeometry( mProfileCurve->clone() ), tolerance() );
1359 request.
setSubsetOfAttributes( mDataDefinedProperties.referencedFields( mExpressionContext ), mFields );
1362 std::function< void(
const QgsPolygon *triangle,
const QgsAbstractGeometry *intersect, QVector< QgsGeometry > &, QVector< QgsGeometry > & ) > processTriangleLineIntersect;
1363 processTriangleLineIntersect = [
this](
const QgsPolygon *triangle,
const QgsAbstractGeometry *intersection, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts ) {
1364 for (
auto it = intersection->const_parts_begin(); !mFeedback->isCanceled() && it != intersection->const_parts_end(); ++it )
1372 processTriangleIntersectForPoint( triangle, p, transformedParts, crossSectionParts );
1379 processTriangleIntersectForLine( triangle, intersectionLine, transformedParts, crossSectionParts );
1386 processTriangleIntersectForPolygon( triangle, poly, transformedParts, crossSectionParts );
1397 auto triangleIsCollinearInXYPlane = [](
const QgsPolygon *polygon ) ->
bool {
1402 auto processPolygon =
1404 &processTriangleLineIntersect,
1405 &triangleIsCollinearInXYPlane](
const QgsCurvePolygon *polygon, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts,
double offset,
bool &wasCollinear ) {
1406 std::unique_ptr< QgsPolygon > clampedPolygon;
1409 clampedPolygon.reset( p->
clone() );
1415 clampAltitudes( clampedPolygon.get(), offset );
1417 if ( mFeedback->isCanceled() )
1420 if ( tolerance() > 0.0 )
1423 if ( mProfileBufferedCurveEngine->intersects( clampedPolygon.get(), &error ) )
1425 std::unique_ptr< QgsAbstractGeometry > intersection;
1426 intersection.reset( mProfileBufferedCurveEngine->intersection( clampedPolygon.get(), &error ) );
1427 if ( error.isEmpty() )
1429 processTriangleLineIntersect( clampedPolygon.get(), intersection.get(), transformedParts, crossSectionParts );
1438 QVector< double > newX( numPoints );
1439 QVector< double > newY( numPoints );
1440 QVector< double > newZ( numPoints );
1441 double *outX = newX.data();
1442 double *outY = newY.data();
1443 double *outZ = newZ.data();
1445 const double *inX = ring->
xData();
1446 const double *inY = ring->
yData();
1447 const double *inZ = ring->
zData();
1448 for (
int i = 0; !mFeedback->isCanceled() && i < ring->numPoints() - 1; ++i )
1450 *outX++ = inX[i] + i * 1.0e-9;
1451 *outY++ = inY[i] + i * 1.0e-9;
1454 std::unique_ptr< QgsPolygon > shiftedPoly;
1455 shiftedPoly = std::make_unique<QgsPolygon>(
new QgsLineString( newX, newY, newZ ) );
1457 intersection.reset( mProfileBufferedCurveEngine->intersection( shiftedPoly.get(), &error ) );
1459 processTriangleLineIntersect( clampedPolygon.get(), intersection.get(), transformedParts, crossSectionParts );
1463 QgsDebugMsgLevel( u
"processPolygon after shift bad geom! error: %1"_s.arg( error ), 0 );
1471 QgsGeometry tessellation;
1472 if ( clampedPolygon->numInteriorRings() == 0 && clampedPolygon->exteriorRing() && clampedPolygon->exteriorRing()->numPoints() == 4 && clampedPolygon->exteriorRing()->isClosed() )
1475 auto multiPolygon = std::make_unique< QgsMultiPolygon >();
1476 multiPolygon->addGeometry( clampedPolygon.release() );
1477 tessellation = QgsGeometry( std::move( multiPolygon ) );
1481 const QgsRectangle bounds = clampedPolygon->boundingBox();
1487 if ( mFeedback->isCanceled() )
1495 for (
int i = 0; !mFeedback->isCanceled() && i < numTriangles; ++i )
1499 if ( triangleIsCollinearInXYPlane( triangle ) )
1501 wasCollinear =
true;
1507 for (
int curveSegmentIndex = 0; curveSegmentIndex < mProfileCurve->numPoints() - 1; ++curveSegmentIndex )
1509 const QgsPoint p1 = ls->pointN( curveSegmentIndex );
1510 const QgsPoint p2 = ls->pointN( curveSegmentIndex + 1 );
1512 QgsPoint intersectionPoint;
1513 bool intersectionFound =
false;
1514 double minZ = std::numeric_limits< double >::max();
1515 double maxZ = std::numeric_limits< double >::lowest();
1517 for (
auto vertexPair : std::array<std::pair<int, int>, 3> { { { 0, 1 }, { 1, 2 }, { 2, 0 } } } )
1519 bool isIntersection =
false;
1520 QgsPoint edgeIntersectionPoint;
1523 if ( !edgeIntersectionPoint.
isEmpty() && !intersectionFound )
1525 intersectionPoint = edgeIntersectionPoint;
1526 intersectionFound =
true;
1531 ring->
xAt( vertexPair.first ), ring->
yAt( vertexPair.first ), ring->
xAt( vertexPair.second ), ring->
yAt( vertexPair.second ), edgeIntersectionPoint.
x(), edgeIntersectionPoint.
y()
1533 double intersectionZ = ring->
zAt( vertexPair.first ) + ( ring->
zAt( vertexPair.second ) - ring->
zAt( vertexPair.first ) ) * fraction;
1534 minZ = std::min( minZ, intersectionZ );
1535 maxZ = std::max( maxZ, intersectionZ );
1539 if ( intersectionFound )
1542 mResults->mRawPoints.append( intersectionPoint );
1543 mResults->minZ = std::min( mResults->minZ, minZ );
1544 mResults->maxZ = std::max( mResults->maxZ, maxZ );
1546 const double distance = mProfileCurveEngine->lineLocatePoint( intersectionPoint, &lastError );
1548 crossSectionParts.append( QgsGeometry(
new QgsLineString( QVector< double > { distance, distance }, QVector< double > { minZ, maxZ } ) ) );
1550 mResults->mDistanceToHeightMap.insert( distance, minZ );
1551 mResults->mDistanceToHeightMap.insert( distance, maxZ );
1558 QgsDebugError( u
"Collinear triangles with curved profile lines are not supported yet"_s );
1564 if ( mProfileBufferedCurveEngine->intersects( triangle, &error ) )
1566 std::unique_ptr< QgsAbstractGeometry > intersection( mProfileBufferedCurveEngine->intersection( triangle, &error ) );
1567 processTriangleLineIntersect( triangle, intersection.get(), transformedParts, crossSectionParts );
1576 QgsFeatureIterator it = mSource->getFeatures( request );
1577 while ( !mFeedback->isCanceled() && it.
nextFeature( feature ) )
1579 if ( !mProfileBufferedCurveEngine->intersects( feature.
geometry().
constGet() ) )
1582 mExpressionContext.setFeature( feature );
1585 const QgsGeometry g = feature.
geometry();
1586 QVector< QgsGeometry > transformedParts;
1587 QVector< QgsGeometry > crossSectionParts;
1588 bool wasCollinear =
false;
1593 if ( mProfileBufferedCurveEngine->intersects( *it ) )
1597 processPolygon( curvePolygon, transformedParts, crossSectionParts, offset, wasCollinear );
1601 for (
int i = 0; i < polySurface->numPatches(); ++i )
1603 const QgsPolygon *polygon = polySurface->patchN( i );
1604 if ( mProfileBufferedCurveEngine->intersects( polygon ) )
1606 processPolygon( polygon, transformedParts, crossSectionParts, offset, wasCollinear );
1612 QgsDebugError( u
"Unhandled Geometry type: %1"_s.arg( ( *it )->wktTypeStr() ) );
1617 if ( mFeedback->isCanceled() )
1621 QgsVectorLayerProfileResults::Feature resultFeature;
1624 if ( !crossSectionParts.empty() )
1626 if ( !wasCollinear )
1628 QgsGeometry unioned = QgsGeometry::unaryUnion( crossSectionParts );
1629 if ( unioned.isEmpty() )
1631 resultFeature.crossSectionGeometry = QgsGeometry::collectGeometry( crossSectionParts );
1635 if ( unioned.type() == Qgis::GeometryType::Line )
1637 unioned = unioned.mergeLines();
1639 resultFeature.crossSectionGeometry = unioned;
1644 resultFeature.crossSectionGeometry = QgsGeometry::collectGeometry( crossSectionParts );
1647 mResults->features[resultFeature.
featureId].append( resultFeature );
1652double QgsVectorLayerProfileGenerator::tolerance()
const
1654 return mCustomToleranceEnabled ? mCustomTolerance : mTolerance;
1657double QgsVectorLayerProfileGenerator::terrainHeight(
double x,
double y )
const
1659 if ( !mTerrainProvider )
1660 return std::numeric_limits<double>::quiet_NaN();
1666 mTargetToTerrainProviderTransform.transformInPlace( x, y, dummyZ );
1668 catch ( QgsCsException & )
1670 return std::numeric_limits<double>::quiet_NaN();
1673 return mTerrainProvider->heightAt( x, y );
1676double QgsVectorLayerProfileGenerator::featureZToHeight(
double x,
double y,
double z,
double offset )
const
1678 switch ( mClamping )
1686 const double terrainZ = terrainHeight( x, y );
1687 if ( !std::isnan( terrainZ ) )
1689 switch ( mClamping )
1692 if ( std::isnan( z ) )
1710 return ( std::isnan( z ) ? 0 : z ) * mScale + offset;
1713void QgsVectorLayerProfileGenerator::clampAltitudes(
QgsLineString *lineString,
const QgsPoint ¢roid,
double offset )
const
1717 if ( mFeedback->isCanceled() )
1720 double terrainZ = 0;
1721 switch ( mClamping )
1730 pt.
setX( lineString->
xAt( i ) );
1731 pt.
setY( lineString->
yAt( i ) );
1735 pt.
set( centroid.
x(), centroid.
y() );
1739 terrainZ = terrainHeight( pt.
x(), pt.
y() );
1749 switch ( mClamping )
1753 geomZ = lineString->
zAt( i );
1760 const double z = ( terrainZ + ( std::isnan( geomZ ) ? 0 : geomZ ) ) * mScale + offset;
1761 lineString->
setZAt( i, z );
1765bool QgsVectorLayerProfileGenerator::clampAltitudes(
QgsPolygon *polygon,
double offset )
const
1767 if ( !polygon->
is3D() )
1781 QgsCurve *curve =
const_cast<QgsCurve *
>( polygon->
exteriorRing() );
1786 clampAltitudes( lineString, centroid, offset );
1790 if ( mFeedback->isCanceled() )
1793 QgsCurve *curve =
const_cast<QgsCurve *
>( polygon->
interiorRing( i ) );
1798 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 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.
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
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
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.