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