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();
662 if ( !mProfileCurve || mFeedback->isCanceled() )
666 mTransformedCurve.reset( mProfileCurve->clone() );
668 if ( mTerrainProvider )
669 mTargetToTerrainProviderTransform =
QgsCoordinateTransform( mTargetCrs, mTerrainProvider->crs(), mTransformContext );
673 mTransformedCurve->transform( mLayerToTargetTransform, Qgis::TransformDirection::Reverse );
677 QgsDebugError( QStringLiteral(
"Error transforming profile line to vector CRS" ) );
681 const QgsRectangle profileCurveBoundingBox = mTransformedCurve->boundingBox();
682 if ( !profileCurveBoundingBox.
intersects( mExtent ) )
685 if ( mFeedback->isCanceled() )
688 mResults = std::make_unique< QgsVectorLayerProfileResults >();
689 mResults->mLayer = mLayer;
690 mResults->copyPropertiesFromGenerator(
this );
692 mProfileCurveEngine.reset(
new QgsGeos( mProfileCurve.get() ) );
693 mProfileCurveEngine->prepareGeometry();
695 mDataDefinedProperties.
prepare( mExpressionContext );
697 if ( mFeedback->isCanceled() )
702 case Qgis::GeometryType::Point:
703 if ( !generateProfileForPoints() )
707 case Qgis::GeometryType::Line:
708 if ( !generateProfileForLines() )
712 case Qgis::GeometryType::Polygon:
713 if ( !generateProfileForPolygons() )
717 case Qgis::GeometryType::Unknown:
718 case Qgis::GeometryType::Null:
727 return mResults.release();
732 return mFeedback.get();
735bool QgsVectorLayerProfileGenerator::generateProfileForPoints()
747 std::unique_ptr< QgsAbstractGeometry > bufferedCurve( mProfileCurveEngine->buffer( mTolerance, 8, Qgis::EndCapStyle::Flat, Qgis::JoinStyle::Round, 2 ) );
748 QgsGeos bufferedCurveEngine( bufferedCurve.get() );
749 bufferedCurveEngine.prepareGeometry();
751 auto processPoint = [
this, &bufferedCurveEngine](
const QgsFeature & feature,
const QgsPoint * point )
753 if ( !bufferedCurveEngine.intersects( point ) )
758 const double height = featureZToHeight( point->x(), point->y(), point->z(), offset );
759 mResults->mRawPoints.append(
QgsPoint( point->x(), point->y(), height ) );
760 mResults->minZ = std::min( mResults->minZ, height );
761 mResults->maxZ = std::max( mResults->maxZ, height );
764 const double distance = mProfileCurveEngine->lineLocatePoint( *point, &lastError );
765 mResults->mDistanceToHeightMap.insert( distance, height );
769 if ( mExtrusionEnabled )
774 QgsPoint( point->x(), point->y(), height + extrusion ) ) );
776 QgsPoint( distance, height + extrusion ) ) );
777 mResults->minZ = std::min( mResults->minZ, height + extrusion );
778 mResults->maxZ = std::max( mResults->maxZ, height + extrusion );
785 mResults->features[resultFeature.
featureId].append( resultFeature );
792 if ( mFeedback->isCanceled() )
802 processPoint( feature, qgsgeometry_cast< const QgsPoint * >( *it ) );
807 processPoint( feature, qgsgeometry_cast< const QgsPoint * >( g.
constGet() ) );
813bool QgsVectorLayerProfileGenerator::generateProfileForLines()
825 std::unique_ptr< QgsAbstractGeometry > intersection( mProfileCurveEngine->intersection( curve, &error ) );
829 if ( mFeedback->isCanceled() )
833 curveGeos.prepareGeometry();
835 if ( mFeedback->isCanceled() )
838 for (
auto it = intersection->const_parts_begin(); it != intersection->const_parts_end(); ++it )
840 if ( mFeedback->isCanceled() )
843 if (
const QgsPoint *intersectionPoint = qgsgeometry_cast< const QgsPoint * >( *it ) )
846 const double distance = curveGeos.lineLocatePoint( *intersectionPoint, &error );
847 std::unique_ptr< QgsPoint > interpolatedPoint( curve->interpolatePoint( distance ) );
851 const double height = featureZToHeight( interpolatedPoint->x(), interpolatedPoint->y(), interpolatedPoint->z(), offset );
852 mResults->mRawPoints.append(
QgsPoint( interpolatedPoint->x(), interpolatedPoint->y(), height ) );
853 mResults->minZ = std::min( mResults->minZ, height );
854 mResults->maxZ = std::max( mResults->maxZ, height );
856 const double distanceAlongProfileCurve = mProfileCurveEngine->lineLocatePoint( *interpolatedPoint, &error );
857 mResults->mDistanceToHeightMap.insert( distanceAlongProfileCurve, height );
861 if ( mExtrusionEnabled )
866 QgsPoint( interpolatedPoint->x(), interpolatedPoint->y(), height + extrusion ) ) );
868 QgsPoint( distanceAlongProfileCurve, height + extrusion ) ) );
869 mResults->minZ = std::min( mResults->minZ, height + extrusion );
870 mResults->maxZ = std::max( mResults->maxZ, height + extrusion );
877 mResults->features[resultFeature.
featureId].append( resultFeature );
886 if ( mFeedback->isCanceled() )
899 if ( !mProfileCurveEngine->intersects( *it ) )
902 processCurve( feature, qgsgeometry_cast< const QgsCurve * >( *it ) );
907 processCurve( feature, qgsgeometry_cast< const QgsCurve * >( g.
constGet() ) );
913bool QgsVectorLayerProfileGenerator::generateProfileForPolygons()
922 auto interpolatePointOnTriangle = [](
const QgsPolygon * triangle,
double x,
double y ) ->
QgsPoint
929 const double z = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, p1.
z(), p2.
z(), p3.
z(),
QgsPointXY( x, y ) );
933 std::function< void(
const QgsPolygon *triangle,
const QgsAbstractGeometry *intersect, QVector< QgsGeometry > &, QVector< QgsGeometry > & ) > processTriangleLineIntersect;
934 processTriangleLineIntersect = [
this, &interpolatePointOnTriangle, &processTriangleLineIntersect](
const QgsPolygon * triangle,
const QgsAbstractGeometry * intersect, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts )
939 case Qgis::GeometryType::Point:
940 if (
const QgsMultiPoint *mp = qgsgeometry_cast< const QgsMultiPoint * >( intersect ) )
942 const int numPoint = mp->numGeometries();
943 for (
int i = 0; i < numPoint; ++i )
945 processTriangleLineIntersect( triangle, mp->geometryN( i ), transformedParts, crossSectionParts );
948 else if (
const QgsPoint *p = qgsgeometry_cast< const QgsPoint * >( intersect ) )
950 const QgsPoint interpolatedPoint = interpolatePointOnTriangle( triangle, p->x(), p->y() );
951 mResults->mRawPoints.append( interpolatedPoint );
952 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() );
953 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() );
956 const double distance = mProfileCurveEngine->lineLocatePoint( *p, &lastError );
957 mResults->mDistanceToHeightMap.insert( distance, interpolatedPoint.
z() );
959 if ( mExtrusionEnabled )
964 QgsPoint( interpolatedPoint.
x(), interpolatedPoint.
y(), interpolatedPoint.
z() + extrusion ) ) ) );
966 QgsPoint( distance, interpolatedPoint.
z() + extrusion ) ) ) );
967 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() + extrusion );
968 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() + extrusion );
977 case Qgis::GeometryType::Line:
978 if (
const QgsMultiLineString *ml = qgsgeometry_cast< const QgsMultiLineString * >( intersect ) )
980 const int numLines = ml->numGeometries();
981 for (
int i = 0; i < numLines; ++i )
983 processTriangleLineIntersect( triangle, ml->geometryN( i ), transformedParts, crossSectionParts );
986 else if (
const QgsLineString *ls = qgsgeometry_cast< const QgsLineString * >( intersect ) )
988 const int numPoints = ls->numPoints();
989 QVector< double > newX;
990 newX.resize( numPoints );
991 QVector< double > newY;
992 newY.resize( numPoints );
993 QVector< double > newZ;
994 newZ.resize( numPoints );
995 QVector< double > newDistance;
996 newDistance.resize( numPoints );
998 const double *inX = ls->xData();
999 const double *inY = ls->yData();
1000 double *outX = newX.data();
1001 double *outY = newY.data();
1002 double *outZ = newZ.data();
1003 double *outDistance = newDistance.data();
1005 QVector< double > extrudedZ;
1006 double *extZOut =
nullptr;
1007 double extrusion = 0;
1008 if ( mExtrusionEnabled )
1010 extrudedZ.resize( numPoints );
1011 extZOut = extrudedZ.data();
1017 for (
int i = 0 ; i < numPoints; ++i )
1022 QgsPoint interpolatedPoint = interpolatePointOnTriangle( triangle, x, y );
1025 *outZ++ = interpolatedPoint.
z();
1027 *extZOut++ = interpolatedPoint.
z() + extrusion;
1029 mResults->mRawPoints.append( interpolatedPoint );
1030 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() );
1031 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() );
1032 if ( mExtrusionEnabled )
1034 mResults->minZ = std::min( mResults->minZ, interpolatedPoint.
z() + extrusion );
1035 mResults->maxZ = std::max( mResults->maxZ, interpolatedPoint.
z() + extrusion );
1038 const double distance = mProfileCurveEngine->lineLocatePoint( interpolatedPoint, &lastError );
1039 *outDistance++ = distance;
1041 mResults->mDistanceToHeightMap.insert( distance, interpolatedPoint.
z() );
1044 if ( mExtrusionEnabled )
1046 std::unique_ptr< QgsLineString > ring = std::make_unique< QgsLineString >( newX, newY, newZ );
1047 std::unique_ptr< QgsLineString > extrudedRing = std::make_unique< QgsLineString >( newX, newY, extrudedZ );
1048 std::unique_ptr< QgsLineString > reversedExtrusion( extrudedRing->reversed() );
1049 ring->append( reversedExtrusion.get() );
1054 std::unique_ptr< QgsLineString > distanceVHeightRing = std::make_unique< QgsLineString >( newDistance, newZ );
1055 std::unique_ptr< QgsLineString > extrudedDistanceVHeightRing = std::make_unique< QgsLineString >( newDistance, extrudedZ );
1056 std::unique_ptr< QgsLineString > reversedDistanceVHeightExtrusion( extrudedDistanceVHeightRing->reversed() );
1057 distanceVHeightRing->append( reversedDistanceVHeightExtrusion.get() );
1058 distanceVHeightRing->close();
1069 case Qgis::GeometryType::Polygon:
1070 case Qgis::GeometryType::Unknown:
1071 case Qgis::GeometryType::Null:
1076 auto processPolygon = [
this, &processTriangleLineIntersect](
const QgsCurvePolygon * polygon, QVector< QgsGeometry > &transformedParts, QVector< QgsGeometry > &crossSectionParts,
double offset )
1078 std::unique_ptr< QgsPolygon > clampedPolygon;
1079 if (
const QgsPolygon *p = qgsgeometry_cast< const QgsPolygon * >( polygon ) )
1081 clampedPolygon.reset( p->clone() );
1085 clampedPolygon.reset( qgsgeometry_cast< QgsPolygon * >( polygon->
segmentize() ) );
1087 clampAltitudes( clampedPolygon.get(), offset );
1089 if ( mFeedback->isCanceled() )
1092 const QgsRectangle bounds = clampedPolygon->boundingBox();
1094 t.addPolygon( *clampedPolygon, 0 );
1097 if ( mFeedback->isCanceled() )
1103 const int numTriangles = qgsgeometry_cast< const QgsMultiPolygon * >( tessellation.constGet() )->numGeometries();
1104 for (
int i = 0; i < numTriangles; ++i )
1106 if ( mFeedback->isCanceled() )
1109 const QgsPolygon *triangle = qgsgeometry_cast< const QgsPolygon * >( qgsgeometry_cast< const QgsMultiPolygon * >( tessellation.constGet() )->geometryN( i ) );
1110 if ( !mProfileCurveEngine->intersects( triangle ) )
1114 std::unique_ptr< QgsAbstractGeometry > intersection( mProfileCurveEngine->intersection( triangle, &error ) );
1115 if ( !intersection )
1118 processTriangleLineIntersect( triangle, intersection.get(), transformedParts, crossSectionParts );
1126 if ( mFeedback->isCanceled() )
1137 QVector< QgsGeometry > transformedParts;
1138 QVector< QgsGeometry > crossSectionParts;
1143 if ( mFeedback->isCanceled() )
1146 if ( !mProfileCurveEngine->intersects( *it ) )
1149 processPolygon( qgsgeometry_cast< const QgsCurvePolygon * >( *it ), transformedParts, crossSectionParts, offset );
1154 processPolygon( qgsgeometry_cast< const QgsCurvePolygon * >( g.
constGet() ), transformedParts, crossSectionParts, offset );
1157 if ( mFeedback->isCanceled() )
1163 if ( !crossSectionParts.empty() )
1166 if ( unioned.
type() == Qgis::GeometryType::Line )
1170 mResults->features[resultFeature.
featureId].append( resultFeature );
1175double QgsVectorLayerProfileGenerator::terrainHeight(
double x,
double y )
1177 if ( !mTerrainProvider )
1178 return std::numeric_limits<double>::quiet_NaN();
1188 return std::numeric_limits<double>::quiet_NaN();
1191 return mTerrainProvider->heightAt( x, y );
1194double QgsVectorLayerProfileGenerator::featureZToHeight(
double x,
double y,
double z,
double offset )
1196 switch ( mClamping )
1204 const double terrainZ = terrainHeight( x, y );
1205 if ( !std::isnan( terrainZ ) )
1207 switch ( mClamping )
1210 if ( std::isnan( z ) )
1228 return ( std::isnan( z ) ? 0 : z ) * mScale + offset;
1235 if ( mFeedback->isCanceled() )
1238 double terrainZ = 0;
1239 switch ( mClamping )
1248 pt.
setX( lineString->
xAt( i ) );
1249 pt.
setY( lineString->
yAt( i ) );
1257 terrainZ = terrainHeight( pt.
x(), pt.
y() );
1267 switch ( mClamping )
1271 geomZ = lineString->
zAt( i );
1278 const double z = ( terrainZ + ( std::isnan( geomZ ) ? 0 : geomZ ) ) * mScale + offset;
1279 lineString->
setZAt( i, z );
1283bool QgsVectorLayerProfileGenerator::clampAltitudes(
QgsPolygon *polygon,
double offset )
1285 if ( !polygon->
is3D() )
1300 QgsLineString *lineString = qgsgeometry_cast<QgsLineString *>( curve );
1304 clampAltitudes( lineString,
centroid, offset );
1308 if ( mFeedback->isCanceled() )
1312 QgsLineString *lineString = qgsgeometry_cast<QgsLineString *>( curve );
1316 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
#define QgsDebugError(str)
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.