QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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
16#include <QPainter>
17
20#include "qgssymbollayerutils.h"
21#include "qgsstyle.h"
22#include "qgsunittypes.h"
23#include "qgscolorutils.h"
24
25
27{
28 mStrokeWidth = strokeWidth;
29}
30
32{
33 return mStrokeWidth;
34}
35
37{
38 mStrokeColoring = strokeColoring;
39}
40
42{
43 return mStrokeColoring;
44}
45
47{
48 mStrokeWidthUnit = strokeWidthUnit;
49}
50
52{
53 return mStrokeWidthUnit;
54}
55
56void QgsInterpolatedLineRenderer::renderInDeviceCoordinates( double valueColor1, double valueColor2, double valueWidth1, double valueWidth2, QPointF p1, QPointF p2, QgsRenderContext &context ) const
57{
58 QPainter *painter = context.painter();
59 QgsScopedQPainterState painterState( painter );
60 context.setPainterFlagsUsingContext( painter );
61
62 QPointF dir = p2 - p1;
63 double length = sqrt( pow( dir.x(), 2 ) + pow( dir.y(), 2 ) );
64 QPointF diru = dir / length;
65 QPointF orthu = QPointF( -diru.y(), diru.x() );
66
67 QList<double> breakValues;
68 QList<QColor> breakColors;
69 QList<QLinearGradient> gradients;
70
71 mStrokeColoring.graduatedColors( valueColor1, valueColor2, breakValues, breakColors, gradients );
72 QColor selectedColor = context.selectionColor();
73
74 if ( gradients.isEmpty() && !breakValues.empty() && !breakColors.isEmpty() ) //exact colors to render
75 {
76 Q_ASSERT( breakColors.count() == breakValues.count() );
77 for ( int i = 0; i < breakValues.count(); ++i )
78 {
79 const bool widthIsInverted { valueWidth1 > valueWidth2 };
80 const double value = breakValues.at( i );
81 const double width = context.convertToPainterUnits( mStrokeWidth.strokeWidth( widthIsInverted ? mStrokeWidth.maximumValue() - value : value ), mStrokeWidthUnit );
82 QPen pen( mSelected ? selectedColor : breakColors.at( i ) );
83 pen.setWidthF( width );
84 pen.setCapStyle( Qt::PenCapStyle::RoundCap );
85 painter->setPen( pen );
86 const QPointF point = p1 + dir * ( value - valueColor1 ) / ( valueColor2 - valueColor1 );
87 painter->drawPoint( point );
88 }
89 }
90 else
91 {
92 double width1 = mStrokeWidth.strokeWidth( valueWidth1 );
93 double width2 = mStrokeWidth.strokeWidth( valueWidth2 );
94
95 if ( !std::isnan( width1 ) && !std::isnan( width2 ) ) // the two widths on extremity are not out of range and ignored
96 {
97 //Draw line cap
98 QBrush brush( Qt::SolidPattern );
99 QPen pen;
100 int startAngle;
101 startAngle = ( acos( -orthu.x() ) / M_PI ) * 180;
102 if ( orthu.y() < 0 )
103 startAngle = 360 - startAngle;
104
105 bool outOfRange1 = std::isnan( width1 );
106 bool outOfRange2 = std::isnan( width2 );
107
108 if ( !outOfRange1 )
109 {
110 width1 = context.convertToPainterUnits( width1, mStrokeWidthUnit );
111 QRectF capBox1( p1.x() - width1 / 2, p1.y() - width1 / 2, width1, width1 );
112 brush.setColor( mSelected ? selectedColor : mStrokeColoring.color( valueColor1 ) );
113 painter->setBrush( brush );
114 pen.setBrush( brush );
115 painter->setPen( pen );
116 painter->drawPie( capBox1, ( startAngle - 1 ) * 16, 182 * 16 );
117 }
118
119 if ( !outOfRange2 )
120 {
121 width2 = context.convertToPainterUnits( width2, mStrokeWidthUnit ) ;
122 QRectF capBox2( p2.x() - width2 / 2, p2.y() - width2 / 2, width2, width2 );
123 brush.setColor( mSelected ? selectedColor : mStrokeColoring.color( valueColor2 ) );
124 pen.setBrush( brush );
125 painter->setBrush( brush );
126 painter->setPen( pen );
127 painter->drawPie( capBox2, ( startAngle + 179 ) * 16, 182 * 16 );
128 }
129
130 if ( ( gradients.isEmpty() && breakValues.empty() && breakColors.count() == 1 ) || mSelected ) //only one color to render
131 {
132 double startAdjusting = 0;
133 if ( outOfRange1 )
134 adjustLine( valueColor1, valueColor1, valueColor2, width1, startAdjusting );
135
136
137 double endAdjusting = 0;
138 if ( outOfRange2 )
139 adjustLine( valueColor2, valueColor1, valueColor2, width2, endAdjusting );
140
141 QPointF pointStartAdjusted = p1 + dir * startAdjusting;
142 QPointF pointEndAdjusted = p2 - dir * endAdjusting;
143
144 QPolygonF varLine;
145 double semiWidth1 = width1 / 2;
146 double semiWidth2 = width2 / 2;
147
148 varLine.append( pointStartAdjusted + orthu * semiWidth1 );
149 varLine.append( pointEndAdjusted + orthu * semiWidth2 );
150 varLine.append( pointEndAdjusted - orthu * semiWidth2 );
151 varLine.append( pointStartAdjusted - orthu * semiWidth1 );
152
153 QBrush brush( Qt::SolidPattern );
154 brush.setColor( mSelected ? selectedColor : breakColors.first() );
155 painter->setBrush( brush );
156 painter->setPen( pen );
157
158 QPen pen;
159 pen.setBrush( brush );
160 pen.setWidthF( 0 );
161 painter->setPen( pen );
162
163 painter->drawPolygon( varLine );
164
165 }
166 else if ( !gradients.isEmpty() && !breakValues.isEmpty() && !breakColors.isEmpty() )
167 {
168 Q_ASSERT( breakColors.count() == breakValues.count() );
169 Q_ASSERT( breakColors.count() == gradients.count() + 1 );
170 double widthColorVariationValueRatio = ( valueWidth2 - valueWidth1 ) / ( valueColor2 - valueColor1 );
171
172 for ( int i = 0; i < gradients.count(); ++i )
173 {
174 double firstValue = breakValues.at( i );
175 double secondValue = breakValues.at( i + 1 );
176 double w1 = mStrokeWidth.strokeWidth( widthColorVariationValueRatio * ( firstValue - valueColor1 ) + valueWidth1 );
177 double w2 = mStrokeWidth.strokeWidth( widthColorVariationValueRatio * ( secondValue - valueColor1 ) + valueWidth1 );
178
179 if ( std::isnan( w1 ) && std::isnan( w2 ) )
180 continue;
181
182 double firstAdjusting = 0;
183 if ( std::isnan( w1 ) )
184 adjustLine( firstValue, valueColor1, valueColor2, w1, firstAdjusting );
185
186
187 double secondAdjusting = 0;
188 if ( std::isnan( w2 ) )
189 adjustLine( secondValue, valueColor1, valueColor2, w2, secondAdjusting );
190
191 w1 = context.convertToPainterUnits( w1, mStrokeWidthUnit );
192 w2 = context.convertToPainterUnits( w2, mStrokeWidthUnit ) ;
193
194 QPointF pointStart = p1 + dir * ( firstValue - valueColor1 ) / ( valueColor2 - valueColor1 );
195 QPointF pointEnd = p1 + dir * ( secondValue - valueColor1 ) / ( valueColor2 - valueColor1 );
196
197 QPointF pointStartAdjusted = pointStart + dir * firstAdjusting;
198 QPointF pointEndAdjusted = pointEnd - dir * secondAdjusting;
199
200 QPolygonF varLine;
201 double sw1 = w1 / 2;
202 double sw2 = w2 / 2;
203
204 varLine.append( pointStartAdjusted + orthu * sw1 );
205 varLine.append( pointEndAdjusted + orthu * sw2 );
206 varLine.append( pointEndAdjusted - orthu * sw2 );
207 varLine.append( pointStartAdjusted - orthu * sw1 );
208
209 QLinearGradient gradient = gradients.at( i );
210 gradient.setStart( pointStart );
211 gradient.setFinalStop( pointEnd );
212 QBrush brush( gradient );
213 painter->setBrush( brush );
214
215 QPen pen;
216 pen.setBrush( brush );
217 pen.setWidthF( 0 );
218 painter->setPen( pen );
219
220 painter->drawPolygon( varLine );
221 }
222 }
223 }
224 }
225}
226
227
228void QgsInterpolatedLineRenderer::render( double value1, double value2, const QgsPointXY &pt1, const QgsPointXY &pt2, QgsRenderContext &context ) const
229{
230 const QgsMapToPixel &mapToPixel = context.mapToPixel();
231
232 QgsPointXY point1 = pt1;
233 QgsPointXY point2 = pt2;
234
235 if ( value1 > value2 )
236 {
237 std::swap( value1, value2 );
238 std::swap( point1, point2 );
239 }
240
241 QPointF p1 = mapToPixel.transform( point1 ).toQPointF();
242 QPointF p2 = mapToPixel.transform( point2 ).toQPointF();
243
244 renderInDeviceCoordinates( value1, value2, value1, value2, p1, p2, context );
245}
246
247void QgsInterpolatedLineRenderer::render( double valueColor1, double valueColor2, double valueWidth1, double valueWidth2, const QgsPointXY &pt1, const QgsPointXY &pt2, QgsRenderContext &context ) const
248{
249 const QgsMapToPixel &mapToPixel = context.mapToPixel();
250
251 QgsPointXY point1 = pt1;
252 QgsPointXY point2 = pt2;
253
254 if ( valueColor1 > valueColor2 )
255 {
256 std::swap( valueColor1, valueColor2 );
257 std::swap( valueWidth1, valueWidth2 );
258 std::swap( point1, point2 );
259 }
260
261 QPointF p1 = mapToPixel.transform( point1 ).toQPointF();
262 QPointF p2 = mapToPixel.transform( point2 ).toQPointF();
263
264 renderInDeviceCoordinates( valueColor1, valueColor2, valueWidth1, valueWidth2, p1, p2, context );
265}
266
268{
269 mSelected = selected;
270}
271
272void QgsInterpolatedLineRenderer::adjustLine( const double value, const double value1, const double value2, double &width, double &adjusting ) const
273{
274 if ( value > mStrokeWidth.maximumValue() )
275 {
276 adjusting = fabs( ( value - mStrokeWidth.maximumValue() ) / ( value2 - value1 ) );
277 width = mStrokeWidth.maximumWidth();
278 }
279 else
280 {
281 adjusting = fabs( ( value - mStrokeWidth.minimumValue() ) / ( value2 - value1 ) );
282 width = mStrokeWidth.minimumWidth();
283 }
284}
285
287{
288 return mMinimumValue;
289}
290
292{
293 mMinimumValue = minimumValue;
294 mNeedUpdateFormula = true;
295}
296
298{
299 return mMaximumValue;
300}
301
303{
304 mMaximumValue = maximumValue;
305 mNeedUpdateFormula = true;
306}
307
309{
310 return mMinimumWidth;
311}
312
314{
315 mMinimumWidth = minimumWidth;
316 mNeedUpdateFormula = true;
317}
318
320{
321 return mMaximumWidth;
322}
323
325{
326 mMaximumWidth = maximumWidth;
327 mNeedUpdateFormula = true;
328}
329
330double QgsInterpolatedLineWidth::strokeWidth( double value ) const
331{
332 if ( mIsWidthVariable )
333 {
334 if ( mNeedUpdateFormula )
335 updateLinearFormula();
336
337 if ( mUseAbsoluteValue )
338 value = std::fabs( value );
339
340 if ( value > mMaximumValue )
341 {
342 if ( mIgnoreOutOfRange )
343 return std::numeric_limits<double>::quiet_NaN();
344 else
345 return mMaximumWidth;
346 }
347
348 if ( value < mMinimumValue )
349 {
350 if ( mIgnoreOutOfRange )
351 return std::numeric_limits<double>::quiet_NaN();
352 else
353 return mMinimumWidth;
354 }
355
356 return ( value - mMinimumValue ) * mLinearCoef + mMinimumWidth;
357 }
358 else
359 return fixedStrokeWidth();
360}
361
362QDomElement QgsInterpolatedLineWidth::writeXml( QDomDocument &doc, const QgsReadWriteContext & ) const
363{
364 QDomElement elem = doc.createElement( QStringLiteral( "mesh-stroke-width" ) );
365
366 elem.setAttribute( QStringLiteral( "width-varying" ), mIsWidthVariable ? 1 : 0 );
367 elem.setAttribute( QStringLiteral( "fixed-width" ), mFixedWidth );
368 elem.setAttribute( QStringLiteral( "minimum-value" ), mMinimumValue );
369 elem.setAttribute( QStringLiteral( "maximum-value" ), mMaximumValue );
370 elem.setAttribute( QStringLiteral( "minimum-width" ), mMinimumWidth );
371 elem.setAttribute( QStringLiteral( "maximum-width" ), mMaximumWidth );
372 elem.setAttribute( QStringLiteral( "ignore-out-of-range" ), mIgnoreOutOfRange ? 1 : 0 );
373 elem.setAttribute( QStringLiteral( "use-absolute-value" ), mUseAbsoluteValue ? 1 : 0 );
374
375 return elem;
376}
377
378void QgsInterpolatedLineWidth::readXml( const QDomElement &elem, const QgsReadWriteContext & )
379{
380 mIsWidthVariable = elem.attribute( QStringLiteral( "width-varying" ) ).toInt();
381 mFixedWidth = elem.attribute( QStringLiteral( "fixed-width" ) ).toDouble();
382 mMinimumValue = elem.attribute( QStringLiteral( "minimum-value" ) ).toDouble();
383 mMaximumValue = elem.attribute( QStringLiteral( "maximum-value" ) ).toDouble();
384 mMinimumWidth = elem.attribute( QStringLiteral( "minimum-width" ) ).toDouble();
385 mMaximumWidth = elem.attribute( QStringLiteral( "maximum-width" ) ).toDouble();
386 mIgnoreOutOfRange = elem.attribute( QStringLiteral( "ignore-out-of-range" ) ).toInt();
387 mUseAbsoluteValue = elem.attribute( QStringLiteral( "use-absolute-value" ) ).toInt();
388}
389
391{
392 return mUseAbsoluteValue;
393}
394
396{
397 mUseAbsoluteValue = useAbsoluteValue;
398}
399
401{
402 return mFixedWidth;
403}
404
406{
407 return mIgnoreOutOfRange;
408}
409
411{
412 mIgnoreOutOfRange = ignoreOutOfRange;
413}
414
416{
417 return mIsWidthVariable;
418}
419
421{
422 mIsWidthVariable = isWidthVarying;
423}
424
426{
427 mFixedWidth = fixedWidth;
428}
429
430void QgsInterpolatedLineWidth::updateLinearFormula() const
431{
432 if ( !qgsDoubleNear( mMaximumWidth, mMinimumWidth ) )
433 mLinearCoef = ( mMaximumWidth - mMinimumWidth ) / ( mMaximumValue - mMinimumValue ) ;
434 else
435 mLinearCoef = 0;
436 mNeedUpdateFormula = false;
437}
438
440{
441 mColorRampShader.setMinimumValue( std::numeric_limits<double>::quiet_NaN() );
442 mColorRampShader.setMaximumValue( std::numeric_limits<double>::quiet_NaN() );
443}
444
446{
448}
449
451{
452 setColor( color );
453 mColoringMethod = SingleColor;
454 mColorRampShader.setMinimumValue( std::numeric_limits<double>::quiet_NaN() );
455 mColorRampShader.setMaximumValue( std::numeric_limits<double>::quiet_NaN() );
456}
457
459{
460 mColorRampShader = colorRampShader;
461 if ( ( mColorRampShader.sourceColorRamp() ) )
462 mColoringMethod = ColorRamp;
463 else
464 mColoringMethod = SingleColor;
465}
466
467void QgsInterpolatedLineColor::setColor( const QColor &color )
468{
469 mSingleColor = color;
470}
471
472QColor QgsInterpolatedLineColor::color( double magnitude ) const
473{
474 QgsColorRamp *lSourceColorRamp = mColorRampShader.sourceColorRamp();
475 if ( mColoringMethod == ColorRamp && lSourceColorRamp )
476 {
477 if ( mColorRampShader.isEmpty() )
478 return lSourceColorRamp->color( 0 );
479
480 int r, g, b, a;
481 if ( mColorRampShader.shade( magnitude, &r, &g, &b, &a ) )
482 return QColor( r, g, b, a );
483 else
484 return QColor( 0, 0, 0, 0 );
485 }
486 else
487 {
488 return mSingleColor;
489 }
490}
491
493{
494 return mColoringMethod;
495}
496
498{
499 return mColorRampShader;
500}
501
503{
504 return mSingleColor;
505}
506
507QDomElement QgsInterpolatedLineColor::writeXml( QDomDocument &doc, const QgsReadWriteContext & ) const
508{
509 QDomElement elem = doc.createElement( QStringLiteral( "mesh-stroke-color" ) );
510
511 elem.setAttribute( QStringLiteral( "single-color" ), QgsColorUtils::colorToString( mSingleColor ) );
512 elem.setAttribute( QStringLiteral( "coloring-method" ), mColoringMethod );
513 elem.appendChild( mColorRampShader.writeXml( doc ) );
514
515 return elem;
516}
517
518void QgsInterpolatedLineColor::readXml( const QDomElement &elem, const QgsReadWriteContext & )
519{
520 QDomElement shaderElem = elem.firstChildElement( QStringLiteral( "colorrampshader" ) );
521 mColorRampShader.readXml( shaderElem );
522
523 mSingleColor = QgsColorUtils::colorFromString( elem.attribute( QStringLiteral( "single-color" ) ) );
524 mColoringMethod = static_cast<QgsInterpolatedLineColor::ColoringMethod>(
525 elem.attribute( QStringLiteral( "coloring-method" ) ).toInt() );
526}
527
528void QgsInterpolatedLineColor::graduatedColors( double value1, double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients ) const
529{
530 breakValues.clear();
531 breakColors.clear();
532 gradients.clear();
533 if ( mColoringMethod == SingleColor )
534 {
535 breakColors.append( mSingleColor );
536 return;
537 }
538
539 switch ( mColorRampShader.colorRampType() )
540 {
542 graduatedColorsInterpolated( value1, value2, breakValues, breakColors, gradients );
543 break;
545 graduatedColorsDiscrete( value1, value2, breakValues, breakColors, gradients );
546 break;
548 graduatedColorsExact( value1, value2, breakValues, breakColors, gradients );
549 break;
550 }
551
552}
553
555{
556 mColoringMethod = coloringMethod;
557}
558
559QLinearGradient QgsInterpolatedLineColor::makeSimpleLinearGradient( const QColor &color1, const QColor &color2 ) const
560{
561 QLinearGradient gradient;
562 gradient.setColorAt( 0, color1 );
563 gradient.setColorAt( 1, color2 );
564
565 return gradient;
566}
567
568int QgsInterpolatedLineColor::itemColorIndexInf( double value ) const
569{
570 QList<QgsColorRampShader::ColorRampItem> itemList = mColorRampShader.colorRampItemList();
571
572 if ( itemList.isEmpty() || itemList.first().value > value )
573 return -1;
574
575 if ( mColorRampShader.colorRampType() == QgsColorRampShader::Discrete )
576 itemList.removeLast(); //remove the inf value
577
578 if ( value > itemList.last().value )
579 return itemList.count() - 1;
580
581 int indSup = itemList.count() - 1;
582 int indInf = 0;
583
584 while ( true )
585 {
586 if ( abs( indSup - indInf ) <= 1 ) //always indSup>indInf, but abs to prevent infinity loop
587 return indInf;
588
589 int newInd = ( indInf + indSup ) / 2;
590
591 if ( std::isnan( itemList.at( newInd ).value ) )
592 return -1;
593
594 if ( itemList.at( newInd ).value <= value )
595 indInf = newInd;
596 else
597 indSup = newInd;
598 }
599}
600
601void QgsInterpolatedLineColor::graduatedColorsExact( double value1, double value2, QList<double> &breakValues, QList<QColor> &breakColors, const QList<QLinearGradient> &gradients ) const
602{
603 Q_ASSERT( mColorRampShader.colorRampType() == QgsColorRampShader::Exact );
604 Q_ASSERT( breakValues.isEmpty() );
605 Q_ASSERT( breakColors.isEmpty() );
606 Q_ASSERT( gradients.isEmpty() );
607
608 const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.colorRampItemList();
609 if ( itemList.isEmpty() )
610 return;
611
612 int index = itemColorIndexInf( value1 );
613 if ( index < 0 || !qgsDoubleNear( value1, itemList.at( index ).value ) )
614 index++;
615
616 if ( qgsDoubleNear( value1, value2 ) && qgsDoubleNear( value1, itemList.at( index ).value ) )
617 {
618 //the two value are the same and are equal to the value in the item list --> render only one color
619 breakColors.append( itemList.at( index ).color );
620 return;
621 }
622
623 while ( index < itemList.count() && itemList.at( index ).value <= value2 )
624 {
625 breakValues.append( itemList.at( index ).value );
626 breakColors.append( itemList.at( index ).color );
627 index++;
628 }
629}
630
631void QgsInterpolatedLineColor::graduatedColorsInterpolated( double value1, double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients ) const
632{
633 Q_ASSERT( mColorRampShader.colorRampType() == QgsColorRampShader::Interpolated );
634 Q_ASSERT( breakValues.isEmpty() );
635 Q_ASSERT( breakColors.isEmpty() );
636 Q_ASSERT( gradients.isEmpty() );
637
638
639 const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.colorRampItemList();
640 if ( itemList.empty() )
641 return;
642
643 if ( itemList.count() == 1 )
644 {
645 breakColors.append( itemList.first().color );
646 return;
647 }
648
649 if ( value2 <= itemList.first().value ) // completely out of range and less
650 {
651 if ( !mColorRampShader.clip() )
652 breakColors.append( itemList.first().color ); // render only the first color in the whole range if not clipped
653 return;
654 }
655
656 if ( value1 > itemList.last().value ) // completely out of range and greater
657 {
658 if ( !mColorRampShader.clip() )
659 breakColors.append( itemList.last().color ); // render only the last color in the whole range if not clipped
660 return;
661 }
662
663 if ( qgsDoubleNear( value1, value2 ) )
664 {
665 // the two values are the same
666 // --> render only one color
667 int r, g, b, a;
668 QColor color;
669 if ( mColorRampShader.shade( value1, &r, &g, &b, &a ) )
670 color = QColor( r, g, b, a );
671 breakColors.append( color );
672 return;
673 }
674
675 // index of the inf value of the interval where value1 is in the color ramp shader
676 int index = itemColorIndexInf( value1 );
677 if ( index < 0 ) // value1 out of range
678 {
679 QColor color = itemList.first().color;
680 breakColors.append( color );
681 if ( mColorRampShader.clip() ) // The first value/color returned is the first of the item list
682 breakValues.append( itemList.first().value );
683 else // The first value/color returned is the first color of the item list and value1
684 breakValues.append( value1 );
685 }
686 else
687 {
688 // shade the color
689 int r, g, b, a;
690 QColor color;
691 if ( mColorRampShader.shade( value1, &r, &g, &b, &a ) )
692 color = QColor( r, g, b, a );
693 breakValues.append( value1 );
694 breakColors.append( color );
695 }
696
697 index++; // increment the index before go through the intervals
698
699 while ( index < itemList.count() && itemList.at( index ).value < value2 )
700 {
701 QColor color1 = breakColors.last();
702 QColor color2 = itemList.at( index ).color;
703 breakValues.append( itemList.at( index ).value );
704 breakColors.append( color2 );
705 gradients.append( makeSimpleLinearGradient( color1, color2 ) );
706 index++;
707 }
708
709 // close the lists with value2 or last item if >value2
710 QColor color1 = breakColors.last();
711 QColor color2;
712 if ( value2 < itemList.last().value )
713 {
714 int r, g, b, a;
715 if ( mColorRampShader.shade( value2, &r, &g, &b, &a ) )
716 color2 = QColor( r, g, b, a );
717 breakValues.append( value2 );
718 }
719 else
720 {
721 color2 = itemList.last().color;
722 if ( mColorRampShader.clip() )
723 breakValues.append( itemList.last().value );
724 else
725 breakValues.append( value2 );
726 }
727 breakColors.append( color2 );
728 gradients.append( makeSimpleLinearGradient( color1, color2 ) );
729}
730
731
732void QgsInterpolatedLineColor::graduatedColorsDiscrete( double value1, double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients ) const
733{
734 Q_ASSERT( mColorRampShader.colorRampType() == QgsColorRampShader::Discrete );
735 Q_ASSERT( breakValues.isEmpty() );
736 Q_ASSERT( breakColors.isEmpty() );
737 Q_ASSERT( gradients.isEmpty() );
738
739 const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.colorRampItemList();
740 if ( itemList.empty() )
741 return;
742
743 if ( itemList.count() == 1 )
744 {
745 breakColors.append( itemList.first().color );
746 return;
747 }
748
749 double lastValue = itemList.at( itemList.count() - 2 ).value;
750
751
752 if ( value2 <= itemList.first().value ) // completely out of range and less
753 {
754 breakColors.append( itemList.first().color ); // render only the first color in the whole range
755 return;
756 }
757
758 if ( value1 > lastValue ) // completely out of range and greater
759 {
760 breakColors.append( itemList.last().color ); // render only the last color in the whole range
761 return;
762 }
763
764 // index of the inf value of the interval where value1 is in the color ramp shader
765 int index = itemColorIndexInf( value1 );
766
767 if ( qgsDoubleNear( value1, value2 ) )
768 {
769 // the two values are the same and are equal to the value in the item list
770 // --> render only one color, the sup one
771 breakColors.append( itemList.at( index + 1 ).color );
772 return;
773 }
774
775 if ( index < 0 ) // value1 out of range
776 {
777 breakValues.append( value1 );
778 breakColors.append( itemList.first().color );
779 }
780 else // append the first value with corresponding color
781 {
782 QColor color = itemList.at( index ).color;
783 breakValues.append( value1 );
784 breakColors.append( color );
785 }
786
787 index++; // increment the index before go through the intervals
788
789 while ( index < ( itemList.count() - 1 ) && itemList.at( index ).value < value2 )
790 {
791 QColor color = itemList.at( index ).color;
792 breakValues.append( itemList.at( index ).value );
793 breakColors.append( color );
794 gradients.append( makeSimpleLinearGradient( color, color ) );
795 index++;
796 }
797
798 // add value2 to close
799 QColor lastColor = itemList.at( index ).color;
800 breakColors.append( lastColor );
801 breakValues.append( value2 );
802 gradients.append( makeSimpleLinearGradient( lastColor, lastColor ) );
803
804}
805
806QString QgsInterpolatedLineSymbolLayer::layerType() const {return QStringLiteral( "InterpolatedLine" );}
807
809{
810}
811
813{
814}
815
817{
820 copyPaintEffect( l );
821 return l;
822}
823
825{
826 std::unique_ptr<QgsInterpolatedLineSymbolLayer> symbolLayer;
827 symbolLayer.reset( new QgsInterpolatedLineSymbolLayer() );
828
829 if ( properties.contains( QStringLiteral( "start_width_expression" ) ) )
830 symbolLayer->setDataDefinedProperty( QgsSymbolLayer::Property::LineStartWidthValue, QgsProperty::fromExpression( properties.value( QStringLiteral( "start_width_expression" ) ).toString() ) );
831 if ( properties.contains( QStringLiteral( "end_width_expression" ) ) )
832 symbolLayer->setDataDefinedProperty( QgsSymbolLayer::Property::LineEndWidthValue, QgsProperty::fromExpression( properties.value( QStringLiteral( "end_width_expression" ) ).toString() ) );
833
834 if ( properties.contains( QStringLiteral( "start_color_expression" ) ) )
835 symbolLayer->setDataDefinedProperty( QgsSymbolLayer::Property::LineStartColorValue, QgsProperty::fromExpression( properties.value( QStringLiteral( "start_color_expression" ) ).toString() ) );
836 if ( properties.contains( QStringLiteral( "end_color_expression" ) ) )
837 symbolLayer->setDataDefinedProperty( QgsSymbolLayer::Property::LineEndColorValue, QgsProperty::fromExpression( properties.value( QStringLiteral( "end_color_expression" ) ).toString() ) );
838
839 if ( properties.contains( QStringLiteral( "line_width" ) ) )
840 symbolLayer->mLineRender.mStrokeWidth.setFixedStrokeWidth( properties.value( QStringLiteral( "line_width" ) ).toDouble() ) ;
841 if ( properties.contains( QStringLiteral( "line_width_unit" ) ) )
842 symbolLayer->mLineRender.setWidthUnit( QgsUnitTypes::decodeRenderUnit( properties.value( QStringLiteral( "line_width_unit" ) ).toString() ) );
843 if ( properties.contains( QStringLiteral( "width_varying_minimum_value" ) ) )
844 symbolLayer->mLineRender.mStrokeWidth.setMinimumValue( properties.value( QStringLiteral( "width_varying_minimum_value" ) ).toDouble() );
845 if ( properties.contains( QStringLiteral( "width_varying_maximum_value" ) ) )
846 symbolLayer->mLineRender.mStrokeWidth.setMaximumValue( properties.value( QStringLiteral( "width_varying_maximum_value" ) ).toDouble() );
847 if ( properties.contains( QStringLiteral( "width_varying_use_absolute_value" ) ) )
848 symbolLayer->mLineRender.mStrokeWidth.setUseAbsoluteValue( properties.value( QStringLiteral( "width_varying_use_absolute_value" ) ).toInt() );
849 if ( properties.contains( QStringLiteral( "width_varying_minimum_width" ) ) )
850 symbolLayer->mLineRender.mStrokeWidth.setMinimumWidth( properties.value( QStringLiteral( "width_varying_minimum_width" ) ).toDouble() );
851 if ( properties.contains( QStringLiteral( "width_varying_maximum_width" ) ) )
852 symbolLayer->mLineRender.mStrokeWidth.setMaximumWidth( properties.value( QStringLiteral( "width_varying_maximum_width" ) ).toDouble() );
853 if ( properties.contains( QStringLiteral( "width_varying_ignore_out_of_range" ) ) )
854 symbolLayer->mLineRender.mStrokeWidth.setIgnoreOutOfRange( properties.value( QStringLiteral( "width_varying_ignore_out_of_range" ) ).toInt() );
855 if ( properties.contains( QStringLiteral( "width_varying_is_variable_width" ) ) )
856 symbolLayer->mLineRender.mStrokeWidth.setIsVariableWidth( properties.value( QStringLiteral( "width_varying_is_variable_width" ) ).toInt() );
857
858 if ( properties.contains( QStringLiteral( "single_color" ) ) )
859 symbolLayer->mLineRender.mStrokeColoring.setColor( QgsColorUtils::colorFromString( properties.value( QStringLiteral( "single_color" ) ).toString() ) );
860 if ( properties.contains( QStringLiteral( "color_ramp_shader" ) ) )
861 symbolLayer->mLineRender.mStrokeColoring.setColor( createColorRampShaderFromProperties( properties.value( QStringLiteral( "color_ramp_shader" ) ) ) );
862 if ( properties.contains( QStringLiteral( "coloring_method" ) ) )
863 symbolLayer->mLineRender.mStrokeColoring.setColoringMethod(
864 static_cast<QgsInterpolatedLineColor::ColoringMethod>( properties.value( QStringLiteral( "coloring_method" ) ).toInt() ) );
865
866 return symbolLayer.release();
867}
868
870{
872}
873
875{
876 QVariantMap props;
877
878 // Line width varying
879 props.insert( QStringLiteral( "line_width" ), QString::number( mLineRender.mStrokeWidth.fixedStrokeWidth() ) );
880 props.insert( QStringLiteral( "line_width_unit" ), QgsUnitTypes::encodeUnit( mLineRender.widthUnit() ) );
881 props.insert( QStringLiteral( "width_varying_minimum_value" ), mLineRender.mStrokeWidth.minimumValue() );
882 props.insert( QStringLiteral( "width_varying_maximum_value" ), mLineRender.mStrokeWidth.maximumValue() );
883 props.insert( QStringLiteral( "width_varying_use_absolute_value" ), mLineRender.mStrokeWidth.useAbsoluteValue() ? 1 : 0 );
884 props.insert( QStringLiteral( "width_varying_minimum_width" ), mLineRender.mStrokeWidth.minimumWidth() );
885 props.insert( QStringLiteral( "width_varying_maximum_width" ), mLineRender.mStrokeWidth.maximumWidth() );
886 props.insert( QStringLiteral( "width_varying_ignore_out_of_range" ), mLineRender.mStrokeWidth.ignoreOutOfRange() ? 1 : 0 );
887 props.insert( QStringLiteral( "width_varying_is_variable_width" ), mLineRender.mStrokeWidth.isVariableWidth() ? 1 : 0 );
888
889 // Color varying
890 props.insert( QStringLiteral( "coloring_method" ), mLineRender.mStrokeColoring.coloringMethod() );
891 props.insert( QStringLiteral( "single_color" ), QgsColorUtils::colorToString( mLineRender.mStrokeColoring.singleColor() ) );
892 props.insert( QStringLiteral( "color_ramp_shader" ), colorRampShaderProperties() );
893
894 return props;
895}
896
898{
899 QgsGeometry geometry = context.patchShape() ? context.patchShape()->geometry()
901
902 startRender( context );
903 double min = std::min( mLineRender.interpolatedLineWidth().minimumValue(), mLineRender.interpolatedColor().colorRampShader().minimumValue() );
904 double max = std::max( mLineRender.interpolatedLineWidth().maximumValue(), mLineRender.interpolatedColor().colorRampShader().maximumValue() );
905
906 double totalLength = geometry.length();
907 if ( qgsDoubleNear( totalLength, 0 ) )
908 return;
909
910 double variation = ( max - min ) / totalLength;
911
912 QPolygonF points = geometry.asQPolygonF();
913 double lengthFromStart = 0;
914 for ( int i = 1; i < points.count(); ++i )
915 {
916 QPointF p1 = points.at( i - 1 );
917 QPointF p2 = points.at( i );
918
919 double v1 = min + variation * lengthFromStart;
920 QPointF vectDist = p2 - p1;
921 lengthFromStart += sqrt( pow( vectDist.x(), 2 ) + pow( vectDist.y(), 2 ) );
922 double v2 = min + variation * lengthFromStart;
923 mLineRender.renderInDeviceCoordinates( v1, v2, v1, v2, p1, p2, context.renderContext() );
924 }
925
926 renderPolyline( points, context );
927
928}
929
931{
932 switch ( mLineRender.interpolatedColor().coloringMethod() )
933 {
935 return mLineRender.interpolatedColor().singleColor();
937 return QColor();
938 }
940}
941
942
943void QgsInterpolatedLineSymbolLayer::setExpressionsStringForWidth( const QString &start, const QString &end )
944{
945 if ( start.isEmpty() )
947 else
949
950 if ( end.isEmpty() )
952 else
954}
955
957{
959}
960
962{
964}
965
967{
968 mLineRender.mStrokeWidthUnit = strokeWidthUnit;
969}
970
972
974{
975 mLineRender.mStrokeWidth = interpolatedLineWidth;
976}
977
979
980void QgsInterpolatedLineSymbolLayer::setExpressionsStringForColor( const QString &start, const QString &end )
981{
982 if ( start.isEmpty() )
984 else
986
987 if ( end.isEmpty() )
989 else
991}
992
994{
996}
997
999{
1001}
1002
1004{
1005 mLineRender.setInterpolatedColor( interpolatedLineColor );
1006}
1007
1009{
1010 return mLineRender.interpolatedColor();
1011}
1012
1013QVariant QgsInterpolatedLineSymbolLayer::colorRampShaderProperties() const
1014{
1015 const QgsColorRampShader &colorRampShader = mLineRender.mStrokeColoring.colorRampShader();
1016
1017 QVariantMap props;
1018 if ( colorRampShader.sourceColorRamp() )
1019 props.insert( QStringLiteral( "color_ramp_source" ), QgsSymbolLayerUtils::colorRampToVariant( QString(), colorRampShader.sourceColorRamp() ) );
1020 props.insert( QStringLiteral( "color_ramp_shader_type" ), colorRampShader.colorRampType() );
1021 props.insert( QStringLiteral( "color_ramp_shader_classification_mode" ), colorRampShader.classificationMode() );
1022 QVariantList colorRampItemListVariant;
1023
1024 const QList<QgsColorRampShader::ColorRampItem> colorRampItemList = colorRampShader.colorRampItemList();
1025 for ( const QgsColorRampShader::ColorRampItem &item : colorRampItemList )
1026 {
1027 QVariantMap itemVar;
1028 itemVar[QStringLiteral( "label" )] = item.label;
1029 itemVar[QStringLiteral( "color" )] = QgsColorUtils::colorToString( item.color );
1030 itemVar[QStringLiteral( "value" )] = item.value;
1031 colorRampItemListVariant.append( itemVar );
1032 }
1033 props.insert( QStringLiteral( "color_ramp_shader_items_list" ), colorRampItemListVariant );
1034
1035 props.insert( QStringLiteral( "color_ramp_shader_minimum_value" ), colorRampShader.minimumValue() );
1036 props.insert( QStringLiteral( "color_ramp_shader_maximum_value" ), colorRampShader.maximumValue() );
1037 props.insert( QStringLiteral( "color_ramp_shader_value_out_of_range" ), colorRampShader.clip() ? 1 : 0 );
1038 props.insert( QStringLiteral( "color_ramp_shader_label_precision" ), colorRampShader.labelPrecision() );
1039
1040 return props;
1041}
1042
1043QgsColorRampShader QgsInterpolatedLineSymbolLayer::createColorRampShaderFromProperties( const QVariant &properties )
1044{
1045 QgsColorRampShader colorRampShader;
1046
1047 if ( properties.type() != QVariant::Map )
1048 return colorRampShader;
1049
1050 QVariantMap shaderVariantMap = properties.toMap();
1051
1052 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_source" ) ) )
1053 colorRampShader.setSourceColorRamp( QgsSymbolLayerUtils::loadColorRamp( shaderVariantMap.value( QStringLiteral( "color_ramp_source" ) ) ) );
1054
1055 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_type" ) ) )
1056 colorRampShader.setColorRampType( static_cast<QgsColorRampShader::Type>( shaderVariantMap.value( QStringLiteral( "color_ramp_shader_type" ) ).toInt() ) );
1057 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_classification_mode" ) ) )
1059 shaderVariantMap.value( QStringLiteral( "color_ramp_shader_classification_mode" ) ).toInt() ) );
1060
1061 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_items_list" ) ) )
1062 {
1063 QVariant colorRampItemsVar = shaderVariantMap.value( QStringLiteral( "color_ramp_shader_items_list" ) );
1064 if ( colorRampItemsVar.type() == QVariant::List )
1065 {
1066 QVariantList itemVariantList = colorRampItemsVar.toList();
1067 QList<QgsColorRampShader::ColorRampItem> colorRampItemList;
1068 for ( const QVariant &itemVar : std::as_const( itemVariantList ) )
1069 {
1071 if ( itemVar.type() != QVariant::Map )
1072 continue;
1073 QVariantMap itemVarMap = itemVar.toMap();
1074 if ( !itemVarMap.contains( QStringLiteral( "label" ) ) || !itemVarMap.contains( QStringLiteral( "color" ) ) || !itemVarMap.contains( QStringLiteral( "value" ) ) )
1075 continue;
1076
1077 item.label = itemVarMap.value( QStringLiteral( "label" ) ).toString();
1078 item.color = QgsColorUtils::colorFromString( itemVarMap.value( QStringLiteral( "color" ) ).toString() );
1079 item.value = itemVarMap.value( QStringLiteral( "value" ) ).toDouble();
1080
1081 colorRampItemList.append( item );
1082 }
1083 colorRampShader.setColorRampItemList( colorRampItemList );
1084 }
1085 }
1086
1087 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_minimum_value" ) ) )
1088 colorRampShader.setMinimumValue( shaderVariantMap.value( QStringLiteral( "color_ramp_shader_minimum_value" ) ).toDouble() );
1089 else
1090 colorRampShader.setMinimumValue( std::numeric_limits<double>::quiet_NaN() );
1091
1092 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_maximum_value" ) ) )
1093 colorRampShader.setMaximumValue( shaderVariantMap.value( QStringLiteral( "color_ramp_shader_maximum_value" ) ).toDouble() );
1094 else
1095 colorRampShader.setMaximumValue( std::numeric_limits<double>::quiet_NaN() );
1096
1097 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_value_out_of_range" ) ) )
1098 colorRampShader.setClip( shaderVariantMap.value( QStringLiteral( "color_ramp_shader_value_out_of_range" ) ).toInt() == 1 );
1099 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_label_precision" ) ) )
1100 colorRampShader.setLabelPrecision( shaderVariantMap.value( QStringLiteral( "color_ramp_shader_label_precision" ) ).toInt() );
1101
1102 return colorRampShader;
1103}
1104
1106
1107
1109{
1110 mRenderingFeature = true;
1111 mLineParts.clear();
1112}
1113
1115{
1116 mRenderingFeature = false;
1117
1118 if ( mLineParts.empty() )
1119 return;
1120
1121 render( mLineParts, context );
1122 mLineParts.clear();
1123}
1124
1125void QgsInterpolatedLineSymbolLayer::render( const QVector< QPolygonF > &parts, QgsRenderContext &context )
1126{
1127 const double totalLength = std::accumulate( parts.begin(), parts.end(), 0.0, []( double total, const QPolygonF & part )
1128 {
1129 return total + QgsSymbolLayerUtils::polylineLength( part );
1130 } );
1131
1132 if ( qgsDoubleNear( totalLength, 0 ) )
1133 return;
1134
1135 double startValWidth = 0;
1136 double variationPerMapUnitWidth = 0;
1137 double startValColor = 0;
1138 double variationPerMapUnitColor = 0;
1139
1140 bool ok = true;
1141
1142 if ( mLineRender.interpolatedLineWidth().isVariableWidth() )
1143 {
1145 {
1147 if ( !ok )
1148 return;
1149 }
1150
1151 double endValWidth = 0;
1153 {
1155 if ( !ok )
1156 return;
1157 }
1158
1159 variationPerMapUnitWidth = ( endValWidth - startValWidth ) / totalLength;
1160 }
1161
1163 {
1165 {
1167 if ( !ok )
1168 return;
1169 }
1170
1171 double endValColor = 0;
1173 {
1175 if ( !ok )
1176 return;
1177 }
1178
1179 variationPerMapUnitColor = ( endValColor - startValColor ) / totalLength;
1180 }
1181
1182 for ( const QPolygonF &poly : parts )
1183 {
1184 double lengthFromStart = 0;
1185 for ( int i = 1; i < poly.count(); ++i )
1186 {
1187 const QPointF p1 = poly.at( i - 1 );
1188 const QPointF p2 = poly.at( i );
1189
1190 const double v1c = startValColor + variationPerMapUnitColor * lengthFromStart;
1191 const double v1w = startValWidth + variationPerMapUnitWidth * lengthFromStart;
1192 lengthFromStart += QgsGeometryUtilsBase::distance2D( p1.x(), p1.y(), p2.x(), p2.y() );
1193 const double v2c = startValColor + variationPerMapUnitColor * lengthFromStart;
1194 const double v2w = startValWidth + variationPerMapUnitWidth * lengthFromStart;
1195 mLineRender.renderInDeviceCoordinates( v1c, v2c, v1w, v2w, p1, p2, context );
1196 }
1197 }
1198}
1199
1201{
1202 mLineRender.setSelected( context.selected() );
1203
1204 if ( points.empty() )
1205 return;
1206
1207 if ( mRenderingFeature )
1208 {
1209 // in the middle of rendering a possibly multi-part feature, so we collect all the parts and defer the actual rendering
1210 // until after we've received the final part
1211 mLineParts.append( points );
1212 }
1213 else
1214 {
1215 // not rendering a feature, so we can just render the polyline immediately
1216 render( { points }, context.renderContext() );
1217 }
1218}
1219
1221{
1222 return true;
1223}
@ DisableFeatureClipping
If present, indicates that features should never be clipped to the map extent during rendering.
QFlags< SymbolLayerFlag > SymbolLayerFlags
Symbol layer flags.
Definition: qgis.h:623
RenderUnit
Rendering size units.
Definition: qgis.h:4255
@ Line
Line symbol.
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.
ClassificationMode classificationMode() const
Returns the classification mode.
bool isEmpty() const
Whether the color ramp contains any items.
Type colorRampType() const
Returns the color ramp type.
void setSourceColorRamp(QgsColorRamp *colorramp)
Set the source color ramp.
QList< QgsColorRampShader::ColorRampItem > colorRampItemList() const
Returns the custom colormap.
ClassificationMode
Classification modes used to create the color ramp shader.
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.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context=QgsReadWriteContext()) const
Writes configuration to a new DOM element.
bool shade(double value, int *returnRedValue, int *returnGreenValue, int *returnBlueValue, int *returnAlphaValue) const override
Generates and new RGB value based on one input value.
QgsColorRamp * sourceColorRamp() const
Returns the source color ramp.
Type
Supported methods for color interpolation.
@ Interpolated
Interpolates the color between two class breaks linearly.
@ Discrete
Assigns the color of the higher class for every pixel between two class breaks.
@ Exact
Assigns the color of the exact matching value in the color ramp item list.
void setClassificationMode(ClassificationMode classificationMode)
Sets classification mode.
void setColorRampItemList(const QList< QgsColorRampShader::ColorRampItem > &list)
Sets a custom colormap.
void setColorRampType(QgsColorRampShader::Type colorRampType)
Sets the color ramp type.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context=QgsReadWriteContext())
Reads configuration from the given DOM element.
Abstract base class for color ramps.
Definition: qgscolorramp.h:29
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:56
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.
Definition: qgsgeometry.h:162
QPolygonF asQPolygonF() const
Returns contents of the geometry as a QPolygonF.
double length() const
Returns the planar, 2-dimensional length of geometry.
Class defining color to render 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.
A symbol layer that represents vector layer line feature as interpolated line The interpolation is do...
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 than 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.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:39
QgsPointXY transform(const QgsPointXY &p) const
Transforms a point p from map (world) coordinates to device coordinates.
Definition: qgsmaptopixel.h:88
A class to represent a 2D point.
Definition: qgspointxy.h:60
QPointF toQPointF() const
Converts a point to a QPointF.
Definition: qgspointxy.h:166
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
bool isActive(int key) const final
Returns true if the collection contains an active property with the specified key.
QgsProperty property(int key) const final
Returns a matching property from the collection, if one exists.
A store for object properties.
Definition: qgsproperty.h:228
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
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.
The class is used as a container of context for various read/write operations on other 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.
Definition: qgsstyle.cpp:1189
static QgsStyle * defaultStyle(bool initialize=true)
Returns the default application-wide style.
Definition: qgsstyle.cpp:145
static QVariant colorRampToVariant(const QString &name, QgsColorRamp *ramp)
Saves a color ramp to a QVariantMap, wrapped in a QVariant.
static 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 (since QGIS 3.22)
@ LineStartColorValue
Start line color for interpolated line renderer (since QGIS 3.22)
@ LineEndWidthValue
End line width for interpolated line renderer (since QGIS 3.22)
@ LineStartWidthValue
Start line width for interpolated line renderer (since QGIS 3.22)
virtual void setDataDefinedProperty(Property key, const QgsProperty &property)
Sets a data defined property for the layer.
void copyPaintEffect(QgsSymbolLayer *destLayer) const
Copies paint effect of this layer to another symbol layer.
QgsPropertyCollection mDataDefinedProperties
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:5853
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:5207