46 return QStringLiteral(
"vector" );
51 QVector<QgsGeometry> res;
55 for (
const Feature &feature : it.value() )
57 res.append( feature.geometry );
68 return snapPointToIndividualFeatures( point, context );
84 visitFeaturesInRange( distanceRange, elevationRange, visitFeature );
88 QVector< QVariantMap> idsList;
89 for (
auto it = ids.constBegin(); it != ids.constEnd(); ++it )
90 idsList.append( QVariantMap( {{QStringLiteral(
"id" ), *it}} ) );
97 QHash< QgsFeatureId, QVariantMap >
features;
98 auto visitFeature = [&
features](
QgsFeatureId featureId,
double delta,
double distance,
double elevation )
100 auto it =
features.find( featureId );
103 features[ featureId ] = QVariantMap( {{QStringLiteral(
"id" ), featureId },
104 {QStringLiteral(
"delta" ), delta },
105 {QStringLiteral(
"distance" ), distance },
106 {QStringLiteral(
"elevation" ), elevation }
111 const double currentDelta = it.value().value( QStringLiteral(
"delta" ) ).toDouble();
112 if ( delta < currentDelta )
114 *it = QVariantMap( {{QStringLiteral(
"id" ), featureId },
115 {QStringLiteral(
"delta" ), delta },
116 {QStringLiteral(
"distance" ), distance },
117 {QStringLiteral(
"elevation" ), elevation }
125 QVector< QVariantMap> attributes;
127 attributes.append( *it );
129 QVector<QgsProfileIdentifyResults> res;
131 if ( !attributes.empty() )
137 res.reserve( surfaceResults.size() );
150 double bestSnapDistance = std::numeric_limits< double >::max();
152 auto visitFeature = [&bestSnapDistance, &res](
QgsFeatureId,
double delta,
double distance,
double elevation )
154 if ( distance < bestSnapDistance )
156 bestSnapDistance = delta;
166void 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 )
174 for (
const Feature &feature : it.value() )
176 const QgsRectangle featureBounds = feature.crossSectionGeometry.boundingBox();
177 if ( ( featureBounds.
xMinimum() - maximumPointDistanceDelta <= point.
distance() ) && ( featureBounds.
xMaximum() + maximumPointDistanceDelta >= point.
distance() ) )
179 switch ( feature.crossSectionGeometry.type() )
181 case Qgis::GeometryType::Point:
183 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
185 if (
const QgsPoint *candidatePoint = qgsgeometry_cast< const QgsPoint * >( *partIt ) )
187 const double snapDistanceDelta = std::fabs( point.
distance() - candidatePoint->x() );
188 if ( snapDistanceDelta > maximumPointDistanceDelta )
191 const double snapHeightDelta = std::fabs( point.
elevation() - candidatePoint->y() );
192 if ( snapHeightDelta > maximumPointElevationDelta )
195 const double snapDistance = candidatePoint->distance( targetPoint );
196 visitor( feature.featureId, snapDistance, candidatePoint->x(), candidatePoint->y() );
202 case Qgis::GeometryType::Line:
204 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
206 if (
const QgsCurve *line = qgsgeometry_cast< const QgsCurve * >( *partIt ) )
209 if (
const QgsLineString *lineString = qgsgeometry_cast< const QgsLineString * >( line ) )
211 if ( lineString->numPoints() == 2 &&
qgsDoubleNear( lineString->pointN( 0 ).x(), lineString->pointN( 1 ).x() ) )
213 const double snapDistanceDelta = std::fabs( point.
distance() - lineString->pointN( 0 ).x() );
214 if ( snapDistanceDelta > maximumPointDistanceDelta )
217 const double snapHeightDelta = std::fabs( point.
elevation() - lineString->pointN( 0 ).y() );
218 if ( snapHeightDelta <= maximumPointElevationDelta )
220 const double snapDistanceP1 = lineString->pointN( 0 ).distance( targetPoint );
221 visitor( feature.featureId, snapDistanceP1, lineString->pointN( 0 ).x(), lineString->pointN( 0 ).y() );
224 const double snapHeightDelta2 = std::fabs( point.
elevation() - lineString->pointN( 1 ).y() );
225 if ( snapHeightDelta2 <= maximumPointElevationDelta )
227 const double snapDistanceP2 = lineString->pointN( 1 ).distance( targetPoint );
228 visitor( feature.featureId, snapDistanceP2, lineString->pointN( 1 ).x(), lineString->pointN( 1 ).y() );
233 double elevation1 = lineString->pointN( 0 ).y();
234 double elevation2 = lineString->pointN( 1 ).y();
235 if ( elevation1 > elevation2 )
236 std::swap( elevation1, elevation2 );
240 const double snapDistance = std::fabs( lineString->pointN( 0 ).x() - point.
distance() );
241 visitor( feature.featureId, snapDistance, lineString->pointN( 0 ).x(), point.
elevation() );
248 const QgsRectangle partBounds = ( *partIt )->boundingBox();
256 QgsGeos cutLineGeos( cutLine.constGet() );
258 const QgsGeometry points( cutLineGeos.intersection( line ) );
260 for (
auto vertexIt = points.vertices_begin(); vertexIt != points.vertices_end(); ++vertexIt )
262 const double snapHeightDelta = std::fabs( point.
elevation() - ( *vertexIt ).y() );
263 if ( snapHeightDelta > maximumSurfaceElevationDelta )
266 const double snapDistance = ( *vertexIt ).distance( targetPoint );
267 visitor( feature.featureId, snapDistance, ( *vertexIt ).x(), ( *vertexIt ).y() );
274 case Qgis::GeometryType::Polygon:
284 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
286 if (
const QgsCurve *exterior = qgsgeometry_cast< const QgsPolygon * >( *partIt )->exteriorRing() )
288 const QgsRectangle partBounds = ( *partIt )->boundingBox();
296 QgsGeos cutLineGeos( cutLine.constGet() );
298 const QgsGeometry points( cutLineGeos.intersection( exterior ) );
299 for (
auto vertexIt = points.vertices_begin(); vertexIt != points.vertices_end(); ++vertexIt )
301 const double snapHeightDelta = std::fabs( point.
elevation() - ( *vertexIt ).y() );
302 if ( snapHeightDelta > maximumSurfaceElevationDelta )
305 const double snapDistance = ( *vertexIt ).distance( targetPoint );
306 visitor( feature.featureId, snapDistance, ( *vertexIt ).x(), ( *vertexIt ).y() );
312 case Qgis::GeometryType::Unknown:
313 case Qgis::GeometryType::Null:
327 profileRangeGeos.prepareGeometry();
331 for (
const Feature &feature : it.value() )
333 if ( feature.crossSectionGeometry.boundingBoxIntersects( profileRange ) )
335 switch ( feature.crossSectionGeometry.type() )
337 case Qgis::GeometryType::Point:
339 for (
auto partIt = feature.crossSectionGeometry.const_parts_begin(); partIt != feature.crossSectionGeometry.const_parts_end(); ++partIt )
341 if (
const QgsPoint *candidatePoint = qgsgeometry_cast< const QgsPoint * >( *partIt ) )
343 if ( profileRange.contains( candidatePoint->x(), candidatePoint->y() ) )
345 visitor( feature.featureId );
352 case Qgis::GeometryType::Line:
353 case Qgis::GeometryType::Polygon:
355 if ( profileRangeGeos.intersects( feature.crossSectionGeometry.constGet() ) )
357 visitor( feature.featureId );
362 case Qgis::GeometryType::Unknown:
363 case Qgis::GeometryType::Null:
377 renderResultsAsIndividualFeatures( context );
382 renderMarkersOverContinuousSurfacePlot( context );
395 painter->setBrush( Qt::NoBrush );
396 painter->setPen( Qt::NoPen );
403 const QRectF visibleRegion( minDistance,
minZ, maxDistance - minDistance,
maxZ -
minZ );
404 QPainterPath clipPath;
405 clipPath.addPolygon( context.
worldTransform().map( visibleRegion ) );
406 painter->setClipPath( clipPath, Qt::ClipOperation::IntersectClip );
408 const QgsRectangle clipPathRect( clipPath.boundingRect() );
412 if ( profileFeature.crossSectionGeometry.isEmpty() )
415 QgsGeometry transformed = profileFeature.crossSectionGeometry;
422 switch ( transformed.
type() )
424 case Qgis::GeometryType::Point:
426 if (
const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( transformed.
constGet() ) )
428 markerSymbol->renderPoint( QPointF( point->x(), point->y() ),
nullptr, context.
renderContext() );
430 else if (
const QgsMultiPoint *multipoint = qgsgeometry_cast< const QgsMultiPoint * >( transformed.
constGet() ) )
432 const int numGeometries = multipoint->numGeometries();
433 for (
int i = 0; i < numGeometries; ++i )
435 markerSymbol->renderPoint( QPointF( multipoint->pointN( i )->x(), multipoint->pointN( i )->y() ),
nullptr, context.
renderContext() );
441 case Qgis::GeometryType::Line:
443 if (
const QgsLineString *line = qgsgeometry_cast< const QgsLineString * >( transformed.
constGet() ) )
445 lineSymbol->renderPolyline( line->asQPolygonF(),
nullptr, context.
renderContext() );
447 else if (
const QgsMultiLineString *multiLinestring = qgsgeometry_cast< const QgsMultiLineString * >( transformed.
constGet() ) )
449 const int numGeometries = multiLinestring->numGeometries();
450 for (
int i = 0; i < numGeometries; ++i )
452 lineSymbol->renderPolyline( multiLinestring->lineStringN( i )->asQPolygonF(),
nullptr, context.
renderContext() );
458 case Qgis::GeometryType::Polygon:
460 if (
const QgsPolygon *polygon = qgsgeometry_cast< const QgsPolygon * >( transformed.
constGet() ) )
462 if (
const QgsCurve *exterior = polygon->exteriorRing() )
463 fillSymbol->renderPolygon( exterior->asQPolygonF(),
nullptr,
nullptr, context.
renderContext() );
465 else if (
const QgsMultiPolygon *multiPolygon = qgsgeometry_cast< const QgsMultiPolygon * >( transformed.
constGet() ) )
467 const int numGeometries = multiPolygon->numGeometries();
468 for (
int i = 0; i < numGeometries; ++i )
470 fillSymbol->renderPolygon( multiPolygon->polygonN( i )->exteriorRing()->asQPolygonF(),
nullptr,
nullptr, context.
renderContext() );
476 case Qgis::GeometryType::Unknown:
477 case Qgis::GeometryType::Null:
487 std::unique_ptr< QgsFeatureRenderer > renderer(
mLayer->renderer()->clone() );
492 QSet<QString> attributes = renderer->usedAttributes( context.
renderContext() );
494 std::unique_ptr< QgsMarkerSymbol > marker(
mMarkerSymbol->clone() );
495 std::unique_ptr< QgsLineSymbol > line(
mLineSymbol->clone() );
496 std::unique_ptr< QgsFillSymbol > fill(
mFillSymbol->clone() );
497 attributes.unite( marker->usedAttributes( context.
renderContext() ) );
498 attributes.unite( line->usedAttributes( context.
renderContext() ) );
499 attributes.unite( fill->usedAttributes( context.
renderContext() ) );
509 if ( !rendererSymbol )
513 marker->setOpacity( rendererSymbol->
opacity() );
514 line->setColor( rendererSymbol->
color() );
515 line->setOpacity( rendererSymbol->
opacity() );
516 fill->setColor( rendererSymbol->
color() );
517 fill->setOpacity( rendererSymbol->
opacity() );
523 const QVector< Feature > profileFeatures =
features.value( feature.
id() );
524 for (
const Feature &profileFeature : profileFeatures )
526 renderResult( profileFeature,
541 QSet<QString> attributes;
556 const QVector< Feature > profileFeatures =
features.value( feature.
id() );
557 for (
const Feature &profileFeature : profileFeatures )
576 painter->setBrush( Qt::NoBrush );
577 painter->setPen( Qt::NoPen );
584 const QRectF visibleRegion( minDistance,
minZ, maxDistance - minDistance,
maxZ -
minZ );
585 QPainterPath clipPath;
586 clipPath.addPolygon( context.
worldTransform().map( visibleRegion ) );
587 painter->setClipPath( clipPath, Qt::ClipOperation::IntersectClip );
593 if ( std::isnan( pointIt.value() ) )
608 mMarkerSymbol.reset( vlGenerator->mProfileMarkerSymbol->clone() );
619 , mProfileCurve( request.profileCurve() ? request.profileCurve()->clone() : nullptr )
620 , mTerrainProvider( request.terrainProvider() ? request.terrainProvider()->clone() : nullptr )
621 , mTolerance( request.tolerance() )
622 , mSourceCrs( layer->
crs() )
623 , mTargetCrs( request.
crs() )
624 , mTransformContext( request.transformContext() )
625 , mExtent( layer->extent() )
627 , mOffset( layer->elevationProperties()->zOffset() )
628 , mScale( layer->elevationProperties()->zScale() )
634 , mExpressionContext( request.expressionContext() )
635 , mFields( layer->fields() )
636 , mDataDefinedProperties( layer->elevationProperties()->dataDefinedProperties() )
637 , mWkbType( layer->wkbType() )
643 if ( mTerrainProvider )
644 mTerrainProvider->prepare();
660 if ( !mProfileCurve || mFeedback->isCanceled() )
664 mTransformedCurve.reset( mProfileCurve->clone() );
666 if ( mTerrainProvider )
667 mTargetToTerrainProviderTransform =
QgsCoordinateTransform( mTargetCrs, mTerrainProvider->crs(), mTransformContext );
671 mTransformedCurve->transform( mLayerToTargetTransform, Qgis::TransformDirection::Reverse );
675 QgsDebugMsg( QStringLiteral(
"Error transforming profile line to vector CRS" ) );
679 const QgsRectangle profileCurveBoundingBox = mTransformedCurve->boundingBox();
680 if ( !profileCurveBoundingBox.
intersects( mExtent ) )
683 if ( mFeedback->isCanceled() )
686 mResults = std::make_unique< QgsVectorLayerProfileResults >();
687 mResults->mLayer = mLayer;
688 mResults->copyPropertiesFromGenerator(
this );
690 mProfileCurveEngine.reset(
new QgsGeos( mProfileCurve.get() ) );
691 mProfileCurveEngine->prepareGeometry();
693 mDataDefinedProperties.
prepare( mExpressionContext );
695 if ( mFeedback->isCanceled() )
700 case Qgis::GeometryType::Point:
701 if ( !generateProfileForPoints() )
705 case Qgis::GeometryType::Line:
706 if ( !generateProfileForLines() )
710 case Qgis::GeometryType::Polygon:
711 if ( !generateProfileForPolygons() )
715 case Qgis::GeometryType::Unknown:
716 case Qgis::GeometryType::Null:
725 return mResults.release();
730 return mFeedback.get();
733bool QgsVectorLayerProfileGenerator::generateProfileForPoints()
745 std::unique_ptr< QgsAbstractGeometry > bufferedCurve( mProfileCurveEngine->buffer( mTolerance, 8, Qgis::EndCapStyle::Flat, Qgis::JoinStyle::Round, 2 ) );
746 QgsGeos bufferedCurveEngine( bufferedCurve.get() );
747 bufferedCurveEngine.prepareGeometry();
749 auto processPoint = [
this, &bufferedCurveEngine](
const QgsFeature & feature,
const QgsPoint * point )
751 if ( !bufferedCurveEngine.intersects( point ) )
756 const double height = featureZToHeight( point->x(), point->y(), point->z(), offset );
757 mResults->mRawPoints.append(
QgsPoint( point->x(), point->y(), height ) );
758 mResults->minZ = std::min( mResults->minZ, height );
759 mResults->maxZ = std::max( mResults->maxZ, height );
762 const double distance = mProfileCurveEngine->lineLocatePoint( *point, &lastError );
763 mResults->mDistanceToHeightMap.insert( distance, height );
767 if ( mExtrusionEnabled )
772 QgsPoint( point->x(), point->y(), height + extrusion ) ) );
774 QgsPoint( distance, height + extrusion ) ) );
775 mResults->minZ = std::min( mResults->minZ, height + extrusion );
776 mResults->maxZ = std::max( mResults->maxZ, height + extrusion );
783 mResults->features[resultFeature.
featureId].append( resultFeature );
790 if ( mFeedback->isCanceled() )
800 processPoint( feature, qgsgeometry_cast< const QgsPoint * >( *it ) );
805 processPoint( feature, qgsgeometry_cast< const QgsPoint * >( g.
constGet() ) );
811bool QgsVectorLayerProfileGenerator::generateProfileForLines()
823 std::unique_ptr< QgsAbstractGeometry > intersection( mProfileCurveEngine->intersection( curve, &error ) );
827 if ( mFeedback->isCanceled() )
831 curveGeos.prepareGeometry();
833 if ( mFeedback->isCanceled() )
836 for (
auto it = intersection->const_parts_begin(); it != intersection->const_parts_end(); ++it )
838 if ( mFeedback->isCanceled() )
841 if (
const QgsPoint *intersectionPoint = qgsgeometry_cast< const QgsPoint * >( *it ) )
844 const double distance = curveGeos.lineLocatePoint( *intersectionPoint, &error );
845 std::unique_ptr< QgsPoint > interpolatedPoint( curve->interpolatePoint( distance ) );
849 const double height = featureZToHeight( interpolatedPoint->x(), interpolatedPoint->y(), interpolatedPoint->z(), offset );
850 mResults->mRawPoints.append(
QgsPoint( interpolatedPoint->x(), interpolatedPoint->y(), height ) );
851 mResults->minZ = std::min( mResults->minZ, height );
852 mResults->maxZ = std::max( mResults->maxZ, height );
854 const double distanceAlongProfileCurve = mProfileCurveEngine->lineLocatePoint( *interpolatedPoint, &error );
855 mResults->mDistanceToHeightMap.insert( distanceAlongProfileCurve, height );
859 if ( mExtrusionEnabled )
864 QgsPoint( interpolatedPoint->x(), interpolatedPoint->y(), height + extrusion ) ) );
866 QgsPoint( distanceAlongProfileCurve, height + extrusion ) ) );
867 mResults->minZ = std::min( mResults->minZ, height + extrusion );
868 mResults->maxZ = std::max( mResults->maxZ, height + extrusion );
875 mResults->features[resultFeature.
featureId].append( resultFeature );
884 if ( mFeedback->isCanceled() )
897 if ( !mProfileCurveEngine->intersects( *it ) )
900 processCurve( feature, qgsgeometry_cast< const QgsCurve * >( *it ) );
905 processCurve( feature, qgsgeometry_cast< const QgsCurve * >( g.
constGet() ) );
911bool QgsVectorLayerProfileGenerator::generateProfileForPolygons()
920 auto interpolatePointOnTriangle = [](
const QgsPolygon * triangle,
double x,
double y ) ->
QgsPoint
927 const double z = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, p1.
z(), p2.
z(), p3.
z(),
QgsPointXY( x, y ) );
931 std::function< void(
const QgsPolygon *triangle,
const QgsAbstractGeometry *intersect, QVector< QgsGeometry > &, QVector< QgsGeometry > & ) > processTriangleLineIntersect;
932 processTriangleLineIntersect = [
this, &interpolatePointOnTriangle, &processTriangleLineIntersect](
const QgsPolygon * triangle,
const QgsAbstractGeometry * intersect, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts )
937 case Qgis::GeometryType::Point:
938 if (
const QgsMultiPoint *mp = qgsgeometry_cast< const QgsMultiPoint * >( intersect ) )
940 const int numPoint = mp->numGeometries();
941 for (
int i = 0; i < numPoint; ++i )
943 processTriangleLineIntersect( triangle, mp->geometryN( i ), transformedParts, crossSectionParts );
946 else if (
const QgsPoint *p = qgsgeometry_cast< const QgsPoint * >( intersect ) )
948 const QgsPoint interpolatedPoint = interpolatePointOnTriangle( triangle, p->x(), p->y() );
949 mResults->mRawPoints.append( interpolatedPoint );
950 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() );
951 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() );
954 const double distance = mProfileCurveEngine->lineLocatePoint( *p, &lastError );
955 mResults->mDistanceToHeightMap.insert( distance, interpolatedPoint.
z() );
957 if ( mExtrusionEnabled )
962 QgsPoint( interpolatedPoint.
x(), interpolatedPoint.
y(), interpolatedPoint.
z() + extrusion ) ) ) );
964 QgsPoint( distance, interpolatedPoint.
z() + extrusion ) ) ) );
965 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() + extrusion );
966 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() + extrusion );
975 case Qgis::GeometryType::Line:
976 if (
const QgsMultiLineString *ml = qgsgeometry_cast< const QgsMultiLineString * >( intersect ) )
978 const int numLines = ml->numGeometries();
979 for (
int i = 0; i < numLines; ++i )
981 processTriangleLineIntersect( triangle, ml->geometryN( i ), transformedParts, crossSectionParts );
984 else if (
const QgsLineString *ls = qgsgeometry_cast< const QgsLineString * >( intersect ) )
986 const int numPoints = ls->numPoints();
987 QVector< double > newX;
988 newX.resize( numPoints );
989 QVector< double > newY;
990 newY.resize( numPoints );
991 QVector< double > newZ;
992 newZ.resize( numPoints );
993 QVector< double > newDistance;
994 newDistance.resize( numPoints );
996 const double *inX = ls->xData();
997 const double *inY = ls->yData();
998 double *outX = newX.data();
999 double *outY = newY.data();
1000 double *outZ = newZ.data();
1001 double *outDistance = newDistance.data();
1003 QVector< double > extrudedZ;
1004 double *extZOut =
nullptr;
1005 double extrusion = 0;
1006 if ( mExtrusionEnabled )
1008 extrudedZ.resize( numPoints );
1009 extZOut = extrudedZ.data();
1015 for (
int i = 0 ; i < numPoints; ++i )
1020 QgsPoint interpolatedPoint = interpolatePointOnTriangle( triangle, x, y );
1023 *outZ++ = interpolatedPoint.
z();
1025 *extZOut++ = interpolatedPoint.
z() + extrusion;
1027 mResults->mRawPoints.append( interpolatedPoint );
1028 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() );
1029 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() );
1030 if ( mExtrusionEnabled )
1032 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() + extrusion );
1033 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() + extrusion );
1036 const double distance = mProfileCurveEngine->lineLocatePoint( interpolatedPoint, &lastError );
1037 *outDistance++ = distance;
1039 mResults->mDistanceToHeightMap.insert( distance, interpolatedPoint.
z() );
1042 if ( mExtrusionEnabled )
1044 std::unique_ptr< QgsLineString > ring = std::make_unique< QgsLineString >( newX, newY, newZ );
1045 std::unique_ptr< QgsLineString > extrudedRing = std::make_unique< QgsLineString >( newX, newY, extrudedZ );
1046 std::unique_ptr< QgsLineString > reversedExtrusion( extrudedRing->reversed() );
1047 ring->append( reversedExtrusion.get() );
1052 std::unique_ptr< QgsLineString > distanceVHeightRing = std::make_unique< QgsLineString >( newDistance, newZ );
1053 std::unique_ptr< QgsLineString > extrudedDistanceVHeightRing = std::make_unique< QgsLineString >( newDistance, extrudedZ );
1054 std::unique_ptr< QgsLineString > reversedDistanceVHeightExtrusion( extrudedDistanceVHeightRing->reversed() );
1055 distanceVHeightRing->append( reversedDistanceVHeightExtrusion.get() );
1056 distanceVHeightRing->close();
1067 case Qgis::GeometryType::Polygon:
1068 case Qgis::GeometryType::Unknown:
1069 case Qgis::GeometryType::Null:
1074 auto processPolygon = [
this, &processTriangleLineIntersect](
const QgsCurvePolygon * polygon, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts,
double offset )
1076 std::unique_ptr< QgsPolygon > clampedPolygon;
1077 if (
const QgsPolygon *p = qgsgeometry_cast< const QgsPolygon * >( polygon ) )
1079 clampedPolygon.reset( p->clone() );
1083 clampedPolygon.reset( qgsgeometry_cast< QgsPolygon * >( polygon->
segmentize() ) );
1085 clampAltitudes( clampedPolygon.get(), offset );
1087 if ( mFeedback->isCanceled() )
1090 const QgsRectangle bounds = clampedPolygon->boundingBox();
1092 t.addPolygon( *clampedPolygon, 0 );
1095 if ( mFeedback->isCanceled() )
1101 const int numTriangles = qgsgeometry_cast< const QgsMultiPolygon * >( tessellation.constGet() )->numGeometries();
1102 for (
int i = 0; i < numTriangles; ++i )
1104 if ( mFeedback->isCanceled() )
1107 const QgsPolygon *triangle = qgsgeometry_cast< const QgsPolygon * >( qgsgeometry_cast< const QgsMultiPolygon * >( tessellation.constGet() )->geometryN( i ) );
1108 if ( !mProfileCurveEngine->intersects( triangle ) )
1112 std::unique_ptr< QgsAbstractGeometry > intersection( mProfileCurveEngine->intersection( triangle, &error ) );
1113 if ( !intersection )
1116 processTriangleLineIntersect( triangle, intersection.get(), transformedParts, crossSectionParts );
1124 if ( mFeedback->isCanceled() )
1135 QVector< QgsGeometry > transformedParts;
1136 QVector< QgsGeometry > crossSectionParts;
1141 if ( mFeedback->isCanceled() )
1144 if ( !mProfileCurveEngine->intersects( *it ) )
1147 processPolygon( qgsgeometry_cast< const QgsCurvePolygon * >( *it ), transformedParts, crossSectionParts, offset );
1152 processPolygon( qgsgeometry_cast< const QgsCurvePolygon * >( g.
constGet() ), transformedParts, crossSectionParts, offset );
1155 if ( mFeedback->isCanceled() )
1161 if ( !crossSectionParts.empty() )
1164 if ( unioned.
type() == Qgis::GeometryType::Line )
1168 mResults->features[resultFeature.
featureId].append( resultFeature );
1173double QgsVectorLayerProfileGenerator::terrainHeight(
double x,
double y )
1175 if ( !mTerrainProvider )
1176 return std::numeric_limits<double>::quiet_NaN();
1186 return std::numeric_limits<double>::quiet_NaN();
1189 return mTerrainProvider->heightAt( x, y );
1192double QgsVectorLayerProfileGenerator::featureZToHeight(
double x,
double y,
double z,
double offset )
1194 switch ( mClamping )
1202 const double terrainZ = terrainHeight( x, y );
1203 if ( !std::isnan( terrainZ ) )
1205 switch ( mClamping )
1208 if ( std::isnan( z ) )
1226 return ( std::isnan( z ) ? 0 : z ) * mScale + offset;
1233 if ( mFeedback->isCanceled() )
1236 double terrainZ = 0;
1237 switch ( mClamping )
1246 pt.
setX( lineString->
xAt( i ) );
1247 pt.
setY( lineString->
yAt( i ) );
1255 terrainZ = terrainHeight( pt.
x(), pt.
y() );
1265 switch ( mClamping )
1269 geomZ = lineString->
zAt( i );
1276 const double z = ( terrainZ + ( std::isnan( geomZ ) ? 0 : geomZ ) ) * mScale + offset;
1277 lineString->
setZAt( i, z );
1281bool QgsVectorLayerProfileGenerator::clampAltitudes(
QgsPolygon *polygon,
double offset )
1283 if ( !polygon->
is3D() )
1298 QgsLineString *lineString = qgsgeometry_cast<QgsLineString *>( curve );
1302 clampAltitudes( lineString,
centroid, offset );
1306 if ( mFeedback->isCanceled() )
1310 QgsLineString *lineString = qgsgeometry_cast<QgsLineString *>( curve );
1314 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)
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.
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< 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.
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.
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
const QgsCoordinateReferenceSystem & crs
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.