QGIS API Documentation 3.41.0-Master (fda2aa46e9a)
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
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
35
37{
38 mStrokeColoring = strokeColoring;
39}
40
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
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
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
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
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() == Qgis::ShaderInterpolationMethod::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() == Qgis::ShaderInterpolationMethod::Linear );
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() == Qgis::ShaderInterpolationMethod::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
811
815
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
875
877{
878 QVariantMap props;
879
880 // Line width varying
881 props.insert( QStringLiteral( "line_width" ), QString::number( mLineRender.mStrokeWidth.fixedStrokeWidth() ) );
882 props.insert( QStringLiteral( "line_width_unit" ), QgsUnitTypes::encodeUnit( mLineRender.widthUnit() ) );
883 props.insert( QStringLiteral( "width_varying_minimum_value" ), mLineRender.mStrokeWidth.minimumValue() );
884 props.insert( QStringLiteral( "width_varying_maximum_value" ), mLineRender.mStrokeWidth.maximumValue() );
885 props.insert( QStringLiteral( "width_varying_use_absolute_value" ), mLineRender.mStrokeWidth.useAbsoluteValue() ? 1 : 0 );
886 props.insert( QStringLiteral( "width_varying_minimum_width" ), mLineRender.mStrokeWidth.minimumWidth() );
887 props.insert( QStringLiteral( "width_varying_maximum_width" ), mLineRender.mStrokeWidth.maximumWidth() );
888 props.insert( QStringLiteral( "width_varying_ignore_out_of_range" ), mLineRender.mStrokeWidth.ignoreOutOfRange() ? 1 : 0 );
889 props.insert( QStringLiteral( "width_varying_is_variable_width" ), mLineRender.mStrokeWidth.isVariableWidth() ? 1 : 0 );
890
891 // Color varying
892 props.insert( QStringLiteral( "coloring_method" ), mLineRender.mStrokeColoring.coloringMethod() );
893 props.insert( QStringLiteral( "single_color" ), QgsColorUtils::colorToString( mLineRender.mStrokeColoring.singleColor() ) );
894 props.insert( QStringLiteral( "color_ramp_shader" ), colorRampShaderProperties() );
895
896 return props;
897}
898
900{
901 QgsGeometry geometry = context.patchShape() ? context.patchShape()->geometry()
903
904 startRender( context );
905 double min = std::min( mLineRender.interpolatedLineWidth().minimumValue(), mLineRender.interpolatedColor().colorRampShader().minimumValue() );
906 double max = std::max( mLineRender.interpolatedLineWidth().maximumValue(), mLineRender.interpolatedColor().colorRampShader().maximumValue() );
907
908 double totalLength = geometry.length();
909 if ( qgsDoubleNear( totalLength, 0 ) )
910 return;
911
912 double variation = ( max - min ) / totalLength;
913
914 QPolygonF points = geometry.asQPolygonF();
915 double lengthFromStart = 0;
916 for ( int i = 1; i < points.count(); ++i )
917 {
918 QPointF p1 = points.at( i - 1 );
919 QPointF p2 = points.at( i );
920
921 double v1 = min + variation * lengthFromStart;
922 QPointF vectDist = p2 - p1;
923 lengthFromStart += sqrt( pow( vectDist.x(), 2 ) + pow( vectDist.y(), 2 ) );
924 double v2 = min + variation * lengthFromStart;
925 mLineRender.renderInDeviceCoordinates( v1, v2, v1, v2, p1, p2, context.renderContext() );
926 }
927
928 renderPolyline( points, context );
929
930}
931
933{
934 switch ( mLineRender.interpolatedColor().coloringMethod() )
935 {
937 return mLineRender.interpolatedColor().singleColor();
939 return QColor();
940 }
942}
943
944
957
962
967
968void QgsInterpolatedLineSymbolLayer::setWidthUnit( Qgis::RenderUnit strokeWidthUnit ) // cppcheck-suppress duplInheritedMember
969{
970 mLineRender.mStrokeWidthUnit = strokeWidthUnit;
971}
972
973Qgis::RenderUnit QgsInterpolatedLineSymbolLayer::widthUnit() const {return mLineRender.widthUnit();} // cppcheck-suppress duplInheritedMember
974
976{
977 mLineRender.mStrokeWidth = interpolatedLineWidth;
978}
979
981
994
999
1004
1006{
1007 mLineRender.setInterpolatedColor( interpolatedLineColor );
1008}
1009
1014
1015QVariant QgsInterpolatedLineSymbolLayer::colorRampShaderProperties() const
1016{
1017 const QgsColorRampShader &colorRampShader = mLineRender.mStrokeColoring.colorRampShader();
1018
1019 QVariantMap props;
1020 if ( colorRampShader.sourceColorRamp() )
1021 props.insert( QStringLiteral( "color_ramp_source" ), QgsSymbolLayerUtils::colorRampToVariant( QString(), colorRampShader.sourceColorRamp() ) );
1022 props.insert( QStringLiteral( "color_ramp_shader_type" ), static_cast< int >( colorRampShader.colorRampType() ) );
1023 props.insert( QStringLiteral( "color_ramp_shader_classification_mode" ), static_cast< int >( colorRampShader.classificationMode() ) );
1024 QVariantList colorRampItemListVariant;
1025
1026 const QList<QgsColorRampShader::ColorRampItem> colorRampItemList = colorRampShader.colorRampItemList();
1027 for ( const QgsColorRampShader::ColorRampItem &item : colorRampItemList )
1028 {
1029 QVariantMap itemVar;
1030 itemVar[QStringLiteral( "label" )] = item.label;
1031 itemVar[QStringLiteral( "color" )] = QgsColorUtils::colorToString( item.color );
1032 itemVar[QStringLiteral( "value" )] = item.value;
1033 colorRampItemListVariant.append( itemVar );
1034 }
1035 props.insert( QStringLiteral( "color_ramp_shader_items_list" ), colorRampItemListVariant );
1036
1037 props.insert( QStringLiteral( "color_ramp_shader_minimum_value" ), colorRampShader.minimumValue() );
1038 props.insert( QStringLiteral( "color_ramp_shader_maximum_value" ), colorRampShader.maximumValue() );
1039 props.insert( QStringLiteral( "color_ramp_shader_value_out_of_range" ), colorRampShader.clip() ? 1 : 0 );
1040 props.insert( QStringLiteral( "color_ramp_shader_label_precision" ), colorRampShader.labelPrecision() );
1041
1042 return props;
1043}
1044
1045QgsColorRampShader QgsInterpolatedLineSymbolLayer::createColorRampShaderFromProperties( const QVariant &properties )
1046{
1047 QgsColorRampShader colorRampShader;
1048
1049 if ( properties.userType() != QMetaType::Type::QVariantMap )
1050 return colorRampShader;
1051
1052 QVariantMap shaderVariantMap = properties.toMap();
1053
1054 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_source" ) ) )
1055 colorRampShader.setSourceColorRamp( QgsSymbolLayerUtils::loadColorRamp( shaderVariantMap.value( QStringLiteral( "color_ramp_source" ) ) ) );
1056
1057 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_type" ) ) )
1058 colorRampShader.setColorRampType( static_cast<Qgis::ShaderInterpolationMethod>( shaderVariantMap.value( QStringLiteral( "color_ramp_shader_type" ) ).toInt() ) );
1059 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_classification_mode" ) ) )
1060 colorRampShader.setClassificationMode( static_cast<Qgis::ShaderClassificationMethod>(
1061 shaderVariantMap.value( QStringLiteral( "color_ramp_shader_classification_mode" ) ).toInt() ) );
1062
1063 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_items_list" ) ) )
1064 {
1065 QVariant colorRampItemsVar = shaderVariantMap.value( QStringLiteral( "color_ramp_shader_items_list" ) );
1066 if ( colorRampItemsVar.userType() == QMetaType::Type::QVariantList )
1067 {
1068 QVariantList itemVariantList = colorRampItemsVar.toList();
1069 QList<QgsColorRampShader::ColorRampItem> colorRampItemList;
1070 for ( const QVariant &itemVar : std::as_const( itemVariantList ) )
1071 {
1073 if ( itemVar.userType() != QMetaType::Type::QVariantMap )
1074 continue;
1075 QVariantMap itemVarMap = itemVar.toMap();
1076 if ( !itemVarMap.contains( QStringLiteral( "label" ) ) || !itemVarMap.contains( QStringLiteral( "color" ) ) || !itemVarMap.contains( QStringLiteral( "value" ) ) )
1077 continue;
1078
1079 item.label = itemVarMap.value( QStringLiteral( "label" ) ).toString();
1080 item.color = QgsColorUtils::colorFromString( itemVarMap.value( QStringLiteral( "color" ) ).toString() );
1081 item.value = itemVarMap.value( QStringLiteral( "value" ) ).toDouble();
1082
1083 colorRampItemList.append( item );
1084 }
1085 colorRampShader.setColorRampItemList( colorRampItemList );
1086 }
1087 }
1088
1089 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_minimum_value" ) ) )
1090 colorRampShader.setMinimumValue( shaderVariantMap.value( QStringLiteral( "color_ramp_shader_minimum_value" ) ).toDouble() );
1091 else
1092 colorRampShader.setMinimumValue( std::numeric_limits<double>::quiet_NaN() );
1093
1094 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_maximum_value" ) ) )
1095 colorRampShader.setMaximumValue( shaderVariantMap.value( QStringLiteral( "color_ramp_shader_maximum_value" ) ).toDouble() );
1096 else
1097 colorRampShader.setMaximumValue( std::numeric_limits<double>::quiet_NaN() );
1098
1099 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_value_out_of_range" ) ) )
1100 colorRampShader.setClip( shaderVariantMap.value( QStringLiteral( "color_ramp_shader_value_out_of_range" ) ).toInt() == 1 );
1101 if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_label_precision" ) ) )
1102 colorRampShader.setLabelPrecision( shaderVariantMap.value( QStringLiteral( "color_ramp_shader_label_precision" ) ).toInt() );
1103
1104 return colorRampShader;
1105}
1106
1108
1109
1111{
1112 mRenderingFeature = true;
1113 mLineParts.clear();
1114}
1115
1117{
1118 mRenderingFeature = false;
1119
1120 if ( mLineParts.empty() )
1121 return;
1122
1123 render( mLineParts, context );
1124 mLineParts.clear();
1125}
1126
1127void QgsInterpolatedLineSymbolLayer::render( const QVector< QPolygonF > &parts, QgsRenderContext &context )
1128{
1129 const double totalLength = std::accumulate( parts.begin(), parts.end(), 0.0, []( double total, const QPolygonF & part )
1130 {
1131 return total + QgsSymbolLayerUtils::polylineLength( part );
1132 } );
1133
1134 if ( qgsDoubleNear( totalLength, 0 ) )
1135 return;
1136
1137 double startValWidth = 0;
1138 double variationPerMapUnitWidth = 0;
1139 double startValColor = 0;
1140 double variationPerMapUnitColor = 0;
1141
1142 bool ok = true;
1143
1144 if ( mLineRender.interpolatedLineWidth().isVariableWidth() )
1145 {
1147 {
1149 if ( !ok )
1150 return;
1151 }
1152
1153 double endValWidth = 0;
1155 {
1157 if ( !ok )
1158 return;
1159 }
1160
1161 variationPerMapUnitWidth = ( endValWidth - startValWidth ) / totalLength;
1162 }
1163
1165 {
1167 {
1169 if ( !ok )
1170 return;
1171 }
1172
1173 double endValColor = 0;
1175 {
1177 if ( !ok )
1178 return;
1179 }
1180
1181 variationPerMapUnitColor = ( endValColor - startValColor ) / totalLength;
1182 }
1183
1184 for ( const QPolygonF &poly : parts )
1185 {
1186 double lengthFromStart = 0;
1187 for ( int i = 1; i < poly.count(); ++i )
1188 {
1189 const QPointF p1 = poly.at( i - 1 );
1190 const QPointF p2 = poly.at( i );
1191
1192 const double v1c = startValColor + variationPerMapUnitColor * lengthFromStart;
1193 const double v1w = startValWidth + variationPerMapUnitWidth * lengthFromStart;
1194 lengthFromStart += QgsGeometryUtilsBase::distance2D( p1.x(), p1.y(), p2.x(), p2.y() );
1195 const double v2c = startValColor + variationPerMapUnitColor * lengthFromStart;
1196 const double v2w = startValWidth + variationPerMapUnitWidth * lengthFromStart;
1197 mLineRender.renderInDeviceCoordinates( v1c, v2c, v1w, v2w, p1, p2, context );
1198 }
1199 }
1200}
1201
1203{
1204 mLineRender.setSelected( context.selected() );
1205
1206 if ( points.empty() )
1207 return;
1208
1209 if ( mRenderingFeature )
1210 {
1211 // in the middle of rendering a possibly multi-part feature, so we collect all the parts and defer the actual rendering
1212 // until after we've received the final part
1213 mLineParts.append( points );
1214 }
1215 else
1216 {
1217 // not rendering a feature, so we can just render the polyline immediately
1218 render( { points }, context.renderContext() );
1219 }
1220}
1221
@ DisableFeatureClipping
If present, indicates that features should never be clipped to the map extent during rendering.
@ CanCalculateMaskGeometryPerFeature
If present, indicates that mask geometry can safely be calculated per feature for the symbol layer....
ShaderInterpolationMethod
Color ramp shader interpolation methods.
Definition qgis.h:1335
@ Exact
Assigns the color of the exact matching value in the color ramp item list.
@ Linear
Interpolates the color between two class breaks linearly.
@ Discrete
Assigns the color of the higher class for every pixel between two class breaks.
QFlags< SymbolLayerFlag > SymbolLayerFlags
Symbol layer flags.
Definition qgis.h:821
ShaderClassificationMethod
Color ramp shader classification methods.
Definition qgis.h:1350
RenderUnit
Rendering size units.
Definition qgis.h:4839
@ 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.
Qgis::ShaderClassificationMethod classificationMode() const
Returns the classification mode.
Qgis::ShaderInterpolationMethod colorRampType() const
Returns the color ramp interpolation method.
bool isEmpty() const
Whether the color ramp contains any items.
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.
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 an new RGBA value based on one input value.
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.
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.
Abstract base class for line symbol layers.
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.
A class to represent a 2D point.
Definition qgspointxy.h:60
QPointF toQPointF() const
Converts a point to a QPointF.
Definition qgspointxy.h:165
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.
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.
static QgsStyle * defaultStyle(bool initialize=true)
Returns the default application-wide style.
Definition qgsstyle.cpp:146
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.
@ LineStartColorValue
Start line color for interpolated line renderer.
@ LineEndWidthValue
End line width for interpolated line renderer.
@ LineStartWidthValue
Start line width for interpolated line renderer.
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.
virtual Qgis::SymbolLayerFlags flags() const
Returns flags which control the symbol layer's behavior.
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:6571
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:5917