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