QGIS API Documentation 3.99.0-Master (26c88405ac0)
Loading...
Searching...
No Matches
qgsinterpolatedlinerenderer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsinterpolatedlinerenderer.cpp
3 --------------------------------------
4 Date : April 2020
5 Copyright : (C) 2020 by Vincent Cloarec
6 Email : vcloarec at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
18#include <memory>
19
20#include "qgscolorutils.h"
22#include "qgsstyle.h"
23#include "qgssymbollayerutils.h"
24#include "qgsunittypes.h"
25
26#include <QPainter>
27
29{
30 mStrokeWidth = strokeWidth;
31}
32
37
39{
40 mStrokeColoring = strokeColoring;
41}
42
47
49{
50 mStrokeWidthUnit = strokeWidthUnit;
51}
52
54{
55 return mStrokeWidthUnit;
56}
57
58void QgsInterpolatedLineRenderer::renderInDeviceCoordinates( double valueColor1, double valueColor2, double valueWidth1, double valueWidth2, QPointF p1, QPointF p2, QgsRenderContext &context ) const
59{
60 QPainter *painter = context.painter();
61 QgsScopedQPainterState painterState( painter );
62 context.setPainterFlagsUsingContext( painter );
63
64 QPointF dir = p2 - p1;
65 double length = sqrt( pow( dir.x(), 2 ) + pow( dir.y(), 2 ) );
66 QPointF diru = dir / length;
67 QPointF orthu = QPointF( -diru.y(), diru.x() );
68
69 QList<double> breakValues;
70 QList<QColor> breakColors;
71 QList<QLinearGradient> gradients;
72
73 mStrokeColoring.graduatedColors( valueColor1, valueColor2, breakValues, breakColors, gradients );
74 QColor selectedColor = context.selectionColor();
75
76 if ( gradients.isEmpty() && !breakValues.empty() && !breakColors.isEmpty() ) //exact colors to render
77 {
78 Q_ASSERT( breakColors.count() == breakValues.count() );
79 for ( int i = 0; i < breakValues.count(); ++i )
80 {
81 const bool widthIsInverted { valueWidth1 > valueWidth2 };
82 const double value = breakValues.at( i );
83 const double width = context.convertToPainterUnits( mStrokeWidth.strokeWidth( widthIsInverted ? mStrokeWidth.maximumValue() - value : value ), mStrokeWidthUnit );
84 QPen pen( mSelected ? selectedColor : breakColors.at( i ) );
85 pen.setWidthF( width );
86 pen.setCapStyle( Qt::PenCapStyle::RoundCap );
87 painter->setPen( pen );
88 const QPointF point = p1 + dir * ( value - valueColor1 ) / ( valueColor2 - valueColor1 );
89 painter->drawPoint( point );
90 }
91 }
92 else
93 {
94 double width1 = mStrokeWidth.strokeWidth( valueWidth1 );
95 double width2 = mStrokeWidth.strokeWidth( valueWidth2 );
96
97 if ( !std::isnan( width1 ) && !std::isnan( width2 ) ) // the two widths on extremity are not out of range and ignored
98 {
99 //Draw line cap
100 QBrush brush( Qt::SolidPattern );
101 QPen pen;
102 int startAngle;
103 startAngle = ( acos( -orthu.x() ) / M_PI ) * 180;
104 if ( orthu.y() < 0 )
105 startAngle = 360 - startAngle;
106
107 bool outOfRange1 = std::isnan( width1 );
108 bool outOfRange2 = std::isnan( width2 );
109
110 if ( !outOfRange1 )
111 {
112 width1 = context.convertToPainterUnits( width1, mStrokeWidthUnit );
113 QRectF capBox1( p1.x() - width1 / 2, p1.y() - width1 / 2, width1, width1 );
114 brush.setColor( mSelected ? selectedColor : mStrokeColoring.color( valueColor1 ) );
115 painter->setBrush( brush );
116 pen.setBrush( brush );
117 painter->setPen( pen );
118 painter->drawPie( capBox1, ( startAngle - 1 ) * 16, 182 * 16 );
119 }
120
121 if ( !outOfRange2 )
122 {
123 width2 = context.convertToPainterUnits( width2, mStrokeWidthUnit ) ;
124 QRectF capBox2( p2.x() - width2 / 2, p2.y() - width2 / 2, width2, width2 );
125 brush.setColor( mSelected ? selectedColor : mStrokeColoring.color( valueColor2 ) );
126 pen.setBrush( brush );
127 painter->setBrush( brush );
128 painter->setPen( pen );
129 painter->drawPie( capBox2, ( startAngle + 179 ) * 16, 182 * 16 );
130 }
131
132 if ( ( gradients.isEmpty() && breakValues.empty() && breakColors.count() == 1 ) || mSelected ) //only one color to render
133 {
134 double startAdjusting = 0;
135 if ( outOfRange1 )
136 adjustLine( valueColor1, valueColor1, valueColor2, width1, startAdjusting );
137
138
139 double endAdjusting = 0;
140 if ( outOfRange2 )
141 adjustLine( valueColor2, valueColor1, valueColor2, width2, endAdjusting );
142
143 QPointF pointStartAdjusted = p1 + dir * startAdjusting;
144 QPointF pointEndAdjusted = p2 - dir * endAdjusting;
145
146 QPolygonF varLine;
147 double semiWidth1 = width1 / 2;
148 double semiWidth2 = width2 / 2;
149
150 varLine.append( pointStartAdjusted + orthu * semiWidth1 );
151 varLine.append( pointEndAdjusted + orthu * semiWidth2 );
152 varLine.append( pointEndAdjusted - orthu * semiWidth2 );
153 varLine.append( pointStartAdjusted - orthu * semiWidth1 );
154
155 QBrush brush( Qt::SolidPattern );
156 brush.setColor( mSelected ? selectedColor : breakColors.first() );
157 painter->setBrush( brush );
158 painter->setPen( pen );
159
160 QPen pen;
161 pen.setBrush( brush );
162 pen.setWidthF( 0 );
163 painter->setPen( pen );
164
165 painter->drawPolygon( varLine );
166
167 }
168 else if ( !gradients.isEmpty() && !breakValues.isEmpty() && !breakColors.isEmpty() )
169 {
170 Q_ASSERT( breakColors.count() == breakValues.count() );
171 Q_ASSERT( breakColors.count() == gradients.count() + 1 );
172 double widthColorVariationValueRatio = ( valueWidth2 - valueWidth1 ) / ( valueColor2 - valueColor1 );
173
174 for ( int i = 0; i < gradients.count(); ++i )
175 {
176 double firstValue = breakValues.at( i );
177 double secondValue = breakValues.at( i + 1 );
178 double w1 = mStrokeWidth.strokeWidth( widthColorVariationValueRatio * ( firstValue - valueColor1 ) + valueWidth1 );
179 double w2 = mStrokeWidth.strokeWidth( widthColorVariationValueRatio * ( secondValue - valueColor1 ) + valueWidth1 );
180
181 if ( std::isnan( w1 ) && std::isnan( w2 ) )
182 continue;
183
184 double firstAdjusting = 0;
185 if ( std::isnan( w1 ) )
186 adjustLine( firstValue, valueColor1, valueColor2, w1, firstAdjusting );
187
188
189 double secondAdjusting = 0;
190 if ( std::isnan( w2 ) )
191 adjustLine( secondValue, valueColor1, valueColor2, w2, secondAdjusting );
192
193 w1 = context.convertToPainterUnits( w1, mStrokeWidthUnit );
194 w2 = context.convertToPainterUnits( w2, mStrokeWidthUnit ) ;
195
196 QPointF pointStart = p1 + dir * ( firstValue - valueColor1 ) / ( valueColor2 - valueColor1 );
197 QPointF pointEnd = p1 + dir * ( secondValue - valueColor1 ) / ( valueColor2 - valueColor1 );
198
199 QPointF pointStartAdjusted = pointStart + dir * firstAdjusting;
200 QPointF pointEndAdjusted = pointEnd - dir * secondAdjusting;
201
202 QPolygonF varLine;
203 double sw1 = w1 / 2;
204 double sw2 = w2 / 2;
205
206 varLine.append( pointStartAdjusted + orthu * sw1 );
207 varLine.append( pointEndAdjusted + orthu * sw2 );
208 varLine.append( pointEndAdjusted - orthu * sw2 );
209 varLine.append( pointStartAdjusted - orthu * sw1 );
210
211 QLinearGradient gradient = gradients.at( i );
212 gradient.setStart( pointStart );
213 gradient.setFinalStop( pointEnd );
214 QBrush brush( gradient );
215 painter->setBrush( brush );
216
217 QPen pen;
218 pen.setBrush( brush );
219 pen.setWidthF( 0 );
220 painter->setPen( pen );
221
222 painter->drawPolygon( varLine );
223 }
224 }
225 }
226 }
227}
228
229
230void QgsInterpolatedLineRenderer::render( double value1, double value2, const QgsPointXY &pt1, const QgsPointXY &pt2, QgsRenderContext &context ) const
231{
232 const QgsMapToPixel &mapToPixel = context.mapToPixel();
233
234 QgsPointXY point1 = pt1;
235 QgsPointXY point2 = pt2;
236
237 if ( value1 > value2 )
238 {
239 std::swap( value1, value2 );
240 std::swap( point1, point2 );
241 }
242
243 QPointF p1 = mapToPixel.transform( point1 ).toQPointF();
244 QPointF p2 = mapToPixel.transform( point2 ).toQPointF();
245
246 renderInDeviceCoordinates( value1, value2, value1, value2, p1, p2, context );
247}
248
249void QgsInterpolatedLineRenderer::render( double valueColor1, double valueColor2, double valueWidth1, double valueWidth2, const QgsPointXY &pt1, const QgsPointXY &pt2, QgsRenderContext &context ) const
250{
251 const QgsMapToPixel &mapToPixel = context.mapToPixel();
252
253 QgsPointXY point1 = pt1;
254 QgsPointXY point2 = pt2;
255
256 if ( valueColor1 > valueColor2 )
257 {
258 std::swap( valueColor1, valueColor2 );
259 std::swap( valueWidth1, valueWidth2 );
260 std::swap( point1, point2 );
261 }
262
263 QPointF p1 = mapToPixel.transform( point1 ).toQPointF();
264 QPointF p2 = mapToPixel.transform( point2 ).toQPointF();
265
266 renderInDeviceCoordinates( valueColor1, valueColor2, valueWidth1, valueWidth2, p1, p2, context );
267}
268
270{
271 mSelected = selected;
272}
273
274void QgsInterpolatedLineRenderer::adjustLine( const double value, const double value1, const double value2, double &width, double &adjusting ) const
275{
276 if ( value > mStrokeWidth.maximumValue() )
277 {
278 adjusting = fabs( ( value - mStrokeWidth.maximumValue() ) / ( value2 - value1 ) );
279 width = mStrokeWidth.maximumWidth();
280 }
281 else
282 {
283 adjusting = fabs( ( value - mStrokeWidth.minimumValue() ) / ( value2 - value1 ) );
284 width = mStrokeWidth.minimumWidth();
285 }
286}
287
289{
290 return mMinimumValue;
291}
292
294{
295 mMinimumValue = minimumValue;
296 mNeedUpdateFormula = true;
297}
298
300{
301 return mMaximumValue;
302}
303
305{
306 mMaximumValue = maximumValue;
307 mNeedUpdateFormula = true;
308}
309
311{
312 return mMinimumWidth;
313}
314
316{
317 mMinimumWidth = minimumWidth;
318 mNeedUpdateFormula = true;
319}
320
322{
323 return mMaximumWidth;
324}
325
327{
328 mMaximumWidth = maximumWidth;
329 mNeedUpdateFormula = true;
330}
331
332double QgsInterpolatedLineWidth::strokeWidth( double value ) const
333{
334 if ( mIsWidthVariable )
335 {
336 if ( mNeedUpdateFormula )
337 updateLinearFormula();
338
339 if ( mUseAbsoluteValue )
340 value = std::fabs( value );
341
342 if ( value > mMaximumValue )
343 {
344 if ( mIgnoreOutOfRange )
345 return std::numeric_limits<double>::quiet_NaN();
346 else
347 return mMaximumWidth;
348 }
349
350 if ( value < mMinimumValue )
351 {
352 if ( mIgnoreOutOfRange )
353 return std::numeric_limits<double>::quiet_NaN();
354 else
355 return mMinimumWidth;
356 }
357
358 return ( value - mMinimumValue ) * mLinearCoef + mMinimumWidth;
359 }
360 else
361 return fixedStrokeWidth();
362}
363
364QDomElement QgsInterpolatedLineWidth::writeXml( QDomDocument &doc, const QgsReadWriteContext & ) const
365{
366 QDomElement elem = doc.createElement( QStringLiteral( "mesh-stroke-width" ) );
367
368 elem.setAttribute( QStringLiteral( "width-varying" ), mIsWidthVariable ? 1 : 0 );
369 elem.setAttribute( QStringLiteral( "fixed-width" ), mFixedWidth );
370 elem.setAttribute( QStringLiteral( "minimum-value" ), mMinimumValue );
371 elem.setAttribute( QStringLiteral( "maximum-value" ), mMaximumValue );
372 elem.setAttribute( QStringLiteral( "minimum-width" ), mMinimumWidth );
373 elem.setAttribute( QStringLiteral( "maximum-width" ), mMaximumWidth );
374 elem.setAttribute( QStringLiteral( "ignore-out-of-range" ), mIgnoreOutOfRange ? 1 : 0 );
375 elem.setAttribute( QStringLiteral( "use-absolute-value" ), mUseAbsoluteValue ? 1 : 0 );
376
377 return elem;
378}
379
380void QgsInterpolatedLineWidth::readXml( const QDomElement &elem, const QgsReadWriteContext & )
381{
382 mIsWidthVariable = elem.attribute( QStringLiteral( "width-varying" ) ).toInt();
383 mFixedWidth = elem.attribute( QStringLiteral( "fixed-width" ) ).toDouble();
384 mMinimumValue = elem.attribute( QStringLiteral( "minimum-value" ) ).toDouble();
385 mMaximumValue = elem.attribute( QStringLiteral( "maximum-value" ) ).toDouble();
386 mMinimumWidth = elem.attribute( QStringLiteral( "minimum-width" ) ).toDouble();
387 mMaximumWidth = elem.attribute( QStringLiteral( "maximum-width" ) ).toDouble();
388 mIgnoreOutOfRange = elem.attribute( QStringLiteral( "ignore-out-of-range" ) ).toInt();
389 mUseAbsoluteValue = elem.attribute( QStringLiteral( "use-absolute-value" ) ).toInt();
390}
391
393{
394 return mUseAbsoluteValue;
395}
396
401
403{
404 return mFixedWidth;
405}
406
408{
409 return mIgnoreOutOfRange;
410}
411
416
418{
419 return mIsWidthVariable;
420}
421
423{
424 mIsWidthVariable = isWidthVarying;
425}
426
428{
429 mFixedWidth = fixedWidth;
430}
431
432void QgsInterpolatedLineWidth::updateLinearFormula() const
433{
434 if ( !qgsDoubleNear( mMaximumWidth, mMinimumWidth ) )
435 mLinearCoef = ( mMaximumWidth - mMinimumWidth ) / ( mMaximumValue - mMinimumValue ) ;
436 else
437 mLinearCoef = 0;
438 mNeedUpdateFormula = false;
439}
440
442{
443 mColorRampShader.setMinimumValue( std::numeric_limits<double>::quiet_NaN() );
444 mColorRampShader.setMaximumValue( std::numeric_limits<double>::quiet_NaN() );
445}
446
451
453{
454 setColor( color );
455 mColoringMethod = SingleColor;
456 mColorRampShader.setMinimumValue( std::numeric_limits<double>::quiet_NaN() );
457 mColorRampShader.setMaximumValue( std::numeric_limits<double>::quiet_NaN() );
458}
459
461{
462 mColorRampShader = colorRampShader;
463 if ( ( mColorRampShader.sourceColorRamp() ) )
464 mColoringMethod = ColorRamp;
465 else
466 mColoringMethod = SingleColor;
467}
468
470{
471 mSingleColor = color;
472}
473
474QColor QgsInterpolatedLineColor::color( double magnitude ) const
475{
476 QgsColorRamp *lSourceColorRamp = mColorRampShader.sourceColorRamp();
477 if ( mColoringMethod == ColorRamp && lSourceColorRamp )
478 {
479 if ( mColorRampShader.isEmpty() )
480 return lSourceColorRamp->color( 0 );
481
482 int r, g, b, a;
483 if ( mColorRampShader.shade( magnitude, &r, &g, &b, &a ) )
484 return QColor( r, g, b, a );
485 else
486 return QColor( 0, 0, 0, 0 );
487 }
488 else
489 {
490 return mSingleColor;
491 }
492}
493
498
500{
501 return mColorRampShader;
502}
503
505{
506 return mSingleColor;
507}
508
509QDomElement QgsInterpolatedLineColor::writeXml( QDomDocument &doc, const QgsReadWriteContext & ) const
510{
511 QDomElement elem = doc.createElement( QStringLiteral( "mesh-stroke-color" ) );
512
513 elem.setAttribute( QStringLiteral( "single-color" ), QgsColorUtils::colorToString( mSingleColor ) );
514 elem.setAttribute( QStringLiteral( "coloring-method" ), mColoringMethod );
515 elem.appendChild( mColorRampShader.writeXml( doc ) );
516
517 return elem;
518}
519
520void QgsInterpolatedLineColor::readXml( const QDomElement &elem, const QgsReadWriteContext & )
521{
522 QDomElement shaderElem = elem.firstChildElement( QStringLiteral( "colorrampshader" ) );
523 mColorRampShader.readXml( shaderElem );
524
525 mSingleColor = QgsColorUtils::colorFromString( elem.attribute( QStringLiteral( "single-color" ) ) );
526 mColoringMethod = static_cast<QgsInterpolatedLineColor::ColoringMethod>(
527 elem.attribute( QStringLiteral( "coloring-method" ) ).toInt() );
528}
529
530void QgsInterpolatedLineColor::graduatedColors( double value1, double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients ) const
531{
532 breakValues.clear();
533 breakColors.clear();
534 gradients.clear();
535 if ( mColoringMethod == SingleColor )
536 {
537 breakColors.append( mSingleColor );
538 return;
539 }
540
541 switch ( mColorRampShader.colorRampType() )
542 {
544 graduatedColorsInterpolated( value1, value2, breakValues, breakColors, gradients );
545 break;
547 graduatedColorsDiscrete( value1, value2, breakValues, breakColors, gradients );
548 break;
550 graduatedColorsExact( value1, value2, breakValues, breakColors, gradients );
551 break;
552 }
553
554}
555
560
561QLinearGradient QgsInterpolatedLineColor::makeSimpleLinearGradient( const QColor &color1, const QColor &color2 ) const
562{
563 QLinearGradient gradient;
564 gradient.setColorAt( 0, color1 );
565 gradient.setColorAt( 1, color2 );
566
567 return gradient;
568}
569
570int QgsInterpolatedLineColor::itemColorIndexInf( double value ) const
571{
572 QList<QgsColorRampShader::ColorRampItem> itemList = mColorRampShader.colorRampItemList();
573
574 if ( itemList.isEmpty() || itemList.first().value > value )
575 return -1;
576
577 if ( mColorRampShader.colorRampType() == Qgis::ShaderInterpolationMethod::Discrete )
578 itemList.removeLast(); //remove the inf value
579
580 if ( value > itemList.last().value )
581 return itemList.count() - 1;
582
583 int indSup = itemList.count() - 1;
584 int indInf = 0;
585
586 while ( true )
587 {
588 if ( abs( indSup - indInf ) <= 1 ) //always indSup>indInf, but abs to prevent infinity loop
589 return indInf;
590
591 int newInd = ( indInf + indSup ) / 2;
592
593 if ( std::isnan( itemList.at( newInd ).value ) )
594 return -1;
595
596 if ( itemList.at( newInd ).value <= value )
597 indInf = newInd;
598 else
599 indSup = newInd;
600 }
601}
602
603void QgsInterpolatedLineColor::graduatedColorsExact( double value1, double value2, QList<double> &breakValues, QList<QColor> &breakColors, const QList<QLinearGradient> &gradients ) const
604{
605 Q_ASSERT( mColorRampShader.colorRampType() == Qgis::ShaderInterpolationMethod::Exact );
606 Q_ASSERT( breakValues.isEmpty() );
607 Q_ASSERT( breakColors.isEmpty() );
608 Q_ASSERT( gradients.isEmpty() );
609
610 const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.colorRampItemList();
611 if ( itemList.isEmpty() )
612 return;
613
614 int index = itemColorIndexInf( value1 );
615 if ( index < 0 || !qgsDoubleNear( value1, itemList.at( index ).value ) )
616 index++;
617
618 if ( qgsDoubleNear( value1, value2 ) && qgsDoubleNear( value1, itemList.at( index ).value ) )
619 {
620 //the two value are the same and are equal to the value in the item list --> render only one color
621 breakColors.append( itemList.at( index ).color );
622 return;
623 }
624
625 while ( index < itemList.count() && itemList.at( index ).value <= value2 )
626 {
627 breakValues.append( itemList.at( index ).value );
628 breakColors.append( itemList.at( index ).color );
629 index++;
630 }
631}
632
633void QgsInterpolatedLineColor::graduatedColorsInterpolated( double value1, double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients ) const
634{
635 Q_ASSERT( mColorRampShader.colorRampType() == Qgis::ShaderInterpolationMethod::Linear );
636 Q_ASSERT( breakValues.isEmpty() );
637 Q_ASSERT( breakColors.isEmpty() );
638 Q_ASSERT( gradients.isEmpty() );
639
640
641 const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.colorRampItemList();
642 if ( itemList.empty() )
643 return;
644
645 if ( itemList.count() == 1 )
646 {
647 breakColors.append( itemList.first().color );
648 return;
649 }
650
651 if ( value2 <= itemList.first().value ) // completely out of range and less
652 {
653 if ( !mColorRampShader.clip() )
654 breakColors.append( itemList.first().color ); // render only the first color in the whole range if not clipped
655 return;
656 }
657
658 if ( value1 > itemList.last().value ) // completely out of range and greater
659 {
660 if ( !mColorRampShader.clip() )
661 breakColors.append( itemList.last().color ); // render only the last color in the whole range if not clipped
662 return;
663 }
664
665 if ( qgsDoubleNear( value1, value2 ) )
666 {
667 // the two values are the same
668 // --> render only one color
669 int r, g, b, a;
670 QColor color;
671 if ( mColorRampShader.shade( value1, &r, &g, &b, &a ) )
672 color = QColor( r, g, b, a );
673 breakColors.append( color );
674 return;
675 }
676
677 // index of the inf value of the interval where value1 is in the color ramp shader
678 int index = itemColorIndexInf( value1 );
679 if ( index < 0 ) // value1 out of range
680 {
681 QColor color = itemList.first().color;
682 breakColors.append( color );
683 if ( mColorRampShader.clip() ) // The first value/color returned is the first of the item list
684 breakValues.append( itemList.first().value );
685 else // The first value/color returned is the first color of the item list and value1
686 breakValues.append( value1 );
687 }
688 else
689 {
690 // shade the color
691 int r, g, b, a;
692 QColor color;
693 if ( mColorRampShader.shade( value1, &r, &g, &b, &a ) )
694 color = QColor( r, g, b, a );
695 breakValues.append( value1 );
696 breakColors.append( color );
697 }
698
699 index++; // increment the index before go through the intervals
700
701 while ( index < itemList.count() && itemList.at( index ).value < value2 )
702 {
703 QColor color1 = breakColors.last();
704 QColor color2 = itemList.at( index ).color;
705 breakValues.append( itemList.at( index ).value );
706 breakColors.append( color2 );
707 gradients.append( makeSimpleLinearGradient( color1, color2 ) );
708 index++;
709 }
710
711 // close the lists with value2 or last item if >value2
712 QColor color1 = breakColors.last();
713 QColor color2;
714 if ( value2 < itemList.last().value )
715 {
716 int r, g, b, a;
717 if ( mColorRampShader.shade( value2, &r, &g, &b, &a ) )
718 color2 = QColor( r, g, b, a );
719 breakValues.append( value2 );
720 }
721 else
722 {
723 color2 = itemList.last().color;
724 if ( mColorRampShader.clip() )
725 breakValues.append( itemList.last().value );
726 else
727 breakValues.append( value2 );
728 }
729 breakColors.append( color2 );
730 gradients.append( makeSimpleLinearGradient( color1, color2 ) );
731}
732
733
734void QgsInterpolatedLineColor::graduatedColorsDiscrete( double value1, double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients ) const
735{
736 Q_ASSERT( mColorRampShader.colorRampType() == Qgis::ShaderInterpolationMethod::Discrete );
737 Q_ASSERT( breakValues.isEmpty() );
738 Q_ASSERT( breakColors.isEmpty() );
739 Q_ASSERT( gradients.isEmpty() );
740
741 const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.colorRampItemList();
742 if ( itemList.empty() )
743 return;
744
745 if ( itemList.count() == 1 )
746 {
747 breakColors.append( itemList.first().color );
748 return;
749 }
750
751 double lastValue = itemList.at( itemList.count() - 2 ).value;
752
753
754 if ( value2 <= itemList.first().value ) // completely out of range and less
755 {
756 breakColors.append( itemList.first().color ); // render only the first color in the whole range
757 return;
758 }
759
760 if ( value1 > lastValue ) // completely out of range and greater
761 {
762 breakColors.append( itemList.last().color ); // render only the last color in the whole range
763 return;
764 }
765
766 // index of the inf value of the interval where value1 is in the color ramp shader
767 int index = itemColorIndexInf( value1 );
768
769 if ( qgsDoubleNear( value1, value2 ) )
770 {
771 // the two values are the same and are equal to the value in the item list
772 // --> render only one color, the sup one
773 breakColors.append( itemList.at( index + 1 ).color );
774 return;
775 }
776
777 if ( index < 0 ) // value1 out of range
778 {
779 breakValues.append( value1 );
780 breakColors.append( itemList.first().color );
781 }
782 else // append the first value with corresponding color
783 {
784 QColor color = itemList.at( index ).color;
785 breakValues.append( value1 );
786 breakColors.append( color );
787 }
788
789 index++; // increment the index before go through the intervals
790
791 while ( index < ( itemList.count() - 1 ) && itemList.at( index ).value < value2 )
792 {
793 QColor color = itemList.at( index ).color;
794 breakValues.append( itemList.at( index ).value );
795 breakColors.append( color );
796 gradients.append( makeSimpleLinearGradient( color, color ) );
797 index++;
798 }
799
800 // add value2 to close
801 QColor lastColor = itemList.at( index ).color;
802 breakColors.append( lastColor );
803 breakValues.append( value2 );
804 gradients.append( makeSimpleLinearGradient( lastColor, lastColor ) );
805
806}
807
808QString QgsInterpolatedLineSymbolLayer::layerType() const {return QStringLiteral( "InterpolatedLine" );}
809
813
817
825
827{
828 std::unique_ptr<QgsInterpolatedLineSymbolLayer> symbolLayer;
829 symbolLayer = std::make_unique<QgsInterpolatedLineSymbolLayer>( );
830
831 if ( properties.contains( QStringLiteral( "start_width_expression" ) ) )
832 symbolLayer->setDataDefinedProperty( QgsSymbolLayer::Property::LineStartWidthValue, QgsProperty::fromExpression( properties.value( QStringLiteral( "start_width_expression" ) ).toString() ) );
833 if ( properties.contains( QStringLiteral( "end_width_expression" ) ) )
834 symbolLayer->setDataDefinedProperty( QgsSymbolLayer::Property::LineEndWidthValue, QgsProperty::fromExpression( properties.value( QStringLiteral( "end_width_expression" ) ).toString() ) );
835
836 if ( properties.contains( QStringLiteral( "start_color_expression" ) ) )
837 symbolLayer->setDataDefinedProperty( QgsSymbolLayer::Property::LineStartColorValue, QgsProperty::fromExpression( properties.value( QStringLiteral( "start_color_expression" ) ).toString() ) );
838 if ( properties.contains( QStringLiteral( "end_color_expression" ) ) )
839 symbolLayer->setDataDefinedProperty( QgsSymbolLayer::Property::LineEndColorValue, QgsProperty::fromExpression( properties.value( QStringLiteral( "end_color_expression" ) ).toString() ) );
840
841 if ( properties.contains( QStringLiteral( "line_width" ) ) )
842 symbolLayer->mLineRender.mStrokeWidth.setFixedStrokeWidth( properties.value( QStringLiteral( "line_width" ) ).toDouble() ) ;
843 if ( properties.contains( QStringLiteral( "line_width_unit" ) ) )
844 symbolLayer->mLineRender.setWidthUnit( QgsUnitTypes::decodeRenderUnit( properties.value( QStringLiteral( "line_width_unit" ) ).toString() ) );
845 if ( properties.contains( QStringLiteral( "width_varying_minimum_value" ) ) )
846 symbolLayer->mLineRender.mStrokeWidth.setMinimumValue( properties.value( QStringLiteral( "width_varying_minimum_value" ) ).toDouble() );
847 if ( properties.contains( QStringLiteral( "width_varying_maximum_value" ) ) )
848 symbolLayer->mLineRender.mStrokeWidth.setMaximumValue( properties.value( QStringLiteral( "width_varying_maximum_value" ) ).toDouble() );
849 if ( properties.contains( QStringLiteral( "width_varying_use_absolute_value" ) ) )
850 symbolLayer->mLineRender.mStrokeWidth.setUseAbsoluteValue( properties.value( QStringLiteral( "width_varying_use_absolute_value" ) ).toInt() );
851 if ( properties.contains( QStringLiteral( "width_varying_minimum_width" ) ) )
852 symbolLayer->mLineRender.mStrokeWidth.setMinimumWidth( properties.value( QStringLiteral( "width_varying_minimum_width" ) ).toDouble() );
853 if ( properties.contains( QStringLiteral( "width_varying_maximum_width" ) ) )
854 symbolLayer->mLineRender.mStrokeWidth.setMaximumWidth( properties.value( QStringLiteral( "width_varying_maximum_width" ) ).toDouble() );
855 if ( properties.contains( QStringLiteral( "width_varying_ignore_out_of_range" ) ) )
856 symbolLayer->mLineRender.mStrokeWidth.setIgnoreOutOfRange( properties.value( QStringLiteral( "width_varying_ignore_out_of_range" ) ).toInt() );
857 if ( properties.contains( QStringLiteral( "width_varying_is_variable_width" ) ) )
858 symbolLayer->mLineRender.mStrokeWidth.setIsVariableWidth( properties.value( QStringLiteral( "width_varying_is_variable_width" ) ).toInt() );
859
860 if ( properties.contains( QStringLiteral( "single_color" ) ) )
861 symbolLayer->mLineRender.mStrokeColoring.setColor( QgsColorUtils::colorFromString( properties.value( QStringLiteral( "single_color" ) ).toString() ) );
862 if ( properties.contains( QStringLiteral( "color_ramp_shader" ) ) )
863 symbolLayer->mLineRender.mStrokeColoring.setColor( createColorRampShaderFromProperties( properties.value( QStringLiteral( "color_ramp_shader" ) ) ) );
864 if ( properties.contains( QStringLiteral( "coloring_method" ) ) )
865 symbolLayer->mLineRender.mStrokeColoring.setColoringMethod(
866 static_cast<QgsInterpolatedLineColor::ColoringMethod>( properties.value( QStringLiteral( "coloring_method" ) ).toInt() ) );
867
868 return symbolLayer.release();
869}
870
877
879{
880 QVariantMap props;
881
882 // Line width varying
883 props.insert( QStringLiteral( "line_width" ), QString::number( mLineRender.mStrokeWidth.fixedStrokeWidth() ) );
884 props.insert( QStringLiteral( "line_width_unit" ), QgsUnitTypes::encodeUnit( mLineRender.widthUnit() ) );
885 props.insert( QStringLiteral( "width_varying_minimum_value" ), mLineRender.mStrokeWidth.minimumValue() );
886 props.insert( QStringLiteral( "width_varying_maximum_value" ), mLineRender.mStrokeWidth.maximumValue() );
887 props.insert( QStringLiteral( "width_varying_use_absolute_value" ), mLineRender.mStrokeWidth.useAbsoluteValue() ? 1 : 0 );
888 props.insert( QStringLiteral( "width_varying_minimum_width" ), mLineRender.mStrokeWidth.minimumWidth() );
889 props.insert( QStringLiteral( "width_varying_maximum_width" ), mLineRender.mStrokeWidth.maximumWidth() );
890 props.insert( QStringLiteral( "width_varying_ignore_out_of_range" ), mLineRender.mStrokeWidth.ignoreOutOfRange() ? 1 : 0 );
891 props.insert( QStringLiteral( "width_varying_is_variable_width" ), mLineRender.mStrokeWidth.isVariableWidth() ? 1 : 0 );
892
893 // Color varying
894 props.insert( QStringLiteral( "coloring_method" ), mLineRender.mStrokeColoring.coloringMethod() );
895 props.insert( QStringLiteral( "single_color" ), QgsColorUtils::colorToString( mLineRender.mStrokeColoring.singleColor() ) );
896 props.insert( QStringLiteral( "color_ramp_shader" ), colorRampShaderProperties() );
897
898 return props;
899}
900
902{
903 QgsGeometry geometry = context.patchShape() ? context.patchShape()->geometry()
905
906 startRender( context );
907 double min = std::min( mLineRender.interpolatedLineWidth().minimumValue(), mLineRender.interpolatedColor().colorRampShader().minimumValue() );
908 double max = std::max( mLineRender.interpolatedLineWidth().maximumValue(), mLineRender.interpolatedColor().colorRampShader().maximumValue() );
909
910 double totalLength = geometry.length();
911 if ( qgsDoubleNear( totalLength, 0 ) )
912 return;
913
914 double variation = ( max - min ) / totalLength;
915
916 QPolygonF points = geometry.asQPolygonF();
917 double lengthFromStart = 0;
918 for ( int i = 1; i < points.count(); ++i )
919 {
920 QPointF p1 = points.at( i - 1 );
921 QPointF p2 = points.at( i );
922
923 double v1 = min + variation * lengthFromStart;
924 QPointF vectDist = p2 - p1;
925 lengthFromStart += sqrt( pow( vectDist.x(), 2 ) + pow( vectDist.y(), 2 ) );
926 double v2 = min + variation * lengthFromStart;
927 mLineRender.renderInDeviceCoordinates( v1, v2, v1, v2, p1, p2, context.renderContext() );
928 }
929
930 renderPolyline( points, context );
931
932}
933
935{
936 switch ( mLineRender.interpolatedColor().coloringMethod() )
937 {
939 return mLineRender.interpolatedColor().singleColor();
941 return QColor();
942 }
944}
945
946
959
964
969
970void QgsInterpolatedLineSymbolLayer::setWidthUnit( Qgis::RenderUnit strokeWidthUnit ) // cppcheck-suppress duplInheritedMember
971{
972 mLineRender.mStrokeWidthUnit = strokeWidthUnit;
973}
974
975Qgis::RenderUnit QgsInterpolatedLineSymbolLayer::widthUnit() const {return mLineRender.widthUnit();} // cppcheck-suppress duplInheritedMember
976
978{
979 mLineRender.mStrokeWidth = interpolatedLineWidth;
980}
981
982QgsInterpolatedLineWidth QgsInterpolatedLineSymbolLayer::interpolatedWidth() const { return mLineRender.interpolatedLineWidth();}
983
996
1001
1006
1008{
1009 mLineRender.setInterpolatedColor( interpolatedLineColor );
1010}
1011
1013{
1014 return mLineRender.interpolatedColor();
1015}
1016
1017QVariant QgsInterpolatedLineSymbolLayer::colorRampShaderProperties() const
1018{
1019 const QgsColorRampShader &colorRampShader = mLineRender.mStrokeColoring.colorRampShader();
1020
1021 QVariantMap props;
1022 if ( colorRampShader.sourceColorRamp() )
1023 props.insert( QStringLiteral( "color_ramp_source" ), QgsSymbolLayerUtils::colorRampToVariant( QString(), colorRampShader.sourceColorRamp() ) );
1024 props.insert( QStringLiteral( "color_ramp_shader_type" ), static_cast< int >( colorRampShader.colorRampType() ) );
1025 props.insert( QStringLiteral( "color_ramp_shader_classification_mode" ), static_cast< int >( colorRampShader.classificationMode() ) );
1026 QVariantList colorRampItemListVariant;
1027
1028 const QList<QgsColorRampShader::ColorRampItem> colorRampItemList = colorRampShader.colorRampItemList();
1029 for ( const QgsColorRampShader::ColorRampItem &item : colorRampItemList )
1030 {
1031 QVariantMap itemVar;
1032 itemVar[QStringLiteral( "label" )] = item.label;
1033 itemVar[QStringLiteral( "color" )] = QgsColorUtils::colorToString( item.color );
1034 itemVar[QStringLiteral( "value" )] = item.value;
1035 colorRampItemListVariant.append( itemVar );
1036 }
1037 props.insert( QStringLiteral( "color_ramp_shader_items_list" ), colorRampItemListVariant );
1038
1039 props.insert( QStringLiteral( "color_ramp_shader_minimum_value" ), colorRampShader.minimumValue() );
1040 props.insert( QStringLiteral( "color_ramp_shader_maximum_value" ), colorRampShader.maximumValue() );
1041 props.insert( QStringLiteral( "color_ramp_shader_value_out_of_range" ), colorRampShader.clip() ? 1 : 0 );
1042 props.insert( QStringLiteral( "color_ramp_shader_label_precision" ), colorRampShader.labelPrecision() );
1043
1044 return props;
1045}
1046
1047QgsColorRampShader QgsInterpolatedLineSymbolLayer::createColorRampShaderFromProperties( const QVariant &properties )
1048{
1049 QgsColorRampShader colorRampShader;
1050
1051 if ( properties.userType() != QMetaType::Type::QVariantMap )
1052 return colorRampShader;
1053
1054 QVariantMap shaderVariantMap = properties.toMap();
1055
1056 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_source" ) ) )
1057 colorRampShader.setSourceColorRamp( QgsSymbolLayerUtils::loadColorRamp( shaderVariantMap.value( QStringLiteral( "color_ramp_source" ) ) ).release() );
1058
1059 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_type" ) ) )
1060 colorRampShader.setColorRampType( static_cast<Qgis::ShaderInterpolationMethod>( shaderVariantMap.value( QStringLiteral( "color_ramp_shader_type" ) ).toInt() ) );
1061 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_classification_mode" ) ) )
1062 colorRampShader.setClassificationMode( static_cast<Qgis::ShaderClassificationMethod>(
1063 shaderVariantMap.value( QStringLiteral( "color_ramp_shader_classification_mode" ) ).toInt() ) );
1064
1065 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_items_list" ) ) )
1066 {
1067 QVariant colorRampItemsVar = shaderVariantMap.value( QStringLiteral( "color_ramp_shader_items_list" ) );
1068 if ( colorRampItemsVar.userType() == QMetaType::Type::QVariantList )
1069 {
1070 QVariantList itemVariantList = colorRampItemsVar.toList();
1071 QList<QgsColorRampShader::ColorRampItem> colorRampItemList;
1072 for ( const QVariant &itemVar : std::as_const( itemVariantList ) )
1073 {
1074 QgsColorRampShader::ColorRampItem item;
1075 if ( itemVar.userType() != QMetaType::Type::QVariantMap )
1076 continue;
1077 QVariantMap itemVarMap = itemVar.toMap();
1078 if ( !itemVarMap.contains( QStringLiteral( "label" ) ) || !itemVarMap.contains( QStringLiteral( "color" ) ) || !itemVarMap.contains( QStringLiteral( "value" ) ) )
1079 continue;
1080
1081 item.label = itemVarMap.value( QStringLiteral( "label" ) ).toString();
1082 item.color = QgsColorUtils::colorFromString( itemVarMap.value( QStringLiteral( "color" ) ).toString() );
1083 item.value = itemVarMap.value( QStringLiteral( "value" ) ).toDouble();
1084
1085 colorRampItemList.append( item );
1086 }
1087 colorRampShader.setColorRampItemList( colorRampItemList );
1088 }
1089 }
1090
1091 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_minimum_value" ) ) )
1092 colorRampShader.setMinimumValue( shaderVariantMap.value( QStringLiteral( "color_ramp_shader_minimum_value" ) ).toDouble() );
1093 else
1094 colorRampShader.setMinimumValue( std::numeric_limits<double>::quiet_NaN() );
1095
1096 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_maximum_value" ) ) )
1097 colorRampShader.setMaximumValue( shaderVariantMap.value( QStringLiteral( "color_ramp_shader_maximum_value" ) ).toDouble() );
1098 else
1099 colorRampShader.setMaximumValue( std::numeric_limits<double>::quiet_NaN() );
1100
1101 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_value_out_of_range" ) ) )
1102 colorRampShader.setClip( shaderVariantMap.value( QStringLiteral( "color_ramp_shader_value_out_of_range" ) ).toInt() == 1 );
1103 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_label_precision" ) ) )
1104 colorRampShader.setLabelPrecision( shaderVariantMap.value( QStringLiteral( "color_ramp_shader_label_precision" ) ).toInt() );
1105
1106 return colorRampShader;
1107}
1108
1110
1111
1113{
1114 mRenderingFeature = true;
1115 mLineParts.clear();
1116}
1117
1119{
1120 mRenderingFeature = false;
1121
1122 if ( mLineParts.empty() )
1123 return;
1124
1125 render( mLineParts, context );
1126 mLineParts.clear();
1127}
1128
1129void QgsInterpolatedLineSymbolLayer::render( const QVector< QPolygonF > &parts, QgsRenderContext &context )
1130{
1131 const double totalLength = std::accumulate( parts.begin(), parts.end(), 0.0, []( double total, const QPolygonF & part )
1132 {
1133 return total + QgsSymbolLayerUtils::polylineLength( part );
1134 } );
1135
1136 if ( qgsDoubleNear( totalLength, 0 ) )
1137 return;
1138
1139 double startValWidth = 0;
1140 double variationPerMapUnitWidth = 0;
1141 double startValColor = 0;
1142 double variationPerMapUnitColor = 0;
1143
1144 bool ok = true;
1145
1146 if ( mLineRender.interpolatedLineWidth().isVariableWidth() )
1147 {
1149 {
1151 if ( !ok )
1152 return;
1153 }
1154
1155 double endValWidth = 0;
1157 {
1158 endValWidth = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::Property::LineEndWidthValue, context.expressionContext(), 0, &ok );
1159 if ( !ok )
1160 return;
1161 }
1162
1163 variationPerMapUnitWidth = ( endValWidth - startValWidth ) / totalLength;
1164 }
1165
1166 if ( mLineRender.interpolatedColor().coloringMethod() == QgsInterpolatedLineColor::ColorRamp )
1167 {
1169 {
1170 startValColor = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::Property::LineStartColorValue, context.expressionContext(), 0, &ok );
1171 if ( !ok )
1172 return;
1173 }
1174
1175 double endValColor = 0;
1177 {
1178 endValColor = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::Property::LineEndColorValue, context.expressionContext(), 0, &ok );
1179 if ( !ok )
1180 return;
1181 }
1182
1183 variationPerMapUnitColor = ( endValColor - startValColor ) / totalLength;
1184 }
1185
1186 for ( const QPolygonF &poly : parts )
1187 {
1188 double lengthFromStart = 0;
1189 for ( int i = 1; i < poly.count(); ++i )
1190 {
1191 const QPointF p1 = poly.at( i - 1 );
1192 const QPointF p2 = poly.at( i );
1193
1194 const double v1c = startValColor + variationPerMapUnitColor * lengthFromStart;
1195 const double v1w = startValWidth + variationPerMapUnitWidth * lengthFromStart;
1196 lengthFromStart += QgsGeometryUtilsBase::distance2D( p1.x(), p1.y(), p2.x(), p2.y() );
1197 const double v2c = startValColor + variationPerMapUnitColor * lengthFromStart;
1198 const double v2w = startValWidth + variationPerMapUnitWidth * lengthFromStart;
1199 mLineRender.renderInDeviceCoordinates( v1c, v2c, v1w, v2w, p1, p2, context );
1200 }
1201 }
1202}
1203
1205{
1206 mLineRender.setSelected( context.selected() );
1207
1208 if ( points.empty() )
1209 return;
1210
1211 if ( mRenderingFeature )
1212 {
1213 // in the middle of rendering a possibly multi-part feature, so we collect all the parts and defer the actual rendering
1214 // until after we've received the final part
1215 mLineParts.append( points );
1216 }
1217 else
1218 {
1219 // not rendering a feature, so we can just render the polyline immediately
1220 render( { points }, context.renderContext() );
1221 }
1222}
1223
@ DisableFeatureClipping
If present, indicates that features should never be clipped to the map extent during rendering.
Definition qgis.h:881
@ CanCalculateMaskGeometryPerFeature
If present, indicates that mask geometry can safely be calculated per feature for the symbol layer....
Definition qgis.h:882
ShaderInterpolationMethod
Color ramp shader interpolation methods.
Definition qgis.h:1425
@ Exact
Assigns the color of the exact matching value in the color ramp item list.
Definition qgis.h:1428
@ Linear
Interpolates the color between two class breaks linearly.
Definition qgis.h:1426
@ Discrete
Assigns the color of the higher class for every pixel between two class breaks.
Definition qgis.h:1427
QFlags< SymbolLayerFlag > SymbolLayerFlags
Symbol layer flags.
Definition qgis.h:887
ShaderClassificationMethod
Color ramp shader classification methods.
Definition qgis.h:1440
RenderUnit
Rendering size units.
Definition qgis.h:5183
@ Line
Line symbol.
Definition qgis.h:612
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
A ramp shader will color a raster pixel based on a list of values ranges in a ramp.
Qgis::ShaderClassificationMethod classificationMode() const
Returns the classification mode.
Qgis::ShaderInterpolationMethod colorRampType() const
Returns the color ramp interpolation method.
void setSourceColorRamp(QgsColorRamp *colorramp)
Set the source color ramp.
void setClassificationMode(Qgis::ShaderClassificationMethod classificationMode)
Sets the classification mode.
QList< QgsColorRampShader::ColorRampItem > colorRampItemList() const
Returns the custom color map.
void setClip(bool clip)
Sets whether the shader should not render values out of range.
bool clip() const
Returns whether the shader will clip values which are out of range.
QgsColorRamp * sourceColorRamp() const
Returns the source color ramp.
void setColorRampType(Qgis::ShaderInterpolationMethod colorRampType)
Sets the color ramp interpolation method.
void setColorRampItemList(const QList< QgsColorRampShader::ColorRampItem > &list)
Sets a custom color map.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context=QgsReadWriteContext())
Reads configuration from the given DOM element.
Abstract base class for color ramps.
virtual QColor color(double value) const =0
Returns the color corresponding to a specified value.
static QColor colorFromString(const QString &string)
Decodes a string into a color value.
static QString colorToString(const QColor &color)
Encodes a color into a string value.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
static double distance2D(double x1, double y1, double x2, double y2)
Returns the 2D distance between (x1, y1) and (x2, y2).
A geometry is the spatial representation of a feature.
QPolygonF asQPolygonF() const
Returns contents of the geometry as a QPolygonF.
double length() const
Returns the planar, 2-dimensional length of geometry.
Defines color interpolation for rendering mesh datasets.
QgsInterpolatedLineColor::ColoringMethod coloringMethod() const
Returns the coloring method used.
QgsColorRampShader colorRampShader() const
Returns the color ramp shader.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Reads configuration from the given DOM element.
QColor color(double magnitude) const
Returns the color corresponding to the magnitude.
void graduatedColors(double value1, double value2, QList< double > &breakValues, QList< QColor > &breakColors, QList< QLinearGradient > &gradients) const
Returns the break values, graduated colors and the associated gradients between two values.
QgsInterpolatedLineColor()
Default constructor.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Writes configuration to a new DOM element.
void setColor(const QgsColorRampShader &colorRampShader)
Sets the color ramp to define the coloring.
QColor singleColor() const
Returns the single color that is used if SingleColor coloring mode is set.
void setColoringMethod(ColoringMethod coloringMethod)
Sets the coloring method used.
ColoringMethod
Defines how the color is defined.
@ ColorRamp
Render with a color ramp.
@ SingleColor
Render with a single color.
void setInterpolatedColor(const QgsInterpolatedLineColor &strokeColoring)
Sets the stroke color used to render.
void renderInDeviceCoordinates(double valueColor1, double valueColor2, double valueWidth1, double valueWidth2, QPointF point1, QPointF point2, QgsRenderContext &context) const
Renders a line in the context between point1 and point2 in device (painter) coordinates with color th...
Qgis::RenderUnit widthUnit() const
Returns the unit of the stroke width.
void setInterpolatedWidth(const QgsInterpolatedLineWidth &strokeWidth)
Sets the stroke width used to render.
void setSelected(bool selected)
Sets if the rendering must be done as the element is selected.
void render(double value1, double value2, const QgsPointXY &point1, const QgsPointXY &point2, QgsRenderContext &context) const
Renders a line in the context between point1 and point2 with color and width that vary depending on v...
QgsInterpolatedLineWidth interpolatedLineWidth() const
Returns the stroke width used to render.
QgsInterpolatedLineColor interpolatedColor() const
Returns the stroke color used to render.
void setWidthUnit(Qgis::RenderUnit strokeWidthUnit)
Sets the unit of the stroke width.
Q_DECL_DEPRECATED QString endValueExpressionForWidth() const
Returns the expression related to the end extremity value for width.
QColor color() const override
Returns the "representative" color of the symbol layer.
Q_DECL_DEPRECATED QString endValueExpressionForColor() const
Returns the expression related to the end extremity value for width for color.
Q_DECL_DEPRECATED void setExpressionsStringForColor(const QString &start, const QString &end)
Sets the expressions (as string) that define the extremety values af the line feature for color.
Qgis::RenderUnit widthUnit() const
Returns the width unit.
Qgis::SymbolLayerFlags flags() const override
Returns flags which control the symbol layer's behavior.
QgsInterpolatedLineSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
bool canCauseArtifactsBetweenAdjacentTiles() const override
Returns true if the symbol layer rendering can cause visible artifacts across a single feature when t...
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
QgsInterpolatedLineColor interpolatedColor() const
Returns the interpolated color used to render the colors of lines, see QgsInterpolatedLineColor.
Q_DECL_DEPRECATED QString startValueExpressionForColor() const
Returns the epression related to the start extremity value for width for color.
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
void startFeatureRender(const QgsFeature &feature, QgsRenderContext &context) override
Called before the layer will be rendered for a particular feature.
QString layerType() const override
Returns a string that represents this layer type.
Q_DECL_DEPRECATED void setExpressionsStringForWidth(const QString &start, const QString &end)
Sets the expressions (as string) that define the extremety values af the line feature for width.
void setInterpolatedWidth(const QgsInterpolatedLineWidth &interpolatedLineWidth)
Sets the interpolated width used to render the width of lines, see QgsInterpolatedLineWidth.
void setInterpolatedColor(const QgsInterpolatedLineColor &interpolatedLineColor)
Sets the interpolated color used to render the colors of lines, see QgsInterpolatedLineColor.
Q_DECL_DEPRECATED QString startValueExpressionForWidth() const
Returns the epression related to the start extremity value for width.
void drawPreviewIcon(QgsSymbolRenderContext &context, QSize size) override
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
QgsInterpolatedLineWidth interpolatedWidth() const
Returns the interpolated width used to render the width of lines, see QgsInterpolatedLineWidth.
void stopFeatureRender(const QgsFeature &feature, QgsRenderContext &context) override
Called after the layer has been rendered for a particular feature.
void setWidthUnit(Qgis::RenderUnit strokeWidthUnit)
Sets the width unit.
static QgsSymbolLayer * create(const QVariantMap &properties)
Creates the symbol layer.
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
Represents a width that can vary depending on values.
void setFixedStrokeWidth(double fixedWidth)
Sets the fixed width.
double strokeWidth(double value) const
Returns the variable width depending on value, if not varying returns the fixed width.
void setUseAbsoluteValue(bool useAbsoluteValue)
Sets whether absolute value are used as input.
double minimumValue() const
Returns the minimum value used to defined the variable width.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Reads configuration from the given DOM element.
void setIgnoreOutOfRange(bool ignoreOutOfRange)
Sets whether the variable width ignores out of range value.
void setMaximumValue(double maximumValue)
Sets the maximum value used to defined the variable width.
bool useAbsoluteValue() const
Returns whether absolute value are used as input.
void setIsVariableWidth(bool isVariableWidth)
Returns whether the width is variable.
void setMinimumValue(double minimumValue)
Sets the minimum value used to defined the variable width.
double maximumWidth() const
Returns the maximum width used to defined the variable width.
void setMaximumWidth(double maximumWidth)
Sets the maximum width used to defined the variable width.
double maximumValue() const
Returns the maximum value used to defined the variable width.
void setMinimumWidth(double minimumWidth)
Sets the minimum width used to defined the variable width.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Writes configuration to a new DOM element.
bool ignoreOutOfRange() const
Returns whether the variable width ignores out of range value.
double minimumWidth() const
Returns the minimum width used to defined the variable width.
double fixedStrokeWidth() const
Returns the fixed width.
bool isVariableWidth() const
Returns whether the width is variable.
QgsGeometry geometry() const
Returns the geometry for the patch shape.
QgsLineSymbolLayer(const QgsLineSymbolLayer &other)=delete
Perform transforms between map coordinates and device coordinates.
QgsPointXY transform(const QgsPointXY &p) const
Transforms a point p from map (world) coordinates to device coordinates.
Represents a 2D point.
Definition qgspointxy.h:60
QPointF toQPointF() const
Converts a point to a QPointF.
Definition qgspointxy.h:165
bool isActive(int key) const final
Returns true if the collection contains an active property with the specified key.
A store for object properties.
static QgsProperty fromExpression(const QString &expression, bool isActive=true)
Returns a new ExpressionBasedProperty created from the specified expression.
double maximumValue() const
Returns the minimum value for the raster shader.
void setLabelPrecision(int labelPrecision)
Sets label precision to labelPrecision.
int labelPrecision() const
Returns label precision.
virtual void setMaximumValue(double value)
Sets the maximum value for the raster shader.
virtual void setMinimumValue(double value)
Sets the minimum value for the raster shader.
double minimumValue() const
Returns the maximum value for the raster shader.
A container for the context for various read/write operations on objects.
Contains information about the context of a rendering operation.
double convertToPainterUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
QPainter * painter()
Returns the destination QPainter for the render operation.
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
QgsExpressionContext & expressionContext()
Gets the expression context.
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
QColor selectionColor() const
Returns the color to use when rendering selected features.
Scoped object for saving and restoring a QPainter object's state.
QgsLegendPatchShape defaultPatch(Qgis::SymbolType type, QSizeF size) const
Returns the default legend patch shape for the given symbol type.
static QgsStyle * defaultStyle(bool initialize=true)
Returns the default application-wide style.
Definition qgsstyle.cpp:147
static QVariant colorRampToVariant(const QString &name, QgsColorRamp *ramp)
Saves a color ramp to a QVariantMap, wrapped in a QVariant.
static std::unique_ptr< QgsColorRamp > loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
void copyDataDefinedProperties(QgsSymbolLayer *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
@ LineEndColorValue
End line color for interpolated line renderer.
@ LineStartColorValue
Start line color for interpolated line renderer.
@ LineEndWidthValue
End line width for interpolated line renderer.
@ LineStartWidthValue
Start line width for interpolated line renderer.
void copyPaintEffect(QgsSymbolLayer *destLayer) const
Copies paint effect of this layer to another symbol layer.
virtual Qgis::SymbolLayerFlags flags() const
Returns flags which control the symbol layer's behavior.
QgsPropertyCollection mDataDefinedProperties
QgsSymbolLayer(const QgsSymbolLayer &other)
Encapsulates the context in which a symbol is being rendered.
bool selected() const
Returns true if symbols should be rendered using the selected symbol coloring and style.
const QgsLegendPatchShape * patchShape() const
Returns the symbol patch shape, to use if rendering symbol preview icons.
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
static Q_INVOKABLE Qgis::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
static Q_INVOKABLE QString encodeUnit(Qgis::DistanceUnit unit)
Encodes a distance unit to a string.
#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