QGIS API Documentation 3.41.0-Master (af5edcb665c)
Loading...
Searching...
No Matches
qgsrasterlayerelevationproperties.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsrasterlayerelevationproperties.cpp
3 ---------------
4 begin : February 2022
5 copyright : (C) 2022 by Nyall Dawson
6 email : nyall dot dawson 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 ***************************************************************************/
17
19#include "moc_qgsrasterlayerelevationproperties.cpp"
20#include "qgsrasterlayer.h"
21#include "qgslinesymbol.h"
22#include "qgsfillsymbol.h"
23#include "qgssymbollayerutils.h"
24#include "qgslinesymbollayer.h"
25#include "qgsfillsymbollayer.h"
26#include "qgsapplication.h"
29
32{
34 setDefaultProfileLineSymbol( color );
35 setDefaultProfileFillSymbol( color );
36}
37
39
41{
42 return mEnabled;
43}
44
45QDomElement QgsRasterLayerElevationProperties::writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context )
46{
47 QDomElement element = document.createElement( QStringLiteral( "elevation" ) );
48 element.setAttribute( QStringLiteral( "enabled" ), mEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
49 element.setAttribute( QStringLiteral( "mode" ), qgsEnumValueToKey( mMode ) );
50 element.setAttribute( QStringLiteral( "symbology" ), qgsEnumValueToKey( mSymbology ) );
51 if ( !std::isnan( mElevationLimit ) )
52 element.setAttribute( QStringLiteral( "elevationLimit" ), qgsDoubleToString( mElevationLimit ) );
53
54 writeCommonProperties( element, document, context );
55
56 switch ( mMode )
57 {
59 element.setAttribute( QStringLiteral( "lower" ), qgsDoubleToString( mFixedRange.lower() ) );
60 element.setAttribute( QStringLiteral( "upper" ), qgsDoubleToString( mFixedRange.upper() ) );
61 element.setAttribute( QStringLiteral( "includeLower" ), mFixedRange.includeLower() ? "1" : "0" );
62 element.setAttribute( QStringLiteral( "includeUpper" ), mFixedRange.includeUpper() ? "1" : "0" );
63 break;
64
66 {
67 QDomElement ranges = document.createElement( QStringLiteral( "ranges" ) );
68 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
69 {
70 QDomElement range = document.createElement( QStringLiteral( "range" ) );
71 range.setAttribute( QStringLiteral( "band" ), it.key() );
72 range.setAttribute( QStringLiteral( "lower" ), qgsDoubleToString( it.value().lower() ) );
73 range.setAttribute( QStringLiteral( "upper" ), qgsDoubleToString( it.value().upper() ) );
74 range.setAttribute( QStringLiteral( "includeLower" ), it.value().includeLower() ? "1" : "0" );
75 range.setAttribute( QStringLiteral( "includeUpper" ), it.value().includeUpper() ? "1" : "0" );
76 ranges.appendChild( range );
77 }
78 element.appendChild( ranges );
79 break;
80 }
81
83 break;
84
86 element.setAttribute( QStringLiteral( "band" ), mBandNumber );
87 break;
88 }
89
90 QDomElement profileLineSymbolElement = document.createElement( QStringLiteral( "profileLineSymbol" ) );
91 profileLineSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileLineSymbol.get(), document, context ) );
92 element.appendChild( profileLineSymbolElement );
93
94 QDomElement profileFillSymbolElement = document.createElement( QStringLiteral( "profileFillSymbol" ) );
95 profileFillSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileFillSymbol.get(), document, context ) );
96 element.appendChild( profileFillSymbolElement );
97
98 parentElement.appendChild( element );
99 return element;
100}
101
102bool QgsRasterLayerElevationProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context )
103{
104 const QDomElement elevationElement = element.firstChildElement( QStringLiteral( "elevation" ) ).toElement();
105 mEnabled = elevationElement.attribute( QStringLiteral( "enabled" ), QStringLiteral( "0" ) ).toInt();
106 mMode = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "mode" ) ), Qgis::RasterElevationMode::RepresentsElevationSurface );
107 mSymbology = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "symbology" ) ), Qgis::ProfileSurfaceSymbology::Line );
108 if ( elevationElement.hasAttribute( QStringLiteral( "elevationLimit" ) ) )
109 mElevationLimit = elevationElement.attribute( QStringLiteral( "elevationLimit" ) ).toDouble();
110 else
111 mElevationLimit = std::numeric_limits< double >::quiet_NaN();
112
113 readCommonProperties( elevationElement, context );
114
115 switch ( mMode )
116 {
118 {
119 const double lower = elevationElement.attribute( QStringLiteral( "lower" ) ).toDouble();
120 const double upper = elevationElement.attribute( QStringLiteral( "upper" ) ).toDouble();
121 const bool includeLower = elevationElement.attribute( QStringLiteral( "includeLower" ) ).toInt();
122 const bool includeUpper = elevationElement.attribute( QStringLiteral( "includeUpper" ) ).toInt();
123 mFixedRange = QgsDoubleRange( lower, upper, includeLower, includeUpper );
124 break;
125 }
126
128 {
129 mRangePerBand.clear();
130
131 const QDomNodeList ranges = elevationElement.firstChildElement( QStringLiteral( "ranges" ) ).childNodes();
132 for ( int i = 0; i < ranges.size(); ++i )
133 {
134 const QDomElement rangeElement = ranges.at( i ).toElement();
135 const int band = rangeElement.attribute( QStringLiteral( "band" ) ).toInt();
136 const double lower = rangeElement.attribute( QStringLiteral( "lower" ) ).toDouble();
137 const double upper = rangeElement.attribute( QStringLiteral( "upper" ) ).toDouble();
138 const bool includeLower = rangeElement.attribute( QStringLiteral( "includeLower" ) ).toInt();
139 const bool includeUpper = rangeElement.attribute( QStringLiteral( "includeUpper" ) ).toInt();
140 mRangePerBand.insert( band, QgsDoubleRange( lower, upper, includeLower, includeUpper ) );
141 }
142 break;
143 }
144
146 break;
147
149 mBandNumber = elevationElement.attribute( QStringLiteral( "band" ), QStringLiteral( "1" ) ).toInt();
150 break;
151 }
152
153 const QColor defaultColor = QgsApplication::colorSchemeRegistry()->fetchRandomStyleColor();
154
155 const QDomElement profileLineSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileLineSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
156 mProfileLineSymbol.reset( QgsSymbolLayerUtils::loadSymbol< QgsLineSymbol >( profileLineSymbolElement, context ) );
157 if ( !mProfileLineSymbol )
158 setDefaultProfileLineSymbol( defaultColor );
159
160 const QDomElement profileFillSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileFillSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
161 mProfileFillSymbol.reset( QgsSymbolLayerUtils::loadSymbol< QgsFillSymbol >( profileFillSymbolElement, context ) );
162 if ( !mProfileFillSymbol )
163 setDefaultProfileFillSymbol( defaultColor );
164
165 return true;
166}
167
169{
170 std::unique_ptr< QgsRasterLayerElevationProperties > res = std::make_unique< QgsRasterLayerElevationProperties >( nullptr );
171 res->setEnabled( mEnabled );
172 res->setMode( mMode );
173 res->setProfileLineSymbol( mProfileLineSymbol->clone() );
174 res->setProfileFillSymbol( mProfileFillSymbol->clone() );
175 res->setProfileSymbology( mSymbology );
176 res->setElevationLimit( mElevationLimit );
177 res->setBandNumber( mBandNumber );
178 res->setFixedRange( mFixedRange );
179 res->setFixedRangePerBand( mRangePerBand );
180 res->copyCommonProperties( this );
181 return res.release();
182}
183
185{
186 QStringList properties;
187 switch ( mMode )
188 {
190 properties << tr( "Elevation range: %1 to %2" ).arg( mFixedRange.lower() ).arg( mFixedRange.upper() );
191 break;
192
194 {
195 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
196 {
197 properties << tr( "Elevation for band %1: %2 to %3" ).arg( it.key() ).arg( it.value().lower() ).arg( it.value().upper() );
198 }
199 break;
200 }
201
203 break;
204
206 properties << tr( "Elevation band: %1" ).arg( mBandNumber );
207 properties << tr( "Scale: %1" ).arg( mZScale );
208 properties << tr( "Offset: %1" ).arg( mZOffset );
209 break;
210 }
211
212 return QStringLiteral( "<li>%1</li>" ).arg( properties.join( QLatin1String( "</li><li>" ) ) );
213}
214
216{
217 switch ( mMode )
218 {
220 return mFixedRange.overlaps( range );
221
223 {
224 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
225 {
226 if ( it.value().overlaps( range ) )
227 return true;
228 }
229 return false;
230 }
231
233 {
234 if ( QgsRasterLayer *rl = qobject_cast< QgsRasterLayer * >( layer ) )
235 {
236 QgsExpressionContext context;
239 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band" ), 1, true, false, tr( "Band number" ) ) );
240 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_name" ), rl->dataProvider()->displayBandName( 1 ), true, false, tr( "Band name" ) ) );
241 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_description" ), rl->dataProvider()->bandDescription( 1 ), true, false, tr( "Band description" ) ) );
242 context.appendScope( bandScope );
243
246 lowerProperty.prepare( context );
247 upperProperty.prepare( context );
248 for ( int band = 1; band <= rl->bandCount(); ++band )
249 {
250 bandScope->setVariable( QStringLiteral( "band" ), band );
251 bandScope->setVariable( QStringLiteral( "band_name" ), rl->dataProvider()->displayBandName( band ) );
252 bandScope->setVariable( QStringLiteral( "band_description" ), rl->dataProvider()->bandDescription( band ) );
253
254 bool ok = false;
255 const double lower = lowerProperty.valueAsDouble( context, 0, &ok );
256 if ( !ok )
257 continue;
258 const double upper = upperProperty.valueAsDouble( context, 0, &ok );
259 if ( !ok )
260 continue;
261
262 if ( QgsDoubleRange( lower, upper ).overlaps( range ) )
263 return true;
264 }
265 }
266 return false;
267 }
268
270 // TODO -- test actual raster z range
271 return true;
272 }
274}
275
277{
278 switch ( mMode )
279 {
281 return mFixedRange;
282
284 {
285 double lower = std::numeric_limits< double >::max();
286 double upper = std::numeric_limits< double >::min();
287 bool includeLower = true;
288 bool includeUpper = true;
289 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
290 {
291 if ( it.value().lower() < lower )
292 {
293 lower = it.value().lower();
294 includeLower = it.value().includeLower();
295 }
296 else if ( !includeLower && it.value().lower() == lower && it.value().includeLower() )
297 {
298 includeLower = true;
299 }
300 if ( it.value().upper() > upper )
301 {
302 upper = it.value().upper();
303 includeUpper = it.value().includeUpper();
304 }
305 else if ( !includeUpper && it.value().upper() == upper && it.value().includeUpper() )
306 {
307 includeUpper = true;
308 }
309 }
310 return QgsDoubleRange( lower, upper, includeLower, includeUpper );
311 }
312
314 {
315 if ( QgsRasterLayer *rl = qobject_cast< QgsRasterLayer * >( layer ) )
316 {
317 QgsExpressionContext context;
320 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band" ), 1, true, false, tr( "Band number" ) ) );
321 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_name" ), rl->dataProvider()->displayBandName( 1 ), true, false, tr( "Band name" ) ) );
322 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_description" ), rl->dataProvider()->bandDescription( 1 ), true, false, tr( "Band description" ) ) );
323 context.appendScope( bandScope );
324
327 lowerProperty.prepare( context );
328 upperProperty.prepare( context );
329 double minLower = std::numeric_limits<double>::max();
330 double maxUpper = std::numeric_limits<double>::lowest();
331 for ( int band = 1; band <= rl->bandCount(); ++band )
332 {
333 bandScope->setVariable( QStringLiteral( "band" ), band );
334 bandScope->setVariable( QStringLiteral( "band_name" ), rl->dataProvider()->displayBandName( band ) );
335 bandScope->setVariable( QStringLiteral( "band_description" ), rl->dataProvider()->bandDescription( band ) );
336
337 bool ok = false;
338 const double lower = lowerProperty.valueAsDouble( context, 0, &ok );
339 if ( !ok )
340 continue;
341 const double upper = upperProperty.valueAsDouble( context, 0, &ok );
342 if ( !ok )
343 continue;
344
345 minLower = std::min( minLower, lower );
346 maxUpper = std::max( maxUpper, upper );
347 }
348 return ( minLower == std::numeric_limits<double>::max() && maxUpper == std::numeric_limits<double>::lowest() ) ? QgsDoubleRange() : QgsDoubleRange( minLower, maxUpper );
349 }
350 return QgsDoubleRange();
351 }
352
354 // TODO -- determine actual z range from raster statistics
355 return QgsDoubleRange();
356 }
358}
359
361{
362 switch ( mMode )
363 {
365 {
366 if ( !mFixedRange.isInfinite() && mFixedRange.lower() != mFixedRange.upper() )
367 return { mFixedRange.lower(), mFixedRange.upper() };
368 else if ( !mFixedRange.isInfinite() )
369 return { mFixedRange.lower() };
370
371 return {};
372 }
373
375 {
376 QList< double > res;
377 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
378 {
379 if ( it.value().isInfinite() )
380 continue;
381
382 if ( !res.contains( it.value().lower( ) ) )
383 res.append( it.value().lower() );
384 if ( !res.contains( it.value().upper( ) ) )
385 res.append( it.value().upper() );
386 }
387 std::sort( res.begin(), res.end() );
388 return res;
389 }
390
392 {
393 QList< double > res;
394 if ( QgsRasterLayer *rl = qobject_cast< QgsRasterLayer * >( layer ) )
395 {
396 QgsExpressionContext context;
399 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band" ), 1, true, false, tr( "Band number" ) ) );
400 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_name" ), rl->dataProvider()->displayBandName( 1 ), true, false, tr( "Band name" ) ) );
401 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_description" ), rl->dataProvider()->bandDescription( 1 ), true, false, tr( "Band description" ) ) );
402 context.appendScope( bandScope );
403
406 lowerProperty.prepare( context );
407 upperProperty.prepare( context );
408 for ( int band = 1; band <= rl->bandCount(); ++band )
409 {
410 bandScope->setVariable( QStringLiteral( "band" ), band );
411 bandScope->setVariable( QStringLiteral( "band_name" ), rl->dataProvider()->displayBandName( band ) );
412 bandScope->setVariable( QStringLiteral( "band_description" ), rl->dataProvider()->bandDescription( band ) );
413
414 bool ok = false;
415 const double lower = lowerProperty.valueAsDouble( context, 0, &ok );
416 if ( ok && !res.contains( lower ) )
417 res.append( lower );
418 const double upper = upperProperty.valueAsDouble( context, 0, &ok );
419 if ( ok && !res.contains( upper ) )
420 res.append( upper );
421 }
422 }
423 return res;
424 }
425
427 return {};
428 }
430}
431
436
454
456{
457 if ( enabled == mEnabled )
458 return;
459
460 mEnabled = enabled;
461 emit changed();
463}
464
469
471{
472 if ( mMode == mode )
473 return;
474
475 mMode = mode;
476 emit changed();
477}
478
480{
481 if ( mBandNumber == band )
482 return;
483
484 mBandNumber = band;
485 emit changed();
487}
488
490{
491 if ( !mEnabled || std::isnan( pixelValue ) )
492 return QgsDoubleRange();
493
494 switch ( mMode )
495 {
497 return mFixedRange;
498
500 {
501 auto it = mRangePerBand.constFind( band );
502 if ( it != mRangePerBand.constEnd() )
503 return it.value();
504 return QgsDoubleRange();
505 }
506
508 {
509 if ( layer && band > 0 && band <= layer->bandCount() )
510 {
511 QgsExpressionContext context;
514 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band" ), band, true, false, tr( "Band number" ) ) );
515 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_name" ), layer->dataProvider()->displayBandName( band ), true, false, tr( "Band name" ) ) );
516 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_description" ), layer->dataProvider()->bandDescription( band ), true, false, tr( "Band description" ) ) );
517 context.appendScope( bandScope );
518
521 lowerProperty.prepare( context );
522 upperProperty.prepare( context );
523
524 bool ok = false;
525 const double lower = lowerProperty.valueAsDouble( context, 0, &ok );
526 if ( !ok )
527 return QgsDoubleRange();
528 const double upper = upperProperty.valueAsDouble( context, 0, &ok );
529 if ( !ok )
530 return QgsDoubleRange();
531
532 return QgsDoubleRange( lower, upper );
533 }
534
535 return QgsDoubleRange();
536 }
537
539 {
540 if ( band != mBandNumber )
541 return QgsDoubleRange();
542
543 const double z = pixelValue * mZScale + mZOffset;
544 return QgsDoubleRange( z, z );
545 }
546 }
548}
549
551{
552 switch ( mMode )
553 {
556 return -1;
557
559 {
560 // find the top-most band which matches the map range
561 int currentMatchingBand = -1;
562 QgsDoubleRange currentMatchingRange;
563 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
564 {
565 if ( it.value().overlaps( range ) )
566 {
567 if ( currentMatchingRange.isInfinite()
568 || ( it.value().includeUpper() && it.value().upper() >= currentMatchingRange.upper() )
569 || ( !currentMatchingRange.includeUpper() && it.value().upper() >= currentMatchingRange.upper() ) )
570 {
571 currentMatchingBand = it.key();
572 currentMatchingRange = it.value();
573 }
574 }
575 }
576 return currentMatchingBand;
577 }
578
580 {
581 if ( layer )
582 {
583 QgsExpressionContext context;
586 context.appendScope( bandScope );
587
590 lowerProperty.prepare( context );
591 upperProperty.prepare( context );
592
593 int currentMatchingBand = -1;
594 QgsDoubleRange currentMatchingRange;
595
596 for ( int band = 1; band <= layer->bandCount(); ++band )
597 {
598 bandScope->setVariable( QStringLiteral( "band" ), band );
599 bandScope->setVariable( QStringLiteral( "band_name" ), layer->dataProvider()->displayBandName( band ) );
600 bandScope->setVariable( QStringLiteral( "band_description" ), layer->dataProvider()->bandDescription( band ) );
601
602 bool ok = false;
603 const double lower = lowerProperty.valueAsDouble( context, 0, &ok );
604 if ( !ok )
605 continue;
606 const double upper = upperProperty.valueAsDouble( context, 0, &ok );
607 if ( !ok )
608 continue;
609
610 const QgsDoubleRange bandRange = QgsDoubleRange( lower, upper );
611 if ( bandRange.overlaps( range ) )
612 {
613 if ( currentMatchingRange.isInfinite()
614 || ( bandRange.includeUpper() && bandRange.upper() >= currentMatchingRange.upper() )
615 || ( !currentMatchingRange.includeUpper() && bandRange.upper() >= currentMatchingRange.upper() ) )
616 {
617 currentMatchingBand = band;
618 currentMatchingRange = bandRange;
619 }
620 }
621 }
622 return currentMatchingBand;
623 }
624 return -1;
625 }
626 }
628}
629
631{
632 return mProfileLineSymbol.get();
633}
634
636{
637 mProfileLineSymbol.reset( symbol );
638 emit changed();
640}
641
643{
644 return mProfileFillSymbol.get();
645}
646
648{
649 mProfileFillSymbol.reset( symbol );
650 emit changed();
652}
653
655{
656 if ( mSymbology == symbology )
657 return;
658
659 mSymbology = symbology;
660 emit changed();
662}
663
665{
666 return mElevationLimit;
667}
668
670{
671 if ( qgsDoubleNear( mElevationLimit, limit ) )
672 return;
673
674 mElevationLimit = limit;
675 emit changed();
677}
678
680{
681 // multiple bands => unlikely to be a DEM
682 if ( layer->bandCount() > 1 )
683 return false;
684
685 // raster attribute table => unlikely to be a DEM
686 if ( layer->attributeTable( 1 ) )
687 return false;
688
689 if ( QgsRasterDataProvider *dataProvider = layer->dataProvider() )
690 {
691 // filter out data types which aren't likely to be DEMs
692 switch ( dataProvider->dataType( 1 ) )
693 {
702 return false;
703
711 break;
712 }
713 }
714
715 // Check the layer's name for DEM-ish hints.
716 // See discussion at https://github.com/qgis/QGIS/pull/30245 - this list must NOT be translated,
717 // but adding hardcoded localized variants of the strings is encouraged.
718 static const QStringList sPartialCandidates{ QStringLiteral( "dem" ),
719 QStringLiteral( "dtm" ),
720 QStringLiteral( "dsm" ),
721 QStringLiteral( "height" ),
722 QStringLiteral( "elev" ),
723 QStringLiteral( "srtm" ),
724 // French hints
725 QStringLiteral( "mne" ),
726 QStringLiteral( "mnt" ),
727 QStringLiteral( "mns" ),
728 QStringLiteral( "rge" ),
729 QStringLiteral( "alti" ),
730 // German hints
731 QStringLiteral( "dhm" ),
732 QStringLiteral( "dgm" ),
733 QStringLiteral( "dom" ),
734 QStringLiteral( "Höhe" ),
735 QStringLiteral( "Hoehe" ) };
736 const QString layerName = layer->name();
737 for ( const QString &candidate : sPartialCandidates )
738 {
739 if ( layerName.contains( candidate, Qt::CaseInsensitive ) )
740 return true;
741 }
742
743 // these candidates must occur with word boundaries (we don't want to find "aster" in "raster"!)
744 static const QStringList sWordCandidates{ QStringLiteral( "aster" ) };
745 for ( const QString &candidate : sWordCandidates )
746 {
747 const thread_local QRegularExpression re( QStringLiteral( "\\b%1\\b" ).arg( candidate ) );
748 if ( re.match( layerName, Qt::CaseInsensitive ).hasMatch() )
749 return true;
750 }
751
752 return false;
753}
754
755void QgsRasterLayerElevationProperties::setDefaultProfileLineSymbol( const QColor &color )
756{
757 std::unique_ptr< QgsSimpleLineSymbolLayer > profileLineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( color, 0.6 );
758 mProfileLineSymbol = std::make_unique< QgsLineSymbol>( QgsSymbolLayerList( { profileLineLayer.release() } ) );
759}
760
761void QgsRasterLayerElevationProperties::setDefaultProfileFillSymbol( const QColor &color )
762{
763 std::unique_ptr< QgsSimpleFillSymbolLayer > profileFillLayer = std::make_unique< QgsSimpleFillSymbolLayer >( color );
764 profileFillLayer->setStrokeStyle( Qt::NoPen );
765 mProfileFillSymbol = std::make_unique< QgsFillSymbol>( QgsSymbolLayerList( { profileFillLayer.release() } ) );
766}
767
769{
770 return mRangePerBand;
771}
772
773void QgsRasterLayerElevationProperties::setFixedRangePerBand( const QMap<int, QgsDoubleRange> &ranges )
774{
775 if ( ranges == mRangePerBand )
776 return;
777
778 mRangePerBand = ranges;
779 emit changed();
780}
781
783{
784 return mFixedRange;
785}
786
788{
789 if ( range == mFixedRange )
790 return;
791
792 mFixedRange = range;
793 emit changed();
794}
RasterElevationMode
Raster layer elevation modes.
Definition qgis.h:3801
@ FixedRangePerBand
Layer has a fixed (manually specified) elevation range per band.
@ FixedElevationRange
Layer has a fixed elevation range.
@ RepresentsElevationSurface
Pixel values represent an elevation surface.
@ DynamicRangePerBand
Layer has a elevation range per band, calculated dynamically from an expression.
@ CInt32
Complex Int32.
@ Float32
Thirty two bit floating point (float)
@ CFloat64
Complex Float64.
@ Int16
Sixteen bit signed integer (qint16)
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
@ Int8
Eight bit signed integer (qint8) (added in QGIS 3.30)
@ UInt16
Sixteen bit unsigned integer (quint16)
@ Byte
Eight bit unsigned integer (quint8)
@ UnknownDataType
Unknown or unspecified type.
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
@ Int32
Thirty two bit signed integer (qint32)
@ Float64
Sixty four bit floating point (double)
@ CFloat32
Complex Float32.
@ CInt16
Complex Int16.
@ UInt32
Thirty two bit unsigned integer (quint32)
ProfileSurfaceSymbology
Surface symbology type for elevation profile plots.
Definition qgis.h:3960
@ Line
The elevation surface will be rendered using a line symbol.
static QgsColorSchemeRegistry * colorSchemeRegistry()
Returns the application's color scheme registry, used for managing color schemes.
QColor fetchRandomStyleColor() const
Returns a random color for use with a new symbol style (e.g.
QgsRange which stores a range of double values.
Definition qgsrange.h:231
bool isInfinite() const
Returns true if the range consists of all possible values.
Definition qgsrange.h:285
Single scope for storing variables and functions for use within a QgsExpressionContext.
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
void setVariable(const QString &name, const QVariant &value, bool isStatic=false)
Convenience method for setting a variable in the context scope by name name and value.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
A line symbol type, for rendering LineString and MultiLineString geometries.
Base class for storage of map layer elevation properties.
QgsPropertyCollection mDataDefinedProperties
Property collection for data defined elevation settings.
void writeCommonProperties(QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context)
Writes common class properties to a DOM element, to be used later with readXml().
void profileGenerationPropertyChanged()
Emitted when any of the elevation properties which relate solely to generation of elevation profiles ...
void readCommonProperties(const QDomElement &element, const QgsReadWriteContext &context)
Reads common class properties from a DOM element previously written by writeXml().
void changed()
Emitted when any of the elevation properties have changed.
void profileRenderingPropertyChanged()
Emitted when any of the elevation properties which relate solely to presentation of elevation results...
@ RasterPerBandUpperElevation
Upper elevation for each raster band.
@ RasterPerBandLowerElevation
Lower elevation for each raster band.
@ FlagDontInvalidateCachedRendersWhenRangeChanges
Any cached rendering will not be invalidated when z range context is modified.
Base class for all map layer types.
Definition qgsmaplayer.h:76
QString name
Definition qgsmaplayer.h:80
QgsProperty property(int key) const final
Returns a matching property from the collection, if one exists.
A store for object properties.
double valueAsDouble(const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property and interprets it as a double.
bool prepare(const QgsExpressionContext &context=QgsExpressionContext()) const
Prepares the property against a specified expression context.
bool includeUpper() const
Returns true if the upper bound is inclusive, or false if the upper bound is exclusive.
Definition qgsrange.h:101
bool overlaps(const QgsRange< T > &other) const
Returns true if this range overlaps another range.
Definition qgsrange.h:176
T lower() const
Returns the lower bound of the range.
Definition qgsrange.h:78
bool includeLower() const
Returns true if the lower bound is inclusive, or false if the lower bound is exclusive.
Definition qgsrange.h:93
T upper() const
Returns the upper bound of the range.
Definition qgsrange.h:85
Base class for raster data providers.
virtual QString bandDescription(int bandNumber)
Returns the description for band bandNumber, or an empty string if the band is not valid or has not d...
QString displayBandName(int bandNumber) const
Generates a friendly, descriptive name for the specified bandNumber.
Raster layer specific subclass of QgsMapLayerElevationProperties.
QgsDoubleRange fixedRange() const
Returns the fixed elevation range for the raster.
void setProfileFillSymbol(QgsFillSymbol *symbol)
Sets the fill symbol used to render the raster profile in elevation profile plots.
void setFixedRange(const QgsDoubleRange &range)
Sets the fixed elevation range for the raster.
QgsDoubleRange elevationRangeForPixelValue(QgsRasterLayer *layer, int band, double pixelValue) const
Returns the elevation range corresponding to a raw pixel value from the specified band.
QList< double > significantZValues(QgsMapLayer *layer) const override
Returns a list of significant elevation/z-values for the specified layer, using the settings defined ...
Qgis::RasterElevationMode mode() const
Returns the elevation mode.
QgsLineSymbol * profileLineSymbol() const
Returns the line symbol used to render the raster profile in elevation profile plots.
bool hasElevation() const override
Returns true if the layer has an elevation or z component.
QgsRasterLayerElevationProperties * clone() const override
Creates a clone of the properties.
QgsDoubleRange calculateZRange(QgsMapLayer *layer) const override
Attempts to calculate the overall elevation or z range for the specified layer, using the settings de...
QgsMapLayerElevationProperties::Flags flags() const override
Returns flags associated to the elevation properties.
void setBandNumber(int band)
Sets the band number from which the elevation should be taken.
int bandForElevationRange(QgsRasterLayer *layer, const QgsDoubleRange &range) const
Returns the band corresponding to the specified range.
QString htmlSummary() const override
Returns a HTML formatted summary of the properties.
void setElevationLimit(double limit)
Sets the elevation limit, which is used when profileSymbology() is Qgis::ProfileSurfaceSymbology::Fil...
void setFixedRangePerBand(const QMap< int, QgsDoubleRange > &ranges)
Sets the fixed elevation range for each band.
bool isVisibleInZRange(const QgsDoubleRange &range, QgsMapLayer *layer=nullptr) const override
Returns true if the layer should be visible and rendered for the specified z range.
void setProfileSymbology(Qgis::ProfileSurfaceSymbology symbology)
Sets the symbology option used to render the raster profile in elevation profile plots.
QMap< int, QgsDoubleRange > fixedRangePerBand() const
Returns the fixed elevation range for each band.
static bool layerLooksLikeDem(QgsRasterLayer *layer)
Returns true if a raster layer looks like a DEM.
QDomElement writeXml(QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context) override
Writes the properties to a DOM element, to be used later with readXml().
QgsFillSymbol * profileFillSymbol() const
Returns the fill symbol used to render the raster profile in elevation profile plots.
double elevationLimit() const
Returns the elevation limit, which is used when profileSymbology() is Qgis::ProfileSurfaceSymbology::...
void setProfileLineSymbol(QgsLineSymbol *symbol)
Sets the line symbol used to render the raster profile in elevation profile plots.
void setMode(Qgis::RasterElevationMode mode)
Sets the elevation mode.
void setEnabled(bool enabled)
Sets whether the elevation properties are enabled, i.e.
QgsRasterLayerElevationProperties(QObject *parent)
Constructor for QgsRasterLayerElevationProperties, with the specified parent object.
bool readXml(const QDomElement &element, const QgsReadWriteContext &context) override
Reads the elevation properties from a DOM element previously written by writeXml().
bool showByDefaultInElevationProfilePlots() const override
Returns true if the layer should be visible by default in newly created elevation profile plots.
Represents a raster layer.
QgsRasterAttributeTable * attributeTable(int bandNumber) const
Returns the (possibly NULL) raster attribute table for the given band bandNumber.
int bandCount() const
Returns the number of bands in this layer.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
The class is used as a container of context for various read/write operations on other objects.
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
Definition qgis.h:6276
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:5983
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:6257
#define BUILTIN_UNREACHABLE
Definition qgis.h:6720
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:6066
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition qgssymbol.h:30
Single variable definition for use within a QgsExpressionContextScope.