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;
166 void 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() )
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() );
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() );
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() );
327 profileRangeGeos.prepareGeometry();
331 for (
const Feature &feature : it.value() )
333 if ( feature.crossSectionGeometry.boundingBoxIntersects( profileRange ) )
335 switch ( feature.crossSectionGeometry.type() )
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 );
355 if ( profileRangeGeos.intersects( feature.crossSectionGeometry.constGet() ) )
357 visitor( feature.featureId );
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() )
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() );
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() );
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() );
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() )
701 if ( !generateProfileForPoints() )
706 if ( !generateProfileForLines() )
711 if ( !generateProfileForPolygons() )
725 return mResults.release();
730 return mFeedback.get();
733 bool 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() ) );
811 bool 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() ) );
911 bool 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 )
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 );
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();
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() )
1168 mResults->features[resultFeature.
featureId].append( resultFeature );
1173 double 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 );
1192 double 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 );
1281 bool 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 );