QGIS API Documentation 3.99.0-Master (09f76ad7019)
Loading...
Searching...
No Matches
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
20#include "qgscurve.h"
21#include "qgsfillsymbol.h"
22#include "qgsgeos.h"
23#include "qgslinesymbol.h"
24#include "qgsmeshlayer.h"
26#include "qgsmeshlayerutils.h"
27#include "qgsprofilepoint.h"
28#include "qgsprofilerequest.h"
29#include "qgsprofilesnapping.h"
30#include "qgsterrainprovider.h"
31
32#include <QString>
33
34using namespace Qt::StringLiterals;
35
36//
37// QgsMeshLayerProfileGenerator
38//
39
41{
42 return u"mesh"_s;
43}
44
45QVector<QgsProfileIdentifyResults> QgsMeshLayerProfileResults::identify( const QgsProfilePoint &point, const QgsProfileIdentifyContext &context )
46{
47 const QVector<QgsProfileIdentifyResults> noLayerResults = QgsAbstractProfileSurfaceResults::identify( point, context );
48
49 // we have to make a new list, with the correct layer reference set
50 QVector<QgsProfileIdentifyResults> res;
51 res.reserve( noLayerResults.size() );
52 for ( const QgsProfileIdentifyResults &result : noLayerResults )
53 {
54 res.append( QgsProfileIdentifyResults( mLayer, result.results() ) );
55 }
56 return res;
57}
58
59//
60// QgsMeshLayerProfileGenerator
61//
62
65 , mId( layer->id() )
66 , mFeedback( std::make_unique< QgsFeedback >() )
67 , mProfileCurve( request.profileCurve() ? request.profileCurve()->clone() : nullptr )
68 , mSourceCrs( layer->crs() )
69 , mTargetCrs( request.crs() )
70 , mTransformContext( request.transformContext() )
71 , mOffset( layer->elevationProperties()->zOffset() )
72 , mScale( layer->elevationProperties()->zScale() )
73 , mLayer( layer )
74 , mStepDistance( request.stepDistance() )
75{
76 layer->updateTriangularMesh();
77 mTriangularMesh = *layer->triangularMesh();
78
79 mSymbology = qgis::down_cast< QgsMeshLayerElevationProperties * >( layer->elevationProperties() )->profileSymbology();
80 mElevationLimit = qgis::down_cast< QgsMeshLayerElevationProperties * >( layer->elevationProperties() )->elevationLimit();
81 mLineSymbol.reset( qgis::down_cast< QgsMeshLayerElevationProperties * >( layer->elevationProperties() )->profileLineSymbol()->clone() );
82 mFillSymbol.reset( qgis::down_cast< QgsMeshLayerElevationProperties * >( layer->elevationProperties() )->profileFillSymbol()->clone() );
83}
84
86{
87 return mId;
88}
89
91{
92 return u"mesh"_s;
93}
94
96
98{
99 if ( !mProfileCurve || mFeedback->isCanceled() )
100 return false;
101
102 // we need to transform the profile curve to the mesh's CRS
103 QgsGeometry transformedCurve( mProfileCurve->clone() );
104 mLayerToTargetTransform = QgsCoordinateTransform( mSourceCrs, mTargetCrs, mTransformContext );
105
106 try
107 {
108 transformedCurve.transform( mLayerToTargetTransform, Qgis::TransformDirection::Reverse );
109 }
110 catch ( QgsCsException & )
111 {
112 QgsDebugError( u"Error transforming profile line to mesh CRS"_s );
113 return false;
114 }
115
116 if ( mFeedback->isCanceled() )
117 return false;
118
119 mResults = std::make_unique< QgsMeshLayerProfileResults >();
120 mResults->mLayer = mLayer;
121 mResults->mId = mId;
122 mResults->copyPropertiesFromGenerator( this );
123
124 // 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
125 const double curveLength = transformedCurve.length();
126
127 if ( !std::isnan( mStepDistance ) )
128 transformedCurve = transformedCurve.densifyByDistance( mStepDistance );
129 else
130 transformedCurve = transformedCurve.densifyByDistance( curveLength / 100 );
131
132 if ( mFeedback->isCanceled() )
133 return false;
134
135 for ( auto it = transformedCurve.vertices_begin(); it != transformedCurve.vertices_end(); ++it )
136 {
137 if ( mFeedback->isCanceled() )
138 return false;
139
140 QgsPoint point = ( *it );
141 const double height = heightAt( point.x(), point.y() );
142
143 try
144 {
145 point.transform( mLayerToTargetTransform );
146 }
147 catch ( QgsCsException & )
148 {
149 continue;
150 }
151 mResults->mRawPoints.append( QgsPoint( point.x(), point.y(), height ) );
152 }
153
154 if ( mFeedback->isCanceled() )
155 return false;
156
157 // convert x/y values back to distance/height values
158 QgsGeos originalCurveGeos( mProfileCurve.get() );
159 originalCurveGeos.prepareGeometry();
160 QString lastError;
161 for ( const QgsPoint &pixel : std::as_const( mResults->mRawPoints ) )
162 {
163 if ( mFeedback->isCanceled() )
164 return false;
165
166 const double distance = originalCurveGeos.lineLocatePoint( pixel, &lastError );
167
168 if ( !std::isnan( pixel.z() ) )
169 {
170 mResults->minZ = std::min( pixel.z(), mResults->minZ );
171 mResults->maxZ = std::max( pixel.z(), mResults->maxZ );
172 }
173 mResults->mDistanceToHeightMap.insert( distance, pixel.z() );
174 }
175
176 return true;
177}
178
183
185{
186 return mFeedback.get();
187}
188
189double QgsMeshLayerProfileGenerator::heightAt( double x, double y )
190{
191 return QgsMeshLayerUtils::interpolateZForPoint( mTriangularMesh, x, y ) * mScale + mOffset;
192}
193
@ Reverse
Reverse/inverse transform (from destination to source).
Definition qgis.h:2731
Abstract base class for storage of elevation profiles.
QgsAbstractProfileSurfaceGenerator(const QgsProfileRequest &request)
Constructor for QgsAbstractProfileSurfaceGenerator.
QVector< QgsProfileIdentifyResults > identify(const QgsProfilePoint &point, const QgsProfileIdentifyContext &context) override
Identify results visible at the specified profile point.
Handles coordinate transforms between two coordinate systems.
Custom exception class for Coordinate Reference System related exceptions.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition qgsfeedback.h:44
A geometry is the spatial representation of a feature.
double length() const
Returns the planar, 2-dimensional length of geometry.
QgsGeometry densifyByDistance(double distance) const
Densifies the geometry by adding regularly placed extra nodes inside each segment so that the maximum...
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
QgsAbstractGeometry::vertex_iterator vertices_begin() const
Returns STL-style iterator pointing to the first vertex of the geometry.
QgsAbstractGeometry::vertex_iterator vertices_end() const
Returns STL-style iterator pointing to the imaginary vertex after the last vertex of the geometry.
Does vector analysis using the GEOS library and handles import, export, and exception handling.
Definition qgsgeos.h:141
void prepareGeometry() override
Prepares the geometry, so that subsequent calls to spatial relation methods are much faster.
Definition qgsgeos.cpp:288
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:3181
~QgsMeshLayerProfileGenerator() override
QgsFeedback * feedback() const override
Access to feedback object of the generator (may be nullptr).
QString type() const override
Returns the unique string identifier for the results type.
QgsMeshLayerProfileGenerator(QgsMeshLayer *layer, const QgsProfileRequest &request)
Constructor for QgsMeshLayerProfileGenerator.
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.
QString type() const override
Returns the unique string identifier for the results type.
QVector< QgsProfileIdentifyResults > identify(const QgsProfilePoint &point, const QgsProfileIdentifyContext &context) override
Identify results visible at the specified profile point.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
void updateTriangularMesh(const QgsCoordinateTransform &transform=QgsCoordinateTransform())
Gets native mesh and updates (creates if it doesn't exist) the base triangular mesh.
QgsMapLayerElevationProperties * elevationProperties() override
Returns the layer's elevation properties.
QgsTriangularMesh * triangularMesh(double minimumTriangleSize=0) const
Returns triangular mesh (nullptr before rendering or calling to updateMesh).
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:53
double x
Definition qgspoint.h:56
void transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false) override
Transforms the geometry using a coordinate transform.
Definition qgspoint.cpp:408
double y
Definition qgspoint.h:57
Encapsulates the context in which an elevation profile is to be generated.
Encapsulates the context of identifying profile results.
Stores identify results generated by a QgsAbstractProfileResults object.
Encapsulates a point on a distance-elevation profile.
Encapsulates properties and constraints relating to fetching elevation profiles from different source...
#define QgsDebugError(str)
Definition qgslogger.h:59