46 return QStringLiteral(
"vector" );
51 QVector<QgsGeometry> res;
55 for (
const Feature &feature : it.value() )
57 res.append( feature.geometry );
69 return asIndividualFeatures(
type, feedback );
84 return snapPointToIndividualFeatures( point, context );
100 visitFeaturesInRange( distanceRange, elevationRange, visitFeature );
104 QVector< QVariantMap> idsList;
105 for (
auto it = ids.constBegin(); it != ids.constEnd(); ++it )
106 idsList.append( QVariantMap( {{QStringLiteral(
"id" ), *it}} ) );
113 QHash< QgsFeatureId, QVariantMap >
features;
114 auto visitFeature = [&
features](
QgsFeatureId featureId,
double delta,
double distance,
double elevation )
116 auto it =
features.find( featureId );
119 features[ featureId ] = QVariantMap( {{QStringLiteral(
"id" ), featureId },
120 {QStringLiteral(
"delta" ), delta },
121 {QStringLiteral(
"distance" ), distance },
122 {QStringLiteral(
"elevation" ), elevation }
127 const double currentDelta = it.value().value( QStringLiteral(
"delta" ) ).toDouble();
128 if ( delta < currentDelta )
130 *it = QVariantMap( {{QStringLiteral(
"id" ), featureId },
131 {QStringLiteral(
"delta" ), delta },
132 {QStringLiteral(
"distance" ), distance },
133 {QStringLiteral(
"elevation" ), elevation }
141 QVector< QVariantMap> attributes;
143 attributes.append( *it );
145 QVector<QgsProfileIdentifyResults> res;
147 if ( !attributes.empty() )
153 res.reserve( surfaceResults.size() );
166 double bestSnapDistance = std::numeric_limits< double >::max();
168 auto visitFeature = [&bestSnapDistance, &res](
QgsFeatureId,
double delta,
double distance,
double elevation )
170 if ( distance < bestSnapDistance )
172 bestSnapDistance = delta;
182void 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 )
190 for (
const Feature &feature : it.value() )
192 const QgsRectangle featureBounds = feature.crossSectionGeometry.boundingBox();
193 if ( ( featureBounds.
xMinimum() - maximumPointDistanceDelta <= point.
distance() ) && ( featureBounds.
xMaximum() + maximumPointDistanceDelta >= point.
distance() ) )
195 switch ( feature.crossSectionGeometry.type() )
197 case Qgis::GeometryType::Point:
199 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
201 if (
const QgsPoint *candidatePoint = qgsgeometry_cast< const QgsPoint * >( *partIt ) )
203 const double snapDistanceDelta = std::fabs( point.
distance() - candidatePoint->x() );
204 if ( snapDistanceDelta > maximumPointDistanceDelta )
207 const double snapHeightDelta = std::fabs( point.
elevation() - candidatePoint->y() );
208 if ( snapHeightDelta > maximumPointElevationDelta )
211 const double snapDistance = candidatePoint->distance( targetPoint );
212 visitor( feature.featureId, snapDistance, candidatePoint->x(), candidatePoint->y() );
218 case Qgis::GeometryType::Line:
220 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
222 if (
const QgsCurve *line = qgsgeometry_cast< const QgsCurve * >( *partIt ) )
225 if (
const QgsLineString *lineString = qgsgeometry_cast< const QgsLineString * >( line ) )
227 if ( lineString->numPoints() == 2 &&
qgsDoubleNear( lineString->pointN( 0 ).x(), lineString->pointN( 1 ).x() ) )
229 const double snapDistanceDelta = std::fabs( point.
distance() - lineString->pointN( 0 ).x() );
230 if ( snapDistanceDelta > maximumPointDistanceDelta )
233 const double snapHeightDelta = std::fabs( point.
elevation() - lineString->pointN( 0 ).y() );
234 if ( snapHeightDelta <= maximumPointElevationDelta )
236 const double snapDistanceP1 = lineString->pointN( 0 ).distance( targetPoint );
237 visitor( feature.featureId, snapDistanceP1, lineString->pointN( 0 ).x(), lineString->pointN( 0 ).y() );
240 const double snapHeightDelta2 = std::fabs( point.
elevation() - lineString->pointN( 1 ).y() );
241 if ( snapHeightDelta2 <= maximumPointElevationDelta )
243 const double snapDistanceP2 = lineString->pointN( 1 ).distance( targetPoint );
244 visitor( feature.featureId, snapDistanceP2, lineString->pointN( 1 ).x(), lineString->pointN( 1 ).y() );
249 double elevation1 = lineString->pointN( 0 ).y();
250 double elevation2 = lineString->pointN( 1 ).y();
251 if ( elevation1 > elevation2 )
252 std::swap( elevation1, elevation2 );
256 const double snapDistance = std::fabs( lineString->pointN( 0 ).x() - point.
distance() );
257 visitor( feature.featureId, snapDistance, lineString->pointN( 0 ).x(), point.
elevation() );
264 const QgsRectangle partBounds = ( *partIt )->boundingBox();
272 QgsGeos cutLineGeos( cutLine.constGet() );
274 const QgsGeometry points( cutLineGeos.intersection( line ) );
276 for (
auto vertexIt = points.vertices_begin(); vertexIt != points.vertices_end(); ++vertexIt )
278 const double snapHeightDelta = std::fabs( point.
elevation() - ( *vertexIt ).y() );
279 if ( snapHeightDelta > maximumSurfaceElevationDelta )
282 const double snapDistance = ( *vertexIt ).distance( targetPoint );
283 visitor( feature.featureId, snapDistance, ( *vertexIt ).x(), ( *vertexIt ).y() );
290 case Qgis::GeometryType::Polygon:
300 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
302 if (
const QgsCurve *exterior = qgsgeometry_cast< const QgsPolygon * >( *partIt )->exteriorRing() )
304 const QgsRectangle partBounds = ( *partIt )->boundingBox();
312 QgsGeos cutLineGeos( cutLine.constGet() );
314 const QgsGeometry points( cutLineGeos.intersection( exterior ) );
315 for (
auto vertexIt = points.vertices_begin(); vertexIt != points.vertices_end(); ++vertexIt )
317 const double snapHeightDelta = std::fabs( point.
elevation() - ( *vertexIt ).y() );
318 if ( snapHeightDelta > maximumSurfaceElevationDelta )
321 const double snapDistance = ( *vertexIt ).distance( targetPoint );
322 visitor( feature.featureId, snapDistance, ( *vertexIt ).x(), ( *vertexIt ).y() );
328 case Qgis::GeometryType::Unknown:
329 case Qgis::GeometryType::Null:
343 profileRangeGeos.prepareGeometry();
347 for (
const Feature &feature : it.value() )
349 if ( feature.crossSectionGeometry.boundingBoxIntersects( profileRange ) )
351 switch ( feature.crossSectionGeometry.type() )
353 case Qgis::GeometryType::Point:
355 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
357 if (
const QgsPoint *candidatePoint = qgsgeometry_cast< const QgsPoint * >( *partIt ) )
359 if ( profileRange.contains( candidatePoint->x(), candidatePoint->y() ) )
361 visitor( feature.featureId );
368 case Qgis::GeometryType::Line:
369 case Qgis::GeometryType::Polygon:
371 if ( profileRangeGeos.intersects( feature.crossSectionGeometry.constGet() ) )
373 visitor( feature.featureId );
378 case Qgis::GeometryType::Unknown:
379 case Qgis::GeometryType::Null:
393 renderResultsAsIndividualFeatures( context );
398 renderMarkersOverContinuousSurfacePlot( context );
411 painter->setBrush( Qt::NoBrush );
412 painter->setPen( Qt::NoPen );
419 const QRectF visibleRegion( minDistance,
minZ, maxDistance - minDistance,
maxZ -
minZ );
420 QPainterPath clipPath;
421 clipPath.addPolygon( context.
worldTransform().map( visibleRegion ) );
422 painter->setClipPath( clipPath, Qt::ClipOperation::IntersectClip );
424 const QgsRectangle clipPathRect( clipPath.boundingRect() );
428 if ( profileFeature.crossSectionGeometry.isEmpty() )
431 QgsGeometry transformed = profileFeature.crossSectionGeometry;
438 switch ( transformed.
type() )
440 case Qgis::GeometryType::Point:
442 if (
const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( transformed.
constGet() ) )
444 markerSymbol->renderPoint( QPointF( point->x(), point->y() ),
nullptr, context.
renderContext() );
446 else if (
const QgsMultiPoint *multipoint = qgsgeometry_cast< const QgsMultiPoint * >( transformed.
constGet() ) )
448 const int numGeometries = multipoint->numGeometries();
449 for (
int i = 0; i < numGeometries; ++i )
451 markerSymbol->renderPoint( QPointF( multipoint->pointN( i )->x(), multipoint->pointN( i )->y() ),
nullptr, context.
renderContext() );
457 case Qgis::GeometryType::Line:
459 if (
const QgsLineString *line = qgsgeometry_cast< const QgsLineString * >( transformed.
constGet() ) )
461 lineSymbol->renderPolyline( line->asQPolygonF(),
nullptr, context.
renderContext() );
463 else if (
const QgsMultiLineString *multiLinestring = qgsgeometry_cast< const QgsMultiLineString * >( transformed.
constGet() ) )
465 const int numGeometries = multiLinestring->numGeometries();
466 for (
int i = 0; i < numGeometries; ++i )
468 lineSymbol->renderPolyline( multiLinestring->lineStringN( i )->asQPolygonF(),
nullptr, context.
renderContext() );
474 case Qgis::GeometryType::Polygon:
476 if (
const QgsPolygon *polygon = qgsgeometry_cast< const QgsPolygon * >( transformed.
constGet() ) )
478 if (
const QgsCurve *exterior = polygon->exteriorRing() )
479 fillSymbol->renderPolygon( exterior->asQPolygonF(),
nullptr,
nullptr, context.
renderContext() );
481 else if (
const QgsMultiPolygon *multiPolygon = qgsgeometry_cast< const QgsMultiPolygon * >( transformed.
constGet() ) )
483 const int numGeometries = multiPolygon->numGeometries();
484 for (
int i = 0; i < numGeometries; ++i )
486 fillSymbol->renderPolygon( multiPolygon->polygonN( i )->exteriorRing()->asQPolygonF(),
nullptr,
nullptr, context.
renderContext() );
492 case Qgis::GeometryType::Unknown:
493 case Qgis::GeometryType::Null:
503 std::unique_ptr< QgsFeatureRenderer > renderer(
mLayer->renderer()->clone() );
508 QSet<QString> attributes = renderer->usedAttributes( context.
renderContext() );
510 std::unique_ptr< QgsMarkerSymbol > marker(
mMarkerSymbol->clone() );
511 std::unique_ptr< QgsLineSymbol > line(
mLineSymbol->clone() );
512 std::unique_ptr< QgsFillSymbol > fill(
mFillSymbol->clone() );
513 attributes.unite( marker->usedAttributes( context.
renderContext() ) );
514 attributes.unite( line->usedAttributes( context.
renderContext() ) );
515 attributes.unite( fill->usedAttributes( context.
renderContext() ) );
525 if ( !rendererSymbol )
529 marker->setOpacity( rendererSymbol->
opacity() );
530 line->setColor( rendererSymbol->
color() );
531 line->setOpacity( rendererSymbol->
opacity() );
532 fill->setColor( rendererSymbol->
color() );
533 fill->setOpacity( rendererSymbol->
opacity() );
539 const QVector< Feature > profileFeatures =
features.value( feature.
id() );
540 for (
const Feature &profileFeature : profileFeatures )
542 renderResult( profileFeature,
557 QSet<QString> attributes;
572 const QVector< Feature > profileFeatures =
features.value( feature.
id() );
573 for (
const Feature &profileFeature : profileFeatures )
592 painter->setBrush( Qt::NoBrush );
593 painter->setPen( Qt::NoPen );
600 const QRectF visibleRegion( minDistance,
minZ, maxDistance - minDistance,
maxZ -
minZ );
601 QPainterPath clipPath;
602 clipPath.addPolygon( context.
worldTransform().map( visibleRegion ) );
603 painter->setClipPath( clipPath, Qt::ClipOperation::IntersectClip );
609 if ( std::isnan( pointIt.value() ) )
619 QVector<QgsAbstractProfileResults::Feature> res;
626 for (
const Feature &feature : it.value() )
633 outFeature.
attributes = {{QStringLiteral(
"id" ), feature.featureId }};
641 outFeature.
geometry = feature.crossSectionGeometry;
658 mId = vlGenerator->mId;
661 mMarkerSymbol.reset( vlGenerator->mProfileMarkerSymbol->clone() );
673 , mProfileCurve( request.profileCurve() ? request.profileCurve()->clone() : nullptr )
674 , mTerrainProvider( request.terrainProvider() ? request.terrainProvider()->clone() : nullptr )
675 , mTolerance( request.tolerance() )
676 , mSourceCrs( layer->
crs() )
677 , mTargetCrs( request.
crs() )
678 , mTransformContext( request.transformContext() )
679 , mExtent( layer->extent() )
681 , mOffset( layer->elevationProperties()->zOffset() )
682 , mScale( layer->elevationProperties()->zScale() )
688 , mExpressionContext( request.expressionContext() )
689 , mFields( layer->fields() )
690 , mDataDefinedProperties( layer->elevationProperties()->dataDefinedProperties() )
691 , mWkbType( layer->wkbType() )
697 if ( mTerrainProvider )
698 mTerrainProvider->prepare();
716 if ( !mProfileCurve || mFeedback->isCanceled() )
720 mTransformedCurve.reset( mProfileCurve->clone() );
722 if ( mTerrainProvider )
723 mTargetToTerrainProviderTransform =
QgsCoordinateTransform( mTargetCrs, mTerrainProvider->crs(), mTransformContext );
727 mTransformedCurve->transform( mLayerToTargetTransform, Qgis::TransformDirection::Reverse );
731 QgsDebugError( QStringLiteral(
"Error transforming profile line to vector CRS" ) );
735 const QgsRectangle profileCurveBoundingBox = mTransformedCurve->boundingBox();
736 if ( !profileCurveBoundingBox.
intersects( mExtent ) )
739 if ( mFeedback->isCanceled() )
742 mResults = std::make_unique< QgsVectorLayerProfileResults >();
743 mResults->mLayer = mLayer;
744 mResults->copyPropertiesFromGenerator(
this );
746 mProfileCurveEngine.reset(
new QgsGeos( mProfileCurve.get() ) );
747 mProfileCurveEngine->prepareGeometry();
749 mDataDefinedProperties.
prepare( mExpressionContext );
751 if ( mFeedback->isCanceled() )
756 case Qgis::GeometryType::Point:
757 if ( !generateProfileForPoints() )
761 case Qgis::GeometryType::Line:
762 if ( !generateProfileForLines() )
766 case Qgis::GeometryType::Polygon:
767 if ( !generateProfileForPolygons() )
771 case Qgis::GeometryType::Unknown:
772 case Qgis::GeometryType::Null:
781 return mResults.release();
786 return mFeedback.get();
789bool QgsVectorLayerProfileGenerator::generateProfileForPoints()
801 std::unique_ptr< QgsAbstractGeometry > bufferedCurve( mProfileCurveEngine->buffer( mTolerance, 8, Qgis::EndCapStyle::Flat, Qgis::JoinStyle::Round, 2 ) );
802 QgsGeos bufferedCurveEngine( bufferedCurve.get() );
803 bufferedCurveEngine.prepareGeometry();
805 auto processPoint = [
this, &bufferedCurveEngine](
const QgsFeature & feature,
const QgsPoint * point )
807 if ( !bufferedCurveEngine.intersects( point ) )
812 const double height = featureZToHeight( point->x(), point->y(), point->z(), offset );
813 mResults->mRawPoints.append(
QgsPoint( point->x(), point->y(), height ) );
814 mResults->minZ = std::min( mResults->minZ, height );
815 mResults->maxZ = std::max( mResults->maxZ, height );
818 const double distance = mProfileCurveEngine->lineLocatePoint( *point, &lastError );
819 mResults->mDistanceToHeightMap.insert( distance, height );
823 if ( mExtrusionEnabled )
828 QgsPoint( point->x(), point->y(), height + extrusion ) ) );
830 QgsPoint( distance, height + extrusion ) ) );
831 mResults->minZ = std::min( mResults->minZ, height + extrusion );
832 mResults->maxZ = std::max( mResults->maxZ, height + extrusion );
839 mResults->features[resultFeature.
featureId].append( resultFeature );
846 if ( mFeedback->isCanceled() )
856 processPoint( feature, qgsgeometry_cast< const QgsPoint * >( *it ) );
861 processPoint( feature, qgsgeometry_cast< const QgsPoint * >( g.
constGet() ) );
867bool QgsVectorLayerProfileGenerator::generateProfileForLines()
879 std::unique_ptr< QgsAbstractGeometry > intersection( mProfileCurveEngine->intersection( curve, &error ) );
883 if ( mFeedback->isCanceled() )
887 curveGeos.prepareGeometry();
889 if ( mFeedback->isCanceled() )
892 for (
auto it = intersection->const_parts_begin(); it != intersection->const_parts_end(); ++it )
894 if ( mFeedback->isCanceled() )
897 if (
const QgsPoint *intersectionPoint = qgsgeometry_cast< const QgsPoint * >( *it ) )
900 const double distance = curveGeos.lineLocatePoint( *intersectionPoint, &error );
901 std::unique_ptr< QgsPoint > interpolatedPoint( curve->interpolatePoint( distance ) );
905 const double height = featureZToHeight( interpolatedPoint->x(), interpolatedPoint->y(), interpolatedPoint->z(), offset );
906 mResults->mRawPoints.append(
QgsPoint( interpolatedPoint->x(), interpolatedPoint->y(), height ) );
907 mResults->minZ = std::min( mResults->minZ, height );
908 mResults->maxZ = std::max( mResults->maxZ, height );
910 const double distanceAlongProfileCurve = mProfileCurveEngine->lineLocatePoint( *interpolatedPoint, &error );
911 mResults->mDistanceToHeightMap.insert( distanceAlongProfileCurve, height );
915 if ( mExtrusionEnabled )
920 QgsPoint( interpolatedPoint->x(), interpolatedPoint->y(), height + extrusion ) ) );
922 QgsPoint( distanceAlongProfileCurve, height + extrusion ) ) );
923 mResults->minZ = std::min( mResults->minZ, height + extrusion );
924 mResults->maxZ = std::max( mResults->maxZ, height + extrusion );
931 mResults->features[resultFeature.
featureId].append( resultFeature );
940 if ( mFeedback->isCanceled() )
953 if ( !mProfileCurveEngine->intersects( *it ) )
956 processCurve( feature, qgsgeometry_cast< const QgsCurve * >( *it ) );
961 processCurve( feature, qgsgeometry_cast< const QgsCurve * >( g.
constGet() ) );
967bool QgsVectorLayerProfileGenerator::generateProfileForPolygons()
976 auto interpolatePointOnTriangle = [](
const QgsPolygon * triangle,
double x,
double y ) ->
QgsPoint
983 const double z = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, p1.
z(), p2.
z(), p3.
z(),
QgsPointXY( x, y ) );
987 std::function< void(
const QgsPolygon *triangle,
const QgsAbstractGeometry *intersect, QVector< QgsGeometry > &, QVector< QgsGeometry > & ) > processTriangleLineIntersect;
988 processTriangleLineIntersect = [
this, &interpolatePointOnTriangle, &processTriangleLineIntersect](
const QgsPolygon * triangle,
const QgsAbstractGeometry * intersect, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts )
993 case Qgis::GeometryType::Point:
994 if (
const QgsMultiPoint *mp = qgsgeometry_cast< const QgsMultiPoint * >( intersect ) )
996 const int numPoint = mp->numGeometries();
997 for (
int i = 0; i < numPoint; ++i )
999 processTriangleLineIntersect( triangle, mp->geometryN( i ), transformedParts, crossSectionParts );
1002 else if (
const QgsPoint *p = qgsgeometry_cast< const QgsPoint * >( intersect ) )
1004 const QgsPoint interpolatedPoint = interpolatePointOnTriangle( triangle, p->x(), p->y() );
1005 mResults->mRawPoints.append( interpolatedPoint );
1006 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() );
1007 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() );
1010 const double distance = mProfileCurveEngine->lineLocatePoint( *p, &lastError );
1011 mResults->mDistanceToHeightMap.insert( distance, interpolatedPoint.
z() );
1013 if ( mExtrusionEnabled )
1018 QgsPoint( interpolatedPoint.
x(), interpolatedPoint.
y(), interpolatedPoint.
z() + extrusion ) ) ) );
1020 QgsPoint( distance, interpolatedPoint.
z() + extrusion ) ) ) );
1021 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() + extrusion );
1022 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() + extrusion );
1031 case Qgis::GeometryType::Line:
1032 if (
const QgsMultiLineString *ml = qgsgeometry_cast< const QgsMultiLineString * >( intersect ) )
1034 const int numLines = ml->numGeometries();
1035 for (
int i = 0; i < numLines; ++i )
1037 processTriangleLineIntersect( triangle, ml->geometryN( i ), transformedParts, crossSectionParts );
1040 else if (
const QgsLineString *ls = qgsgeometry_cast< const QgsLineString * >( intersect ) )
1042 const int numPoints = ls->numPoints();
1043 QVector< double > newX;
1044 newX.resize( numPoints );
1045 QVector< double > newY;
1046 newY.resize( numPoints );
1047 QVector< double > newZ;
1048 newZ.resize( numPoints );
1049 QVector< double > newDistance;
1050 newDistance.resize( numPoints );
1052 const double *inX = ls->xData();
1053 const double *inY = ls->yData();
1054 double *outX = newX.data();
1055 double *outY = newY.data();
1056 double *outZ = newZ.data();
1057 double *outDistance = newDistance.data();
1059 QVector< double > extrudedZ;
1060 double *extZOut =
nullptr;
1061 double extrusion = 0;
1062 if ( mExtrusionEnabled )
1064 extrudedZ.resize( numPoints );
1065 extZOut = extrudedZ.data();
1071 for (
int i = 0 ; i < numPoints; ++i )
1076 QgsPoint interpolatedPoint = interpolatePointOnTriangle( triangle, x, y );
1079 *outZ++ = interpolatedPoint.
z();
1081 *extZOut++ = interpolatedPoint.
z() + extrusion;
1083 mResults->mRawPoints.append( interpolatedPoint );
1084 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() );
1085 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() );
1086 if ( mExtrusionEnabled )
1088 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() + extrusion );
1089 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() + extrusion );
1092 const double distance = mProfileCurveEngine->lineLocatePoint( interpolatedPoint, &lastError );
1093 *outDistance++ = distance;
1095 mResults->mDistanceToHeightMap.insert( distance, interpolatedPoint.
z() );
1098 if ( mExtrusionEnabled )
1100 std::unique_ptr< QgsLineString > ring = std::make_unique< QgsLineString >( newX, newY, newZ );
1101 std::unique_ptr< QgsLineString > extrudedRing = std::make_unique< QgsLineString >( newX, newY, extrudedZ );
1102 std::unique_ptr< QgsLineString > reversedExtrusion( extrudedRing->reversed() );
1103 ring->append( reversedExtrusion.get() );
1108 std::unique_ptr< QgsLineString > distanceVHeightRing = std::make_unique< QgsLineString >( newDistance, newZ );
1109 std::unique_ptr< QgsLineString > extrudedDistanceVHeightRing = std::make_unique< QgsLineString >( newDistance, extrudedZ );
1110 std::unique_ptr< QgsLineString > reversedDistanceVHeightExtrusion( extrudedDistanceVHeightRing->reversed() );
1111 distanceVHeightRing->append( reversedDistanceVHeightExtrusion.get() );
1112 distanceVHeightRing->close();
1123 case Qgis::GeometryType::Polygon:
1124 case Qgis::GeometryType::Unknown:
1125 case Qgis::GeometryType::Null:
1130 auto processPolygon = [
this, &processTriangleLineIntersect](
const QgsCurvePolygon * polygon, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts,
double offset )
1132 std::unique_ptr< QgsPolygon > clampedPolygon;
1133 if (
const QgsPolygon *p = qgsgeometry_cast< const QgsPolygon * >( polygon ) )
1135 clampedPolygon.reset( p->clone() );
1139 clampedPolygon.reset( qgsgeometry_cast< QgsPolygon * >( polygon->
segmentize() ) );
1141 clampAltitudes( clampedPolygon.get(), offset );
1143 if ( mFeedback->isCanceled() )
1146 const QgsRectangle bounds = clampedPolygon->boundingBox();
1148 t.addPolygon( *clampedPolygon, 0 );
1151 if ( mFeedback->isCanceled() )
1157 const int numTriangles = qgsgeometry_cast< const QgsMultiPolygon * >( tessellation.constGet() )->numGeometries();
1158 for (
int i = 0; i < numTriangles; ++i )
1160 if ( mFeedback->isCanceled() )
1163 const QgsPolygon *triangle = qgsgeometry_cast< const QgsPolygon * >( qgsgeometry_cast< const QgsMultiPolygon * >( tessellation.constGet() )->geometryN( i ) );
1164 if ( !mProfileCurveEngine->intersects( triangle ) )
1168 std::unique_ptr< QgsAbstractGeometry > intersection( mProfileCurveEngine->intersection( triangle, &error ) );
1169 if ( !intersection )
1172 processTriangleLineIntersect( triangle, intersection.get(), transformedParts, crossSectionParts );
1180 if ( mFeedback->isCanceled() )
1191 QVector< QgsGeometry > transformedParts;
1192 QVector< QgsGeometry > crossSectionParts;
1197 if ( mFeedback->isCanceled() )
1200 if ( !mProfileCurveEngine->intersects( *it ) )
1203 processPolygon( qgsgeometry_cast< const QgsCurvePolygon * >( *it ), transformedParts, crossSectionParts, offset );
1208 processPolygon( qgsgeometry_cast< const QgsCurvePolygon * >( g.
constGet() ), transformedParts, crossSectionParts, offset );
1211 if ( mFeedback->isCanceled() )
1217 if ( !crossSectionParts.empty() )
1220 if ( unioned.
type() == Qgis::GeometryType::Line )
1224 mResults->features[resultFeature.
featureId].append( resultFeature );
1229double QgsVectorLayerProfileGenerator::terrainHeight(
double x,
double y )
1231 if ( !mTerrainProvider )
1232 return std::numeric_limits<double>::quiet_NaN();
1242 return std::numeric_limits<double>::quiet_NaN();
1245 return mTerrainProvider->heightAt( x, y );
1248double QgsVectorLayerProfileGenerator::featureZToHeight(
double x,
double y,
double z,
double offset )
1250 switch ( mClamping )
1258 const double terrainZ = terrainHeight( x, y );
1259 if ( !std::isnan( terrainZ ) )
1261 switch ( mClamping )
1264 if ( std::isnan( z ) )
1282 return ( std::isnan( z ) ? 0 : z ) * mScale + offset;
1289 if ( mFeedback->isCanceled() )
1292 double terrainZ = 0;
1293 switch ( mClamping )
1302 pt.
setX( lineString->
xAt( i ) );
1303 pt.
setY( lineString->
yAt( i ) );
1311 terrainZ = terrainHeight( pt.
x(), pt.
y() );
1321 switch ( mClamping )
1325 geomZ = lineString->
zAt( i );
1332 const double z = ( terrainZ + ( std::isnan( geomZ ) ? 0 : geomZ ) ) * mScale + offset;
1333 lineString->
setZAt( i, z );
1337bool QgsVectorLayerProfileGenerator::clampAltitudes(
QgsPolygon *polygon,
double offset )
1339 if ( !polygon->
is3D() )
1354 QgsLineString *lineString = qgsgeometry_cast<QgsLineString *>( curve );
1358 clampAltitudes( lineString,
centroid, offset );
1362 if ( mFeedback->isCanceled() )
1366 QgsLineString *lineString = qgsgeometry_cast<QgsLineString *>( curve );
1370 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.
@ Centroid
Clamp just centroid of feature.
@ Vertex
Clamp every vertex of feature.
@ 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.
Abstract base class for all geometries.
bool is3D() const SIP_HOLDGIL
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.
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
QgsAbstractGeometry * segmentize(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a geometry without curves.
int numInteriorRings() const SIP_HOLDGIL
Returns the number of interior rings contained with the curve polygon.
Abstract base class for curved geometry type.
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)
This class wraps a request for features to a vector layer (or directly its vector data provider).
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 SIP_HOLDGIL
Tells whether the operation has been canceled already.
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
A geometry is the spatial representation of a feature.
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
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) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
Creates a new geometry from a QgsRectangle.
bool isMultipart() const SIP_HOLDGIL
Returns true if WKB of the geometry is of WKBMulti* type.
static QgsGeometry fromPointXY(const QgsPointXY &point) SIP_HOLDGIL
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 ...
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.
Does vector analysis using the geos library and handles import, export, exception handling*.
Line string geometry type, with support for z-dimension and m-values.
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.
int nCoordinates() const override SIP_HOLDGIL
Returns the number of nodes contained in 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
Z offset.
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 set(double x, double y) SIP_HOLDGIL
Sets the x and y value of the point.
void setX(double x) SIP_HOLDGIL
Sets the x value of the point.
void setY(double y) SIP_HOLDGIL
Sets the y value of the point.
Point geometry type, with support for z-dimension and m-values.
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 SIP_HOLDGIL
Returns the elevation of the point.
double distance() const SIP_HOLDGIL
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 override
Returns the set of any fields referenced by the active properties from the collection.
bool prepare(const QgsExpressionContext &context=QgsExpressionContext()) const override
Prepares the collection against a specified expression context.
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 SIP_HOLDGIL
Returns true when rectangle intersects with other rectangle.
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of 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) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
CORE_EXPORT QgsMeshVertex centroid(const QgsMeshFace &face, const QVector< QgsMeshVertex > &vertices)
Returns the centroid of the face.
#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 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.