52 return QStringLiteral(
"vector" );
57 QVector<QgsGeometry> res;
61 for (
const Feature &feature : it.value() )
63 res.append( feature.geometry );
75 return asIndividualFeatures(
type, feedback );
90 return snapPointToIndividualFeatures( point, context );
106 visitFeaturesInRange( distanceRange, elevationRange, visitFeature );
110 QVector< QVariantMap> idsList;
111 for (
auto it = ids.constBegin(); it != ids.constEnd(); ++it )
112 idsList.append( QVariantMap( {{QStringLiteral(
"id" ), *it}} ) );
119 QHash< QgsFeatureId, QVariantMap >
features;
120 auto visitFeature = [&
features](
QgsFeatureId featureId,
double delta,
double distance,
double elevation )
122 auto it =
features.find( featureId );
125 features[ featureId ] = QVariantMap( {{QStringLiteral(
"id" ), featureId },
126 {QStringLiteral(
"delta" ), delta },
127 {QStringLiteral(
"distance" ), distance },
128 {QStringLiteral(
"elevation" ), elevation }
133 const double currentDelta = it.value().value( QStringLiteral(
"delta" ) ).toDouble();
134 if ( delta < currentDelta )
136 *it = QVariantMap( {{QStringLiteral(
"id" ), featureId },
137 {QStringLiteral(
"delta" ), delta },
138 {QStringLiteral(
"distance" ), distance },
139 {QStringLiteral(
"elevation" ), elevation }
147 QVector< QVariantMap> attributes;
149 attributes.append( *it );
151 QVector<QgsProfileIdentifyResults> res;
153 if ( !attributes.empty() )
159 res.reserve( surfaceResults.size() );
172 double bestSnapDistance = std::numeric_limits< double >::max();
174 auto visitFeature = [&bestSnapDistance, &res](
QgsFeatureId,
double delta,
double distance,
double elevation )
176 if ( distance < bestSnapDistance )
178 bestSnapDistance = delta;
188void QgsVectorLayerProfileResults::visitFeaturesAtPoint(
const QgsProfilePoint &point,
double maximumPointDistanceDelta,
double maximumPointElevationDelta,
double maximumSurfaceElevationDelta,
const std::function<
void(
QgsFeatureId,
double delta,
double distance,
double elevation ) > &visitor,
bool visitWithin )
const
196 for (
const Feature &feature : it.value() )
198 const QgsRectangle featureBounds = feature.crossSectionGeometry.boundingBox();
199 if ( ( featureBounds.
xMinimum() - maximumPointDistanceDelta <= point.
distance() ) && ( featureBounds.
xMaximum() + maximumPointDistanceDelta >= point.
distance() ) )
201 switch ( feature.crossSectionGeometry.type() )
205 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
209 const double snapDistanceDelta = std::fabs( point.
distance() - candidatePoint->x() );
210 if ( snapDistanceDelta > maximumPointDistanceDelta )
213 const double snapHeightDelta = std::fabs( point.
elevation() - candidatePoint->y() );
214 if ( snapHeightDelta > maximumPointElevationDelta )
217 const double snapDistance = candidatePoint->distance( targetPoint );
218 visitor( feature.featureId, snapDistance, candidatePoint->x(), candidatePoint->y() );
226 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
233 if ( lineString->numPoints() == 2 &&
qgsDoubleNear( lineString->pointN( 0 ).x(), lineString->pointN( 1 ).x() ) )
235 const double snapDistanceDelta = std::fabs( point.
distance() - lineString->pointN( 0 ).x() );
236 if ( snapDistanceDelta > maximumPointDistanceDelta )
239 const double snapHeightDelta = std::fabs( point.
elevation() - lineString->pointN( 0 ).y() );
240 if ( snapHeightDelta <= maximumPointElevationDelta )
242 const double snapDistanceP1 = lineString->pointN( 0 ).distance( targetPoint );
243 visitor( feature.featureId, snapDistanceP1, lineString->pointN( 0 ).x(), lineString->pointN( 0 ).y() );
246 const double snapHeightDelta2 = std::fabs( point.
elevation() - lineString->pointN( 1 ).y() );
247 if ( snapHeightDelta2 <= maximumPointElevationDelta )
249 const double snapDistanceP2 = lineString->pointN( 1 ).distance( targetPoint );
250 visitor( feature.featureId, snapDistanceP2, lineString->pointN( 1 ).x(), lineString->pointN( 1 ).y() );
255 double elevation1 = lineString->pointN( 0 ).y();
256 double elevation2 = lineString->pointN( 1 ).y();
257 if ( elevation1 > elevation2 )
258 std::swap( elevation1, elevation2 );
262 const double snapDistance = std::fabs( lineString->pointN( 0 ).x() - point.
distance() );
263 visitor( feature.featureId, snapDistance, lineString->pointN( 0 ).x(), point.
elevation() );
270 const QgsRectangle partBounds = ( *partIt )->boundingBox();
278 QgsGeos cutLineGeos( cutLine.constGet() );
280 const QgsGeometry points( cutLineGeos.intersection( line ) );
282 for (
auto vertexIt = points.vertices_begin(); vertexIt != points.vertices_end(); ++vertexIt )
284 const double snapHeightDelta = std::fabs( point.
elevation() - ( *vertexIt ).y() );
285 if ( snapHeightDelta > maximumSurfaceElevationDelta )
288 const double snapDistance = ( *vertexIt ).distance( targetPoint );
289 visitor( feature.featureId, snapDistance, ( *vertexIt ).x(), ( *vertexIt ).y() );
306 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
310 const QgsRectangle partBounds = ( *partIt )->boundingBox();
318 QgsGeos cutLineGeos( cutLine.constGet() );
320 const QgsGeometry points( cutLineGeos.intersection( exterior ) );
321 for (
auto vertexIt = points.vertices_begin(); vertexIt != points.vertices_end(); ++vertexIt )
323 const double snapHeightDelta = std::fabs( point.
elevation() - ( *vertexIt ).y() );
324 if ( snapHeightDelta > maximumSurfaceElevationDelta )
327 const double snapDistance = ( *vertexIt ).distance( targetPoint );
328 visitor( feature.featureId, snapDistance, ( *vertexIt ).x(), ( *vertexIt ).y() );
346 const QgsRectangle profileRange( distanceRange.
lower(), elevationRange.
lower(), distanceRange.
upper(), elevationRange.
upper() );
348 QgsGeos profileRangeGeos( profileRangeGeometry.
constGet() );
349 profileRangeGeos.prepareGeometry();
353 for (
const Feature &feature : it.value() )
355 if ( feature.crossSectionGeometry.boundingBoxIntersects( profileRange ) )
357 switch ( feature.crossSectionGeometry.type() )
361 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
365 if ( profileRange.contains( candidatePoint->x(), candidatePoint->y() ) )
367 visitor( feature.featureId );
377 if ( profileRangeGeos.intersects( feature.crossSectionGeometry.constGet() ) )
379 visitor( feature.featureId );
399 renderResultsAsIndividualFeatures( context );
404 renderMarkersOverContinuousSurfacePlot( context );
417 painter->setBrush( Qt::NoBrush );
418 painter->setPen( Qt::NoPen );
425 const QRectF visibleRegion( minDistance,
minZ, maxDistance - minDistance,
maxZ -
minZ );
426 QPainterPath clipPath;
427 clipPath.addPolygon( context.
worldTransform().map( visibleRegion ) );
428 painter->setClipPath( clipPath, Qt::ClipOperation::IntersectClip );
430 const QgsRectangle clipPathRect( clipPath.boundingRect() );
434 if ( profileFeature.crossSectionGeometry.isEmpty() )
437 QgsGeometry transformed = profileFeature.crossSectionGeometry;
444 switch ( transformed.
type() )
450 markerSymbol->renderPoint( QPointF( point->x(), point->y() ),
nullptr, context.
renderContext() );
454 const int numGeometries = multipoint->numGeometries();
455 for (
int i = 0; i < numGeometries; ++i )
457 markerSymbol->renderPoint( QPointF( multipoint->pointN( i )->x(), multipoint->pointN( i )->y() ),
nullptr, context.
renderContext() );
467 lineSymbol->renderPolyline( line->asQPolygonF(),
nullptr, context.
renderContext() );
471 const int numGeometries = multiLinestring->numGeometries();
472 for (
int i = 0; i < numGeometries; ++i )
474 lineSymbol->renderPolyline( multiLinestring->lineStringN( i )->asQPolygonF(),
nullptr, context.
renderContext() );
484 if (
const QgsCurve *exterior = polygon->exteriorRing() )
485 fillSymbol->renderPolygon( exterior->asQPolygonF(),
nullptr,
nullptr, context.
renderContext() );
489 const int numGeometries = multiPolygon->numGeometries();
490 for (
int i = 0; i < numGeometries; ++i )
492 fillSymbol->renderPolygon( multiPolygon->polygonN( i )->exteriorRing()->asQPolygonF(),
nullptr,
nullptr, context.
renderContext() );
504 QgsFeatureRequest req;
509 std::unique_ptr< QgsFeatureRenderer > renderer(
mLayer->renderer()->clone() );
514 QSet<QString> attributes = renderer->usedAttributes( context.
renderContext() );
516 std::unique_ptr< QgsMarkerSymbol > marker(
mMarkerSymbol->clone() );
517 std::unique_ptr< QgsLineSymbol > line(
mLineSymbol->clone() );
518 std::unique_ptr< QgsFillSymbol > fill(
mFillSymbol->clone() );
519 attributes.unite( marker->usedAttributes( context.
renderContext() ) );
520 attributes.unite( line->usedAttributes( context.
renderContext() ) );
521 attributes.unite( fill->usedAttributes( context.
renderContext() ) );
526 QgsFeatureIterator it =
mLayer->getFeatures( req );
530 QgsSymbol *rendererSymbol = renderer->symbolForFeature( feature, context.
renderContext() );
531 if ( !rendererSymbol )
534 marker->setColor( rendererSymbol->
color() );
535 marker->setOpacity( rendererSymbol->
opacity() );
536 line->setColor( rendererSymbol->
color() );
537 line->setOpacity( rendererSymbol->
opacity() );
538 fill->setColor( rendererSymbol->
color() );
539 fill->setOpacity( rendererSymbol->
opacity() );
545 const QVector< Feature > profileFeatures =
features.value( feature.
id() );
546 for (
const Feature &profileFeature : profileFeatures )
548 renderResult( profileFeature,
563 QSet<QString> attributes;
574 QgsFeatureIterator it =
mLayer->getFeatures( req );
578 const QVector< Feature > profileFeatures =
features.value( feature.
id() );
579 for (
const Feature &profileFeature : profileFeatures )
596 const QgsScopedQPainterState painterState( painter );
598 painter->setBrush( Qt::NoBrush );
599 painter->setPen( Qt::NoPen );
606 const QRectF visibleRegion( minDistance,
minZ, maxDistance - minDistance,
maxZ -
minZ );
607 QPainterPath clipPath;
608 clipPath.addPolygon( context.
worldTransform().map( visibleRegion ) );
609 painter->setClipPath( clipPath, Qt::ClipOperation::IntersectClip );
615 if ( std::isnan( pointIt.value() ) )
625 QVector<QgsAbstractProfileResults::Feature> res;
632 for (
const Feature &feature : it.value() )
637 QgsAbstractProfileResults::Feature outFeature;
639 outFeature.
attributes = {{QStringLiteral(
"id" ), feature.featureId }};
647 outFeature.
geometry = feature.crossSectionGeometry;
664 mId = vlGenerator->mId;
667 mMarkerSymbol.reset( vlGenerator->mProfileMarkerSymbol->clone() );
679 , mProfileCurve( request.profileCurve() ? request.profileCurve()->clone() : nullptr )
680 , mTerrainProvider( request.terrainProvider() ? request.terrainProvider()->clone() : nullptr )
681 , mTolerance( request.tolerance() )
682 , mSourceCrs( layer->crs3D() )
683 , mTargetCrs( request.crs() )
684 , mTransformContext( request.transformContext() )
685 , mExtent( layer->extent() )
687 , mOffset( layer->elevationProperties()->zOffset() )
688 , mScale( layer->elevationProperties()->zScale() )
696 , mExpressionContext( request.expressionContext() )
697 , mFields( layer->fields() )
698 , mDataDefinedProperties( layer->elevationProperties()->dataDefinedProperties() )
699 , mWkbType( layer->wkbType() )
705 if ( mTerrainProvider )
706 mTerrainProvider->prepare();
710 mProfileCurve->dropZValue();
728 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();
767 it != mResults->mDistanceToHeightMap.constKeyValueEnd();
770 totalResults->mDistanceToHeightMap[it->first + distanceProcessed] = it->second;
772 for (
auto it = mResults->features.constKeyValueBegin();
773 it != mResults->features.constKeyValueEnd();
779 totalResults->features[it->first].push_back( feature );
784 distanceProcessed += mProfileCurve->length();
787 mProfileCurve = std::move( origCurve );
788 mResults = std::move( totalResults );
792 return generateProfileInner();
800 if ( mTerrainProvider )
801 mTargetToTerrainProviderTransform =
QgsCoordinateTransform( mTargetCrs, mTerrainProvider->crs(), mTransformContext );
807 catch ( QgsCsException & )
809 QgsDebugError( QStringLiteral(
"Error transforming profile line to vector CRS" ) );
813 const QgsRectangle profileCurveBoundingBox = mTransformedCurve->boundingBox();
814 if ( !profileCurveBoundingBox.
intersects( mExtent ) )
817 if ( mFeedback->isCanceled() )
820 mResults = std::make_unique< QgsVectorLayerProfileResults >();
821 mResults->mLayer = mLayer;
822 mResults->copyPropertiesFromGenerator(
this );
824 mProfileCurveEngine = std::make_unique<QgsGeos>( mProfileCurve.get() );
825 mProfileCurveEngine->prepareGeometry();
827 if ( tolerance() == 0.0 )
829 mProfileBufferedCurve = std::unique_ptr<QgsAbstractGeometry>( mProfileCurve->clone() );
836 mProfileBufferedCurveEngine = std::make_unique<QgsGeos>( mProfileBufferedCurve.get() );
837 mProfileBufferedCurveEngine->prepareGeometry();
839 mDataDefinedProperties.prepare( mExpressionContext );
841 if ( mFeedback->isCanceled() )
847 if ( !generateProfileForPoints() )
852 if ( !generateProfileForLines() )
857 if ( !generateProfileForPolygons() )
871 return mResults.release();
876 return mFeedback.get();
879bool QgsVectorLayerProfileGenerator::generateProfileForPoints()
894 while ( !mFeedback->isCanceled() && it.
nextFeature( feature ) )
901 if ( mProfileBufferedCurveEngine->intersects( *it ) )
907 return !mFeedback->isCanceled();
910void QgsVectorLayerProfileGenerator::processIntersectionPoint(
const QgsPoint *point,
const QgsFeature &feature )
915 const double height = featureZToHeight( point->
x(), point->
y(), point->
z(), offset );
916 mResults->mRawPoints.append( QgsPoint( point->
x(), point->
y(), height ) );
917 mResults->minZ = std::min( mResults->minZ, height );
918 mResults->maxZ = std::max( mResults->maxZ, height );
920 const double distanceAlongProfileCurve = mProfileCurveEngine->lineLocatePoint( *point, &error );
921 mResults->mDistanceToHeightMap.insert( distanceAlongProfileCurve, height );
923 QgsVectorLayerProfileResults::Feature resultFeature;
925 if ( mExtrusionEnabled )
929 resultFeature.
geometry = QgsGeometry(
new QgsLineString( QgsPoint( point->
x(), point->
y(), height ),
930 QgsPoint( point->
x(), point->
y(), height + extrusion ) ) );
931 resultFeature.
crossSectionGeometry = QgsGeometry(
new QgsLineString( QgsPoint( distanceAlongProfileCurve, height ),
932 QgsPoint( distanceAlongProfileCurve, height + extrusion ) ) );
933 mResults->minZ = std::min( mResults->minZ, height + extrusion );
934 mResults->maxZ = std::max( mResults->maxZ, height + extrusion );
938 resultFeature.
geometry = QgsGeometry(
new QgsPoint( point->
x(), point->
y(), height ) );
939 resultFeature.
crossSectionGeometry = QgsGeometry(
new QgsPoint( distanceAlongProfileCurve, height ) );
942 mResults->features[resultFeature.
featureId].append( resultFeature );
945void QgsVectorLayerProfileGenerator::processIntersectionCurve(
const QgsLineString *intersectionCurve,
const QgsFeature &feature )
949 QgsVectorLayerProfileResults::Feature resultFeature;
951 double maxDistanceAlongProfileCurve = std::numeric_limits<double>::lowest();
956 const int numPoints = intersectionCurve->
numPoints();
957 QVector< double > newX( numPoints );
958 QVector< double > newY( numPoints );
959 QVector< double > newZ( numPoints );
960 QVector< double > newDistance( numPoints );
962 const double *inX = intersectionCurve->
xData();
963 const double *inY = intersectionCurve->
yData();
964 const double *inZ = intersectionCurve->
is3D() ? intersectionCurve->
zData() :
nullptr;
965 double *outX = newX.data();
966 double *outY = newY.data();
967 double *outZ = newZ.data();
968 double *outDistance = newDistance.data();
970 QVector< double > extrudedZ;
971 double *extZOut =
nullptr;
972 if ( mExtrusionEnabled )
974 extrudedZ.resize( numPoints );
975 extZOut = extrudedZ.data();
978 for (
int i = 0 ; ! mFeedback->isCanceled() && i < numPoints; ++i )
980 QgsPoint intersectionPoint( *inX, *inY, ( inZ ? *inZ : std::numeric_limits<double>::quiet_NaN() ) );
982 const double height = featureZToHeight( intersectionPoint.x(), intersectionPoint.y(), intersectionPoint.z(), offset );
983 const double distanceAlongProfileCurve = mProfileCurveEngine->lineLocatePoint( intersectionPoint, &error );
985 maxDistanceAlongProfileCurve = std::max( maxDistanceAlongProfileCurve, distanceAlongProfileCurve );
987 mResults->mRawPoints.append( QgsPoint( intersectionPoint.x(), intersectionPoint.y(), height ) );
988 mResults->minZ = std::min( mResults->minZ, height );
989 mResults->maxZ = std::max( mResults->maxZ, height );
991 mResults->mDistanceToHeightMap.insert( distanceAlongProfileCurve, height );
992 *outDistance++ = distanceAlongProfileCurve;
994 *outX++ = intersectionPoint.x();
995 *outY++ = intersectionPoint.y();
998 *extZOut++ = height + extrusion;
1000 if ( mExtrusionEnabled )
1002 mResults->minZ = std::min( mResults->minZ, height + extrusion );
1003 mResults->maxZ = std::max( mResults->maxZ, height + extrusion );
1011 mResults->mDistanceToHeightMap.insert( maxDistanceAlongProfileCurve + 0.000001, std::numeric_limits<double>::quiet_NaN() );
1013 if ( mFeedback->isCanceled() )
1017 if ( mExtrusionEnabled )
1019 auto ring = std::make_unique< QgsLineString >( newX, newY, newZ );
1020 auto extrudedRing = std::make_unique< QgsLineString >( newX, newY, extrudedZ );
1021 std::unique_ptr< QgsLineString > reversedExtrusion( extrudedRing->reversed() );
1022 ring->append( reversedExtrusion.get() );
1024 resultFeature.
geometry = QgsGeometry(
new QgsPolygon( ring.release() ) );
1026 auto distanceVHeightRing = std::make_unique< QgsLineString >( newDistance, newZ );
1027 auto extrudedDistanceVHeightRing = std::make_unique< QgsLineString >( newDistance, extrudedZ );
1028 std::unique_ptr< QgsLineString > reversedDistanceVHeightExtrusion( extrudedDistanceVHeightRing->reversed() );
1029 distanceVHeightRing->append( reversedDistanceVHeightExtrusion.get() );
1030 distanceVHeightRing->close();
1031 resultFeature.
crossSectionGeometry = QgsGeometry(
new QgsPolygon( distanceVHeightRing.release() ) );
1035 resultFeature.
geometry = QgsGeometry(
new QgsLineString( newX, newY, newZ ) ) ;
1039 mResults->features[resultFeature.
featureId].append( resultFeature );
1042bool QgsVectorLayerProfileGenerator::generateProfileForLines()
1045 QgsFeatureRequest request;
1047 if ( tolerance() > 0 )
1049 request.
setDistanceWithin( QgsGeometry( mProfileCurve->clone() ), tolerance() );
1055 request.
setSubsetOfAttributes( mDataDefinedProperties.referencedFields( mExpressionContext ), mFields );
1058 auto processCurve = [
this](
const QgsFeature & feature,
const QgsCurve * featGeomPart )
1061 std::unique_ptr< QgsAbstractGeometry > intersection( mProfileBufferedCurveEngine->intersection( featGeomPart, &error ) );
1062 if ( !intersection )
1065 if ( mFeedback->isCanceled() )
1070 if ( intersection->isEmpty() )
1072 intersection.reset( featGeomPart->clone() );
1075 QgsGeos featGeomPartGeos( featGeomPart );
1076 featGeomPartGeos.prepareGeometry();
1078 for (
auto it = intersection->const_parts_begin();
1079 !mFeedback->isCanceled() && it != intersection->const_parts_end();
1086 const double distance = featGeomPartGeos.lineLocatePoint( *intersectionPoint, &error );
1087 std::unique_ptr< QgsPoint > interpolatedPoint( featGeomPart->interpolatePoint( distance ) );
1089 processIntersectionPoint( interpolatedPoint.get(), feature );
1093 processIntersectionCurve( intersectionCurve, feature );
1099 QgsFeatureIterator it = mSource->getFeatures( request );
1100 while ( !mFeedback->isCanceled() && it.
nextFeature( feature ) )
1102 mExpressionContext.setFeature( feature );
1104 const QgsGeometry g = feature.
geometry();
1107 if ( mProfileBufferedCurveEngine->intersects( *it ) )
1114 return !mFeedback->isCanceled();
1117QgsPoint QgsVectorLayerProfileGenerator::interpolatePointOnTriangle(
const QgsPolygon *triangle,
double x,
double y )
const
1119 QgsPoint p1, p2, p3;
1124 const double z = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, p1.
z(), p2.
z(), p3.
z(), QgsPointXY( x, y ) );
1125 return QgsPoint( x, y, z );
1128void QgsVectorLayerProfileGenerator::processTriangleIntersectForPoint(
const QgsPolygon *triangle,
const QgsPoint *p, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts )
1130 const QgsPoint interpolatedPoint = interpolatePointOnTriangle( triangle, p->
x(), p->
y() );
1131 mResults->mRawPoints.append( interpolatedPoint );
1132 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() );
1133 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() );
1136 const double distance = mProfileCurveEngine->lineLocatePoint( *p, &lastError );
1137 mResults->mDistanceToHeightMap.insert( distance, interpolatedPoint.
z() );
1139 if ( mExtrusionEnabled )
1143 transformedParts.append( QgsGeometry(
new QgsLineString( interpolatedPoint,
1144 QgsPoint( interpolatedPoint.
x(), interpolatedPoint.
y(), interpolatedPoint.
z() + extrusion ) ) ) );
1145 crossSectionParts.append( QgsGeometry(
new QgsLineString( QgsPoint( distance, interpolatedPoint.
z() ),
1146 QgsPoint( distance, interpolatedPoint.
z() + extrusion ) ) ) );
1147 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() + extrusion );
1148 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() + extrusion );
1152 transformedParts.append( QgsGeometry(
new QgsPoint( interpolatedPoint ) ) );
1153 crossSectionParts.append( QgsGeometry(
new QgsPoint( distance, interpolatedPoint.
z() ) ) );
1157void QgsVectorLayerProfileGenerator::processTriangleIntersectForLine(
const QgsPolygon *triangle,
const QgsLineString *intersectionLine, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts )
1162 int numPoints = intersectionLine->
numPoints();
1163 QVector< double > newX( numPoints );
1164 QVector< double > newY( numPoints );
1165 QVector< double > newZ( numPoints );
1166 QVector< double > newDistance( numPoints );
1168 const double *inX = intersectionLine->
xData();
1169 const double *inY = intersectionLine->
yData();
1170 const double *inZ = intersectionLine->
is3D() ? intersectionLine->
zData() :
nullptr;
1171 double *outX = newX.data();
1172 double *outY = newY.data();
1173 double *outZ = newZ.data();
1174 double *outDistance = newDistance.data();
1176 double lastDistanceAlongProfileCurve = 0.0;
1177 QVector< double > extrudedZ;
1178 double *extZOut =
nullptr;
1179 double extrusion = 0;
1181 if ( mExtrusionEnabled )
1183 extrudedZ.resize( numPoints );
1184 extZOut = extrudedZ.data();
1190 for (
int i = 0 ; ! mFeedback->isCanceled() && i < numPoints; ++i )
1194 double z = inZ ? *inZ++ : 0;
1196 QgsPoint interpolatedPoint( x, y, z );
1202 interpolatedPoint = interpolatePointOnTriangle( triangle, x, y );
1204 double tempOutZ = std::isnan( interpolatedPoint.
z() ) ? 0.0 : interpolatedPoint.
z();
1207 if ( mExtrusionEnabled )
1208 *extZOut++ = tempOutZ + extrusion;
1210 mResults->mRawPoints.append( interpolatedPoint );
1211 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() );
1212 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() );
1213 if ( mExtrusionEnabled )
1215 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() + extrusion );
1216 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() + extrusion );
1219 const double distance = mProfileCurveEngine->lineLocatePoint( interpolatedPoint, &lastError );
1220 *outDistance++ = distance;
1222 mResults->mDistanceToHeightMap.insert( distance, interpolatedPoint.
z() );
1223 lastDistanceAlongProfileCurve = distance;
1227 mResults->mDistanceToHeightMap.insert( lastDistanceAlongProfileCurve + 0.000001, std::numeric_limits<double>::quiet_NaN() );
1229 if ( mFeedback->isCanceled() )
1232 if ( mExtrusionEnabled )
1234 auto ring = std::make_unique< QgsLineString >( newX, newY, newZ );
1235 auto extrudedRing = std::make_unique< QgsLineString >( newX, newY, extrudedZ );
1236 std::unique_ptr< QgsLineString > reversedExtrusion( extrudedRing->reversed() );
1237 ring->append( reversedExtrusion.get() );
1239 transformedParts.append( QgsGeometry(
new QgsPolygon( ring.release() ) ) );
1241 auto distanceVHeightRing = std::make_unique< QgsLineString >( newDistance, newZ );
1242 auto extrudedDistanceVHeightRing = std::make_unique< QgsLineString >( newDistance, extrudedZ );
1243 std::unique_ptr< QgsLineString > reversedDistanceVHeightExtrusion( extrudedDistanceVHeightRing->reversed() );
1244 distanceVHeightRing->append( reversedDistanceVHeightExtrusion.get() );
1245 distanceVHeightRing->close();
1246 crossSectionParts.append( QgsGeometry(
new QgsPolygon( distanceVHeightRing.release() ) ) );
1250 transformedParts.append( QgsGeometry(
new QgsLineString( newX, newY, newZ ) ) );
1251 crossSectionParts.append( QgsGeometry(
new QgsLineString( newDistance, newZ ) ) );
1255void QgsVectorLayerProfileGenerator::processTriangleIntersectForPolygon(
const QgsPolygon *sourcePolygon,
const QgsPolygon *intersectionPolygon, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts )
1257 bool oldExtrusion = mExtrusionEnabled;
1290 mExtrusionEnabled =
false;
1291 if ( mProfileBufferedCurveEngine->contains( sourcePolygon ) )
1293 if (
const QgsCurve *exterior = sourcePolygon->
exteriorRing() )
1296 processTriangleIntersectForLine( sourcePolygon, exteriorLine, transformedParts, crossSectionParts );
1301 processTriangleIntersectForLine( sourcePolygon, interiorLine, transformedParts, crossSectionParts );
1307 if (
const QgsCurve *exterior = intersectionPolygon->
exteriorRing() )
1311 processTriangleIntersectForLine( sourcePolygon, exteriorLine, transformedParts, crossSectionParts );
1312 delete exteriorLine;
1317 if ( mProfileBufferedCurveEngine->contains( interiorLine ) )
1319 processTriangleIntersectForLine( sourcePolygon, interiorLine, transformedParts, crossSectionParts );
1324 newInteriorLine->deleteVertex( QgsVertexId( 0, 0, interiorLine->
numPoints() - 1 ) );
1325 processTriangleIntersectForLine( sourcePolygon, newInteriorLine.get(), transformedParts, crossSectionParts );
1330 mExtrusionEnabled = oldExtrusion;
1333bool QgsVectorLayerProfileGenerator::generateProfileForPolygons()
1336 QgsFeatureRequest request;
1338 if ( tolerance() > 0 )
1340 request.
setDistanceWithin( QgsGeometry( mProfileCurve->clone() ), tolerance() );
1346 request.
setSubsetOfAttributes( mDataDefinedProperties.referencedFields( mExpressionContext ), mFields );
1349 std::function< void(
const QgsPolygon *triangle,
const QgsAbstractGeometry *intersect, QVector< QgsGeometry > &, QVector< QgsGeometry > & ) > processTriangleLineIntersect;
1350 processTriangleLineIntersect = [
this](
const QgsPolygon * triangle,
const QgsAbstractGeometry * intersection, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts )
1352 for (
auto it = intersection->const_parts_begin();
1353 ! mFeedback->isCanceled() && it != intersection->const_parts_end();
1362 processTriangleIntersectForPoint( triangle, p, transformedParts, crossSectionParts );
1369 processTriangleIntersectForLine( triangle, intersectionLine, transformedParts, crossSectionParts );
1376 processTriangleIntersectForPolygon( triangle, poly, transformedParts, crossSectionParts );
1387 auto triangleIsCollinearInXYPlane = [](
const QgsPolygon * polygon )->
bool
1391 ring->
xAt( 1 ), ring->
yAt( 1 ),
1392 ring->
xAt( 2 ), ring->
yAt( 2 ), 0.005 );
1395 auto processPolygon = [
this, &processTriangleLineIntersect, &triangleIsCollinearInXYPlane](
const QgsCurvePolygon * polygon, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts,
double offset,
bool & wasCollinear )
1397 std::unique_ptr< QgsPolygon > clampedPolygon;
1400 clampedPolygon.reset( p->
clone() );
1406 clampAltitudes( clampedPolygon.get(), offset );
1408 if ( mFeedback->isCanceled() )
1411 if ( tolerance() > 0.0 )
1414 if ( mProfileBufferedCurveEngine->intersects( clampedPolygon.get(), &error ) )
1416 std::unique_ptr< QgsAbstractGeometry > intersection;
1417 intersection.reset( mProfileBufferedCurveEngine->intersection( clampedPolygon.get(), &error ) );
1418 if ( error.isEmpty() )
1420 processTriangleLineIntersect( clampedPolygon.get(), intersection.get(), transformedParts, crossSectionParts );
1429 QVector< double > newX( numPoints );
1430 QVector< double > newY( numPoints );
1431 QVector< double > newZ( numPoints );
1432 double *outX = newX.data();
1433 double *outY = newY.data();
1434 double *outZ = newZ.data();
1436 const double *inX = ring->
xData();
1437 const double *inY = ring->
yData();
1438 const double *inZ = ring->
zData();
1439 for (
int i = 0 ; ! mFeedback->isCanceled() && i < ring->numPoints() - 1; ++i )
1441 *outX++ = inX[i] + i * 1.0e-9;
1442 *outY++ = inY[i] + i * 1.0e-9;
1445 std::unique_ptr< QgsPolygon > shiftedPoly;
1446 shiftedPoly = std::make_unique<QgsPolygon>(
new QgsLineString( newX, newY, newZ ) );
1448 intersection.reset( mProfileBufferedCurveEngine->intersection( shiftedPoly.get(), &error ) );
1450 processTriangleLineIntersect( clampedPolygon.get(), intersection.get(), transformedParts, crossSectionParts );
1454 QgsDebugMsgLevel( QStringLiteral(
"processPolygon after shift bad geom! error: %1" ).arg( error ), 0 );
1463 QgsGeometry tessellation;
1464 if ( clampedPolygon->numInteriorRings() == 0 && clampedPolygon->exteriorRing() && clampedPolygon->exteriorRing()->numPoints() == 4 && clampedPolygon->exteriorRing()->isClosed() )
1467 auto multiPolygon = std::make_unique< QgsMultiPolygon >();
1468 multiPolygon->addGeometry( clampedPolygon.release() );
1469 tessellation = QgsGeometry( std::move( multiPolygon ) );
1473 const QgsRectangle bounds = clampedPolygon->boundingBox();
1480 if ( mFeedback->isCanceled() )
1488 for (
int i = 0; ! mFeedback->isCanceled() && i < numTriangles; ++i )
1492 if ( triangleIsCollinearInXYPlane( triangle ) )
1494 wasCollinear =
true;
1500 for (
int curveSegmentIndex = 0; curveSegmentIndex < mProfileCurve->numPoints() - 1; ++curveSegmentIndex )
1502 const QgsPoint p1 = ls->pointN( curveSegmentIndex );
1503 const QgsPoint p2 = ls->pointN( curveSegmentIndex + 1 );
1505 QgsPoint intersectionPoint;
1506 double minZ = std::numeric_limits< double >::max();
1507 double maxZ = std::numeric_limits< double >::lowest();
1509 for (
auto vertexPair : std::array<std::pair<int, int>, 3> {{ { 0, 1}, {1, 2}, {2, 0} }} )
1511 bool isIntersection =
false;
1515 const double intersectionZ = ring->
zAt( vertexPair.first ) + ( ring->
zAt( vertexPair.second ) - ring->
zAt( vertexPair.first ) ) * fraction;
1516 minZ = std::min( minZ, intersectionZ );
1517 maxZ = std::max( maxZ, intersectionZ );
1521 if ( !intersectionPoint.
isEmpty() )
1524 mResults->mRawPoints.append( intersectionPoint );
1525 mResults->minZ = std::min( mResults->minZ, minZ );
1526 mResults->maxZ = std::max( mResults->maxZ, maxZ );
1528 const double distance = mProfileCurveEngine->lineLocatePoint( intersectionPoint, &lastError );
1530 crossSectionParts.append( QgsGeometry(
new QgsLineString( QVector< double > {distance, distance}, QVector< double > {minZ, maxZ} ) ) );
1532 mResults->mDistanceToHeightMap.insert( distance, minZ );
1533 mResults->mDistanceToHeightMap.insert( distance, maxZ );
1540 QgsDebugError( QStringLiteral(
"Collinear triangles with curved profile lines are not supported yet" ) );
1546 if ( mProfileBufferedCurveEngine->intersects( triangle, &error ) )
1548 std::unique_ptr< QgsAbstractGeometry > intersection( mProfileBufferedCurveEngine->intersection( triangle, &error ) );
1549 processTriangleLineIntersect( triangle, intersection.get(), transformedParts, crossSectionParts );
1558 QgsFeatureIterator it = mSource->getFeatures( request );
1559 while ( ! mFeedback->isCanceled() && it.
nextFeature( feature ) )
1561 if ( !mProfileBufferedCurveEngine->intersects( feature.
geometry().
constGet() ) )
1564 mExpressionContext.setFeature( feature );
1567 const QgsGeometry g = feature.
geometry();
1568 QVector< QgsGeometry > transformedParts;
1569 QVector< QgsGeometry > crossSectionParts;
1570 bool wasCollinear =
false;
1575 if ( mProfileBufferedCurveEngine->intersects( *it ) )
1579 processPolygon( curvePolygon, transformedParts, crossSectionParts, offset, wasCollinear );
1583 for (
int i = 0; i < polySurface->numPatches(); ++i )
1585 const QgsPolygon *polygon = polySurface->patchN( i );
1586 if ( mProfileBufferedCurveEngine->intersects( polygon ) )
1588 processPolygon( polygon, transformedParts, crossSectionParts, offset, wasCollinear );
1594 QgsDebugError( QStringLiteral(
"Unhandled Geometry type: %1" ).arg( ( *it )->wktTypeStr() ) );
1599 if ( mFeedback->isCanceled() )
1603 QgsVectorLayerProfileResults::Feature resultFeature;
1606 if ( !crossSectionParts.empty() )
1608 if ( !wasCollinear )
1610 QgsGeometry unioned = QgsGeometry::unaryUnion( crossSectionParts );
1611 if ( unioned.isEmpty() )
1613 resultFeature.crossSectionGeometry = QgsGeometry::collectGeometry( crossSectionParts );
1617 if ( unioned.type() == Qgis::GeometryType::Line )
1619 unioned = unioned.mergeLines();
1621 resultFeature.crossSectionGeometry = unioned;
1626 resultFeature.crossSectionGeometry = QgsGeometry::collectGeometry( crossSectionParts );
1629 mResults->features[resultFeature.
featureId].append( resultFeature );
1634double QgsVectorLayerProfileGenerator::tolerance()
const
1636 return mCustomToleranceEnabled ? mCustomTolerance : mTolerance;
1639double QgsVectorLayerProfileGenerator::terrainHeight(
double x,
double y )
const
1641 if ( !mTerrainProvider )
1642 return std::numeric_limits<double>::quiet_NaN();
1648 mTargetToTerrainProviderTransform.transformInPlace( x, y, dummyZ );
1650 catch ( QgsCsException & )
1652 return std::numeric_limits<double>::quiet_NaN();
1655 return mTerrainProvider->heightAt( x, y );
1658double QgsVectorLayerProfileGenerator::featureZToHeight(
double x,
double y,
double z,
double offset )
const
1660 switch ( mClamping )
1668 const double terrainZ = terrainHeight( x, y );
1669 if ( !std::isnan( terrainZ ) )
1671 switch ( mClamping )
1674 if ( std::isnan( z ) )
1692 return ( std::isnan( z ) ? 0 : z ) * mScale + offset;
1695void QgsVectorLayerProfileGenerator::clampAltitudes(
QgsLineString *lineString,
const QgsPoint ¢roid,
double offset )
const
1699 if ( mFeedback->isCanceled() )
1702 double terrainZ = 0;
1703 switch ( mClamping )
1712 pt.
setX( lineString->
xAt( i ) );
1713 pt.
setY( lineString->
yAt( i ) );
1717 pt.
set( centroid.
x(), centroid.
y() );
1721 terrainZ = terrainHeight( pt.
x(), pt.
y() );
1731 switch ( mClamping )
1735 geomZ = lineString->
zAt( i );
1742 const double z = ( terrainZ + ( std::isnan( geomZ ) ? 0 : geomZ ) ) * mScale + offset;
1743 lineString->
setZAt( i, z );
1747bool QgsVectorLayerProfileGenerator::clampAltitudes(
QgsPolygon *polygon,
double offset )
const
1749 if ( !polygon->
is3D() )
1763 QgsCurve *curve =
const_cast<QgsCurve *
>( polygon->
exteriorRing() );
1768 clampAltitudes( lineString, centroid, offset );
1772 if ( mFeedback->isCanceled() )
1775 QgsCurve *curve =
const_cast<QgsCurve *
>( polygon->
interiorRing( i ) );
1780 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 id 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.
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.
const double * yData() const
Returns a const pointer to the y vertex data.
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 linestring does not have z values.
int numPoints() const override
Returns the number of points in the curve.
QgsPoint pointN(int i) const
Returns the specified point from inside the line string.
int nCoordinates() const override
Returns the number of nodes contained in the geometry.
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 line string.
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
double zAt(int index) const override
Returns the z-coordinate of the specified node in the line string.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
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.
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.
void setOutputZUp(bool zUp)
Sets whether the "up" direction should be the Z axis on output (true), otherwise the "up" direction w...
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.
~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.