QGIS API Documentation 3.99.0-Master (8e76e220402)
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
827
829{
830 std::unique_ptr<QgsInterpolatedLineSymbolLayer> symbolLayer;
831 symbolLayer = std::make_unique<QgsInterpolatedLineSymbolLayer>( );
832
833 if ( properties.contains( u"start_width_expression"_s ) )
834 symbolLayer->setDataDefinedProperty( QgsSymbolLayer::Property::LineStartWidthValue, QgsProperty::fromExpression( properties.value( u"start_width_expression"_s ).toString() ) );
835 if ( properties.contains( u"end_width_expression"_s ) )
836 symbolLayer->setDataDefinedProperty( QgsSymbolLayer::Property::LineEndWidthValue, QgsProperty::fromExpression( properties.value( u"end_width_expression"_s ).toString() ) );
837
838 if ( properties.contains( u"start_color_expression"_s ) )
839 symbolLayer->setDataDefinedProperty( QgsSymbolLayer::Property::LineStartColorValue, QgsProperty::fromExpression( properties.value( u"start_color_expression"_s ).toString() ) );
840 if ( properties.contains( u"end_color_expression"_s ) )
841 symbolLayer->setDataDefinedProperty( QgsSymbolLayer::Property::LineEndColorValue, QgsProperty::fromExpression( properties.value( u"end_color_expression"_s ).toString() ) );
842
843 if ( properties.contains( u"line_width"_s ) )
844 symbolLayer->mLineRender.mStrokeWidth.setFixedStrokeWidth( properties.value( u"line_width"_s ).toDouble() ) ;
845 if ( properties.contains( u"line_width_unit"_s ) )
846 symbolLayer->mLineRender.setWidthUnit( QgsUnitTypes::decodeRenderUnit( properties.value( u"line_width_unit"_s ).toString() ) );
847 if ( properties.contains( u"width_varying_minimum_value"_s ) )
848 symbolLayer->mLineRender.mStrokeWidth.setMinimumValue( properties.value( u"width_varying_minimum_value"_s ).toDouble() );
849 if ( properties.contains( u"width_varying_maximum_value"_s ) )
850 symbolLayer->mLineRender.mStrokeWidth.setMaximumValue( properties.value( u"width_varying_maximum_value"_s ).toDouble() );
851 if ( properties.contains( u"width_varying_use_absolute_value"_s ) )
852 symbolLayer->mLineRender.mStrokeWidth.setUseAbsoluteValue( properties.value( u"width_varying_use_absolute_value"_s ).toInt() );
853 if ( properties.contains( u"width_varying_minimum_width"_s ) )
854 symbolLayer->mLineRender.mStrokeWidth.setMinimumWidth( properties.value( u"width_varying_minimum_width"_s ).toDouble() );
855 if ( properties.contains( u"width_varying_maximum_width"_s ) )
856 symbolLayer->mLineRender.mStrokeWidth.setMaximumWidth( properties.value( u"width_varying_maximum_width"_s ).toDouble() );
857 if ( properties.contains( u"width_varying_ignore_out_of_range"_s ) )
858 symbolLayer->mLineRender.mStrokeWidth.setIgnoreOutOfRange( properties.value( u"width_varying_ignore_out_of_range"_s ).toInt() );
859 if ( properties.contains( u"width_varying_is_variable_width"_s ) )
860 symbolLayer->mLineRender.mStrokeWidth.setIsVariableWidth( properties.value( u"width_varying_is_variable_width"_s ).toInt() );
861
862 if ( properties.contains( u"single_color"_s ) )
863 symbolLayer->mLineRender.mStrokeColoring.setColor( QgsColorUtils::colorFromString( properties.value( u"single_color"_s ).toString() ) );
864 if ( properties.contains( u"color_ramp_shader"_s ) )
865 symbolLayer->mLineRender.mStrokeColoring.setColor( createColorRampShaderFromProperties( properties.value( u"color_ramp_shader"_s ) ) );
866 if ( properties.contains( u"coloring_method"_s ) )
867 symbolLayer->mLineRender.mStrokeColoring.setColoringMethod(
868 static_cast<QgsInterpolatedLineColor::ColoringMethod>( properties.value( u"coloring_method"_s ).toInt() ) );
869
870 return symbolLayer.release();
871}
872
879
881{
882 QVariantMap props;
883
884 // Line width varying
885 props.insert( u"line_width"_s, QString::number( mLineRender.mStrokeWidth.fixedStrokeWidth() ) );
886 props.insert( u"line_width_unit"_s, QgsUnitTypes::encodeUnit( mLineRender.widthUnit() ) );
887 props.insert( u"width_varying_minimum_value"_s, mLineRender.mStrokeWidth.minimumValue() );
888 props.insert( u"width_varying_maximum_value"_s, mLineRender.mStrokeWidth.maximumValue() );
889 props.insert( u"width_varying_use_absolute_value"_s, mLineRender.mStrokeWidth.useAbsoluteValue() ? 1 : 0 );
890 props.insert( u"width_varying_minimum_width"_s, mLineRender.mStrokeWidth.minimumWidth() );
891 props.insert( u"width_varying_maximum_width"_s, mLineRender.mStrokeWidth.maximumWidth() );
892 props.insert( u"width_varying_ignore_out_of_range"_s, mLineRender.mStrokeWidth.ignoreOutOfRange() ? 1 : 0 );
893 props.insert( u"width_varying_is_variable_width"_s, mLineRender.mStrokeWidth.isVariableWidth() ? 1 : 0 );
894
895 // Color varying
896 props.insert( u"coloring_method"_s, mLineRender.mStrokeColoring.coloringMethod() );
897 props.insert( u"single_color"_s, QgsColorUtils::colorToString( mLineRender.mStrokeColoring.singleColor() ) );
898 props.insert( u"color_ramp_shader"_s, colorRampShaderProperties() );
899
900 return props;
901}
902
904{
905 QgsGeometry geometry = context.patchShape() ? context.patchShape()->geometry()
907
908 startRender( context );
909 double min = std::min( mLineRender.interpolatedLineWidth().minimumValue(), mLineRender.interpolatedColor().colorRampShader().minimumValue() );
910 double max = std::max( mLineRender.interpolatedLineWidth().maximumValue(), mLineRender.interpolatedColor().colorRampShader().maximumValue() );
911
912 double totalLength = geometry.length();
913 if ( qgsDoubleNear( totalLength, 0 ) )
914 return;
915
916 double variation = ( max - min ) / totalLength;
917
918 QPolygonF points = geometry.asQPolygonF();
919 double lengthFromStart = 0;
920 for ( int i = 1; i < points.count(); ++i )
921 {
922 QPointF p1 = points.at( i - 1 );
923 QPointF p2 = points.at( i );
924
925 double v1 = min + variation * lengthFromStart;
926 QPointF vectDist = p2 - p1;
927 lengthFromStart += sqrt( pow( vectDist.x(), 2 ) + pow( vectDist.y(), 2 ) );
928 double v2 = min + variation * lengthFromStart;
929 mLineRender.renderInDeviceCoordinates( v1, v2, v1, v2, p1, p2, context.renderContext() );
930 }
931
932 renderPolyline( points, context );
933
934}
935
937{
938 switch ( mLineRender.interpolatedColor().coloringMethod() )
939 {
941 return mLineRender.interpolatedColor().singleColor();
943 return QColor();
944 }
946}
947
948
961
966
971
972void QgsInterpolatedLineSymbolLayer::setWidthUnit( Qgis::RenderUnit strokeWidthUnit ) // cppcheck-suppress duplInheritedMember
973{
974 mLineRender.mStrokeWidthUnit = strokeWidthUnit;
975}
976
977Qgis::RenderUnit QgsInterpolatedLineSymbolLayer::widthUnit() const {return mLineRender.widthUnit();} // cppcheck-suppress duplInheritedMember
978
980{
981 mLineRender.mStrokeWidth = interpolatedLineWidth;
982}
983
984QgsInterpolatedLineWidth QgsInterpolatedLineSymbolLayer::interpolatedWidth() const { return mLineRender.interpolatedLineWidth();}
985
998
1003
1008
1010{
1011 mLineRender.setInterpolatedColor( interpolatedLineColor );
1012}
1013
1015{
1016 return mLineRender.interpolatedColor();
1017}
1018
1019QVariant QgsInterpolatedLineSymbolLayer::colorRampShaderProperties() const
1020{
1021 const QgsColorRampShader &colorRampShader = mLineRender.mStrokeColoring.colorRampShader();
1022
1023 QVariantMap props;
1024 if ( colorRampShader.sourceColorRamp() )
1025 props.insert( u"color_ramp_source"_s, QgsSymbolLayerUtils::colorRampToVariant( QString(), colorRampShader.sourceColorRamp() ) );
1026 props.insert( u"color_ramp_shader_type"_s, static_cast< int >( colorRampShader.colorRampType() ) );
1027 props.insert( u"color_ramp_shader_classification_mode"_s, static_cast< int >( colorRampShader.classificationMode() ) );
1028 QVariantList colorRampItemListVariant;
1029
1030 const QList<QgsColorRampShader::ColorRampItem> colorRampItemList = colorRampShader.colorRampItemList();
1031 for ( const QgsColorRampShader::ColorRampItem &item : colorRampItemList )
1032 {
1033 QVariantMap itemVar;
1034 itemVar[u"label"_s] = item.label;
1035 itemVar[u"color"_s] = QgsColorUtils::colorToString( item.color );
1036 itemVar[u"value"_s] = item.value;
1037 colorRampItemListVariant.append( itemVar );
1038 }
1039 props.insert( u"color_ramp_shader_items_list"_s, colorRampItemListVariant );
1040
1041 props.insert( u"color_ramp_shader_minimum_value"_s, colorRampShader.minimumValue() );
1042 props.insert( u"color_ramp_shader_maximum_value"_s, colorRampShader.maximumValue() );
1043 props.insert( u"color_ramp_shader_value_out_of_range"_s, colorRampShader.clip() ? 1 : 0 );
1044 props.insert( u"color_ramp_shader_label_precision"_s, colorRampShader.labelPrecision() );
1045
1046 return props;
1047}
1048
1049QgsColorRampShader QgsInterpolatedLineSymbolLayer::createColorRampShaderFromProperties( const QVariant &properties )
1050{
1051 QgsColorRampShader colorRampShader;
1052
1053 if ( properties.userType() != QMetaType::Type::QVariantMap )
1054 return colorRampShader;
1055
1056 QVariantMap shaderVariantMap = properties.toMap();
1057
1058 if ( shaderVariantMap.contains( u"color_ramp_source"_s ) )
1059 colorRampShader.setSourceColorRamp( QgsSymbolLayerUtils::loadColorRamp( shaderVariantMap.value( u"color_ramp_source"_s ) ).release() );
1060
1061 if ( shaderVariantMap.contains( u"color_ramp_shader_type"_s ) )
1062 colorRampShader.setColorRampType( static_cast<Qgis::ShaderInterpolationMethod>( shaderVariantMap.value( u"color_ramp_shader_type"_s ).toInt() ) );
1063 if ( shaderVariantMap.contains( u"color_ramp_shader_classification_mode"_s ) )
1064 colorRampShader.setClassificationMode( static_cast<Qgis::ShaderClassificationMethod>(
1065 shaderVariantMap.value( u"color_ramp_shader_classification_mode"_s ).toInt() ) );
1066
1067 if ( shaderVariantMap.contains( u"color_ramp_shader_items_list"_s ) )
1068 {
1069 QVariant colorRampItemsVar = shaderVariantMap.value( u"color_ramp_shader_items_list"_s );
1070 if ( colorRampItemsVar.userType() == QMetaType::Type::QVariantList )
1071 {
1072 QVariantList itemVariantList = colorRampItemsVar.toList();
1073 QList<QgsColorRampShader::ColorRampItem> colorRampItemList;
1074 for ( const QVariant &itemVar : std::as_const( itemVariantList ) )
1075 {
1076 QgsColorRampShader::ColorRampItem item;
1077 if ( itemVar.userType() != QMetaType::Type::QVariantMap )
1078 continue;
1079 QVariantMap itemVarMap = itemVar.toMap();
1080 if ( !itemVarMap.contains( u"label"_s ) || !itemVarMap.contains( u"color"_s ) || !itemVarMap.contains( u"value"_s ) )
1081 continue;
1082
1083 item.label = itemVarMap.value( u"label"_s ).toString();
1084 item.color = QgsColorUtils::colorFromString( itemVarMap.value( u"color"_s ).toString() );
1085 item.value = itemVarMap.value( u"value"_s ).toDouble();
1086
1087 colorRampItemList.append( item );
1088 }
1089 colorRampShader.setColorRampItemList( colorRampItemList );
1090 }
1091 }
1092
1093 if ( shaderVariantMap.contains( u"color_ramp_shader_minimum_value"_s ) )
1094 colorRampShader.setMinimumValue( shaderVariantMap.value( u"color_ramp_shader_minimum_value"_s ).toDouble() );
1095 else
1096 colorRampShader.setMinimumValue( std::numeric_limits<double>::quiet_NaN() );
1097
1098 if ( shaderVariantMap.contains( u"color_ramp_shader_maximum_value"_s ) )
1099 colorRampShader.setMaximumValue( shaderVariantMap.value( u"color_ramp_shader_maximum_value"_s ).toDouble() );
1100 else
1101 colorRampShader.setMaximumValue( std::numeric_limits<double>::quiet_NaN() );
1102
1103 if ( shaderVariantMap.contains( u"color_ramp_shader_value_out_of_range"_s ) )
1104 colorRampShader.setClip( shaderVariantMap.value( u"color_ramp_shader_value_out_of_range"_s ).toInt() == 1 );
1105 if ( shaderVariantMap.contains( u"color_ramp_shader_label_precision"_s ) )
1106 colorRampShader.setLabelPrecision( shaderVariantMap.value( u"color_ramp_shader_label_precision"_s ).toInt() );
1107
1108 return colorRampShader;
1109}
1110
1112
1113
1115{
1116 mRenderingFeature = true;
1117 mLineParts.clear();
1118}
1119
1121{
1122 mRenderingFeature = false;
1123
1124 if ( mLineParts.empty() )
1125 return;
1126
1127 render( mLineParts, context );
1128 mLineParts.clear();
1129}
1130
1131void QgsInterpolatedLineSymbolLayer::render( const QVector< QPolygonF > &parts, QgsRenderContext &context )
1132{
1133 const double totalLength = std::accumulate( parts.begin(), parts.end(), 0.0, []( double total, const QPolygonF & part )
1134 {
1135 return total + QgsSymbolLayerUtils::polylineLength( part );
1136 } );
1137
1138 if ( qgsDoubleNear( totalLength, 0 ) )
1139 return;
1140
1141 double startValWidth = 0;
1142 double variationPerMapUnitWidth = 0;
1143 double startValColor = 0;
1144 double variationPerMapUnitColor = 0;
1145
1146 bool ok = true;
1147
1148 if ( mLineRender.interpolatedLineWidth().isVariableWidth() )
1149 {
1151 {
1153 if ( !ok )
1154 return;
1155 }
1156
1157 double endValWidth = 0;
1159 {
1160 endValWidth = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::Property::LineEndWidthValue, context.expressionContext(), 0, &ok );
1161 if ( !ok )
1162 return;
1163 }
1164
1165 variationPerMapUnitWidth = ( endValWidth - startValWidth ) / totalLength;
1166 }
1167
1168 if ( mLineRender.interpolatedColor().coloringMethod() == QgsInterpolatedLineColor::ColorRamp )
1169 {
1171 {
1172 startValColor = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::Property::LineStartColorValue, context.expressionContext(), 0, &ok );
1173 if ( !ok )
1174 return;
1175 }
1176
1177 double endValColor = 0;
1179 {
1180 endValColor = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::Property::LineEndColorValue, context.expressionContext(), 0, &ok );
1181 if ( !ok )
1182 return;
1183 }
1184
1185 variationPerMapUnitColor = ( endValColor - startValColor ) / totalLength;
1186 }
1187
1188 for ( const QPolygonF &poly : parts )
1189 {
1190 double lengthFromStart = 0;
1191 for ( int i = 1; i < poly.count(); ++i )
1192 {
1193 const QPointF p1 = poly.at( i - 1 );
1194 const QPointF p2 = poly.at( i );
1195
1196 const double v1c = startValColor + variationPerMapUnitColor * lengthFromStart;
1197 const double v1w = startValWidth + variationPerMapUnitWidth * lengthFromStart;
1198 lengthFromStart += QgsGeometryUtilsBase::distance2D( p1.x(), p1.y(), p2.x(), p2.y() );
1199 const double v2c = startValColor + variationPerMapUnitColor * lengthFromStart;
1200 const double v2w = startValWidth + variationPerMapUnitWidth * lengthFromStart;
1201 mLineRender.renderInDeviceCoordinates( v1c, v2c, v1w, v2w, p1, p2, context );
1202 }
1203 }
1204}
1205
1207{
1208 mLineRender.setSelected( context.selected() );
1209
1210 if ( points.empty() )
1211 return;
1212
1213 if ( mRenderingFeature )
1214 {
1215 // in the middle of rendering a possibly multi-part feature, so we collect all the parts and defer the actual rendering
1216 // until after we've received the final part
1217 mLineParts.append( points );
1218 }
1219 else
1220 {
1221 // not rendering a feature, so we can just render the polyline immediately
1222 render( { points }, context.renderContext() );
1223 }
1224}
1225
@ 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:5290
@ 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 copyCommonProperties(QgsSymbolLayer *destLayer) const
Copies all common base class properties from this layer to another symbol layer.
@ LineEndColorValue
End line color for interpolated line renderer.
@ LineStartColorValue
Start line color for interpolated line renderer.
@ LineEndWidthValue
End line width for interpolated line renderer.
@ LineStartWidthValue
Start line width for interpolated line renderer.
virtual 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:7524
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6935