QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsmeshlayerprofilegenerator.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmeshlayerprofilegenerator.cpp
3  ---------------
4  begin : March 2022
5  copyright : (C) 2022 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
18 #include "qgsprofilerequest.h"
19 #include "qgscurve.h"
20 #include "qgsmeshlayer.h"
21 #include "qgscoordinatetransform.h"
22 #include "qgsgeos.h"
23 #include "qgsterrainprovider.h"
24 #include "qgsmeshlayerutils.h"
25 #include "qgslinesymbol.h"
26 #include "qgsfillsymbol.h"
28 #include "qgsprofilesnapping.h"
29 #include "qgsprofilepoint.h"
30 
31 //
32 // QgsMeshLayerProfileGenerator
33 //
34 
36 {
37  return QStringLiteral( "mesh" );
38 }
39 
40 QVector<QgsProfileIdentifyResults> QgsMeshLayerProfileResults::identify( const QgsProfilePoint &point, const QgsProfileIdentifyContext &context )
41 {
42  const QVector<QgsProfileIdentifyResults> noLayerResults = QgsAbstractProfileSurfaceResults::identify( point, context );
43 
44  // we have to make a new list, with the correct layer reference set
45  QVector<QgsProfileIdentifyResults> res;
46  res.reserve( noLayerResults.size() );
47  for ( const QgsProfileIdentifyResults &result : noLayerResults )
48  {
49  res.append( QgsProfileIdentifyResults( mLayer, result.results() ) );
50  }
51  return res;
52 }
53 
54 //
55 // QgsMeshLayerProfileGenerator
56 //
57 
59  : mId( layer->id() )
60  , mFeedback( std::make_unique< QgsFeedback >() )
61  , mProfileCurve( request.profileCurve() ? request.profileCurve()->clone() : nullptr )
62  , mSourceCrs( layer->crs() )
63  , mTargetCrs( request.crs() )
64  , mTransformContext( request.transformContext() )
65  , mOffset( layer->elevationProperties()->zOffset() )
66  , mScale( layer->elevationProperties()->zScale() )
67  , mLayer( layer )
68  , mStepDistance( request.stepDistance() )
69 {
70  layer->updateTriangularMesh();
71  mTriangularMesh = *layer->triangularMesh();
72 
73  mSymbology = qgis::down_cast< QgsMeshLayerElevationProperties * >( layer->elevationProperties() )->profileSymbology();
74  mLineSymbol.reset( qgis::down_cast< QgsMeshLayerElevationProperties * >( layer->elevationProperties() )->profileLineSymbol()->clone() );
75  mFillSymbol.reset( qgis::down_cast< QgsMeshLayerElevationProperties * >( layer->elevationProperties() )->profileFillSymbol()->clone() );
76 }
77 
79 {
80  return mId;
81 }
82 
84 
86 {
87  if ( !mProfileCurve || mFeedback->isCanceled() )
88  return false;
89 
90  // we need to transform the profile curve to the mesh's CRS
91  QgsGeometry transformedCurve( mProfileCurve->clone() );
92  mLayerToTargetTransform = QgsCoordinateTransform( mSourceCrs, mTargetCrs, mTransformContext );
93 
94  try
95  {
96  transformedCurve.transform( mLayerToTargetTransform, Qgis::TransformDirection::Reverse );
97  }
98  catch ( QgsCsException & )
99  {
100  QgsDebugMsg( QStringLiteral( "Error transforming profile line to mesh CRS" ) );
101  return false;
102  }
103 
104  if ( mFeedback->isCanceled() )
105  return false;
106 
107  mResults = std::make_unique< QgsMeshLayerProfileResults >();
108  mResults->mLayer = mLayer;
109  mResults->copyPropertiesFromGenerator( this );
110 
111  // we don't currently have any method to determine line->mesh intersection points, so for now we just sample at about 100(?) points over the line
112  const double curveLength = transformedCurve.length();
113 
114  if ( !std::isnan( mStepDistance ) )
115  transformedCurve = transformedCurve.densifyByDistance( mStepDistance );
116  else
117  transformedCurve = transformedCurve.densifyByDistance( curveLength / 100 );
118 
119  if ( mFeedback->isCanceled() )
120  return false;
121 
122  for ( auto it = transformedCurve.vertices_begin(); it != transformedCurve.vertices_end(); ++it )
123  {
124  if ( mFeedback->isCanceled() )
125  return false;
126 
127  QgsPoint point = ( *it );
128  const double height = heightAt( point.x(), point.y() );
129 
130  try
131  {
132  point.transform( mLayerToTargetTransform );
133  }
134  catch ( QgsCsException & )
135  {
136  continue;
137  }
138  mResults->mRawPoints.append( QgsPoint( point.x(), point.y(), height ) );
139  }
140 
141  if ( mFeedback->isCanceled() )
142  return false;
143 
144  // convert x/y values back to distance/height values
145  QgsGeos originalCurveGeos( mProfileCurve.get() );
146  originalCurveGeos.prepareGeometry();
147  QString lastError;
148  for ( const QgsPoint &pixel : std::as_const( mResults->mRawPoints ) )
149  {
150  if ( mFeedback->isCanceled() )
151  return false;
152 
153  const double distance = originalCurveGeos.lineLocatePoint( pixel, &lastError );
154 
155  if ( !std::isnan( pixel.z() ) )
156  {
157  mResults->minZ = std::min( pixel.z(), mResults->minZ );
158  mResults->maxZ = std::max( pixel.z(), mResults->maxZ );
159  }
160  mResults->mDistanceToHeightMap.insert( distance, pixel.z() );
161  }
162 
163  return true;
164 }
165 
167 {
168  return mResults.release();
169 }
170 
172 {
173  return mFeedback.get();
174 }
175 
176 double QgsMeshLayerProfileGenerator::heightAt( double x, double y )
177 {
178  return QgsMeshLayerUtils::interpolateZForPoint( mTriangularMesh, x, y ) * mScale + mOffset;
179 }
180 
QgsProfileIdentifyContext
Encapsulates the context of identifying profile results.
Definition: qgsabstractprofilegenerator.h:125
qgsmeshlayerutils.h
qgsmeshlayerprofilegenerator.h
QgsPoint
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:48
QgsGeometry::transform
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.
Definition: qgsgeometry.cpp:3128
QgsAbstractProfileSurfaceGenerator::mFillSymbol
std::unique_ptr< QgsFillSymbol > mFillSymbol
Definition: qgsabstractprofilesurfacegenerator.h:94
crs
const QgsCoordinateReferenceSystem & crs
Definition: qgswfsgetfeature.cpp:105
QgsMeshLayerProfileResults::type
QString type() const override
Returns the unique string identifier for the results type.
Definition: qgsmeshlayerprofilegenerator.cpp:35
QgsMeshLayerProfileGenerator::feedback
QgsFeedback * feedback() const override
Access to feedback object of the generator (may be nullptr)
Definition: qgsmeshlayerprofilegenerator.cpp:171
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsMeshLayerProfileGenerator::generateProfile
bool generateProfile(const QgsProfileGenerationContext &context=QgsProfileGenerationContext()) override
Generate the profile (based on data stored in the class).
Definition: qgsmeshlayerprofilegenerator.cpp:85
qgsmeshlayerelevationproperties.h
QgsMeshLayer::triangularMesh
QgsTriangularMesh * triangularMesh(double minimumTriangleSize=0) const
Returns triangular mesh (nullptr before rendering or calling to updateMesh).
Definition: qgsmeshlayer.cpp:285
QgsProfilePoint
Encapsulates a point on a distance-elevation profile.
Definition: qgsprofilepoint.h:30
QgsProfileGenerationContext
Encapsulates the context in which an elevation profile is to be generated.
Definition: qgsabstractprofilegenerator.h:262
QgsMeshLayer::updateTriangularMesh
void updateTriangularMesh(const QgsCoordinateTransform &transform=QgsCoordinateTransform())
Gets native mesh and updates (creates if it doesn't exist) the base triangular mesh.
Definition: qgsmeshlayer.cpp:317
QgsProfileIdentifyResults
Stores identify results generated by a QgsAbstractProfileResults object.
Definition: qgsabstractprofilegenerator.h:158
QgsPoint::y
double y
Definition: qgspoint.h:70
QgsAbstractProfileSurfaceGenerator::mSymbology
Qgis::ProfileSurfaceSymbology mSymbology
Definition: qgsabstractprofilesurfacegenerator.h:92
QgsCsException
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
qgsprofilesnapping.h
QgsMeshLayerProfileGenerator::QgsMeshLayerProfileGenerator
QgsMeshLayerProfileGenerator(QgsMeshLayer *layer, const QgsProfileRequest &request)
Constructor for QgsMeshLayerProfileGenerator.
Definition: qgsmeshlayerprofilegenerator.cpp:58
qgsprofilepoint.h
QgsAbstractProfileSurfaceGenerator::mLineSymbol
std::unique_ptr< QgsLineSymbol > mLineSymbol
Definition: qgsabstractprofilesurfacegenerator.h:93
QgsPoint::transform
void transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false) override SIP_THROW(QgsCsException)
Transforms the geometry using a coordinate transform.
Definition: qgspoint.cpp:382
QgsFeedback
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:44
qgsprofilerequest.h
QgsMeshLayer
Represents a mesh layer supporting display of data on structured or unstructured meshes.
Definition: qgsmeshlayer.h:98
QgsGeos
Does vector analysis using the geos library and handles import, export, exception handling*.
Definition: qgsgeos.h:103
QgsMeshLayerProfileGenerator::takeResults
QgsAbstractProfileResults * takeResults() override
Takes results from the generator.
Definition: qgsmeshlayerprofilegenerator.cpp:166
QgsMeshLayerProfileGenerator::~QgsMeshLayerProfileGenerator
~QgsMeshLayerProfileGenerator() override
QgsGeometry::densifyByDistance
QgsGeometry densifyByDistance(double distance) const
Densifies the geometry by adding regularly placed extra nodes inside each segment so that the maximum...
Definition: qgsgeometry.cpp:2270
QgsProfileRequest
Encapsulates properties and constraints relating to fetching elevation profiles from different source...
Definition: qgsprofilerequest.h:37
QgsGeometry::length
double length() const
Returns the planar, 2-dimensional length of geometry.
Definition: qgsgeometry.cpp:1890
qgscoordinatetransform.h
QgsAbstractProfileSurfaceResults::identify
QVector< QgsProfileIdentifyResults > identify(const QgsProfilePoint &point, const QgsProfileIdentifyContext &context) override
Identify results visible at the specified profile point.
Definition: qgsabstractprofilesurfacegenerator.cpp:85
qgsmeshlayer.h
qgscurve.h
QgsGeometry
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
QgsGeos::lineLocatePoint
double lineLocatePoint(const QgsPoint &point, QString *errorMsg=nullptr) const
Returns a distance representing the location along this linestring of the closest point on this lines...
Definition: qgsgeos.cpp:2733
qgsterrainprovider.h
QgsAbstractProfileResults
Abstract base class for storage of elevation profiles.
Definition: qgsabstractprofilegenerator.h:193
QgsMeshLayerProfileGenerator::sourceId
QString sourceId() const override
Returns a unique identifier representing the source of the profile.
Definition: qgsmeshlayerprofilegenerator.cpp:78
QgsGeometry::vertices_end
QgsAbstractGeometry::vertex_iterator vertices_end() const
Returns STL-style iterator pointing to the imaginary vertex after the last vertex of the geometry.
Definition: qgsgeometry.cpp:1989
QgsMeshLayer::elevationProperties
QgsMapLayerElevationProperties * elevationProperties() override
Returns the layer's elevation properties.
Definition: qgsmeshlayer.cpp:1829
QgsGeometry::vertices_begin
QgsAbstractGeometry::vertex_iterator vertices_begin() const
Returns STL-style iterator pointing to the first vertex of the geometry.
Definition: qgsgeometry.cpp:1982
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:57
qgsfillsymbol.h
QgsPoint::x
double x
Definition: qgspoint.h:69
QgsGeos::prepareGeometry
void prepareGeometry() override
Prepares the geometry, so that subsequent calls to spatial relation methods are much faster.
Definition: qgsgeos.cpp:213
qgsgeos.h
qgslinesymbol.h
QgsMeshLayerProfileResults::identify
QVector< QgsProfileIdentifyResults > identify(const QgsProfilePoint &point, const QgsProfileIdentifyContext &context) override
Identify results visible at the specified profile point.
Definition: qgsmeshlayerprofilegenerator.cpp:40