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 );
109 visitFeaturesInRange( distanceRange, elevationRange, visitFeature );
113 QVector< QVariantMap> idsList;
114 for (
auto it = ids.constBegin(); it != ids.constEnd(); ++it )
115 idsList.append( QVariantMap( {{u
"id"_s, *it}} ) );
122 QHash< QgsFeatureId, QVariantMap >
features;
123 auto visitFeature = [&
features](
QgsFeatureId featureId,
double delta,
double distance,
double elevation )
125 auto it =
features.find( featureId );
128 features[ featureId ] = QVariantMap( {{u
"id"_s, featureId },
129 {u
"delta"_s, delta },
130 {u
"distance"_s, distance },
131 {u
"elevation"_s, elevation }
136 const double currentDelta = it.value().value( u
"delta"_s ).toDouble();
137 if ( delta < currentDelta )
139 *it = QVariantMap( {{u
"id"_s, featureId },
140 {u
"delta"_s, delta },
141 {u
"distance"_s, distance },
142 {u
"elevation"_s, elevation }
150 QVector< QVariantMap> attributes;
152 attributes.append( *it );
154 QVector<QgsProfileIdentifyResults> res;
156 if ( !attributes.empty() )
162 res.reserve( surfaceResults.size() );
175 double bestSnapDistance = std::numeric_limits< double >::max();
177 auto visitFeature = [&bestSnapDistance, &res](
QgsFeatureId,
double delta,
double distance,
double elevation )
179 if ( distance < bestSnapDistance )
181 bestSnapDistance = delta;
191void 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
199 for (
const Feature &feature : it.value() )
201 const QgsRectangle featureBounds = feature.crossSectionGeometry.boundingBox();
202 if ( ( featureBounds.
xMinimum() - maximumPointDistanceDelta <= point.
distance() ) && ( featureBounds.
xMaximum() + maximumPointDistanceDelta >= point.
distance() ) )
204 switch ( feature.crossSectionGeometry.type() )
208 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
212 const double snapDistanceDelta = std::fabs( point.
distance() - candidatePoint->x() );
213 if ( snapDistanceDelta > maximumPointDistanceDelta )
216 const double snapHeightDelta = std::fabs( point.
elevation() - candidatePoint->y() );
217 if ( snapHeightDelta > maximumPointElevationDelta )
220 const double snapDistance = candidatePoint->distance( targetPoint );
221 visitor( feature.featureId, snapDistance, candidatePoint->x(), candidatePoint->y() );
229 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
236 if ( lineString->numPoints() == 2 &&
qgsDoubleNear( lineString->pointN( 0 ).x(), lineString->pointN( 1 ).x() ) )
238 const double snapDistanceDelta = std::fabs( point.
distance() - lineString->pointN( 0 ).x() );
239 if ( snapDistanceDelta > maximumPointDistanceDelta )
242 const double snapHeightDelta = std::fabs( point.
elevation() - lineString->pointN( 0 ).y() );
243 if ( snapHeightDelta <= maximumPointElevationDelta )
245 const double snapDistanceP1 = lineString->pointN( 0 ).distance( targetPoint );
246 visitor( feature.featureId, snapDistanceP1, lineString->pointN( 0 ).x(), lineString->pointN( 0 ).y() );
249 const double snapHeightDelta2 = std::fabs( point.
elevation() - lineString->pointN( 1 ).y() );
250 if ( snapHeightDelta2 <= maximumPointElevationDelta )
252 const double snapDistanceP2 = lineString->pointN( 1 ).distance( targetPoint );
253 visitor( feature.featureId, snapDistanceP2, lineString->pointN( 1 ).x(), lineString->pointN( 1 ).y() );
258 double elevation1 = lineString->pointN( 0 ).y();
259 double elevation2 = lineString->pointN( 1 ).y();
260 if ( elevation1 > elevation2 )
261 std::swap( elevation1, elevation2 );
265 const double snapDistance = std::fabs( lineString->pointN( 0 ).x() - point.
distance() );
266 visitor( feature.featureId, snapDistance, lineString->pointN( 0 ).x(), point.
elevation() );
273 const QgsRectangle partBounds = ( *partIt )->boundingBox();
281 QgsGeos cutLineGeos( cutLine.constGet() );
283 const QgsGeometry points( cutLineGeos.intersection( line ) );
285 for (
auto vertexIt = points.vertices_begin(); vertexIt != points.vertices_end(); ++vertexIt )
287 const double snapHeightDelta = std::fabs( point.
elevation() - ( *vertexIt ).y() );
288 if ( snapHeightDelta > maximumSurfaceElevationDelta )
291 const double snapDistance = ( *vertexIt ).distance( targetPoint );
292 visitor( feature.featureId, snapDistance, ( *vertexIt ).x(), ( *vertexIt ).y() );
309 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
313 const QgsRectangle partBounds = ( *partIt )->boundingBox();
321 QgsGeos cutLineGeos( cutLine.constGet() );
323 const QgsGeometry points( cutLineGeos.intersection( exterior ) );
324 for (
auto vertexIt = points.vertices_begin(); vertexIt != points.vertices_end(); ++vertexIt )
326 const double snapHeightDelta = std::fabs( point.
elevation() - ( *vertexIt ).y() );
327 if ( snapHeightDelta > maximumSurfaceElevationDelta )
330 const double snapDistance = ( *vertexIt ).distance( targetPoint );
331 visitor( feature.featureId, snapDistance, ( *vertexIt ).x(), ( *vertexIt ).y() );
349 const QgsRectangle profileRange( distanceRange.
lower(), elevationRange.
lower(), distanceRange.
upper(), elevationRange.
upper() );
351 QgsGeos profileRangeGeos( profileRangeGeometry.
constGet() );
352 profileRangeGeos.prepareGeometry();
356 for (
const Feature &feature : it.value() )
358 if ( feature.crossSectionGeometry.boundingBoxIntersects( profileRange ) )
360 switch ( feature.crossSectionGeometry.type() )
364 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
368 if ( profileRange.contains( candidatePoint->x(), candidatePoint->y() ) )
370 visitor( feature.featureId );
380 if ( profileRangeGeos.intersects( feature.crossSectionGeometry.constGet() ) )
382 visitor( feature.featureId );
402 renderResultsAsIndividualFeatures( context );
407 renderMarkersOverContinuousSurfacePlot( context );
420 painter->setBrush( Qt::NoBrush );
421 painter->setPen( Qt::NoPen );
428 const QRectF visibleRegion( minDistance,
minZ, maxDistance - minDistance,
maxZ -
minZ );
429 QPainterPath clipPath;
430 clipPath.addPolygon( context.
worldTransform().map( visibleRegion ) );
431 painter->setClipPath( clipPath, Qt::ClipOperation::IntersectClip );
433 const QgsRectangle clipPathRect( clipPath.boundingRect() );
437 if ( profileFeature.crossSectionGeometry.isEmpty() )
440 QgsGeometry transformed = profileFeature.crossSectionGeometry;
447 switch ( transformed.
type() )
453 markerSymbol->renderPoint( QPointF( point->x(), point->y() ),
nullptr, context.
renderContext() );
457 const int numGeometries = multipoint->numGeometries();
458 for (
int i = 0; i < numGeometries; ++i )
460 markerSymbol->renderPoint( QPointF( multipoint->pointN( i )->x(), multipoint->pointN( i )->y() ),
nullptr, context.
renderContext() );
470 lineSymbol->renderPolyline( line->asQPolygonF(),
nullptr, context.
renderContext() );
474 const int numGeometries = multiLinestring->numGeometries();
475 for (
int i = 0; i < numGeometries; ++i )
477 lineSymbol->renderPolyline( multiLinestring->lineStringN( i )->asQPolygonF(),
nullptr, context.
renderContext() );
487 if (
const QgsCurve *exterior = polygon->exteriorRing() )
488 fillSymbol->renderPolygon( exterior->asQPolygonF(),
nullptr,
nullptr, context.
renderContext() );
492 const int numGeometries = multiPolygon->numGeometries();
493 for (
int i = 0; i < numGeometries; ++i )
495 fillSymbol->renderPolygon( multiPolygon->polygonN( i )->exteriorRing()->asQPolygonF(),
nullptr,
nullptr, context.
renderContext() );
507 QgsFeatureRequest req;
512 std::unique_ptr< QgsFeatureRenderer > renderer(
mLayer->renderer()->clone() );
517 QSet<QString> attributes = renderer->usedAttributes( context.
renderContext() );
519 std::unique_ptr< QgsMarkerSymbol > marker(
mMarkerSymbol->clone() );
520 std::unique_ptr< QgsLineSymbol > line(
mLineSymbol->clone() );
521 std::unique_ptr< QgsFillSymbol > fill(
mFillSymbol->clone() );
522 attributes.unite( marker->usedAttributes( context.
renderContext() ) );
523 attributes.unite( line->usedAttributes( context.
renderContext() ) );
524 attributes.unite( fill->usedAttributes( context.
renderContext() ) );
529 QgsFeatureIterator it =
mLayer->getFeatures( req );
533 QgsSymbol *rendererSymbol = renderer->symbolForFeature( feature, context.
renderContext() );
534 if ( !rendererSymbol )
537 marker->setColor( rendererSymbol->
color() );
538 marker->setOpacity( rendererSymbol->
opacity() );
539 line->setColor( rendererSymbol->
color() );
540 line->setOpacity( rendererSymbol->
opacity() );
541 fill->setColor( rendererSymbol->
color() );
542 fill->setOpacity( rendererSymbol->
opacity() );
548 const QVector< Feature > profileFeatures =
features.value( feature.
id() );
549 for (
const Feature &profileFeature : profileFeatures )
551 renderResult( profileFeature,
566 QSet<QString> attributes;
577 QgsFeatureIterator it =
mLayer->getFeatures( req );
581 const QVector< Feature > profileFeatures =
features.value( feature.
id() );
582 for (
const Feature &profileFeature : profileFeatures )
599 const QgsScopedQPainterState painterState( painter );
601 painter->setBrush( Qt::NoBrush );
602 painter->setPen( Qt::NoPen );
609 const QRectF visibleRegion( minDistance,
minZ, maxDistance - minDistance,
maxZ -
minZ );
610 QPainterPath clipPath;
611 clipPath.addPolygon( context.
worldTransform().map( visibleRegion ) );
612 painter->setClipPath( clipPath, Qt::ClipOperation::IntersectClip );
618 if ( std::isnan( pointIt.value() ) )
628 QVector<QgsAbstractProfileResults::Feature> res;
635 for (
const Feature &feature : it.value() )
640 QgsAbstractProfileResults::Feature outFeature;
642 outFeature.
attributes = {{u
"id"_s, feature.featureId }};
650 outFeature.
geometry = feature.crossSectionGeometry;
667 mId = vlGenerator->mId;
670 mMarkerSymbol.reset( vlGenerator->mProfileMarkerSymbol->clone() );
682 , mProfileCurve( request.profileCurve() ? request.profileCurve()->clone() : nullptr )
683 , mTerrainProvider( request.terrainProvider() ? request.terrainProvider()->clone() : nullptr )
684 , mTolerance( request.tolerance() )
685 , mSourceCrs( layer->crs3D() )
686 , mTargetCrs( request.crs() )
687 , mTransformContext( request.transformContext() )
688 , mExtent( layer->extent() )
690 , mOffset( layer->elevationProperties()->zOffset() )
691 , mScale( layer->elevationProperties()->zScale() )
699 , mExpressionContext( request.expressionContext() )
700 , mFields( layer->fields() )
701 , mDataDefinedProperties( layer->elevationProperties()->dataDefinedProperties() )
702 , mWkbType( layer->wkbType() )
708 if ( mTerrainProvider )
709 mTerrainProvider->prepare();
713 mProfileCurve->dropZValue();
736 if ( !mProfileCurve || mFeedback->isCanceled() )
746 std::unique_ptr< QgsCurve > origCurve = std::move( mProfileCurve );
747 std::unique_ptr< QgsVectorLayerProfileResults > totalResults;
748 double distanceProcessed = 0;
750 QVector<QgsLineString *> disjointParts = profileLine->splitToDisjointXYParts();
751 for (
int i = 0; i < disjointParts.size(); i++ )
753 mProfileCurve.reset( disjointParts[i] );
754 if ( !generateProfileInner() )
756 mProfileCurve = std::move( origCurve );
759 for (
int j = i + 1; j < disjointParts.size(); j++ )
760 delete disjointParts[j];
767 totalResults = std::move( mResults );
771 totalResults->mRawPoints.append( mResults->mRawPoints );
772 totalResults->minZ = std::min( totalResults->minZ, mResults->minZ );
773 totalResults->maxZ = std::max( totalResults->maxZ, mResults->maxZ );
774 for (
auto it = mResults->mDistanceToHeightMap.constKeyValueBegin();
775 it != mResults->mDistanceToHeightMap.constKeyValueEnd();
778 totalResults->mDistanceToHeightMap[it->first + distanceProcessed] = it->second;
780 for (
auto it = mResults->features.constKeyValueBegin();
781 it != mResults->features.constKeyValueEnd();
787 totalResults->features[it->first].push_back( feature );
792 distanceProcessed += mProfileCurve->length();
795 mProfileCurve = std::move( origCurve );
796 mResults = std::move( totalResults );
800 return generateProfileInner();
808 if ( mTerrainProvider )
809 mTargetToTerrainProviderTransform =
QgsCoordinateTransform( mTargetCrs, mTerrainProvider->crs(), mTransformContext );
815 catch ( QgsCsException & )
817 QgsDebugError( u
"Error transforming profile line to vector CRS"_s );
821 const QgsRectangle profileCurveBoundingBox = mTransformedCurve->boundingBox();
822 if ( !profileCurveBoundingBox.
intersects( mExtent ) )
825 if ( mFeedback->isCanceled() )
828 mResults = std::make_unique< QgsVectorLayerProfileResults >();
829 mResults->mLayer = mLayer;
830 mResults->copyPropertiesFromGenerator(
this );
832 mProfileCurveEngine = std::make_unique<QgsGeos>( mProfileCurve.get() );
833 mProfileCurveEngine->prepareGeometry();
835 if ( tolerance() == 0.0 )
837 mProfileBufferedCurve = std::unique_ptr<QgsAbstractGeometry>( mProfileCurve->clone() );
844 mProfileBufferedCurveEngine = std::make_unique<QgsGeos>( mProfileBufferedCurve.get() );
845 mProfileBufferedCurveEngine->prepareGeometry();
847 mDataDefinedProperties.prepare( mExpressionContext );
849 if ( mFeedback->isCanceled() )
855 if ( !generateProfileForPoints() )
860 if ( !generateProfileForLines() )
865 if ( !generateProfileForPolygons() )
879 return mResults.release();
884 return mFeedback.get();
887bool QgsVectorLayerProfileGenerator::generateProfileForPoints()
902 while ( !mFeedback->isCanceled() && it.
nextFeature( feature ) )
909 if ( mProfileBufferedCurveEngine->intersects( *it ) )
915 return !mFeedback->isCanceled();
918void QgsVectorLayerProfileGenerator::processIntersectionPoint(
const QgsPoint *point,
const QgsFeature &feature )
923 const double height = featureZToHeight( point->
x(), point->
y(), point->
z(), offset );
924 mResults->mRawPoints.append( QgsPoint( point->
x(), point->
y(), height ) );
925 mResults->minZ = std::min( mResults->minZ, height );
926 mResults->maxZ = std::max( mResults->maxZ, height );
928 const double distanceAlongProfileCurve = mProfileCurveEngine->lineLocatePoint( *point, &error );
929 mResults->mDistanceToHeightMap.insert( distanceAlongProfileCurve, height );
931 QgsVectorLayerProfileResults::Feature resultFeature;
933 if ( mExtrusionEnabled )
937 resultFeature.
geometry = QgsGeometry(
new QgsLineString( QgsPoint( point->
x(), point->
y(), height ),
938 QgsPoint( point->
x(), point->
y(), height + extrusion ) ) );
939 resultFeature.
crossSectionGeometry = QgsGeometry(
new QgsLineString( QgsPoint( distanceAlongProfileCurve, height ),
940 QgsPoint( distanceAlongProfileCurve, height + extrusion ) ) );
941 mResults->minZ = std::min( mResults->minZ, height + extrusion );
942 mResults->maxZ = std::max( mResults->maxZ, height + extrusion );
946 resultFeature.
geometry = QgsGeometry(
new QgsPoint( point->
x(), point->
y(), height ) );
947 resultFeature.
crossSectionGeometry = QgsGeometry(
new QgsPoint( distanceAlongProfileCurve, height ) );
950 mResults->features[resultFeature.
featureId].append( resultFeature );
953void QgsVectorLayerProfileGenerator::processIntersectionCurve(
const QgsLineString *intersectionCurve,
const QgsFeature &feature )
957 QgsVectorLayerProfileResults::Feature resultFeature;
959 double maxDistanceAlongProfileCurve = std::numeric_limits<double>::lowest();
964 const int numPoints = intersectionCurve->
numPoints();
965 QVector< double > newX( numPoints );
966 QVector< double > newY( numPoints );
967 QVector< double > newZ( numPoints );
968 QVector< double > newDistance( numPoints );
970 const double *inX = intersectionCurve->
xData();
971 const double *inY = intersectionCurve->
yData();
972 const double *inZ = intersectionCurve->
is3D() ? intersectionCurve->
zData() :
nullptr;
973 double *outX = newX.data();
974 double *outY = newY.data();
975 double *outZ = newZ.data();
976 double *outDistance = newDistance.data();
978 QVector< double > extrudedZ;
979 double *extZOut =
nullptr;
980 if ( mExtrusionEnabled )
982 extrudedZ.resize( numPoints );
983 extZOut = extrudedZ.data();
986 for (
int i = 0 ; ! mFeedback->isCanceled() && i < numPoints; ++i )
988 QgsPoint intersectionPoint( *inX, *inY, ( inZ ? *inZ : std::numeric_limits<double>::quiet_NaN() ) );
990 const double height = featureZToHeight( intersectionPoint.x(), intersectionPoint.y(), intersectionPoint.z(), offset );
991 const double distanceAlongProfileCurve = mProfileCurveEngine->lineLocatePoint( intersectionPoint, &error );
993 maxDistanceAlongProfileCurve = std::max( maxDistanceAlongProfileCurve, distanceAlongProfileCurve );
995 mResults->mRawPoints.append( QgsPoint( intersectionPoint.x(), intersectionPoint.y(), height ) );
996 mResults->minZ = std::min( mResults->minZ, height );
997 mResults->maxZ = std::max( mResults->maxZ, height );
999 mResults->mDistanceToHeightMap.insert( distanceAlongProfileCurve, height );
1000 *outDistance++ = distanceAlongProfileCurve;
1002 *outX++ = intersectionPoint.x();
1003 *outY++ = intersectionPoint.y();
1006 *extZOut++ = height + extrusion;
1008 if ( mExtrusionEnabled )
1010 mResults->minZ = std::min( mResults->minZ, height + extrusion );
1011 mResults->maxZ = std::max( mResults->maxZ, height + extrusion );
1019 mResults->mDistanceToHeightMap.insert( maxDistanceAlongProfileCurve + 0.000001, std::numeric_limits<double>::quiet_NaN() );
1021 if ( mFeedback->isCanceled() )
1025 if ( mExtrusionEnabled )
1027 auto ring = std::make_unique< QgsLineString >( newX, newY, newZ );
1028 auto extrudedRing = std::make_unique< QgsLineString >( newX, newY, extrudedZ );
1029 std::unique_ptr< QgsLineString > reversedExtrusion( extrudedRing->reversed() );
1030 ring->append( reversedExtrusion.get() );
1032 resultFeature.
geometry = QgsGeometry(
new QgsPolygon( ring.release() ) );
1034 auto distanceVHeightRing = std::make_unique< QgsLineString >( newDistance, newZ );
1035 auto extrudedDistanceVHeightRing = std::make_unique< QgsLineString >( newDistance, extrudedZ );
1036 std::unique_ptr< QgsLineString > reversedDistanceVHeightExtrusion( extrudedDistanceVHeightRing->reversed() );
1037 distanceVHeightRing->append( reversedDistanceVHeightExtrusion.get() );
1038 distanceVHeightRing->close();
1039 resultFeature.
crossSectionGeometry = QgsGeometry(
new QgsPolygon( distanceVHeightRing.release() ) );
1043 resultFeature.
geometry = QgsGeometry(
new QgsLineString( newX, newY, newZ ) ) ;
1047 mResults->features[resultFeature.
featureId].append( resultFeature );
1050bool QgsVectorLayerProfileGenerator::generateProfileForLines()
1053 QgsFeatureRequest request;
1055 if ( tolerance() > 0 )
1057 request.
setDistanceWithin( QgsGeometry( mProfileCurve->clone() ), tolerance() );
1063 request.
setSubsetOfAttributes( mDataDefinedProperties.referencedFields( mExpressionContext ), mFields );
1066 auto processCurve = [
this](
const QgsFeature & feature,
const QgsCurve * featGeomPart )
1069 std::unique_ptr< QgsAbstractGeometry > intersection( mProfileBufferedCurveEngine->intersection( featGeomPart, &error ) );
1070 if ( !intersection )
1073 if ( mFeedback->isCanceled() )
1078 if ( intersection->isEmpty() )
1080 intersection.reset( featGeomPart->clone() );
1083 QgsGeos featGeomPartGeos( featGeomPart );
1084 featGeomPartGeos.prepareGeometry();
1086 for (
auto it = intersection->const_parts_begin();
1087 !mFeedback->isCanceled() && it != intersection->const_parts_end();
1094 const double distance = featGeomPartGeos.lineLocatePoint( *intersectionPoint, &error );
1095 std::unique_ptr< QgsPoint > interpolatedPoint( featGeomPart->interpolatePoint( distance ) );
1097 processIntersectionPoint( interpolatedPoint.get(), feature );
1101 processIntersectionCurve( intersectionCurve, feature );
1107 QgsFeatureIterator it = mSource->getFeatures( request );
1108 while ( !mFeedback->isCanceled() && it.
nextFeature( feature ) )
1110 mExpressionContext.setFeature( feature );
1112 const QgsGeometry g = feature.
geometry();
1115 if ( mProfileBufferedCurveEngine->intersects( *it ) )
1122 return !mFeedback->isCanceled();
1125QgsPoint QgsVectorLayerProfileGenerator::interpolatePointOnTriangle(
const QgsPolygon *triangle,
double x,
double y )
const
1127 QgsPoint p1, p2, p3;
1132 const double z = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, p1.
z(), p2.
z(), p3.
z(), QgsPointXY( x, y ) );
1133 return QgsPoint( x, y, z );
1136void QgsVectorLayerProfileGenerator::processTriangleIntersectForPoint(
const QgsPolygon *triangle,
const QgsPoint *p, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts )
1138 const QgsPoint interpolatedPoint = interpolatePointOnTriangle( triangle, p->
x(), p->
y() );
1139 mResults->mRawPoints.append( interpolatedPoint );
1140 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() );
1141 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() );
1144 const double distance = mProfileCurveEngine->lineLocatePoint( *p, &lastError );
1145 mResults->mDistanceToHeightMap.insert( distance, interpolatedPoint.
z() );
1147 if ( mExtrusionEnabled )
1151 transformedParts.append( QgsGeometry(
new QgsLineString( interpolatedPoint,
1152 QgsPoint( interpolatedPoint.
x(), interpolatedPoint.
y(), interpolatedPoint.
z() + extrusion ) ) ) );
1153 crossSectionParts.append( QgsGeometry(
new QgsLineString( QgsPoint( distance, interpolatedPoint.
z() ),
1154 QgsPoint( distance, interpolatedPoint.
z() + extrusion ) ) ) );
1155 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() + extrusion );
1156 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() + extrusion );
1160 transformedParts.append( QgsGeometry(
new QgsPoint( interpolatedPoint ) ) );
1161 crossSectionParts.append( QgsGeometry(
new QgsPoint( distance, interpolatedPoint.
z() ) ) );
1165void QgsVectorLayerProfileGenerator::processTriangleIntersectForLine(
const QgsPolygon *triangle,
const QgsLineString *intersectionLine, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts )
1170 int numPoints = intersectionLine->
numPoints();
1171 QVector< double > newX( numPoints );
1172 QVector< double > newY( numPoints );
1173 QVector< double > newZ( numPoints );
1174 QVector< double > newDistance( numPoints );
1176 const double *inX = intersectionLine->
xData();
1177 const double *inY = intersectionLine->
yData();
1178 const double *inZ = intersectionLine->
is3D() ? intersectionLine->
zData() :
nullptr;
1179 double *outX = newX.data();
1180 double *outY = newY.data();
1181 double *outZ = newZ.data();
1182 double *outDistance = newDistance.data();
1184 double lastDistanceAlongProfileCurve = 0.0;
1185 QVector< double > extrudedZ;
1186 double *extZOut =
nullptr;
1187 double extrusion = 0;
1189 if ( mExtrusionEnabled )
1191 extrudedZ.resize( numPoints );
1192 extZOut = extrudedZ.data();
1198 for (
int i = 0 ; ! mFeedback->isCanceled() && i < numPoints; ++i )
1202 double z = inZ ? *inZ++ : 0;
1204 QgsPoint interpolatedPoint( x, y, z );
1210 interpolatedPoint = interpolatePointOnTriangle( triangle, x, y );
1212 double tempOutZ = std::isnan( interpolatedPoint.
z() ) ? 0.0 : interpolatedPoint.
z();
1215 if ( mExtrusionEnabled )
1216 *extZOut++ = tempOutZ + extrusion;
1218 mResults->mRawPoints.append( interpolatedPoint );
1219 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() );
1220 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() );
1221 if ( mExtrusionEnabled )
1223 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() + extrusion );
1224 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() + extrusion );
1227 const double distance = mProfileCurveEngine->lineLocatePoint( interpolatedPoint, &lastError );
1228 *outDistance++ = distance;
1230 mResults->mDistanceToHeightMap.insert( distance, interpolatedPoint.
z() );
1231 lastDistanceAlongProfileCurve = distance;
1235 mResults->mDistanceToHeightMap.insert( lastDistanceAlongProfileCurve + 0.000001, std::numeric_limits<double>::quiet_NaN() );
1237 if ( mFeedback->isCanceled() )
1240 if ( mExtrusionEnabled )
1242 auto ring = std::make_unique< QgsLineString >( newX, newY, newZ );
1243 auto extrudedRing = std::make_unique< QgsLineString >( newX, newY, extrudedZ );
1244 std::unique_ptr< QgsLineString > reversedExtrusion( extrudedRing->reversed() );
1245 ring->append( reversedExtrusion.get() );
1247 transformedParts.append( QgsGeometry(
new QgsPolygon( ring.release() ) ) );
1249 auto distanceVHeightRing = std::make_unique< QgsLineString >( newDistance, newZ );
1250 auto extrudedDistanceVHeightRing = std::make_unique< QgsLineString >( newDistance, extrudedZ );
1251 std::unique_ptr< QgsLineString > reversedDistanceVHeightExtrusion( extrudedDistanceVHeightRing->reversed() );
1252 distanceVHeightRing->append( reversedDistanceVHeightExtrusion.get() );
1253 distanceVHeightRing->close();
1254 crossSectionParts.append( QgsGeometry(
new QgsPolygon( distanceVHeightRing.release() ) ) );
1258 transformedParts.append( QgsGeometry(
new QgsLineString( newX, newY, newZ ) ) );
1259 crossSectionParts.append( QgsGeometry(
new QgsLineString( newDistance, newZ ) ) );
1263void QgsVectorLayerProfileGenerator::processTriangleIntersectForPolygon(
const QgsPolygon *sourcePolygon,
const QgsPolygon *intersectionPolygon, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts )
1265 bool oldExtrusion = mExtrusionEnabled;
1298 mExtrusionEnabled =
false;
1299 if ( mProfileBufferedCurveEngine->contains( sourcePolygon ) )
1301 if (
const QgsCurve *exterior = sourcePolygon->
exteriorRing() )
1304 processTriangleIntersectForLine( sourcePolygon, exteriorLine, transformedParts, crossSectionParts );
1309 processTriangleIntersectForLine( sourcePolygon, interiorLine, transformedParts, crossSectionParts );
1315 if (
const QgsCurve *exterior = intersectionPolygon->
exteriorRing() )
1319 processTriangleIntersectForLine( sourcePolygon, exteriorLine, transformedParts, crossSectionParts );
1320 delete exteriorLine;
1325 if ( mProfileBufferedCurveEngine->contains( interiorLine ) )
1327 processTriangleIntersectForLine( sourcePolygon, interiorLine, transformedParts, crossSectionParts );
1332 newInteriorLine->deleteVertex( QgsVertexId( 0, 0, interiorLine->
numPoints() - 1 ) );
1333 processTriangleIntersectForLine( sourcePolygon, newInteriorLine.get(), transformedParts, crossSectionParts );
1338 mExtrusionEnabled = oldExtrusion;
1341bool QgsVectorLayerProfileGenerator::generateProfileForPolygons()
1344 QgsFeatureRequest request;
1346 if ( tolerance() > 0 )
1348 request.
setDistanceWithin( QgsGeometry( mProfileCurve->clone() ), tolerance() );
1354 request.
setSubsetOfAttributes( mDataDefinedProperties.referencedFields( mExpressionContext ), mFields );
1357 std::function< void(
const QgsPolygon *triangle,
const QgsAbstractGeometry *intersect, QVector< QgsGeometry > &, QVector< QgsGeometry > & ) > processTriangleLineIntersect;
1358 processTriangleLineIntersect = [
this](
const QgsPolygon * triangle,
const QgsAbstractGeometry * intersection, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts )
1360 for (
auto it = intersection->const_parts_begin();
1361 ! mFeedback->isCanceled() && it != intersection->const_parts_end();
1370 processTriangleIntersectForPoint( triangle, p, transformedParts, crossSectionParts );
1377 processTriangleIntersectForLine( triangle, intersectionLine, transformedParts, crossSectionParts );
1384 processTriangleIntersectForPolygon( triangle, poly, transformedParts, crossSectionParts );
1395 auto triangleIsCollinearInXYPlane = [](
const QgsPolygon * polygon )->
bool
1399 ring->
xAt( 1 ), ring->
yAt( 1 ),
1400 ring->
xAt( 2 ), ring->
yAt( 2 ), 0.005 );
1403 auto processPolygon = [
this, &processTriangleLineIntersect, &triangleIsCollinearInXYPlane](
const QgsCurvePolygon * polygon, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts,
double offset,
bool & wasCollinear )
1405 std::unique_ptr< QgsPolygon > clampedPolygon;
1408 clampedPolygon.reset( p->
clone() );
1414 clampAltitudes( clampedPolygon.get(), offset );
1416 if ( mFeedback->isCanceled() )
1419 if ( tolerance() > 0.0 )
1422 if ( mProfileBufferedCurveEngine->intersects( clampedPolygon.get(), &error ) )
1424 std::unique_ptr< QgsAbstractGeometry > intersection;
1425 intersection.reset( mProfileBufferedCurveEngine->intersection( clampedPolygon.get(), &error ) );
1426 if ( error.isEmpty() )
1428 processTriangleLineIntersect( clampedPolygon.get(), intersection.get(), transformedParts, crossSectionParts );
1437 QVector< double > newX( numPoints );
1438 QVector< double > newY( numPoints );
1439 QVector< double > newZ( numPoints );
1440 double *outX = newX.data();
1441 double *outY = newY.data();
1442 double *outZ = newZ.data();
1444 const double *inX = ring->
xData();
1445 const double *inY = ring->
yData();
1446 const double *inZ = ring->
zData();
1447 for (
int i = 0 ; ! mFeedback->isCanceled() && i < ring->numPoints() - 1; ++i )
1449 *outX++ = inX[i] + i * 1.0e-9;
1450 *outY++ = inY[i] + i * 1.0e-9;
1453 std::unique_ptr< QgsPolygon > shiftedPoly;
1454 shiftedPoly = std::make_unique<QgsPolygon>(
new QgsLineString( newX, newY, newZ ) );
1456 intersection.reset( mProfileBufferedCurveEngine->intersection( shiftedPoly.get(), &error ) );
1458 processTriangleLineIntersect( clampedPolygon.get(), intersection.get(), transformedParts, crossSectionParts );
1462 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();
1488 if ( mFeedback->isCanceled() )
1496 for (
int i = 0; ! mFeedback->isCanceled() && i < numTriangles; ++i )
1500 if ( triangleIsCollinearInXYPlane( triangle ) )
1502 wasCollinear =
true;
1508 for (
int curveSegmentIndex = 0; curveSegmentIndex < mProfileCurve->numPoints() - 1; ++curveSegmentIndex )
1510 const QgsPoint p1 = ls->pointN( curveSegmentIndex );
1511 const QgsPoint p2 = ls->pointN( curveSegmentIndex + 1 );
1513 QgsPoint intersectionPoint;
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;
1523 const double intersectionZ = ring->
zAt( vertexPair.first ) + ( ring->
zAt( vertexPair.second ) - ring->
zAt( vertexPair.first ) ) * fraction;
1524 minZ = std::min( minZ, intersectionZ );
1525 maxZ = std::max( maxZ, intersectionZ );
1529 if ( !intersectionPoint.
isEmpty() )
1532 mResults->mRawPoints.append( intersectionPoint );
1533 mResults->minZ = std::min( mResults->minZ, minZ );
1534 mResults->maxZ = std::max( mResults->maxZ, maxZ );
1536 const double distance = mProfileCurveEngine->lineLocatePoint( intersectionPoint, &lastError );
1538 crossSectionParts.append( QgsGeometry(
new QgsLineString( QVector< double > {distance, distance}, QVector< double > {minZ, maxZ} ) ) );
1540 mResults->mDistanceToHeightMap.insert( distance, minZ );
1541 mResults->mDistanceToHeightMap.insert( distance, maxZ );
1548 QgsDebugError( u
"Collinear triangles with curved profile lines are not supported yet"_s );
1554 if ( mProfileBufferedCurveEngine->intersects( triangle, &error ) )
1556 std::unique_ptr< QgsAbstractGeometry > intersection( mProfileBufferedCurveEngine->intersection( triangle, &error ) );
1557 processTriangleLineIntersect( triangle, intersection.get(), transformedParts, crossSectionParts );
1566 QgsFeatureIterator it = mSource->getFeatures( request );
1567 while ( ! mFeedback->isCanceled() && it.
nextFeature( feature ) )
1569 if ( !mProfileBufferedCurveEngine->intersects( feature.
geometry().
constGet() ) )
1572 mExpressionContext.setFeature( feature );
1575 const QgsGeometry g = feature.
geometry();
1576 QVector< QgsGeometry > transformedParts;
1577 QVector< QgsGeometry > crossSectionParts;
1578 bool wasCollinear =
false;
1583 if ( mProfileBufferedCurveEngine->intersects( *it ) )
1587 processPolygon( curvePolygon, transformedParts, crossSectionParts, offset, wasCollinear );
1591 for (
int i = 0; i < polySurface->numPatches(); ++i )
1593 const QgsPolygon *polygon = polySurface->patchN( i );
1594 if ( mProfileBufferedCurveEngine->intersects( polygon ) )
1596 processPolygon( polygon, transformedParts, crossSectionParts, offset, wasCollinear );
1602 QgsDebugError( u
"Unhandled Geometry type: %1"_s.arg( ( *it )->wktTypeStr() ) );
1607 if ( mFeedback->isCanceled() )
1611 QgsVectorLayerProfileResults::Feature resultFeature;
1614 if ( !crossSectionParts.empty() )
1616 if ( !wasCollinear )
1618 QgsGeometry unioned = QgsGeometry::unaryUnion( crossSectionParts );
1619 if ( unioned.isEmpty() )
1621 resultFeature.crossSectionGeometry = QgsGeometry::collectGeometry( crossSectionParts );
1625 if ( unioned.type() == Qgis::GeometryType::Line )
1627 unioned = unioned.mergeLines();
1629 resultFeature.crossSectionGeometry = unioned;
1634 resultFeature.crossSectionGeometry = QgsGeometry::collectGeometry( crossSectionParts );
1637 mResults->features[resultFeature.
featureId].append( resultFeature );
1642double QgsVectorLayerProfileGenerator::tolerance()
const
1644 return mCustomToleranceEnabled ? mCustomTolerance : mTolerance;
1647double QgsVectorLayerProfileGenerator::terrainHeight(
double x,
double y )
const
1649 if ( !mTerrainProvider )
1650 return std::numeric_limits<double>::quiet_NaN();
1656 mTargetToTerrainProviderTransform.transformInPlace( x, y, dummyZ );
1658 catch ( QgsCsException & )
1660 return std::numeric_limits<double>::quiet_NaN();
1663 return mTerrainProvider->heightAt( x, y );
1666double QgsVectorLayerProfileGenerator::featureZToHeight(
double x,
double y,
double z,
double offset )
const
1668 switch ( mClamping )
1676 const double terrainZ = terrainHeight( x, y );
1677 if ( !std::isnan( terrainZ ) )
1679 switch ( mClamping )
1682 if ( std::isnan( z ) )
1700 return ( std::isnan( z ) ? 0 : z ) * mScale + offset;
1703void QgsVectorLayerProfileGenerator::clampAltitudes(
QgsLineString *lineString,
const QgsPoint ¢roid,
double offset )
const
1707 if ( mFeedback->isCanceled() )
1710 double terrainZ = 0;
1711 switch ( mClamping )
1720 pt.
setX( lineString->
xAt( i ) );
1721 pt.
setY( lineString->
yAt( i ) );
1725 pt.
set( centroid.
x(), centroid.
y() );
1729 terrainZ = terrainHeight( pt.
x(), pt.
y() );
1739 switch ( mClamping )
1743 geomZ = lineString->
zAt( i );
1750 const double z = ( terrainZ + ( std::isnan( geomZ ) ? 0 : geomZ ) ) * mScale + offset;
1751 lineString->
setZAt( i, z );
1755bool QgsVectorLayerProfileGenerator::clampAltitudes(
QgsPolygon *polygon,
double offset )
const
1757 if ( !polygon->
is3D() )
1771 QgsCurve *curve =
const_cast<QgsCurve *
>( polygon->
exteriorRing() );
1776 clampAltitudes( lineString, centroid, offset );
1780 if ( mFeedback->isCanceled() )
1783 QgsCurve *curve =
const_cast<QgsCurve *
>( polygon->
interiorRing( i ) );
1788 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.
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.