QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsabstractprofilesurfacegenerator.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsabstractprofilegenerator.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 "qgsprofilesnapping.h"
19 #include "qgsfillsymbol.h"
20 #include "qgslinesymbol.h"
21 
22 #include <QPainterPath>
23 #include <optional>
24 
25 //
26 // QgsAbstractProfileSurfaceResults
27 //
28 
30 
32 {
33  return mDistanceToHeightMap;
34 }
35 
37 {
38  return mRawPoints;
39 }
40 
42 {
43  return QgsDoubleRange( minZ, maxZ );
44 }
45 
47 {
48  QVector<QgsGeometry> res;
49  res.reserve( mRawPoints.size() );
50  for ( const QgsPoint &point : mRawPoints )
51  res.append( QgsGeometry( point.clone() ) );
52 
53  return res;
54 }
55 
57 {
58  // TODO -- consider an index if performance is an issue
59  QgsProfileSnapResult result;
60 
61  double prevDistance = std::numeric_limits< double >::max();
62  double prevElevation = 0;
63  for ( auto it = mDistanceToHeightMap.constBegin(); it != mDistanceToHeightMap.constEnd(); ++it )
64  {
65  // find segment which corresponds to the given distance along curve
66  if ( it != mDistanceToHeightMap.constBegin() && prevDistance <= point.distance() && it.key() >= point.distance() )
67  {
68  const double dx = it.key() - prevDistance;
69  const double dy = it.value() - prevElevation;
70  const double snappedZ = ( dy / dx ) * ( point.distance() - prevDistance ) + prevElevation;
71 
72  if ( std::fabs( point.elevation() - snappedZ ) > context.maximumSurfaceElevationDelta )
73  return QgsProfileSnapResult();
74 
75  result.snappedPoint = QgsProfilePoint( point.distance(), snappedZ );
76  break;
77  }
78 
79  prevDistance = it.key();
80  prevElevation = it.value();
81  }
82  return result;
83 }
84 
85 QVector<QgsProfileIdentifyResults> QgsAbstractProfileSurfaceResults::identify( const QgsProfilePoint &point, const QgsProfileIdentifyContext &context )
86 {
87  // TODO -- consider an index if performance is an issue
88  std::optional< QgsProfileIdentifyResults > result;
89 
90  double prevDistance = std::numeric_limits< double >::max();
91  double prevElevation = 0;
92  for ( auto it = mDistanceToHeightMap.constBegin(); it != mDistanceToHeightMap.constEnd(); ++it )
93  {
94  // find segment which corresponds to the given distance along curve
95  if ( it != mDistanceToHeightMap.constBegin() && prevDistance <= point.distance() && it.key() >= point.distance() )
96  {
97  const double dx = it.key() - prevDistance;
98  const double dy = it.value() - prevElevation;
99  const double snappedZ = ( dy / dx ) * ( point.distance() - prevDistance ) + prevElevation;
100 
101  if ( std::fabs( point.elevation() - snappedZ ) > context.maximumSurfaceElevationDelta )
102  return {};
103 
104  result = QgsProfileIdentifyResults( nullptr,
105  {
106  QVariantMap(
107  {
108  {QStringLiteral( "distance" ), point.distance() },
109  {QStringLiteral( "elevation" ), snappedZ }
110  } )
111  } );
112  break;
113  }
114 
115  prevDistance = it.key();
116  prevElevation = it.value();
117  }
118  if ( result.has_value() )
119  return {result.value()};
120  else
121  return {};
122 }
123 
125 {
126  QPainter *painter = context.renderContext().painter();
127  if ( !painter )
128  return;
129 
130  const QgsScopedQPainterState painterState( painter );
131 
132  painter->setBrush( Qt::NoBrush );
133  painter->setPen( Qt::NoPen );
134 
135  const double minDistance = context.distanceRange().lower();
136  const double maxDistance = context.distanceRange().upper();
137  const double minZ = context.elevationRange().lower();
138  const double maxZ = context.elevationRange().upper();
139 
140  const QRectF visibleRegion( minDistance, minZ, maxDistance - minDistance, maxZ - minZ );
141  QPainterPath clipPath;
142  clipPath.addPolygon( context.worldTransform().map( visibleRegion ) );
143  painter->setClipPath( clipPath, Qt::ClipOperation::IntersectClip );
144 
145  switch ( symbology )
146  {
148  mLineSymbol->startRender( context.renderContext() );
149  break;
151  mFillSymbol->startRender( context.renderContext() );
152  break;
153  }
154 
155  QPolygonF currentLine;
156  double prevDistance = std::numeric_limits< double >::quiet_NaN();
157  double currentPartStartDistance = 0;
158  for ( auto pointIt = mDistanceToHeightMap.constBegin(); pointIt != mDistanceToHeightMap.constEnd(); ++pointIt )
159  {
160  if ( std::isnan( prevDistance ) )
161  {
162  currentPartStartDistance = pointIt.key();
163  }
164  if ( std::isnan( pointIt.value() ) )
165  {
166  if ( currentLine.length() > 1 )
167  {
168  switch ( symbology )
169  {
171  mLineSymbol->renderPolyline( currentLine, nullptr, context.renderContext() );
172  break;
174  currentLine.append( context.worldTransform().map( QPointF( prevDistance, minZ ) ) );
175  currentLine.append( context.worldTransform().map( QPointF( currentPartStartDistance, minZ ) ) );
176  currentLine.append( currentLine.at( 0 ) );
177  mFillSymbol->renderPolygon( currentLine, nullptr, nullptr, context.renderContext() );
178  break;
179  }
180  }
181  prevDistance = pointIt.key();
182  currentLine.clear();
183  continue;
184  }
185 
186  currentLine.append( context.worldTransform().map( QPointF( pointIt.key(), pointIt.value() ) ) );
187  prevDistance = pointIt.key();
188  }
189  if ( currentLine.length() > 1 )
190  {
191  switch ( symbology )
192  {
194  mLineSymbol->renderPolyline( currentLine, nullptr, context.renderContext() );
195  break;
197  currentLine.append( context.worldTransform().map( QPointF( prevDistance, minZ ) ) );
198  currentLine.append( context.worldTransform().map( QPointF( currentPartStartDistance, minZ ) ) );
199  currentLine.append( currentLine.at( 0 ) );
200  mFillSymbol->renderPolygon( currentLine, nullptr, nullptr, context.renderContext() );
201  break;
202  }
203  }
204 
205  switch ( symbology )
206  {
208  mLineSymbol->stopRender( context.renderContext() );
209  break;
211  mFillSymbol->stopRender( context.renderContext() );
212  break;
213  }
214 }
215 
216 
218 {
219  const QgsAbstractProfileSurfaceGenerator *surfaceGenerator = qgis::down_cast< const QgsAbstractProfileSurfaceGenerator * >( generator );
220 
221  mLineSymbol.reset( surfaceGenerator->lineSymbol()->clone() );
222  mFillSymbol.reset( surfaceGenerator->fillSymbol()->clone() );
223  symbology = surfaceGenerator->symbology();
224 }
225 
226 //
227 // QgsAbstractProfileSurfaceGenerator
228 //
229 
231 
233 {
234  return mSymbology;
235 }
236 
238 {
239  return mLineSymbol.get();
240 }
241 
243 {
244  return mFillSymbol.get();
245 }
QgsProfileIdentifyContext
Encapsulates the context of identifying profile results.
Definition: qgsabstractprofilegenerator.h:125
QgsAbstractProfileSurfaceResults::copyPropertiesFromGenerator
void copyPropertiesFromGenerator(const QgsAbstractProfileGenerator *generator) override
Copies properties from specified generator to the results object.
Definition: qgsabstractprofilesurfacegenerator.cpp:217
QgsProfileRenderContext::distanceRange
QgsDoubleRange distanceRange() const
Returns the range of distances to include in the render.
Definition: qgsabstractprofilegenerator.cpp:37
QgsPoint
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:48
QgsAbstractProfileSurfaceResults::renderResults
void renderResults(QgsProfileRenderContext &context) override
Renders the results to the specified context.
Definition: qgsabstractprofilesurfacegenerator.cpp:124
QgsProfileSnapResult
Encapsulates results of snapping a profile point.
Definition: qgsprofilesnapping.h:56
QgsAbstractProfileSurfaceResults::distanceToHeightMap
QMap< double, double > distanceToHeightMap() const override
Returns the map of distance (chainage) to height.
Definition: qgsabstractprofilesurfacegenerator.cpp:31
QgsAbstractProfileSurfaceGenerator::mFillSymbol
std::unique_ptr< QgsFillSymbol > mFillSymbol
Definition: qgsabstractprofilesurfacegenerator.h:94
QgsAbstractProfileSurfaceResults::symbology
Qgis::ProfileSurfaceSymbology symbology
Definition: qgsabstractprofilesurfacegenerator.h:48
Qgis::ProfileSurfaceSymbology
ProfileSurfaceSymbology
Surface symbology type for elevation profile plots.
Definition: qgis.h:1849
QgsLineSymbol::clone
QgsLineSymbol * clone() const override
Returns a deep copy of this symbol.
Definition: qgslinesymbol.cpp:303
Qgis::ProfileSurfaceSymbology::FillBelow
@ FillBelow
The elevation surface will be rendered using a fill symbol below the surface level.
qgsabstractprofilesurfacegenerator.h
QgsAbstractProfileGenerator
Abstract base class for objects which generate elevation profiles.
Definition: qgsabstractprofilegenerator.h:392
QgsProfileRenderContext
Abstract base class for storage of elevation profiles.
Definition: qgsabstractprofilegenerator.h:40
QgsAbstractProfileSurfaceResults::mLineSymbol
std::unique_ptr< QgsLineSymbol > mLineSymbol
Definition: qgsabstractprofilesurfacegenerator.h:49
QgsAbstractProfileSurfaceGenerator::fillSymbol
QgsFillSymbol * fillSymbol() const
Returns the fill symbol to be used for rendering the results.
Definition: qgsabstractprofilesurfacegenerator.cpp:242
QgsProfileSnapContext
Encapsulates the context of snapping a profile point.
Definition: qgsprofilesnapping.h:30
QgsProfileIdentifyContext::maximumSurfaceElevationDelta
double maximumSurfaceElevationDelta
Maximum allowed snapping delta for the elevation values when identifying a continuous elevation surfa...
Definition: qgsabstractprofilegenerator.h:133
QgsProfilePoint
Encapsulates a point on a distance-elevation profile.
Definition: qgsprofilepoint.h:30
Qgis::ProfileSurfaceSymbology::Line
@ Line
The elevation surface will be rendered using a line symbol.
QgsAbstractProfileSurfaceResults::asGeometries
QVector< QgsGeometry > asGeometries() const override
Returns a list of geometries representing the calculated elevation results.
Definition: qgsabstractprofilesurfacegenerator.cpp:46
QgsProfileIdentifyResults
Stores identify results generated by a QgsAbstractProfileResults object.
Definition: qgsabstractprofilegenerator.h:158
QgsProfileRenderContext::renderContext
QgsRenderContext & renderContext()
Returns a reference to the component QgsRenderContext.
Definition: qgsabstractprofilegenerator.h:52
QgsAbstractProfileSurfaceGenerator::mSymbology
Qgis::ProfileSurfaceSymbology mSymbology
Definition: qgsabstractprofilesurfacegenerator.h:92
QgsRange::lower
T lower() const
Returns the lower bound of the range.
Definition: qgsrange.h:66
QgsAbstractProfileSurfaceResults::minZ
double minZ
Definition: qgsabstractprofilesurfacegenerator.h:45
qgsprofilesnapping.h
QgsAbstractProfileSurfaceResults::snapPoint
QgsProfileSnapResult snapPoint(const QgsProfilePoint &point, const QgsProfileSnapContext &context) override
Snaps a point to the generated elevation profile.
Definition: qgsabstractprofilesurfacegenerator.cpp:56
QgsAbstractProfileSurfaceGenerator::mLineSymbol
std::unique_ptr< QgsLineSymbol > mLineSymbol
Definition: qgsabstractprofilesurfacegenerator.h:93
QgsAbstractProfileSurfaceResults::mRawPoints
QgsPointSequence mRawPoints
Definition: qgsabstractprofilesurfacegenerator.h:43
QgsRange::upper
T upper() const
Returns the upper bound of the range.
Definition: qgsrange.h:73
QgsProfileSnapContext::maximumSurfaceElevationDelta
double maximumSurfaceElevationDelta
Maximum allowed snapping delta for the elevation values when snapping to a continuous elevation surfa...
Definition: qgsprofilesnapping.h:51
QgsAbstractProfileSurfaceResults::~QgsAbstractProfileSurfaceResults
~QgsAbstractProfileSurfaceResults() override
QgsLineSymbol
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgslinesymbol.h:29
QgsAbstractProfileSurfaceGenerator::symbology
Qgis::ProfileSurfaceSymbology symbology() const
Returns the symbology type for rendering the results.
Definition: qgsabstractprofilesurfacegenerator.cpp:232
QgsAbstractProfileSurfaceResults::mFillSymbol
std::unique_ptr< QgsFillSymbol > mFillSymbol
Definition: qgsabstractprofilesurfacegenerator.h:50
QgsAbstractProfileSurfaceResults::identify
QVector< QgsProfileIdentifyResults > identify(const QgsProfilePoint &point, const QgsProfileIdentifyContext &context) override
Identify results visible at the specified profile point.
Definition: qgsabstractprofilesurfacegenerator.cpp:85
QgsProfileSnapResult::snappedPoint
QgsProfilePoint snappedPoint
Snapped point.
Definition: qgsprofilesnapping.h:61
QgsProfilePoint::distance
double distance() const SIP_HOLDGIL
Returns the distance of the point.
Definition: qgsprofilepoint.h:88
QgsScopedQPainterState
Scoped object for saving and restoring a QPainter object's state.
Definition: qgsrendercontext.h:1336
QgsAbstractProfileSurfaceGenerator
Abstract base class for objects which generate elevation profiles which represent a continuous surfac...
Definition: qgsabstractprofilesurfacegenerator.h:69
QgsAbstractProfileSurfaceResults::mDistanceToHeightMap
QMap< double, double > mDistanceToHeightMap
Definition: qgsabstractprofilesurfacegenerator.h:44
QgsAbstractProfileSurfaceGenerator::~QgsAbstractProfileSurfaceGenerator
~QgsAbstractProfileSurfaceGenerator() override
QgsDoubleRange
QgsRange which stores a range of double values.
Definition: qgsrange.h:202
QgsPointSequence
QVector< QgsPoint > QgsPointSequence
Definition: qgsabstractgeometry.h:52
QgsGeometry
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
QgsAbstractProfileSurfaceResults::maxZ
double maxZ
Definition: qgsabstractprofilesurfacegenerator.h:46
QgsProfileRenderContext::worldTransform
const QTransform & worldTransform() const
Returns the transform from world coordinates to painter coordinates.
Definition: qgsabstractprofilegenerator.cpp:27
QgsFillSymbol::clone
QgsFillSymbol * clone() const override
Returns a deep copy of this symbol.
Definition: qgsfillsymbol.cpp:144
QgsFillSymbol
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
Definition: qgsfillsymbol.h:29
QgsProfileRenderContext::elevationRange
QgsDoubleRange elevationRange() const
Returns the range of elevations to include in the render.
Definition: qgsabstractprofilegenerator.cpp:47
QgsAbstractProfileSurfaceResults::sampledPoints
QgsPointSequence sampledPoints() const override
Returns a list of sampled points, with their calculated elevation as the point z value.
Definition: qgsabstractprofilesurfacegenerator.cpp:36
QgsRenderContext::painter
QPainter * painter()
Returns the destination QPainter for the render operation.
Definition: qgsrendercontext.h:112
qgsfillsymbol.h
QgsAbstractProfileSurfaceResults::zRange
QgsDoubleRange zRange() const override
Returns the range of the retrieved elevation values.
Definition: qgsabstractprofilesurfacegenerator.cpp:41
QgsProfilePoint::elevation
double elevation() const SIP_HOLDGIL
Returns the elevation of the point.
Definition: qgsprofilepoint.h:98
qgslinesymbol.h
QgsAbstractProfileSurfaceGenerator::lineSymbol
QgsLineSymbol * lineSymbol() const
Returns the line symbol to be used for rendering the results.
Definition: qgsabstractprofilesurfacegenerator.cpp:237