48 return QStringLiteral(
"vector" );
53 QVector<QgsGeometry> res;
57 for (
const Feature &feature : it.value() )
59 res.append( feature.geometry );
71 return asIndividualFeatures(
type, feedback );
86 return snapPointToIndividualFeatures( point, context );
102 visitFeaturesInRange( distanceRange, elevationRange, visitFeature );
106 QVector< QVariantMap> idsList;
107 for (
auto it = ids.constBegin(); it != ids.constEnd(); ++it )
108 idsList.append( QVariantMap( {{QStringLiteral(
"id" ), *it}} ) );
115 QHash< QgsFeatureId, QVariantMap >
features;
116 auto visitFeature = [&
features](
QgsFeatureId featureId,
double delta,
double distance,
double elevation )
118 auto it =
features.find( featureId );
121 features[ featureId ] = QVariantMap( {{QStringLiteral(
"id" ), featureId },
122 {QStringLiteral(
"delta" ), delta },
123 {QStringLiteral(
"distance" ), distance },
124 {QStringLiteral(
"elevation" ), elevation }
129 const double currentDelta = it.value().value( QStringLiteral(
"delta" ) ).toDouble();
130 if ( delta < currentDelta )
132 *it = QVariantMap( {{QStringLiteral(
"id" ), featureId },
133 {QStringLiteral(
"delta" ), delta },
134 {QStringLiteral(
"distance" ), distance },
135 {QStringLiteral(
"elevation" ), elevation }
143 QVector< QVariantMap> attributes;
145 attributes.append( *it );
147 QVector<QgsProfileIdentifyResults> res;
149 if ( !attributes.empty() )
155 res.reserve( surfaceResults.size() );
168 double bestSnapDistance = std::numeric_limits< double >::max();
170 auto visitFeature = [&bestSnapDistance, &res](
QgsFeatureId,
double delta,
double distance,
double elevation )
172 if ( distance < bestSnapDistance )
174 bestSnapDistance = delta;
184void 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
192 for (
const Feature &feature : it.value() )
194 const QgsRectangle featureBounds = feature.crossSectionGeometry.boundingBox();
195 if ( ( featureBounds.
xMinimum() - maximumPointDistanceDelta <= point.
distance() ) && ( featureBounds.
xMaximum() + maximumPointDistanceDelta >= point.
distance() ) )
197 switch ( feature.crossSectionGeometry.type() )
201 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
203 if (
const QgsPoint *candidatePoint = qgsgeometry_cast< const QgsPoint * >( *partIt ) )
205 const double snapDistanceDelta = std::fabs( point.
distance() - candidatePoint->x() );
206 if ( snapDistanceDelta > maximumPointDistanceDelta )
209 const double snapHeightDelta = std::fabs( point.
elevation() - candidatePoint->y() );
210 if ( snapHeightDelta > maximumPointElevationDelta )
213 const double snapDistance = candidatePoint->distance( targetPoint );
214 visitor( feature.featureId, snapDistance, candidatePoint->x(), candidatePoint->y() );
222 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
224 if (
const QgsCurve *line = qgsgeometry_cast< const QgsCurve * >( *partIt ) )
227 if (
const QgsLineString *lineString = qgsgeometry_cast< const QgsLineString * >( line ) )
229 if ( lineString->numPoints() == 2 &&
qgsDoubleNear( lineString->pointN( 0 ).x(), lineString->pointN( 1 ).x() ) )
231 const double snapDistanceDelta = std::fabs( point.
distance() - lineString->pointN( 0 ).x() );
232 if ( snapDistanceDelta > maximumPointDistanceDelta )
235 const double snapHeightDelta = std::fabs( point.
elevation() - lineString->pointN( 0 ).y() );
236 if ( snapHeightDelta <= maximumPointElevationDelta )
238 const double snapDistanceP1 = lineString->pointN( 0 ).distance( targetPoint );
239 visitor( feature.featureId, snapDistanceP1, lineString->pointN( 0 ).x(), lineString->pointN( 0 ).y() );
242 const double snapHeightDelta2 = std::fabs( point.
elevation() - lineString->pointN( 1 ).y() );
243 if ( snapHeightDelta2 <= maximumPointElevationDelta )
245 const double snapDistanceP2 = lineString->pointN( 1 ).distance( targetPoint );
246 visitor( feature.featureId, snapDistanceP2, lineString->pointN( 1 ).x(), lineString->pointN( 1 ).y() );
251 double elevation1 = lineString->pointN( 0 ).y();
252 double elevation2 = lineString->pointN( 1 ).y();
253 if ( elevation1 > elevation2 )
254 std::swap( elevation1, elevation2 );
258 const double snapDistance = std::fabs( lineString->pointN( 0 ).x() - point.
distance() );
259 visitor( feature.featureId, snapDistance, lineString->pointN( 0 ).x(), point.
elevation() );
266 const QgsRectangle partBounds = ( *partIt )->boundingBox();
276 const QgsGeometry points( cutLineGeos.intersection( line ) );
278 for (
auto vertexIt = points.vertices_begin(); vertexIt != points.vertices_end(); ++vertexIt )
280 const double snapHeightDelta = std::fabs( point.
elevation() - ( *vertexIt ).y() );
281 if ( snapHeightDelta > maximumSurfaceElevationDelta )
284 const double snapDistance = ( *vertexIt ).distance( targetPoint );
285 visitor( feature.featureId, snapDistance, ( *vertexIt ).x(), ( *vertexIt ).y() );
302 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
304 if (
const QgsCurve *exterior = qgsgeometry_cast< const QgsPolygon * >( *partIt )->exteriorRing() )
306 const QgsRectangle partBounds = ( *partIt )->boundingBox();
316 const QgsGeometry points( cutLineGeos.intersection( exterior ) );
317 for (
auto vertexIt = points.vertices_begin(); vertexIt != points.vertices_end(); ++vertexIt )
319 const double snapHeightDelta = std::fabs( point.
elevation() - ( *vertexIt ).y() );
320 if ( snapHeightDelta > maximumSurfaceElevationDelta )
323 const double snapDistance = ( *vertexIt ).distance( targetPoint );
324 visitor( feature.featureId, snapDistance, ( *vertexIt ).x(), ( *vertexIt ).y() );
345 profileRangeGeos.prepareGeometry();
349 for (
const Feature &feature : it.value() )
351 if ( feature.crossSectionGeometry.boundingBoxIntersects( profileRange ) )
353 switch ( feature.crossSectionGeometry.type() )
357 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
359 if (
const QgsPoint *candidatePoint = qgsgeometry_cast< const QgsPoint * >( *partIt ) )
361 if ( profileRange.contains( candidatePoint->x(), candidatePoint->y() ) )
363 visitor( feature.featureId );
373 if ( profileRangeGeos.intersects( feature.crossSectionGeometry.constGet() ) )
375 visitor( feature.featureId );
395 renderResultsAsIndividualFeatures( context );
400 renderMarkersOverContinuousSurfacePlot( context );
413 painter->setBrush( Qt::NoBrush );
414 painter->setPen( Qt::NoPen );
421 const QRectF visibleRegion( minDistance,
minZ, maxDistance - minDistance,
maxZ -
minZ );
422 QPainterPath clipPath;
423 clipPath.addPolygon( context.
worldTransform().map( visibleRegion ) );
424 painter->setClipPath( clipPath, Qt::ClipOperation::IntersectClip );
426 const QgsRectangle clipPathRect( clipPath.boundingRect() );
430 if ( profileFeature.crossSectionGeometry.isEmpty() )
433 QgsGeometry transformed = profileFeature.crossSectionGeometry;
440 switch ( transformed.
type() )
444 if (
const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( transformed.
constGet() ) )
446 markerSymbol->renderPoint( QPointF( point->x(), point->y() ),
nullptr, context.
renderContext() );
448 else if (
const QgsMultiPoint *multipoint = qgsgeometry_cast< const QgsMultiPoint * >( transformed.
constGet() ) )
450 const int numGeometries = multipoint->numGeometries();
451 for (
int i = 0; i < numGeometries; ++i )
453 markerSymbol->renderPoint( QPointF( multipoint->pointN( i )->x(), multipoint->pointN( i )->y() ),
nullptr, context.
renderContext() );
461 if (
const QgsLineString *line = qgsgeometry_cast< const QgsLineString * >( transformed.
constGet() ) )
463 lineSymbol->renderPolyline( line->asQPolygonF(),
nullptr, context.
renderContext() );
465 else if (
const QgsMultiLineString *multiLinestring = qgsgeometry_cast< const QgsMultiLineString * >( transformed.
constGet() ) )
467 const int numGeometries = multiLinestring->numGeometries();
468 for (
int i = 0; i < numGeometries; ++i )
470 lineSymbol->renderPolyline( multiLinestring->lineStringN( i )->asQPolygonF(),
nullptr, context.
renderContext() );
478 if (
const QgsPolygon *polygon = qgsgeometry_cast< const QgsPolygon * >( transformed.
constGet() ) )
480 if (
const QgsCurve *exterior = polygon->exteriorRing() )
481 fillSymbol->renderPolygon( exterior->asQPolygonF(),
nullptr,
nullptr, context.
renderContext() );
483 else if (
const QgsMultiPolygon *multiPolygon = qgsgeometry_cast< const QgsMultiPolygon * >( transformed.
constGet() ) )
485 const int numGeometries = multiPolygon->numGeometries();
486 for (
int i = 0; i < numGeometries; ++i )
488 fillSymbol->renderPolygon( multiPolygon->polygonN( i )->exteriorRing()->asQPolygonF(),
nullptr,
nullptr, context.
renderContext() );
505 std::unique_ptr< QgsFeatureRenderer > renderer(
mLayer->renderer()->clone() );
510 QSet<QString> attributes = renderer->usedAttributes( context.
renderContext() );
512 std::unique_ptr< QgsMarkerSymbol > marker(
mMarkerSymbol->clone() );
513 std::unique_ptr< QgsLineSymbol > line(
mLineSymbol->clone() );
514 std::unique_ptr< QgsFillSymbol > fill(
mFillSymbol->clone() );
515 attributes.unite( marker->usedAttributes( context.
renderContext() ) );
516 attributes.unite( line->usedAttributes( context.
renderContext() ) );
517 attributes.unite( fill->usedAttributes( context.
renderContext() ) );
527 if ( !rendererSymbol )
531 marker->setOpacity( rendererSymbol->
opacity() );
532 line->setColor( rendererSymbol->
color() );
533 line->setOpacity( rendererSymbol->
opacity() );
534 fill->setColor( rendererSymbol->
color() );
535 fill->setOpacity( rendererSymbol->
opacity() );
541 const QVector< Feature > profileFeatures =
features.value( feature.
id() );
542 for (
const Feature &profileFeature : profileFeatures )
544 renderResult( profileFeature,
546 rendererSymbol->
type() ==
Qgis::SymbolType::Line ? qgis::down_cast<
QgsLineSymbol * >( rendererSymbol ) : line.get(),
547 rendererSymbol->
type() ==
Qgis::SymbolType::Fill ? qgis::down_cast<
QgsFillSymbol * >( rendererSymbol ) : fill.get() );
559 QSet<QString> attributes;
574 const QVector< Feature > profileFeatures =
features.value( feature.
id() );
575 for (
const Feature &profileFeature : profileFeatures )
594 painter->setBrush( Qt::NoBrush );
595 painter->setPen( Qt::NoPen );
602 const QRectF visibleRegion( minDistance,
minZ, maxDistance - minDistance,
maxZ -
minZ );
603 QPainterPath clipPath;
604 clipPath.addPolygon( context.
worldTransform().map( visibleRegion ) );
605 painter->setClipPath( clipPath, Qt::ClipOperation::IntersectClip );
611 if ( std::isnan( pointIt.value() ) )
621 QVector<QgsAbstractProfileResults::Feature> res;
628 for (
const Feature &feature : it.value() )
635 outFeature.
attributes = {{QStringLiteral(
"id" ), feature.featureId }};
643 outFeature.
geometry = feature.crossSectionGeometry;
660 mId = vlGenerator->mId;
663 mMarkerSymbol.reset( vlGenerator->mProfileMarkerSymbol->clone() );
675 , mProfileCurve( request.profileCurve() ? request.profileCurve()->clone() : nullptr )
676 , mTerrainProvider( request.terrainProvider() ? request.terrainProvider()->clone() : nullptr )
677 , mTolerance( request.tolerance() )
678 , mSourceCrs( layer->crs3D() )
679 , mTargetCrs( request.
crs() )
680 , mTransformContext( request.transformContext() )
681 , mExtent( layer->extent() )
683 , mOffset( layer->elevationProperties()->zOffset() )
684 , mScale( layer->elevationProperties()->zScale() )
692 , mExpressionContext( request.expressionContext() )
693 , mFields( layer->fields() )
694 , mDataDefinedProperties( layer->elevationProperties()->dataDefinedProperties() )
695 , mWkbType( layer->wkbType() )
701 if ( mTerrainProvider )
702 mTerrainProvider->prepare();
706 mProfileCurve->dropZValue();
724 if ( !mProfileCurve || mFeedback->isCanceled() )
728 qgsgeometry_cast<QgsLineString *>( mProfileCurve.get() ) )
734 std::unique_ptr< QgsCurve > origCurve = std::move( mProfileCurve );
735 std::unique_ptr< QgsVectorLayerProfileResults > totalResults;
736 double distanceProcessed = 0;
738 QVector<QgsLineString *> disjointParts = profileLine->splitToDisjointXYParts();
739 for (
int i = 0; i < disjointParts.size(); i++ )
741 mProfileCurve.reset( disjointParts[i] );
742 if ( !generateProfileInner() )
744 mProfileCurve = std::move( origCurve );
747 for (
int j = i + 1; j < disjointParts.size(); j++ )
748 delete disjointParts[j];
755 totalResults.reset( mResults.release() );
759 totalResults->mRawPoints.append( mResults->mRawPoints );
760 totalResults->minZ = std::min( totalResults->minZ, mResults->minZ );
761 totalResults->maxZ = std::max( totalResults->maxZ, mResults->maxZ );
762 for (
auto it = mResults->mDistanceToHeightMap.constKeyValueBegin();
763 it != mResults->mDistanceToHeightMap.constKeyValueEnd();
766 totalResults->mDistanceToHeightMap[it->first + distanceProcessed] = it->second;
768 for (
auto it = mResults->features.constKeyValueBegin();
769 it != mResults->features.constKeyValueEnd();
774 feature.crossSectionGeometry.translate( distanceProcessed, 0 );
775 totalResults->features[it->first].push_back( feature );
780 distanceProcessed += mProfileCurve->length();
783 mProfileCurve = std::move( origCurve );
784 mResults.reset( totalResults.release() );
788 return generateProfileInner();
794 mTransformedCurve.reset( mProfileCurve->clone() );
796 if ( mTerrainProvider )
797 mTargetToTerrainProviderTransform =
QgsCoordinateTransform( mTargetCrs, mTerrainProvider->crs(), mTransformContext );
805 QgsDebugError( QStringLiteral(
"Error transforming profile line to vector CRS" ) );
809 const QgsRectangle profileCurveBoundingBox = mTransformedCurve->boundingBox();
810 if ( !profileCurveBoundingBox.
intersects( mExtent ) )
813 if ( mFeedback->isCanceled() )
816 mResults = std::make_unique< QgsVectorLayerProfileResults >();
817 mResults->mLayer = mLayer;
818 mResults->copyPropertiesFromGenerator(
this );
820 mProfileCurveEngine.reset(
new QgsGeos( mProfileCurve.get() ) );
821 mProfileCurveEngine->prepareGeometry();
823 if ( tolerance() == 0.0 )
825 mProfileBufferedCurve = std::unique_ptr<QgsAbstractGeometry>( mProfileCurve->clone() );
832 mProfileBufferedCurveEngine.reset(
new QgsGeos( mProfileBufferedCurve.get() ) );
833 mProfileBufferedCurveEngine->prepareGeometry();
835 mDataDefinedProperties.
prepare( mExpressionContext );
837 if ( mFeedback->isCanceled() )
843 if ( !generateProfileForPoints() )
848 if ( !generateProfileForLines() )
853 if ( !generateProfileForPolygons() )
867 return mResults.release();
872 return mFeedback.get();
875bool QgsVectorLayerProfileGenerator::generateProfileForPoints()
890 while ( !mFeedback->isCanceled() && it.
nextFeature( feature ) )
897 if ( mProfileBufferedCurveEngine->intersects( *it ) )
899 processIntersectionPoint( qgsgeometry_cast< const QgsPoint * >( *it ), feature );
903 return !mFeedback->isCanceled();
906void QgsVectorLayerProfileGenerator::processIntersectionPoint(
const QgsPoint *point,
const QgsFeature &feature )
911 const double height = featureZToHeight( point->
x(), point->
y(), point->
z(), offset );
912 mResults->mRawPoints.append(
QgsPoint( point->
x(), point->
y(), height ) );
913 mResults->minZ = std::min( mResults->minZ, height );
914 mResults->maxZ = std::max( mResults->maxZ, height );
916 const double distanceAlongProfileCurve = mProfileCurveEngine->lineLocatePoint( *point, &error );
917 mResults->mDistanceToHeightMap.insert( distanceAlongProfileCurve, height );
921 if ( mExtrusionEnabled )
926 QgsPoint( point->
x(), point->
y(), height + extrusion ) ) );
928 QgsPoint( distanceAlongProfileCurve, height + extrusion ) ) );
929 mResults->minZ = std::min( mResults->minZ, height + extrusion );
930 mResults->maxZ = std::max( mResults->maxZ, height + extrusion );
938 mResults->features[resultFeature.
featureId].append( resultFeature );
941void QgsVectorLayerProfileGenerator::processIntersectionCurve(
const QgsLineString *intersectionCurve,
const QgsFeature &feature )
947 double maxDistanceAlongProfileCurve = std::numeric_limits<double>::lowest();
952 const int numPoints = intersectionCurve->
numPoints();
953 QVector< double > newX( numPoints );
954 QVector< double > newY( numPoints );
955 QVector< double > newZ( numPoints );
956 QVector< double > newDistance( numPoints );
958 const double *inX = intersectionCurve->
xData();
959 const double *inY = intersectionCurve->
yData();
960 const double *inZ = intersectionCurve->
is3D() ? intersectionCurve->
zData() :
nullptr;
961 double *outX = newX.data();
962 double *outY = newY.data();
963 double *outZ = newZ.data();
964 double *outDistance = newDistance.data();
966 QVector< double > extrudedZ;
967 double *extZOut =
nullptr;
968 if ( mExtrusionEnabled )
970 extrudedZ.resize( numPoints );
971 extZOut = extrudedZ.data();
974 for (
int i = 0 ; ! mFeedback->isCanceled() && i < numPoints; ++i )
976 QgsPoint intersectionPoint( *inX, *inY, ( inZ ? *inZ : std::numeric_limits<double>::quiet_NaN() ) );
978 const double height = featureZToHeight( intersectionPoint.
x(), intersectionPoint.
y(), intersectionPoint.
z(), offset );
979 const double distanceAlongProfileCurve = mProfileCurveEngine->lineLocatePoint( intersectionPoint, &error );
981 maxDistanceAlongProfileCurve = std::max( maxDistanceAlongProfileCurve, distanceAlongProfileCurve );
983 mResults->mRawPoints.append(
QgsPoint( intersectionPoint.
x(), intersectionPoint.
y(), height ) );
984 mResults->minZ = std::min( mResults->minZ, height );
985 mResults->maxZ = std::max( mResults->maxZ, height );
987 mResults->mDistanceToHeightMap.insert( distanceAlongProfileCurve, height );
988 *outDistance++ = distanceAlongProfileCurve;
990 *outX++ = intersectionPoint.
x();
991 *outY++ = intersectionPoint.
y();
994 *extZOut++ = height + extrusion;
996 if ( mExtrusionEnabled )
998 mResults->minZ = std::min( mResults->minZ, height + extrusion );
999 mResults->maxZ = std::max( mResults->maxZ, height + extrusion );
1007 mResults->mDistanceToHeightMap.insert( maxDistanceAlongProfileCurve + 0.000001, std::numeric_limits<double>::quiet_NaN() );
1009 if ( mFeedback->isCanceled() )
1013 if ( mExtrusionEnabled )
1015 std::unique_ptr< QgsLineString > ring = std::make_unique< QgsLineString >( newX, newY, newZ );
1016 std::unique_ptr< QgsLineString > extrudedRing = std::make_unique< QgsLineString >( newX, newY, extrudedZ );
1017 std::unique_ptr< QgsLineString > reversedExtrusion( extrudedRing->reversed() );
1018 ring->append( reversedExtrusion.get() );
1022 std::unique_ptr< QgsLineString > distanceVHeightRing = std::make_unique< QgsLineString >( newDistance, newZ );
1023 std::unique_ptr< QgsLineString > extrudedDistanceVHeightRing = std::make_unique< QgsLineString >( newDistance, extrudedZ );
1024 std::unique_ptr< QgsLineString > reversedDistanceVHeightExtrusion( extrudedDistanceVHeightRing->reversed() );
1025 distanceVHeightRing->append( reversedDistanceVHeightExtrusion.get() );
1026 distanceVHeightRing->close();
1035 mResults->features[resultFeature.
featureId].append( resultFeature );
1038bool QgsVectorLayerProfileGenerator::generateProfileForLines()
1043 if ( tolerance() > 0 )
1054 auto processCurve = [
this](
const QgsFeature & feature,
const QgsCurve * featGeomPart )
1057 std::unique_ptr< QgsAbstractGeometry > intersection( mProfileBufferedCurveEngine->intersection( featGeomPart, &error ) );
1058 if ( !intersection )
1061 if ( mFeedback->isCanceled() )
1066 if ( intersection->isEmpty() )
1068 intersection.reset( featGeomPart->clone() );
1071 QgsGeos featGeomPartGeos( featGeomPart );
1072 featGeomPartGeos.prepareGeometry();
1074 for (
auto it = intersection->const_parts_begin();
1075 !mFeedback->isCanceled() && it != intersection->const_parts_end();
1078 if (
const QgsPoint *intersectionPoint = qgsgeometry_cast< const QgsPoint * >( *it ) )
1082 const double distance = featGeomPartGeos.lineLocatePoint( *intersectionPoint, &error );
1083 std::unique_ptr< QgsPoint > interpolatedPoint( featGeomPart->interpolatePoint( distance ) );
1085 processIntersectionPoint( interpolatedPoint.get(), feature );
1087 else if (
const QgsLineString *intersectionCurve = qgsgeometry_cast< const QgsLineString * >( *it ) )
1089 processIntersectionCurve( intersectionCurve, feature );
1096 while ( !mFeedback->isCanceled() && it.
nextFeature( feature ) )
1103 if ( mProfileBufferedCurveEngine->intersects( *it ) )
1105 processCurve( feature, qgsgeometry_cast< const QgsCurve * >( *it ) );
1110 return !mFeedback->isCanceled();
1113QgsPoint QgsVectorLayerProfileGenerator::interpolatePointOnTriangle(
const QgsPolygon *triangle,
double x,
double y )
const
1120 const double z = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, p1.
z(), p2.
z(), p3.
z(),
QgsPointXY( x, y ) );
1124void QgsVectorLayerProfileGenerator::processTriangleIntersectForPoint(
const QgsPolygon *triangle,
const QgsPoint *p, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts )
1126 const QgsPoint interpolatedPoint = interpolatePointOnTriangle( triangle, p->
x(), p->
y() );
1127 mResults->mRawPoints.append( interpolatedPoint );
1128 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() );
1129 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() );
1132 const double distance = mProfileCurveEngine->lineLocatePoint( *p, &lastError );
1133 mResults->mDistanceToHeightMap.insert( distance, interpolatedPoint.
z() );
1135 if ( mExtrusionEnabled )
1140 QgsPoint( interpolatedPoint.
x(), interpolatedPoint.
y(), interpolatedPoint.
z() + extrusion ) ) ) );
1142 QgsPoint( distance, interpolatedPoint.
z() + extrusion ) ) ) );
1143 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() + extrusion );
1144 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() + extrusion );
1153void QgsVectorLayerProfileGenerator::processTriangleIntersectForLine(
const QgsPolygon *triangle,
const QgsLineString *intersectionLine, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts )
1158 int numPoints = intersectionLine->
numPoints();
1159 QVector< double > newX( numPoints );
1160 QVector< double > newY( numPoints );
1161 QVector< double > newZ( numPoints );
1162 QVector< double > newDistance( numPoints );
1164 const double *inX = intersectionLine->
xData();
1165 const double *inY = intersectionLine->
yData();
1166 const double *inZ = intersectionLine->
is3D() ? intersectionLine->
zData() :
nullptr;
1167 double *outX = newX.data();
1168 double *outY = newY.data();
1169 double *outZ = newZ.data();
1170 double *outDistance = newDistance.data();
1172 double lastDistanceAlongProfileCurve = 0.0;
1173 QVector< double > extrudedZ;
1174 double *extZOut =
nullptr;
1175 double extrusion = 0;
1177 if ( mExtrusionEnabled )
1179 extrudedZ.resize( numPoints );
1180 extZOut = extrudedZ.data();
1186 for (
int i = 0 ; ! mFeedback->isCanceled() && i < numPoints; ++i )
1190 double z = inZ ? *inZ++ : 0;
1192 QgsPoint interpolatedPoint( x, y, z );
1198 interpolatedPoint = interpolatePointOnTriangle( triangle, x, y );
1200 double tempOutZ = std::isnan( interpolatedPoint.
z() ) ? 0.0 : interpolatedPoint.
z();
1203 if ( mExtrusionEnabled )
1204 *extZOut++ = tempOutZ + extrusion;
1206 mResults->mRawPoints.append( interpolatedPoint );
1207 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() );
1208 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() );
1209 if ( mExtrusionEnabled )
1211 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() + extrusion );
1212 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() + extrusion );
1215 const double distance = mProfileCurveEngine->lineLocatePoint( interpolatedPoint, &lastError );
1216 *outDistance++ = distance;
1218 mResults->mDistanceToHeightMap.insert( distance, interpolatedPoint.
z() );
1219 lastDistanceAlongProfileCurve = distance;
1223 mResults->mDistanceToHeightMap.insert( lastDistanceAlongProfileCurve + 0.000001, std::numeric_limits<double>::quiet_NaN() );
1225 if ( mFeedback->isCanceled() )
1228 if ( mExtrusionEnabled )
1230 std::unique_ptr< QgsLineString > ring = std::make_unique< QgsLineString >( newX, newY, newZ );
1231 std::unique_ptr< QgsLineString > extrudedRing = std::make_unique< QgsLineString >( newX, newY, extrudedZ );
1232 std::unique_ptr< QgsLineString > reversedExtrusion( extrudedRing->reversed() );
1233 ring->append( reversedExtrusion.get() );
1237 std::unique_ptr< QgsLineString > distanceVHeightRing = std::make_unique< QgsLineString >( newDistance, newZ );
1238 std::unique_ptr< QgsLineString > extrudedDistanceVHeightRing = std::make_unique< QgsLineString >( newDistance, extrudedZ );
1239 std::unique_ptr< QgsLineString > reversedDistanceVHeightExtrusion( extrudedDistanceVHeightRing->reversed() );
1240 distanceVHeightRing->append( reversedDistanceVHeightExtrusion.get() );
1241 distanceVHeightRing->close();
1251void QgsVectorLayerProfileGenerator::processTriangleIntersectForPolygon(
const QgsPolygon *sourcePolygon,
const QgsPolygon *intersectionPolygon, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts )
1253 bool oldExtrusion = mExtrusionEnabled;
1286 mExtrusionEnabled =
false;
1287 if ( mProfileBufferedCurveEngine->contains( sourcePolygon ) )
1291 QgsLineString *exteriorLine = qgsgeometry_cast<QgsLineString *>( exterior );
1292 processTriangleIntersectForLine( sourcePolygon, exteriorLine, transformedParts, crossSectionParts );
1297 processTriangleIntersectForLine( sourcePolygon, interiorLine, transformedParts, crossSectionParts );
1305 QgsLineString *exteriorLine = qgsgeometry_cast<QgsLineString *>( exterior )->
clone();
1307 processTriangleIntersectForLine( sourcePolygon, exteriorLine, transformedParts, crossSectionParts );
1308 delete exteriorLine;
1313 if ( mProfileBufferedCurveEngine->contains( interiorLine ) )
1315 processTriangleIntersectForLine( sourcePolygon, interiorLine, transformedParts, crossSectionParts );
1319 interiorLine = qgsgeometry_cast<QgsLineString *>( intersectionPolygon->
interiorRing( i ) )->
clone();
1321 processTriangleIntersectForLine( sourcePolygon, interiorLine, transformedParts, crossSectionParts );
1322 delete interiorLine;
1327 mExtrusionEnabled = oldExtrusion;
1330bool QgsVectorLayerProfileGenerator::generateProfileForPolygons()
1335 if ( tolerance() > 0 )
1346 std::function< void(
const QgsPolygon *triangle,
const QgsAbstractGeometry *intersect, QVector< QgsGeometry > &, QVector< QgsGeometry > & ) > processTriangleLineIntersect;
1347 processTriangleLineIntersect = [
this](
const QgsPolygon * triangle,
const QgsAbstractGeometry * intersection, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts )
1349 for (
auto it = intersection->const_parts_begin();
1350 ! mFeedback->isCanceled() && it != intersection->const_parts_end();
1357 if (
const QgsPoint *p = qgsgeometry_cast< const QgsPoint * >( *it ) )
1359 processTriangleIntersectForPoint( triangle, p, transformedParts, crossSectionParts );
1364 if (
const QgsLineString *intersectionLine = qgsgeometry_cast< const QgsLineString * >( *it ) )
1366 processTriangleIntersectForLine( triangle, intersectionLine, transformedParts, crossSectionParts );
1371 if (
const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon * >( *it ) )
1373 processTriangleIntersectForPolygon( triangle, poly, transformedParts, crossSectionParts );
1384 auto triangleIsCollinearInXYPlane = [](
const QgsPolygon * polygon )->
bool
1386 const QgsLineString *ring = qgsgeometry_cast< const QgsLineString * >( polygon->exteriorRing() );
1388 ring->
xAt( 1 ), ring->
yAt( 1 ),
1389 ring->
xAt( 2 ), ring->
yAt( 2 ), 0.005 );
1392 auto processPolygon = [
this, &processTriangleLineIntersect, &triangleIsCollinearInXYPlane](
const QgsCurvePolygon * polygon, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts,
double offset,
bool & wasCollinear )
1394 std::unique_ptr< QgsPolygon > clampedPolygon;
1395 if (
const QgsPolygon *p = qgsgeometry_cast< const QgsPolygon * >( polygon ) )
1397 clampedPolygon.reset( p->
clone() );
1401 clampedPolygon.reset( qgsgeometry_cast< QgsPolygon * >( polygon->segmentize() ) );
1403 clampAltitudes( clampedPolygon.get(), offset );
1405 if ( mFeedback->isCanceled() )
1408 if ( tolerance() > 0.0 )
1411 if ( mProfileBufferedCurveEngine->intersects( clampedPolygon.get(), &error ) )
1413 std::unique_ptr< QgsAbstractGeometry > intersection;
1414 intersection.reset( mProfileBufferedCurveEngine->intersection( clampedPolygon.get(), &error ) );
1415 if ( error.isEmpty() )
1417 processTriangleLineIntersect( clampedPolygon.get(), intersection.get(), transformedParts, crossSectionParts );
1424 QgsLineString *ring = qgsgeometry_cast< QgsLineString * >( clampedPolygon->exteriorRing() );
1426 QVector< double > newX( numPoints );
1427 QVector< double > newY( numPoints );
1428 QVector< double > newZ( numPoints );
1429 double *outX = newX.data();
1430 double *outY = newY.data();
1431 double *outZ = newZ.data();
1433 const double *inX = ring->
xData();
1434 const double *inY = ring->
yData();
1435 const double *inZ = ring->
zData();
1436 for (
int i = 0 ; ! mFeedback->isCanceled() && i < ring->numPoints() - 1; ++i )
1438 *outX++ = inX[i] + i * 1.0e-9;
1439 *outY++ = inY[i] + i * 1.0e-9;
1442 std::unique_ptr< QgsPolygon > shiftedPoly;
1445 intersection.reset( mProfileBufferedCurveEngine->intersection( shiftedPoly.get(), &error ) );
1446 if ( intersection.get() )
1447 processTriangleLineIntersect( clampedPolygon.get(), intersection.get(), transformedParts, crossSectionParts );
1451 QgsDebugMsgLevel( QStringLiteral(
"processPolygon after shift bad geom! error: %1" ).arg( error ), 0 );
1461 if ( clampedPolygon->numInteriorRings() == 0 && clampedPolygon->exteriorRing() && clampedPolygon->exteriorRing()->numPoints() == 4 && clampedPolygon->exteriorRing()->isClosed() )
1464 std::unique_ptr< QgsMultiPolygon > multiPolygon = std::make_unique< QgsMultiPolygon >();
1465 multiPolygon->addGeometry( clampedPolygon.release() );
1466 tessellation =
QgsGeometry( std::move( multiPolygon ) );
1470 const QgsRectangle bounds = clampedPolygon->boundingBox();
1472 t.setOutputZUp(
true );
1473 t.addPolygon( *clampedPolygon, 0 );
1476 if ( mFeedback->isCanceled() )
1483 const int numTriangles = qgsgeometry_cast< const QgsMultiPolygon * >( tessellation.
constGet() )->numGeometries();
1484 for (
int i = 0; ! mFeedback->isCanceled() && i < numTriangles; ++i )
1486 const QgsPolygon *triangle = qgsgeometry_cast< const QgsPolygon * >( qgsgeometry_cast< const QgsMultiPolygon * >( tessellation.
constGet() )->geometryN( i ) );
1488 if ( triangleIsCollinearInXYPlane( triangle ) )
1490 wasCollinear =
true;
1491 const QgsLineString *ring = qgsgeometry_cast< const QgsLineString * >( polygon->exteriorRing() );
1494 if (
const QgsLineString *ls = qgsgeometry_cast< const QgsLineString * >( mProfileCurve.get() ) )
1496 for (
int curveSegmentIndex = 0; curveSegmentIndex < mProfileCurve->numPoints() - 1; ++curveSegmentIndex )
1498 const QgsPoint p1 = ls->pointN( curveSegmentIndex );
1499 const QgsPoint p2 = ls->pointN( curveSegmentIndex + 1 );
1502 double minZ = std::numeric_limits< double >::max();
1503 double maxZ = std::numeric_limits< double >::lowest();
1505 for (
auto vertexPair : std::array<std::pair<int, int>, 3> {{ { 0, 1}, {1, 2}, {2, 0} }} )
1507 bool isIntersection =
false;
1511 const double intersectionZ = ring->
zAt( vertexPair.first ) + ( ring->
zAt( vertexPair.second ) - ring->
zAt( vertexPair.first ) ) * fraction;
1512 minZ = std::min( minZ, intersectionZ );
1513 maxZ = std::max( maxZ, intersectionZ );
1517 if ( !intersectionPoint.
isEmpty() )
1520 mResults->mRawPoints.append( intersectionPoint );
1521 mResults->minZ = std::min( mResults->minZ, minZ );
1522 mResults->maxZ = std::max( mResults->maxZ, maxZ );
1524 const double distance = mProfileCurveEngine->lineLocatePoint( intersectionPoint, &lastError );
1526 crossSectionParts.append(
QgsGeometry(
new QgsLineString( QVector< double > {distance, distance}, QVector< double > {minZ, maxZ} ) ) );
1528 mResults->mDistanceToHeightMap.insert( distance, minZ );
1529 mResults->mDistanceToHeightMap.insert( distance, maxZ );
1536 QgsDebugError( QStringLiteral(
"Collinear triangles with curved profile lines are not supported yet" ) );
1542 if ( mProfileBufferedCurveEngine->intersects( triangle, &error ) )
1544 std::unique_ptr< QgsAbstractGeometry > intersection( mProfileBufferedCurveEngine->intersection( triangle, &error ) );
1545 processTriangleLineIntersect( triangle, intersection.get(), transformedParts, crossSectionParts );
1555 while ( ! mFeedback->isCanceled() && it.
nextFeature( feature ) )
1557 if ( !mProfileBufferedCurveEngine->intersects( feature.
geometry().
constGet() ) )
1564 QVector< QgsGeometry > transformedParts;
1565 QVector< QgsGeometry > crossSectionParts;
1566 bool wasCollinear =
false;
1571 if ( mProfileBufferedCurveEngine->intersects( *it ) )
1573 if (
const QgsCurvePolygon *curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( *it ) )
1575 processPolygon( curvePolygon, transformedParts, crossSectionParts, offset, wasCollinear );
1577 else if (
const QgsPolyhedralSurface *polySurface = qgsgeometry_cast< const QgsPolyhedralSurface * >( *it ) )
1579 for (
int i = 0; i < polySurface->numPatches(); ++i )
1581 const QgsPolygon *polygon = polySurface->patchN( i );
1582 if ( mProfileBufferedCurveEngine->intersects( polygon ) )
1584 processPolygon( polygon, transformedParts, crossSectionParts, offset, wasCollinear );
1590 QgsDebugError( QStringLiteral(
"Unhandled Geometry type: %1" ).arg( ( *it )->wktTypeStr() ) );
1595 if ( mFeedback->isCanceled() )
1602 if ( !crossSectionParts.empty() )
1604 if ( !wasCollinear )
1625 mResults->features[resultFeature.
featureId].append( resultFeature );
1630double QgsVectorLayerProfileGenerator::tolerance()
const
1632 return mCustomToleranceEnabled ? mCustomTolerance : mTolerance;
1635double QgsVectorLayerProfileGenerator::terrainHeight(
double x,
double y )
const
1637 if ( !mTerrainProvider )
1638 return std::numeric_limits<double>::quiet_NaN();
1648 return std::numeric_limits<double>::quiet_NaN();
1651 return mTerrainProvider->heightAt( x, y );
1654double QgsVectorLayerProfileGenerator::featureZToHeight(
double x,
double y,
double z,
double offset )
const
1656 switch ( mClamping )
1664 const double terrainZ = terrainHeight( x, y );
1665 if ( !std::isnan( terrainZ ) )
1667 switch ( mClamping )
1670 if ( std::isnan( z ) )
1688 return ( std::isnan( z ) ? 0 : z ) * mScale + offset;
1691void QgsVectorLayerProfileGenerator::clampAltitudes(
QgsLineString *lineString,
const QgsPoint ¢roid,
double offset )
const
1695 if ( mFeedback->isCanceled() )
1698 double terrainZ = 0;
1699 switch ( mClamping )
1708 pt.
setX( lineString->
xAt( i ) );
1709 pt.
setY( lineString->
yAt( i ) );
1713 pt.
set( centroid.
x(), centroid.
y() );
1717 terrainZ = terrainHeight( pt.
x(), pt.
y() );
1727 switch ( mClamping )
1731 geomZ = lineString->
zAt( i );
1738 const double z = ( terrainZ + ( std::isnan( geomZ ) ? 0 : geomZ ) ) * mScale + offset;
1739 lineString->
setZAt( i, z );
1743bool QgsVectorLayerProfileGenerator::clampAltitudes(
QgsPolygon *polygon,
double offset )
const
1745 if ( !polygon->
is3D() )
1760 QgsLineString *lineString = qgsgeometry_cast<QgsLineString *>( curve );
1764 clampAltitudes( lineString, centroid, offset );
1768 if ( mFeedback->isCanceled() )
1772 QgsLineString *lineString = qgsgeometry_cast<QgsLineString *>( curve );
1776 clampAltitudes( lineString, centroid, offset );
The Qgis class provides global constants for use throughout the application.
@ 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)
Abstract base class for all geometries.
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.
Abstract base class for objects which generate elevation profiles which represent a continuous surfac...
std::unique_ptr< QgsLineSymbol > mLineSymbol
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.
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
Custom exception class for Coordinate Reference System related exceptions.
Curve polygon geometry type.
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.
Abstract base class for curved geometry type.
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.
This class 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.
QgsGeometry mergeLines() const
Merges any connected lines in a LineString/MultiLineString geometry and converts them to single line ...
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
QgsAbstractGeometry::const_part_iterator const_parts_end() const
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry.
static QgsGeometry unaryUnion(const QVector< QgsGeometry > &geometries, const QgsGeometryParameters ¶meters=QgsGeometryParameters())
Compute the unary union on a list of geometries.
Qgis::GeometryOperationResult translate(double dx, double dy, double dz=0.0, double dm=0.0)
Translates this geometry by dx, dy, dz and dm.
Does vector analysis using the GEOS library and handles import, export, and exception handling.
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.
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
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.
Multi line string geometry collection.
Multi point geometry collection.
Multi polygon geometry collection.
A class to represent a 2D point.
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.
Polyhedral surface geometry type.
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.
bool prepare(const QgsExpressionContext &context=QgsExpressionContext()) const final
Prepares the collection against a specified expression context.
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.
Abstract base class for all rendered symbols.
void setColor(const QColor &color) const
Sets the color for the symbol.
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.
Class that takes care of tessellation of polygons into triangles.
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 data sets.
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)
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)
const QgsCoordinateReferenceSystem & crs
Encapsulates information about a feature exported from the profile results.
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.
Utility class for identifying a unique vertex within a geometry.