QGIS API Documentation 3.99.0-Master (2fe06baccd8)
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
20#include "qgsapplication.h"
23#include "qgsfillsymbol.h"
24#include "qgsfillsymbollayer.h"
25#include "qgslinesymbol.h"
26#include "qgslinesymbollayer.h"
27#include "qgsrasterlayer.h"
28#include "qgssymbollayerutils.h"
29
30#include "moc_qgsrasterlayerelevationproperties.cpp"
31
34{
36 setDefaultProfileLineSymbol( color );
37 setDefaultProfileFillSymbol( color );
38}
39
41
43{
44 return mEnabled;
45}
46
47QDomElement QgsRasterLayerElevationProperties::writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context )
48{
49 QDomElement element = document.createElement( QStringLiteral( "elevation" ) );
50 element.setAttribute( QStringLiteral( "enabled" ), mEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
51 element.setAttribute( QStringLiteral( "mode" ), qgsEnumValueToKey( mMode ) );
52 element.setAttribute( QStringLiteral( "symbology" ), qgsEnumValueToKey( mSymbology ) );
53 if ( !std::isnan( mElevationLimit ) )
54 element.setAttribute( QStringLiteral( "elevationLimit" ), qgsDoubleToString( mElevationLimit ) );
55
56 writeCommonProperties( element, document, context );
57
58 switch ( mMode )
59 {
61 element.setAttribute( QStringLiteral( "lower" ), qgsDoubleToString( mFixedRange.lower() ) );
62 element.setAttribute( QStringLiteral( "upper" ), qgsDoubleToString( mFixedRange.upper() ) );
63 element.setAttribute( QStringLiteral( "includeLower" ), mFixedRange.includeLower() ? "1" : "0" );
64 element.setAttribute( QStringLiteral( "includeUpper" ), mFixedRange.includeUpper() ? "1" : "0" );
65 break;
66
68 {
69 QDomElement ranges = document.createElement( QStringLiteral( "ranges" ) );
70 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
71 {
72 QDomElement range = document.createElement( QStringLiteral( "range" ) );
73 range.setAttribute( QStringLiteral( "band" ), it.key() );
74 range.setAttribute( QStringLiteral( "lower" ), qgsDoubleToString( it.value().lower() ) );
75 range.setAttribute( QStringLiteral( "upper" ), qgsDoubleToString( it.value().upper() ) );
76 range.setAttribute( QStringLiteral( "includeLower" ), it.value().includeLower() ? "1" : "0" );
77 range.setAttribute( QStringLiteral( "includeUpper" ), it.value().includeUpper() ? "1" : "0" );
78 ranges.appendChild( range );
79 }
80 element.appendChild( ranges );
81 break;
82 }
83
85 break;
86
88 element.setAttribute( QStringLiteral( "band" ), mBandNumber );
89 break;
90 }
91
92 QDomElement profileLineSymbolElement = document.createElement( QStringLiteral( "profileLineSymbol" ) );
93 profileLineSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileLineSymbol.get(), document, context ) );
94 element.appendChild( profileLineSymbolElement );
95
96 QDomElement profileFillSymbolElement = document.createElement( QStringLiteral( "profileFillSymbol" ) );
97 profileFillSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileFillSymbol.get(), document, context ) );
98 element.appendChild( profileFillSymbolElement );
99
100 parentElement.appendChild( element );
101 return element;
102}
103
104bool QgsRasterLayerElevationProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context )
105{
106 const QDomElement elevationElement = element.firstChildElement( QStringLiteral( "elevation" ) ).toElement();
107 mEnabled = elevationElement.attribute( QStringLiteral( "enabled" ), QStringLiteral( "0" ) ).toInt();
108 mMode = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "mode" ) ), Qgis::RasterElevationMode::RepresentsElevationSurface );
109 mSymbology = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "symbology" ) ), Qgis::ProfileSurfaceSymbology::Line );
110 if ( elevationElement.hasAttribute( QStringLiteral( "elevationLimit" ) ) )
111 mElevationLimit = elevationElement.attribute( QStringLiteral( "elevationLimit" ) ).toDouble();
112 else
113 mElevationLimit = std::numeric_limits< double >::quiet_NaN();
114
115 readCommonProperties( elevationElement, context );
116
117 switch ( mMode )
118 {
120 {
121 const double lower = elevationElement.attribute( QStringLiteral( "lower" ) ).toDouble();
122 const double upper = elevationElement.attribute( QStringLiteral( "upper" ) ).toDouble();
123 const bool includeLower = elevationElement.attribute( QStringLiteral( "includeLower" ) ).toInt();
124 const bool includeUpper = elevationElement.attribute( QStringLiteral( "includeUpper" ) ).toInt();
125 mFixedRange = QgsDoubleRange( lower, upper, includeLower, includeUpper );
126 break;
127 }
128
130 {
131 mRangePerBand.clear();
132
133 const QDomNodeList ranges = elevationElement.firstChildElement( QStringLiteral( "ranges" ) ).childNodes();
134 for ( int i = 0; i < ranges.size(); ++i )
135 {
136 const QDomElement rangeElement = ranges.at( i ).toElement();
137 const int band = rangeElement.attribute( QStringLiteral( "band" ) ).toInt();
138 const double lower = rangeElement.attribute( QStringLiteral( "lower" ) ).toDouble();
139 const double upper = rangeElement.attribute( QStringLiteral( "upper" ) ).toDouble();
140 const bool includeLower = rangeElement.attribute( QStringLiteral( "includeLower" ) ).toInt();
141 const bool includeUpper = rangeElement.attribute( QStringLiteral( "includeUpper" ) ).toInt();
142 mRangePerBand.insert( band, QgsDoubleRange( lower, upper, includeLower, includeUpper ) );
143 }
144 break;
145 }
146
148 break;
149
151 mBandNumber = elevationElement.attribute( QStringLiteral( "band" ), QStringLiteral( "1" ) ).toInt();
152 break;
153 }
154
155 const QColor defaultColor = QgsApplication::colorSchemeRegistry()->fetchRandomStyleColor();
156
157 const QDomElement profileLineSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileLineSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
158 mProfileLineSymbol = QgsSymbolLayerUtils::loadSymbol< QgsLineSymbol >( profileLineSymbolElement, context );
159 if ( !mProfileLineSymbol )
160 setDefaultProfileLineSymbol( defaultColor );
161
162 const QDomElement profileFillSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileFillSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
163 mProfileFillSymbol = QgsSymbolLayerUtils::loadSymbol< QgsFillSymbol >( profileFillSymbolElement, context );
164 if ( !mProfileFillSymbol )
165 setDefaultProfileFillSymbol( defaultColor );
166
167 return true;
168}
169
171{
172 auto res = std::make_unique< QgsRasterLayerElevationProperties >( nullptr );
173 res->setEnabled( mEnabled );
174 res->setMode( mMode );
175 res->setProfileLineSymbol( mProfileLineSymbol->clone() );
176 res->setProfileFillSymbol( mProfileFillSymbol->clone() );
177 res->setProfileSymbology( mSymbology );
178 res->setElevationLimit( mElevationLimit );
179 res->setBandNumber( mBandNumber );
180 res->setFixedRange( mFixedRange );
181 res->setFixedRangePerBand( mRangePerBand );
182 res->copyCommonProperties( this );
183 return res.release();
184}
185
187{
188 QStringList properties;
189 switch ( mMode )
190 {
192 properties << tr( "Elevation range: %1 to %2" ).arg( mFixedRange.lower() ).arg( mFixedRange.upper() );
193 break;
194
196 {
197 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
198 {
199 properties << tr( "Elevation for band %1: %2 to %3" ).arg( it.key() ).arg( it.value().lower() ).arg( it.value().upper() );
200 }
201 break;
202 }
203
205 break;
206
208 properties << tr( "Elevation band: %1" ).arg( mBandNumber );
209 properties << tr( "Scale: %1" ).arg( mZScale );
210 properties << tr( "Offset: %1" ).arg( mZOffset );
211 break;
212 }
213
214 return QStringLiteral( "<li>%1</li>" ).arg( properties.join( QLatin1String( "</li><li>" ) ) );
215}
216
218{
219 switch ( mMode )
220 {
222 return mFixedRange.overlaps( range );
223
225 {
226 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
227 {
228 if ( it.value().overlaps( range ) )
229 return true;
230 }
231 return false;
232 }
233
235 {
236 if ( QgsRasterLayer *rl = qobject_cast< QgsRasterLayer * >( layer ) )
237 {
238 QgsExpressionContext context;
241 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band" ), 1, true, false, tr( "Band number" ) ) );
242 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_name" ), rl->dataProvider()->displayBandName( 1 ), true, false, tr( "Band name" ) ) );
243 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_description" ), rl->dataProvider()->bandDescription( 1 ), true, false, tr( "Band description" ) ) );
244 context.appendScope( bandScope );
245
248 lowerProperty.prepare( context );
249 upperProperty.prepare( context );
250 for ( int band = 1; band <= rl->bandCount(); ++band )
251 {
252 bandScope->setVariable( QStringLiteral( "band" ), band );
253 bandScope->setVariable( QStringLiteral( "band_name" ), rl->dataProvider()->displayBandName( band ) );
254 bandScope->setVariable( QStringLiteral( "band_description" ), rl->dataProvider()->bandDescription( band ) );
255
256 bool ok = false;
257 const double lower = lowerProperty.valueAsDouble( context, 0, &ok );
258 if ( !ok )
259 continue;
260 const double upper = upperProperty.valueAsDouble( context, 0, &ok );
261 if ( !ok )
262 continue;
263
264 if ( QgsDoubleRange( lower, upper ).overlaps( range ) )
265 return true;
266 }
267 }
268 return false;
269 }
270
272 // TODO -- test actual raster z range
273 return true;
274 }
276}
277
279{
280 switch ( mMode )
281 {
283 return mFixedRange;
284
286 {
287 double lower = std::numeric_limits< double >::max();
288 double upper = std::numeric_limits< double >::min();
289 bool includeLower = true;
290 bool includeUpper = true;
291 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
292 {
293 if ( it.value().lower() < lower )
294 {
295 lower = it.value().lower();
296 includeLower = it.value().includeLower();
297 }
298 else if ( !includeLower && it.value().lower() == lower && it.value().includeLower() )
299 {
300 includeLower = true;
301 }
302 if ( it.value().upper() > upper )
303 {
304 upper = it.value().upper();
305 includeUpper = it.value().includeUpper();
306 }
307 else if ( !includeUpper && it.value().upper() == upper && it.value().includeUpper() )
308 {
309 includeUpper = true;
310 }
311 }
312 return QgsDoubleRange( lower, upper, includeLower, includeUpper );
313 }
314
316 {
317 if ( QgsRasterLayer *rl = qobject_cast< QgsRasterLayer * >( layer ) )
318 {
319 QgsExpressionContext context;
322 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band" ), 1, true, false, tr( "Band number" ) ) );
323 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_name" ), rl->dataProvider()->displayBandName( 1 ), true, false, tr( "Band name" ) ) );
324 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_description" ), rl->dataProvider()->bandDescription( 1 ), true, false, tr( "Band description" ) ) );
325 context.appendScope( bandScope );
326
329 lowerProperty.prepare( context );
330 upperProperty.prepare( context );
331 double minLower = std::numeric_limits<double>::max();
332 double maxUpper = std::numeric_limits<double>::lowest();
333 for ( int band = 1; band <= rl->bandCount(); ++band )
334 {
335 bandScope->setVariable( QStringLiteral( "band" ), band );
336 bandScope->setVariable( QStringLiteral( "band_name" ), rl->dataProvider()->displayBandName( band ) );
337 bandScope->setVariable( QStringLiteral( "band_description" ), rl->dataProvider()->bandDescription( band ) );
338
339 bool ok = false;
340 const double lower = lowerProperty.valueAsDouble( context, 0, &ok );
341 if ( !ok )
342 continue;
343 const double upper = upperProperty.valueAsDouble( context, 0, &ok );
344 if ( !ok )
345 continue;
346
347 minLower = std::min( minLower, lower );
348 maxUpper = std::max( maxUpper, upper );
349 }
350 return ( minLower == std::numeric_limits<double>::max() && maxUpper == std::numeric_limits<double>::lowest() ) ? QgsDoubleRange() : QgsDoubleRange( minLower, maxUpper );
351 }
352 return QgsDoubleRange();
353 }
354
356 // TODO -- determine actual z range from raster statistics
357 return QgsDoubleRange();
358 }
360}
361
363{
364 switch ( mMode )
365 {
367 {
368 if ( !mFixedRange.isInfinite() && mFixedRange.lower() != mFixedRange.upper() )
369 return { mFixedRange.lower(), mFixedRange.upper() };
370 else if ( !mFixedRange.isInfinite() )
371 return { mFixedRange.lower() };
372
373 return {};
374 }
375
377 {
378 QList< double > res;
379 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
380 {
381 if ( it.value().isInfinite() )
382 continue;
383
384 if ( !res.contains( it.value().lower( ) ) )
385 res.append( it.value().lower() );
386 if ( !res.contains( it.value().upper( ) ) )
387 res.append( it.value().upper() );
388 }
389 std::sort( res.begin(), res.end() );
390 return res;
391 }
392
394 {
395 QList< double > res;
396 if ( QgsRasterLayer *rl = qobject_cast< QgsRasterLayer * >( layer ) )
397 {
398 QgsExpressionContext context;
401 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band" ), 1, true, false, tr( "Band number" ) ) );
402 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_name" ), rl->dataProvider()->displayBandName( 1 ), true, false, tr( "Band name" ) ) );
403 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_description" ), rl->dataProvider()->bandDescription( 1 ), true, false, tr( "Band description" ) ) );
404 context.appendScope( bandScope );
405
408 lowerProperty.prepare( context );
409 upperProperty.prepare( context );
410 for ( int band = 1; band <= rl->bandCount(); ++band )
411 {
412 bandScope->setVariable( QStringLiteral( "band" ), band );
413 bandScope->setVariable( QStringLiteral( "band_name" ), rl->dataProvider()->displayBandName( band ) );
414 bandScope->setVariable( QStringLiteral( "band_description" ), rl->dataProvider()->bandDescription( band ) );
415
416 bool ok = false;
417 const double lower = lowerProperty.valueAsDouble( context, 0, &ok );
418 if ( ok && !res.contains( lower ) )
419 res.append( lower );
420 const double upper = upperProperty.valueAsDouble( context, 0, &ok );
421 if ( ok && !res.contains( upper ) )
422 res.append( upper );
423 }
424 }
425 return res;
426 }
427
429 return {};
430 }
432}
433
438
456
458{
459 if ( enabled == mEnabled )
460 return;
461
462 mEnabled = enabled;
463 emit changed();
465}
466
471
473{
474 if ( mMode == mode )
475 return;
476
477 mMode = mode;
478 emit changed();
479}
480
482{
483 if ( mBandNumber == band )
484 return;
485
486 mBandNumber = band;
487 emit changed();
489}
490
492{
493 if ( !mEnabled || std::isnan( pixelValue ) )
494 return QgsDoubleRange();
495
496 switch ( mMode )
497 {
499 return mFixedRange;
500
502 {
503 auto it = mRangePerBand.constFind( band );
504 if ( it != mRangePerBand.constEnd() )
505 return it.value();
506 return QgsDoubleRange();
507 }
508
510 {
511 if ( layer && band > 0 && band <= layer->bandCount() )
512 {
513 QgsExpressionContext context;
516 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band" ), band, true, false, tr( "Band number" ) ) );
517 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_name" ), layer->dataProvider()->displayBandName( band ), true, false, tr( "Band name" ) ) );
518 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_description" ), layer->dataProvider()->bandDescription( band ), true, false, tr( "Band description" ) ) );
519 context.appendScope( bandScope );
520
523 lowerProperty.prepare( context );
524 upperProperty.prepare( context );
525
526 bool ok = false;
527 const double lower = lowerProperty.valueAsDouble( context, 0, &ok );
528 if ( !ok )
529 return QgsDoubleRange();
530 const double upper = upperProperty.valueAsDouble( context, 0, &ok );
531 if ( !ok )
532 return QgsDoubleRange();
533
534 return QgsDoubleRange( lower, upper );
535 }
536
537 return QgsDoubleRange();
538 }
539
541 {
542 if ( band != mBandNumber )
543 return QgsDoubleRange();
544
545 const double z = pixelValue * mZScale + mZOffset;
546 return QgsDoubleRange( z, z );
547 }
548 }
550}
551
553{
554 switch ( mMode )
555 {
558 return -1;
559
561 {
562 // find the top-most band which matches the map range
563 int currentMatchingBand = -1;
564 QgsDoubleRange currentMatchingRange;
565 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
566 {
567 if ( it.value().overlaps( range ) )
568 {
569 if ( currentMatchingRange.isInfinite()
570 || ( it.value().includeUpper() && it.value().upper() >= currentMatchingRange.upper() )
571 || ( !currentMatchingRange.includeUpper() && it.value().upper() >= currentMatchingRange.upper() ) )
572 {
573 currentMatchingBand = it.key();
574 currentMatchingRange = it.value();
575 }
576 }
577 }
578 return currentMatchingBand;
579 }
580
582 {
583 if ( layer )
584 {
585 QgsExpressionContext context;
588 context.appendScope( bandScope );
589
592 lowerProperty.prepare( context );
593 upperProperty.prepare( context );
594
595 int currentMatchingBand = -1;
596 QgsDoubleRange currentMatchingRange;
597
598 for ( int band = 1; band <= layer->bandCount(); ++band )
599 {
600 bandScope->setVariable( QStringLiteral( "band" ), band );
601 bandScope->setVariable( QStringLiteral( "band_name" ), layer->dataProvider()->displayBandName( band ) );
602 bandScope->setVariable( QStringLiteral( "band_description" ), layer->dataProvider()->bandDescription( band ) );
603
604 bool ok = false;
605 const double lower = lowerProperty.valueAsDouble( context, 0, &ok );
606 if ( !ok )
607 continue;
608 const double upper = upperProperty.valueAsDouble( context, 0, &ok );
609 if ( !ok )
610 continue;
611
612 const QgsDoubleRange bandRange = QgsDoubleRange( lower, upper );
613 if ( bandRange.overlaps( range ) )
614 {
615 if ( currentMatchingRange.isInfinite()
616 || ( bandRange.includeUpper() && bandRange.upper() >= currentMatchingRange.upper() )
617 || ( !currentMatchingRange.includeUpper() && bandRange.upper() >= currentMatchingRange.upper() ) )
618 {
619 currentMatchingBand = band;
620 currentMatchingRange = bandRange;
621 }
622 }
623 }
624 return currentMatchingBand;
625 }
626 return -1;
627 }
628 }
630}
631
633{
634 return mProfileLineSymbol.get();
635}
636
638{
639 mProfileLineSymbol.reset( symbol );
640 emit changed();
642}
643
645{
646 return mProfileFillSymbol.get();
647}
648
650{
651 mProfileFillSymbol.reset( symbol );
652 emit changed();
654}
655
657{
658 if ( mSymbology == symbology )
659 return;
660
661 mSymbology = symbology;
662 emit changed();
664}
665
667{
668 return mElevationLimit;
669}
670
672{
673 if ( qgsDoubleNear( mElevationLimit, limit ) )
674 return;
675
676 mElevationLimit = limit;
677 emit changed();
679}
680
682{
683 // multiple bands => unlikely to be a DEM
684 if ( layer->bandCount() > 1 )
685 return false;
686
687 // raster attribute table => unlikely to be a DEM
688 if ( layer->attributeTable( 1 ) )
689 return false;
690
691 if ( QgsRasterDataProvider *dataProvider = layer->dataProvider() )
692 {
693 // filter out data types which aren't likely to be DEMs
694 switch ( dataProvider->dataType( 1 ) )
695 {
704 return false;
705
713 break;
714 }
715 }
716
717 // Check the layer's name for DEM-ish hints.
718 // See discussion at https://github.com/qgis/QGIS/pull/30245 - this list must NOT be translated,
719 // but adding hardcoded localized variants of the strings is encouraged.
720 static const QStringList sPartialCandidates{ QStringLiteral( "dem" ),
721 QStringLiteral( "dtm" ),
722 QStringLiteral( "dsm" ),
723 QStringLiteral( "height" ),
724 QStringLiteral( "elev" ),
725 QStringLiteral( "srtm" ),
726 QStringLiteral( "dted" ),
727 // French hints
728 QStringLiteral( "mne" ),
729 QStringLiteral( "mnt" ),
730 QStringLiteral( "mns" ),
731 QStringLiteral( "rge" ),
732 QStringLiteral( "alti" ),
733 // German hints
734 QStringLiteral( "dhm" ),
735 QStringLiteral( "dgm" ),
736 QStringLiteral( "dom" ),
737 QStringLiteral( "Höhe" ),
738 QStringLiteral( "Hoehe" ) };
739 const QString layerName = layer->name();
740 for ( const QString &candidate : sPartialCandidates )
741 {
742 if ( layerName.contains( candidate, Qt::CaseInsensitive ) )
743 return true;
744 }
745
746 // these candidates must occur with word boundaries (we don't want to find "aster" in "raster"!)
747 static const QStringList sWordCandidates{ QStringLiteral( "aster" ) };
748 for ( const QString &candidate : sWordCandidates )
749 {
750 const thread_local QRegularExpression re( QStringLiteral( "\\b%1\\b" ).arg( candidate ) );
751 if ( re.match( layerName, Qt::CaseInsensitive ).hasMatch() )
752 return true;
753 }
754
755 return false;
756}
757
758void QgsRasterLayerElevationProperties::setDefaultProfileLineSymbol( const QColor &color )
759{
760 auto profileLineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( color, 0.6 );
761 mProfileLineSymbol = std::make_unique< QgsLineSymbol>( QgsSymbolLayerList( { profileLineLayer.release() } ) );
762}
763
764void QgsRasterLayerElevationProperties::setDefaultProfileFillSymbol( const QColor &color )
765{
766 auto profileFillLayer = std::make_unique< QgsSimpleFillSymbolLayer >( color );
767 profileFillLayer->setStrokeStyle( Qt::NoPen );
768 mProfileFillSymbol = std::make_unique< QgsFillSymbol>( QgsSymbolLayerList( { profileFillLayer.release() } ) );
769}
770
772{
773 return mRangePerBand;
774}
775
776void QgsRasterLayerElevationProperties::setFixedRangePerBand( const QMap<int, QgsDoubleRange> &ranges )
777{
778 if ( ranges == mRangePerBand )
779 return;
780
781 mRangePerBand = ranges;
782 emit changed();
783}
784
786{
787 return mFixedRange;
788}
789
791{
792 if ( range == mFixedRange )
793 return;
794
795 mFixedRange = range;
796 emit changed();
797}
RasterElevationMode
Raster layer elevation modes.
Definition qgis.h:4021
@ FixedRangePerBand
Layer has a fixed (manually specified) elevation range per band.
Definition qgis.h:4024
@ FixedElevationRange
Layer has a fixed elevation range.
Definition qgis.h:4022
@ RepresentsElevationSurface
Pixel values represent an elevation surface.
Definition qgis.h:4023
@ DynamicRangePerBand
Layer has a elevation range per band, calculated dynamically from an expression.
Definition qgis.h:4025
@ CInt32
Complex Int32.
Definition qgis.h:383
@ Float32
Thirty two bit floating point (float).
Definition qgis.h:380
@ CFloat64
Complex Float64.
Definition qgis.h:385
@ Int16
Sixteen bit signed integer (qint16).
Definition qgis.h:377
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition qgis.h:387
@ Int8
Eight bit signed integer (qint8) (added in QGIS 3.30).
Definition qgis.h:375
@ UInt16
Sixteen bit unsigned integer (quint16).
Definition qgis.h:376
@ Byte
Eight bit unsigned integer (quint8).
Definition qgis.h:374
@ UnknownDataType
Unknown or unspecified type.
Definition qgis.h:373
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition qgis.h:386
@ Int32
Thirty two bit signed integer (qint32).
Definition qgis.h:379
@ Float64
Sixty four bit floating point (double).
Definition qgis.h:381
@ CFloat32
Complex Float32.
Definition qgis.h:384
@ CInt16
Complex Int16.
Definition qgis.h:382
@ UInt32
Thirty two bit unsigned integer (quint32).
Definition qgis.h:378
ProfileSurfaceSymbology
Surface symbology type for elevation profile plots.
Definition qgis.h:4193
@ Line
The elevation surface will be rendered using a line symbol.
Definition qgis.h:4194
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:233
bool isInfinite() const
Returns true if the range consists of all possible values.
Definition qgsrange.h:287
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.
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 ...
QgsMapLayerElevationProperties(QObject *parent)
Constructor for QgsMapLayerElevationProperties, with the specified parent object.
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:80
QString name
Definition qgsmaplayer.h:84
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 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.
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.
A container for the context for various read/write operations on objects.
static std::unique_ptr< QgsSymbol > loadSymbol(const QDomElement &element, const QgsReadWriteContext &context)
Attempts to load a symbol from a DOM element.
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:6817
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:6524
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:6798
#define BUILTIN_UNREACHABLE
Definition qgis.h:7208
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6607
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition qgssymbol.h:30
Single variable definition for use within a QgsExpressionContextScope.