QGIS API Documentation 3.39.0-Master (47f7b3a4989)
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 "qgsrasterlayer.h"
20#include "qgslinesymbol.h"
21#include "qgsfillsymbol.h"
22#include "qgssymbollayerutils.h"
23#include "qgslinesymbollayer.h"
24#include "qgsfillsymbollayer.h"
25#include "qgsapplication.h"
28
31{
33 setDefaultProfileLineSymbol( color );
34 setDefaultProfileFillSymbol( color );
35}
36
38
40{
41 return mEnabled;
42}
43
44QDomElement QgsRasterLayerElevationProperties::writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context )
45{
46 QDomElement element = document.createElement( QStringLiteral( "elevation" ) );
47 element.setAttribute( QStringLiteral( "enabled" ), mEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
48 element.setAttribute( QStringLiteral( "mode" ), qgsEnumValueToKey( mMode ) );
49 element.setAttribute( QStringLiteral( "symbology" ), qgsEnumValueToKey( mSymbology ) );
50 if ( !std::isnan( mElevationLimit ) )
51 element.setAttribute( QStringLiteral( "elevationLimit" ), qgsDoubleToString( mElevationLimit ) );
52
53 writeCommonProperties( element, document, context );
54
55 switch ( mMode )
56 {
58 element.setAttribute( QStringLiteral( "lower" ), qgsDoubleToString( mFixedRange.lower() ) );
59 element.setAttribute( QStringLiteral( "upper" ), qgsDoubleToString( mFixedRange.upper() ) );
60 element.setAttribute( QStringLiteral( "includeLower" ), mFixedRange.includeLower() ? "1" : "0" );
61 element.setAttribute( QStringLiteral( "includeUpper" ), mFixedRange.includeUpper() ? "1" : "0" );
62 break;
63
65 {
66 QDomElement ranges = document.createElement( QStringLiteral( "ranges" ) );
67 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
68 {
69 QDomElement range = document.createElement( QStringLiteral( "range" ) );
70 range.setAttribute( QStringLiteral( "band" ), it.key() );
71 range.setAttribute( QStringLiteral( "lower" ), qgsDoubleToString( it.value().lower() ) );
72 range.setAttribute( QStringLiteral( "upper" ), qgsDoubleToString( it.value().upper() ) );
73 range.setAttribute( QStringLiteral( "includeLower" ), it.value().includeLower() ? "1" : "0" );
74 range.setAttribute( QStringLiteral( "includeUpper" ), it.value().includeUpper() ? "1" : "0" );
75 ranges.appendChild( range );
76 }
77 element.appendChild( ranges );
78 break;
79 }
80
82 break;
83
85 element.setAttribute( QStringLiteral( "band" ), mBandNumber );
86 break;
87 }
88
89 QDomElement profileLineSymbolElement = document.createElement( QStringLiteral( "profileLineSymbol" ) );
90 profileLineSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileLineSymbol.get(), document, context ) );
91 element.appendChild( profileLineSymbolElement );
92
93 QDomElement profileFillSymbolElement = document.createElement( QStringLiteral( "profileFillSymbol" ) );
94 profileFillSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileFillSymbol.get(), document, context ) );
95 element.appendChild( profileFillSymbolElement );
96
97 parentElement.appendChild( element );
98 return element;
99}
100
101bool QgsRasterLayerElevationProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context )
102{
103 const QDomElement elevationElement = element.firstChildElement( QStringLiteral( "elevation" ) ).toElement();
104 mEnabled = elevationElement.attribute( QStringLiteral( "enabled" ), QStringLiteral( "0" ) ).toInt();
105 mMode = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "mode" ) ), Qgis::RasterElevationMode::RepresentsElevationSurface );
106 mSymbology = qgsEnumKeyToValue( elevationElement.attribute( QStringLiteral( "symbology" ) ), Qgis::ProfileSurfaceSymbology::Line );
107 if ( elevationElement.hasAttribute( QStringLiteral( "elevationLimit" ) ) )
108 mElevationLimit = elevationElement.attribute( QStringLiteral( "elevationLimit" ) ).toDouble();
109 else
110 mElevationLimit = std::numeric_limits< double >::quiet_NaN();
111
112 readCommonProperties( elevationElement, context );
113
114 switch ( mMode )
115 {
117 {
118 const double lower = elevationElement.attribute( QStringLiteral( "lower" ) ).toDouble();
119 const double upper = elevationElement.attribute( QStringLiteral( "upper" ) ).toDouble();
120 const bool includeLower = elevationElement.attribute( QStringLiteral( "includeLower" ) ).toInt();
121 const bool includeUpper = elevationElement.attribute( QStringLiteral( "includeUpper" ) ).toInt();
122 mFixedRange = QgsDoubleRange( lower, upper, includeLower, includeUpper );
123 break;
124 }
125
127 {
128 mRangePerBand.clear();
129
130 const QDomNodeList ranges = elevationElement.firstChildElement( QStringLiteral( "ranges" ) ).childNodes();
131 for ( int i = 0; i < ranges.size(); ++i )
132 {
133 const QDomElement rangeElement = ranges.at( i ).toElement();
134 const int band = rangeElement.attribute( QStringLiteral( "band" ) ).toInt();
135 const double lower = rangeElement.attribute( QStringLiteral( "lower" ) ).toDouble();
136 const double upper = rangeElement.attribute( QStringLiteral( "upper" ) ).toDouble();
137 const bool includeLower = rangeElement.attribute( QStringLiteral( "includeLower" ) ).toInt();
138 const bool includeUpper = rangeElement.attribute( QStringLiteral( "includeUpper" ) ).toInt();
139 mRangePerBand.insert( band, QgsDoubleRange( lower, upper, includeLower, includeUpper ) );
140 }
141 break;
142 }
143
145 break;
146
148 mBandNumber = elevationElement.attribute( QStringLiteral( "band" ), QStringLiteral( "1" ) ).toInt();
149 break;
150 }
151
152 const QColor defaultColor = QgsApplication::colorSchemeRegistry()->fetchRandomStyleColor();
153
154 const QDomElement profileLineSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileLineSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
155 mProfileLineSymbol.reset( QgsSymbolLayerUtils::loadSymbol< QgsLineSymbol >( profileLineSymbolElement, context ) );
156 if ( !mProfileLineSymbol )
157 setDefaultProfileLineSymbol( defaultColor );
158
159 const QDomElement profileFillSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileFillSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) );
160 mProfileFillSymbol.reset( QgsSymbolLayerUtils::loadSymbol< QgsFillSymbol >( profileFillSymbolElement, context ) );
161 if ( !mProfileFillSymbol )
162 setDefaultProfileFillSymbol( defaultColor );
163
164 return true;
165}
166
168{
169 std::unique_ptr< QgsRasterLayerElevationProperties > res = std::make_unique< QgsRasterLayerElevationProperties >( nullptr );
170 res->setEnabled( mEnabled );
171 res->setMode( mMode );
172 res->setProfileLineSymbol( mProfileLineSymbol->clone() );
173 res->setProfileFillSymbol( mProfileFillSymbol->clone() );
174 res->setProfileSymbology( mSymbology );
175 res->setElevationLimit( mElevationLimit );
176 res->setBandNumber( mBandNumber );
177 res->setFixedRange( mFixedRange );
178 res->setFixedRangePerBand( mRangePerBand );
179 res->copyCommonProperties( this );
180 return res.release();
181}
182
184{
185 QStringList properties;
186 switch ( mMode )
187 {
189 properties << tr( "Elevation range: %1 to %2" ).arg( mFixedRange.lower() ).arg( mFixedRange.upper() );
190 break;
191
193 {
194 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
195 {
196 properties << tr( "Elevation for band %1: %2 to %3" ).arg( it.key() ).arg( it.value().lower() ).arg( it.value().upper() );
197 }
198 break;
199 }
200
202 break;
203
205 properties << tr( "Elevation band: %1" ).arg( mBandNumber );
206 properties << tr( "Scale: %1" ).arg( mZScale );
207 properties << tr( "Offset: %1" ).arg( mZOffset );
208 break;
209 }
210
211 return QStringLiteral( "<li>%1</li>" ).arg( properties.join( QLatin1String( "</li><li>" ) ) );
212}
213
215{
216 switch ( mMode )
217 {
219 return mFixedRange.overlaps( range );
220
222 {
223 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
224 {
225 if ( it.value().overlaps( range ) )
226 return true;
227 }
228 return false;
229 }
230
232 {
233 if ( QgsRasterLayer *rl = qobject_cast< QgsRasterLayer * >( layer ) )
234 {
235 QgsExpressionContext context;
238 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band" ), 1, true, false, tr( "Band number" ) ) );
239 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_name" ), rl->dataProvider()->displayBandName( 1 ), true, false, tr( "Band name" ) ) );
240 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_description" ), rl->dataProvider()->bandDescription( 1 ), true, false, tr( "Band description" ) ) );
241 context.appendScope( bandScope );
242
245 lowerProperty.prepare( context );
246 upperProperty.prepare( context );
247 for ( int band = 1; band <= rl->bandCount(); ++band )
248 {
249 bandScope->setVariable( QStringLiteral( "band" ), band );
250 bandScope->setVariable( QStringLiteral( "band_name" ), rl->dataProvider()->displayBandName( band ) );
251 bandScope->setVariable( QStringLiteral( "band_description" ), rl->dataProvider()->bandDescription( band ) );
252
253 bool ok = false;
254 const double lower = lowerProperty.valueAsDouble( context, 0, &ok );
255 if ( !ok )
256 continue;
257 const double upper = upperProperty.valueAsDouble( context, 0, &ok );
258 if ( !ok )
259 continue;
260
261 if ( QgsDoubleRange( lower, upper ).overlaps( range ) )
262 return true;
263 }
264 }
265 return false;
266 }
267
269 // TODO -- test actual raster z range
270 return true;
271 }
273}
274
276{
277 switch ( mMode )
278 {
280 return mFixedRange;
281
283 {
284 double lower = std::numeric_limits< double >::max();
285 double upper = std::numeric_limits< double >::min();
286 bool includeLower = true;
287 bool includeUpper = true;
288 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
289 {
290 if ( it.value().lower() < lower )
291 {
292 lower = it.value().lower();
293 includeLower = it.value().includeLower();
294 }
295 else if ( !includeLower && it.value().lower() == lower && it.value().includeLower() )
296 {
297 includeLower = true;
298 }
299 if ( it.value().upper() > upper )
300 {
301 upper = it.value().upper();
302 includeUpper = it.value().includeUpper();
303 }
304 else if ( !includeUpper && it.value().upper() == upper && it.value().includeUpper() )
305 {
306 includeUpper = true;
307 }
308 }
309 return QgsDoubleRange( lower, upper, includeLower, includeUpper );
310 }
311
313 {
314 if ( QgsRasterLayer *rl = qobject_cast< QgsRasterLayer * >( layer ) )
315 {
316 QgsExpressionContext context;
319 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band" ), 1, true, false, tr( "Band number" ) ) );
320 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_name" ), rl->dataProvider()->displayBandName( 1 ), true, false, tr( "Band name" ) ) );
321 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_description" ), rl->dataProvider()->bandDescription( 1 ), true, false, tr( "Band description" ) ) );
322 context.appendScope( bandScope );
323
326 lowerProperty.prepare( context );
327 upperProperty.prepare( context );
328 double minLower = std::numeric_limits<double>::max();
329 double maxUpper = std::numeric_limits<double>::lowest();
330 for ( int band = 1; band <= rl->bandCount(); ++band )
331 {
332 bandScope->setVariable( QStringLiteral( "band" ), band );
333 bandScope->setVariable( QStringLiteral( "band_name" ), rl->dataProvider()->displayBandName( band ) );
334 bandScope->setVariable( QStringLiteral( "band_description" ), rl->dataProvider()->bandDescription( band ) );
335
336 bool ok = false;
337 const double lower = lowerProperty.valueAsDouble( context, 0, &ok );
338 if ( !ok )
339 continue;
340 const double upper = upperProperty.valueAsDouble( context, 0, &ok );
341 if ( !ok )
342 continue;
343
344 minLower = std::min( minLower, lower );
345 maxUpper = std::max( maxUpper, upper );
346 }
347 return ( minLower == std::numeric_limits<double>::max() && maxUpper == std::numeric_limits<double>::lowest() ) ? QgsDoubleRange() : QgsDoubleRange( minLower, maxUpper );
348 }
349 return QgsDoubleRange();
350 }
351
353 // TODO -- determine actual z range from raster statistics
354 return QgsDoubleRange();
355 }
357}
358
360{
361 switch ( mMode )
362 {
364 {
365 if ( !mFixedRange.isInfinite() && mFixedRange.lower() != mFixedRange.upper() )
366 return { mFixedRange.lower(), mFixedRange.upper() };
367 else if ( !mFixedRange.isInfinite() )
368 return { mFixedRange.lower() };
369
370 return {};
371 }
372
374 {
375 QList< double > res;
376 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
377 {
378 if ( it.value().isInfinite() )
379 continue;
380
381 if ( !res.contains( it.value().lower( ) ) )
382 res.append( it.value().lower() );
383 if ( !res.contains( it.value().upper( ) ) )
384 res.append( it.value().upper() );
385 }
386 std::sort( res.begin(), res.end() );
387 return res;
388 }
389
391 {
392 QList< double > res;
393 if ( QgsRasterLayer *rl = qobject_cast< QgsRasterLayer * >( layer ) )
394 {
395 QgsExpressionContext context;
398 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band" ), 1, true, false, tr( "Band number" ) ) );
399 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_name" ), rl->dataProvider()->displayBandName( 1 ), true, false, tr( "Band name" ) ) );
400 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_description" ), rl->dataProvider()->bandDescription( 1 ), true, false, tr( "Band description" ) ) );
401 context.appendScope( bandScope );
402
405 lowerProperty.prepare( context );
406 upperProperty.prepare( context );
407 for ( int band = 1; band <= rl->bandCount(); ++band )
408 {
409 bandScope->setVariable( QStringLiteral( "band" ), band );
410 bandScope->setVariable( QStringLiteral( "band_name" ), rl->dataProvider()->displayBandName( band ) );
411 bandScope->setVariable( QStringLiteral( "band_description" ), rl->dataProvider()->bandDescription( band ) );
412
413 bool ok = false;
414 const double lower = lowerProperty.valueAsDouble( context, 0, &ok );
415 if ( ok && !res.contains( lower ) )
416 res.append( lower );
417 const double upper = upperProperty.valueAsDouble( context, 0, &ok );
418 if ( ok && !res.contains( upper ) )
419 res.append( upper );
420 }
421 }
422 return res;
423 }
424
426 return {};
427 }
429}
430
435
453
455{
456 if ( enabled == mEnabled )
457 return;
458
459 mEnabled = enabled;
460 emit changed();
462}
463
468
470{
471 if ( mMode == mode )
472 return;
473
474 mMode = mode;
475 emit changed();
476}
477
479{
480 if ( mBandNumber == band )
481 return;
482
483 mBandNumber = band;
484 emit changed();
486}
487
489{
490 if ( !mEnabled || std::isnan( pixelValue ) )
491 return QgsDoubleRange();
492
493 switch ( mMode )
494 {
496 return mFixedRange;
497
499 {
500 auto it = mRangePerBand.constFind( band );
501 if ( it != mRangePerBand.constEnd() )
502 return it.value();
503 return QgsDoubleRange();
504 }
505
507 {
508 if ( layer && band > 0 && band <= layer->bandCount() )
509 {
510 QgsExpressionContext context;
513 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band" ), band, true, false, tr( "Band number" ) ) );
514 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_name" ), layer->dataProvider()->displayBandName( band ), true, false, tr( "Band name" ) ) );
515 bandScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "band_description" ), layer->dataProvider()->bandDescription( band ), true, false, tr( "Band description" ) ) );
516 context.appendScope( bandScope );
517
520 lowerProperty.prepare( context );
521 upperProperty.prepare( context );
522
523 bool ok = false;
524 const double lower = lowerProperty.valueAsDouble( context, 0, &ok );
525 if ( !ok )
526 return QgsDoubleRange();
527 const double upper = upperProperty.valueAsDouble( context, 0, &ok );
528 if ( !ok )
529 return QgsDoubleRange();
530
531 return QgsDoubleRange( lower, upper );
532 }
533
534 return QgsDoubleRange();
535 }
536
538 {
539 if ( band != mBandNumber )
540 return QgsDoubleRange();
541
542 const double z = pixelValue * mZScale + mZOffset;
543 return QgsDoubleRange( z, z );
544 }
545 }
547}
548
550{
551 switch ( mMode )
552 {
555 return -1;
556
558 {
559 // find the top-most band which matches the map range
560 int currentMatchingBand = -1;
561 QgsDoubleRange currentMatchingRange;
562 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
563 {
564 if ( it.value().overlaps( range ) )
565 {
566 if ( currentMatchingRange.isInfinite()
567 || ( it.value().includeUpper() && it.value().upper() >= currentMatchingRange.upper() )
568 || ( !currentMatchingRange.includeUpper() && it.value().upper() >= currentMatchingRange.upper() ) )
569 {
570 currentMatchingBand = it.key();
571 currentMatchingRange = it.value();
572 }
573 }
574 }
575 return currentMatchingBand;
576 }
577
579 {
580 if ( layer )
581 {
582 QgsExpressionContext context;
585 context.appendScope( bandScope );
586
589 lowerProperty.prepare( context );
590 upperProperty.prepare( context );
591
592 int currentMatchingBand = -1;
593 QgsDoubleRange currentMatchingRange;
594
595 for ( int band = 1; band <= layer->bandCount(); ++band )
596 {
597 bandScope->setVariable( QStringLiteral( "band" ), band );
598 bandScope->setVariable( QStringLiteral( "band_name" ), layer->dataProvider()->displayBandName( band ) );
599 bandScope->setVariable( QStringLiteral( "band_description" ), layer->dataProvider()->bandDescription( band ) );
600
601 bool ok = false;
602 const double lower = lowerProperty.valueAsDouble( context, 0, &ok );
603 if ( !ok )
604 continue;
605 const double upper = upperProperty.valueAsDouble( context, 0, &ok );
606 if ( !ok )
607 continue;
608
609 const QgsDoubleRange bandRange = QgsDoubleRange( lower, upper );
610 if ( bandRange.overlaps( range ) )
611 {
612 if ( currentMatchingRange.isInfinite()
613 || ( bandRange.includeUpper() && bandRange.upper() >= currentMatchingRange.upper() )
614 || ( !currentMatchingRange.includeUpper() && bandRange.upper() >= currentMatchingRange.upper() ) )
615 {
616 currentMatchingBand = band;
617 currentMatchingRange = bandRange;
618 }
619 }
620 }
621 return currentMatchingBand;
622 }
623 return -1;
624 }
625 }
627}
628
630{
631 return mProfileLineSymbol.get();
632}
633
635{
636 mProfileLineSymbol.reset( symbol );
637 emit changed();
639}
640
642{
643 return mProfileFillSymbol.get();
644}
645
647{
648 mProfileFillSymbol.reset( symbol );
649 emit changed();
651}
652
654{
655 if ( mSymbology == symbology )
656 return;
657
658 mSymbology = symbology;
659 emit changed();
661}
662
664{
665 return mElevationLimit;
666}
667
669{
670 if ( qgsDoubleNear( mElevationLimit, limit ) )
671 return;
672
673 mElevationLimit = limit;
674 emit changed();
676}
677
679{
680 // multiple bands => unlikely to be a DEM
681 if ( layer->bandCount() > 1 )
682 return false;
683
684 // raster attribute table => unlikely to be a DEM
685 if ( layer->attributeTable( 1 ) )
686 return false;
687
688 if ( QgsRasterDataProvider *dataProvider = layer->dataProvider() )
689 {
690 // filter out data types which aren't likely to be DEMs
691 switch ( dataProvider->dataType( 1 ) )
692 {
701 return false;
702
710 break;
711 }
712 }
713
714 // Check the layer's name for DEM-ish hints.
715 // See discussion at https://github.com/qgis/QGIS/pull/30245 - this list must NOT be translated,
716 // but adding hardcoded localized variants of the strings is encouraged.
717 static const QStringList sPartialCandidates{ QStringLiteral( "dem" ),
718 QStringLiteral( "dtm" ),
719 QStringLiteral( "dsm" ),
720 QStringLiteral( "height" ),
721 QStringLiteral( "elev" ),
722 QStringLiteral( "srtm" ),
723 // French hints
724 QStringLiteral( "mne" ),
725 QStringLiteral( "mnt" ),
726 QStringLiteral( "mns" ),
727 QStringLiteral( "rge" ),
728 QStringLiteral( "alti" ),
729 // German hints
730 QStringLiteral( "dhm" ),
731 QStringLiteral( "dgm" ),
732 QStringLiteral( "dom" ),
733 QStringLiteral( "Höhe" ),
734 QStringLiteral( "Hoehe" ) };
735 const QString layerName = layer->name();
736 for ( const QString &candidate : sPartialCandidates )
737 {
738 if ( layerName.contains( candidate, Qt::CaseInsensitive ) )
739 return true;
740 }
741
742 // these candidates must occur with word boundaries (we don't want to find "aster" in "raster"!)
743 static const QStringList sWordCandidates{ QStringLiteral( "aster" ) };
744 for ( const QString &candidate : sWordCandidates )
745 {
746 const thread_local QRegularExpression re( QStringLiteral( "\\b%1\\b" ).arg( candidate ) );
747 if ( re.match( layerName, Qt::CaseInsensitive ).hasMatch() )
748 return true;
749 }
750
751 return false;
752}
753
754void QgsRasterLayerElevationProperties::setDefaultProfileLineSymbol( const QColor &color )
755{
756 std::unique_ptr< QgsSimpleLineSymbolLayer > profileLineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( color, 0.6 );
757 mProfileLineSymbol = std::make_unique< QgsLineSymbol>( QgsSymbolLayerList( { profileLineLayer.release() } ) );
758}
759
760void QgsRasterLayerElevationProperties::setDefaultProfileFillSymbol( const QColor &color )
761{
762 std::unique_ptr< QgsSimpleFillSymbolLayer > profileFillLayer = std::make_unique< QgsSimpleFillSymbolLayer >( color );
763 profileFillLayer->setStrokeStyle( Qt::NoPen );
764 mProfileFillSymbol = std::make_unique< QgsFillSymbol>( QgsSymbolLayerList( { profileFillLayer.release() } ) );
765}
766
768{
769 return mRangePerBand;
770}
771
772void QgsRasterLayerElevationProperties::setFixedRangePerBand( const QMap<int, QgsDoubleRange> &ranges )
773{
774 if ( ranges == mRangePerBand )
775 return;
776
777 mRangePerBand = ranges;
778 emit changed();
779}
780
782{
783 return mFixedRange;
784}
785
787{
788 if ( range == mFixedRange )
789 return;
790
791 mFixedRange = range;
792 emit changed();
793}
RasterElevationMode
Raster layer elevation modes.
Definition qgis.h:3447
@ 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:3606
@ 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 (since QGIS 3.38)
@ RasterPerBandLowerElevation
Lower elevation for each raster band (since QGIS 3.38)
@ FlagDontInvalidateCachedRendersWhenRangeChanges
Any cached rendering will not be invalidated when z range context is modified.
Base class for all map layer types.
Definition qgsmaplayer.h:75
QString name
Definition qgsmaplayer.h:79
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:5675
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:5382
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:5656
#define BUILTIN_UNREACHABLE
Definition qgis.h:6119
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:5465
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition qgssymbol.h:30
Single variable definition for use within a QgsExpressionContextScope.