QGIS API Documentation 4.3.0-Master (0ad0cdb9438)
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 "qgspainting.h"
23#include "qgsstyle.h"
24#include "qgssymbollayerutils.h"
25#include "qgsunittypes.h"
26
27#include <QPainter>
28#include <QString>
29
30using namespace Qt::StringLiterals;
31
33{
34 mStrokeWidth = strokeWidth;
35}
36
41
43{
44 mStrokeColoring = strokeColoring;
45}
46
51
53{
54 mStrokeWidthUnit = strokeWidthUnit;
55}
56
58{
59 return mStrokeWidthUnit;
60}
61
62void QgsInterpolatedLineRenderer::renderInDeviceCoordinates( double valueColor1, double valueColor2, double valueWidth1, double valueWidth2, QPointF p1, QPointF p2, QgsRenderContext &context ) const
63{
64 QPainter *painter = context.painter();
65 QgsScopedQPainterState painterState( painter );
66 context.setPainterFlagsUsingContext( painter );
67
68 QPointF dir = p2 - p1;
69 double length = sqrt( pow( dir.x(), 2 ) + pow( dir.y(), 2 ) );
70 QPointF diru = dir / length;
71 QPointF orthu = QPointF( -diru.y(), diru.x() );
72
73 QList<double> breakValues;
74 QList<QColor> breakColors;
75 QList<QLinearGradient> gradients;
76
77 mStrokeColoring.graduatedColors( valueColor1, valueColor2, breakValues, breakColors, gradients );
78 QColor selectedColor = context.selectionColor();
79
80 if ( gradients.isEmpty() && !breakValues.empty() && !breakColors.isEmpty() ) //exact colors to render
81 {
82 Q_ASSERT( breakColors.count() == breakValues.count() );
83 for ( int i = 0; i < breakValues.count(); ++i )
84 {
85 const bool widthIsInverted { valueWidth1 > valueWidth2 };
86 const double value = breakValues.at( i );
87 const double width = context.convertToPainterUnits( mStrokeWidth.strokeWidth( widthIsInverted ? mStrokeWidth.maximumValue() - value : value ), mStrokeWidthUnit );
88 QPen pen( mSelected ? selectedColor : breakColors.at( i ) );
89 pen.setWidthF( width );
90 pen.setCapStyle( Qt::PenCapStyle::RoundCap );
91 painter->setPen( pen );
92 const QPointF point = p1 + dir * ( value - valueColor1 ) / ( valueColor2 - valueColor1 );
93 painter->drawPoint( point );
94 }
95 }
96 else
97 {
98 double width1 = mStrokeWidth.strokeWidth( valueWidth1 );
99 double width2 = mStrokeWidth.strokeWidth( valueWidth2 );
100
101 if ( !std::isnan( width1 ) && !std::isnan( width2 ) ) // the two widths on extremity are not out of range and ignored
102 {
103 //Draw line cap
104 QBrush brush( Qt::SolidPattern );
105 QPen pen;
106 int startAngle;
107 startAngle = ( acos( -orthu.x() ) / M_PI ) * 180;
108 if ( orthu.y() < 0 )
109 startAngle = 360 - startAngle;
110
111 bool outOfRange1 = std::isnan( width1 );
112 bool outOfRange2 = std::isnan( width2 );
113
114 if ( !outOfRange1 )
115 {
116 width1 = context.convertToPainterUnits( width1, mStrokeWidthUnit );
117 QRectF capBox1( p1.x() - width1 / 2, p1.y() - width1 / 2, width1, width1 );
118 brush.setColor( mSelected ? selectedColor : mStrokeColoring.color( valueColor1 ) );
119 painter->setBrush( brush );
120 pen.setBrush( brush );
121 painter->setPen( pen );
122 painter->drawPie( capBox1, ( startAngle - 1 ) * 16, 182 * 16 );
123 }
124
125 if ( !outOfRange2 )
126 {
127 width2 = context.convertToPainterUnits( width2, mStrokeWidthUnit );
128 QRectF capBox2( p2.x() - width2 / 2, p2.y() - width2 / 2, width2, width2 );
129 brush.setColor( mSelected ? selectedColor : mStrokeColoring.color( valueColor2 ) );
130 pen.setBrush( brush );
131 painter->setBrush( brush );
132 painter->setPen( pen );
133 painter->drawPie( capBox2, ( startAngle + 179 ) * 16, 182 * 16 );
134 }
135
136 if ( ( gradients.isEmpty() && breakValues.empty() && breakColors.count() == 1 ) || mSelected ) //only one color to render
137 {
138 double startAdjusting = 0;
139 if ( outOfRange1 )
140 adjustLine( valueColor1, valueColor1, valueColor2, width1, startAdjusting );
141
142
143 double endAdjusting = 0;
144 if ( outOfRange2 )
145 adjustLine( valueColor2, valueColor1, valueColor2, width2, endAdjusting );
146
147 QPointF pointStartAdjusted = p1 + dir * startAdjusting;
148 QPointF pointEndAdjusted = p2 - dir * endAdjusting;
149
150 QPolygonF varLine;
151 double semiWidth1 = width1 / 2;
152 double semiWidth2 = width2 / 2;
153
154 varLine.append( pointStartAdjusted + orthu * semiWidth1 );
155 varLine.append( pointEndAdjusted + orthu * semiWidth2 );
156 varLine.append( pointEndAdjusted - orthu * semiWidth2 );
157 varLine.append( pointStartAdjusted - orthu * semiWidth1 );
158
159 QBrush brush( Qt::SolidPattern );
160 brush.setColor( mSelected ? selectedColor : breakColors.first() );
161 painter->setBrush( brush );
162 painter->setPen( pen );
163
164 QPen pen;
165 pen.setBrush( brush );
166 pen.setWidthF( 0 );
167 painter->setPen( pen );
168
169 painter->drawPolygon( varLine );
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>( elem.attribute( u"coloring-method"_s ).toInt() );
530}
531
532void QgsInterpolatedLineColor::graduatedColors( double value1, double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients ) const
533{
534 breakValues.clear();
535 breakColors.clear();
536 gradients.clear();
537 if ( mColoringMethod == SingleColor )
538 {
539 breakColors.append( mSingleColor );
540 return;
541 }
542
543 switch ( mColorRampShader.colorRampType() )
544 {
546 graduatedColorsInterpolated( value1, value2, breakValues, breakColors, gradients );
547 break;
549 graduatedColorsDiscrete( value1, value2, breakValues, breakColors, gradients );
550 break;
552 graduatedColorsExact( value1, value2, breakValues, breakColors, gradients );
553 break;
554 }
555}
556
561
562QLinearGradient QgsInterpolatedLineColor::makeSimpleLinearGradient( const QColor &color1, const QColor &color2 ) const
563{
564 QLinearGradient gradient;
565 gradient.setColorAt( 0, color1 );
566 gradient.setColorAt( 1, color2 );
567
568 return gradient;
569}
570
571int QgsInterpolatedLineColor::itemColorIndexInf( double value ) const
572{
573 QList<QgsColorRampShader::ColorRampItem> itemList = mColorRampShader.colorRampItemList();
574
575 if ( itemList.isEmpty() || itemList.first().value > value )
576 return -1;
577
578 if ( mColorRampShader.colorRampType() == Qgis::ShaderInterpolationMethod::Discrete )
579 itemList.removeLast(); //remove the inf value
580
581 if ( value > itemList.last().value )
582 return itemList.count() - 1;
583
584 int indSup = itemList.count() - 1;
585 int indInf = 0;
586
587 while ( true )
588 {
589 if ( abs( indSup - indInf ) <= 1 ) //always indSup>indInf, but abs to prevent infinity loop
590 return indInf;
591
592 int newInd = ( indInf + indSup ) / 2;
593
594 if ( std::isnan( itemList.at( newInd ).value ) )
595 return -1;
596
597 if ( itemList.at( newInd ).value <= value )
598 indInf = newInd;
599 else
600 indSup = newInd;
601 }
602}
603
604void QgsInterpolatedLineColor::graduatedColorsExact( double value1, double value2, QList<double> &breakValues, QList<QColor> &breakColors, const QList<QLinearGradient> &gradients ) const
605{
606 Q_ASSERT( mColorRampShader.colorRampType() == Qgis::ShaderInterpolationMethod::Exact );
607 Q_ASSERT( breakValues.isEmpty() );
608 Q_ASSERT( breakColors.isEmpty() );
609 Q_ASSERT( gradients.isEmpty() );
610
611 const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.colorRampItemList();
612 if ( itemList.isEmpty() )
613 return;
614
615 int index = itemColorIndexInf( value1 );
616 if ( index < 0 || !qgsDoubleNear( value1, itemList.at( index ).value ) )
617 index++;
618
619 if ( qgsDoubleNear( value1, value2 ) && qgsDoubleNear( value1, itemList.at( index ).value ) )
620 {
621 //the two value are the same and are equal to the value in the item list --> render only one color
622 breakColors.append( itemList.at( index ).color );
623 return;
624 }
625
626 while ( index < itemList.count() && itemList.at( index ).value <= value2 )
627 {
628 breakValues.append( itemList.at( index ).value );
629 breakColors.append( itemList.at( index ).color );
630 index++;
631 }
632}
633
634void QgsInterpolatedLineColor::graduatedColorsInterpolated( double value1, double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients ) const
635{
636 Q_ASSERT( mColorRampShader.colorRampType() == Qgis::ShaderInterpolationMethod::Linear );
637 Q_ASSERT( breakValues.isEmpty() );
638 Q_ASSERT( breakColors.isEmpty() );
639 Q_ASSERT( gradients.isEmpty() );
640
641
642 const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.colorRampItemList();
643 if ( itemList.empty() )
644 return;
645
646 if ( itemList.count() == 1 )
647 {
648 breakColors.append( itemList.first().color );
649 return;
650 }
651
652 if ( value2 <= itemList.first().value ) // completely out of range and less
653 {
654 if ( !mColorRampShader.clip() )
655 breakColors.append( itemList.first().color ); // render only the first color in the whole range if not clipped
656 return;
657 }
658
659 if ( value1 > itemList.last().value ) // completely out of range and greater
660 {
661 if ( !mColorRampShader.clip() )
662 breakColors.append( itemList.last().color ); // render only the last color in the whole range if not clipped
663 return;
664 }
665
666 if ( qgsDoubleNear( value1, value2 ) )
667 {
668 // the two values are the same
669 // --> render only one color
670 int r, g, b, a;
671 QColor color;
672 if ( mColorRampShader.shade( value1, &r, &g, &b, &a ) )
673 color = QColor( r, g, b, a );
674 breakColors.append( color );
675 return;
676 }
677
678 // index of the inf value of the interval where value1 is in the color ramp shader
679 int index = itemColorIndexInf( value1 );
680 if ( index < 0 ) // value1 out of range
681 {
682 QColor color = itemList.first().color;
683 breakColors.append( color );
684 if ( mColorRampShader.clip() ) // The first value/color returned is the first of the item list
685 breakValues.append( itemList.first().value );
686 else // The first value/color returned is the first color of the item list and value1
687 breakValues.append( value1 );
688 }
689 else
690 {
691 // shade the color
692 int r, g, b, a;
693 QColor color;
694 if ( mColorRampShader.shade( value1, &r, &g, &b, &a ) )
695 color = QColor( r, g, b, a );
696 breakValues.append( value1 );
697 breakColors.append( color );
698 }
699
700 index++; // increment the index before go through the intervals
701
702 while ( index < itemList.count() && itemList.at( index ).value < value2 )
703 {
704 QColor color1 = breakColors.last();
705 QColor color2 = itemList.at( index ).color;
706 breakValues.append( itemList.at( index ).value );
707 breakColors.append( color2 );
708 gradients.append( makeSimpleLinearGradient( color1, color2 ) );
709 index++;
710 }
711
712 // close the lists with value2 or last item if >value2
713 QColor color1 = breakColors.last();
714 QColor color2;
715 if ( value2 < itemList.last().value )
716 {
717 int r, g, b, a;
718 if ( mColorRampShader.shade( value2, &r, &g, &b, &a ) )
719 color2 = QColor( r, g, b, a );
720 breakValues.append( value2 );
721 }
722 else
723 {
724 color2 = itemList.last().color;
725 if ( mColorRampShader.clip() )
726 breakValues.append( itemList.last().value );
727 else
728 breakValues.append( value2 );
729 }
730 breakColors.append( color2 );
731 gradients.append( makeSimpleLinearGradient( color1, color2 ) );
732}
733
734
735void QgsInterpolatedLineColor::graduatedColorsDiscrete( double value1, double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients ) const
736{
737 Q_ASSERT( mColorRampShader.colorRampType() == Qgis::ShaderInterpolationMethod::Discrete );
738 Q_ASSERT( breakValues.isEmpty() );
739 Q_ASSERT( breakColors.isEmpty() );
740 Q_ASSERT( gradients.isEmpty() );
741
742 const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.colorRampItemList();
743 if ( itemList.empty() )
744 return;
745
746 if ( itemList.count() == 1 )
747 {
748 breakColors.append( itemList.first().color );
749 return;
750 }
751
752 double lastValue = itemList.at( itemList.count() - 2 ).value;
753
754
755 if ( value2 <= itemList.first().value ) // completely out of range and less
756 {
757 breakColors.append( itemList.first().color ); // render only the first color in the whole range
758 return;
759 }
760
761 if ( value1 > lastValue ) // completely out of range and greater
762 {
763 breakColors.append( itemList.last().color ); // render only the last color in the whole range
764 return;
765 }
766
767 // index of the inf value of the interval where value1 is in the color ramp shader
768 int index = itemColorIndexInf( value1 );
769
770 if ( qgsDoubleNear( value1, value2 ) )
771 {
772 // the two values are the same and are equal to the value in the item list
773 // --> render only one color, the sup one
774 breakColors.append( itemList.at( index + 1 ).color );
775 return;
776 }
777
778 if ( index < 0 ) // value1 out of range
779 {
780 breakValues.append( value1 );
781 breakColors.append( itemList.first().color );
782 }
783 else // append the first value with corresponding color
784 {
785 QColor color = itemList.at( index ).color;
786 breakValues.append( value1 );
787 breakColors.append( color );
788 }
789
790 index++; // increment the index before go through the intervals
791
792 while ( index < ( itemList.count() - 1 ) && itemList.at( index ).value < value2 )
793 {
794 QColor color = itemList.at( index ).color;
795 breakValues.append( itemList.at( index ).value );
796 breakColors.append( color );
797 gradients.append( makeSimpleLinearGradient( color, color ) );
798 index++;
799 }
800
801 // add value2 to close
802 QColor lastColor = itemList.at( index ).color;
803 breakColors.append( lastColor );
804 breakValues.append( value2 );
805 gradients.append( makeSimpleLinearGradient( lastColor, lastColor ) );
806}
807
809{
810 return u"InterpolatedLine"_s;
811}
812
815
818
820{
821 auto l = qgis::unique_ptr_static_cast<QgsInterpolatedLineSymbolLayer>( create( properties() ) );
822 copyCommonProperties( l.get() );
823 return l.release();
824}
825
826std::unique_ptr<QgsSymbolLayer> QgsInterpolatedLineSymbolLayer::create( const QVariantMap &properties )
827{
828 std::unique_ptr<QgsInterpolatedLineSymbolLayer> symbolLayer;
829 symbolLayer = std::make_unique<QgsInterpolatedLineSymbolLayer>();
830
831 if ( properties.contains( u"start_width_expression"_s ) )
832 symbolLayer->setDataDefinedProperty( QgsSymbolLayer::Property::LineStartWidthValue, QgsProperty::fromExpression( properties.value( u"start_width_expression"_s ).toString() ) );
833 if ( properties.contains( u"end_width_expression"_s ) )
834 symbolLayer->setDataDefinedProperty( QgsSymbolLayer::Property::LineEndWidthValue, QgsProperty::fromExpression( properties.value( u"end_width_expression"_s ).toString() ) );
835
836 if ( properties.contains( u"start_color_expression"_s ) )
837 symbolLayer->setDataDefinedProperty( QgsSymbolLayer::Property::LineStartColorValue, QgsProperty::fromExpression( properties.value( u"start_color_expression"_s ).toString() ) );
838 if ( properties.contains( u"end_color_expression"_s ) )
839 symbolLayer->setDataDefinedProperty( QgsSymbolLayer::Property::LineEndColorValue, QgsProperty::fromExpression( properties.value( u"end_color_expression"_s ).toString() ) );
840
841 if ( properties.contains( u"line_width"_s ) )
842 symbolLayer->mLineRender.mStrokeWidth.setFixedStrokeWidth( properties.value( u"line_width"_s ).toDouble() );
843 if ( properties.contains( u"line_width_unit"_s ) )
844 symbolLayer->mLineRender.setWidthUnit( QgsUnitTypes::decodeRenderUnit( properties.value( u"line_width_unit"_s ).toString() ) );
845 if ( properties.contains( u"width_varying_minimum_value"_s ) )
846 symbolLayer->mLineRender.mStrokeWidth.setMinimumValue( properties.value( u"width_varying_minimum_value"_s ).toDouble() );
847 if ( properties.contains( u"width_varying_maximum_value"_s ) )
848 symbolLayer->mLineRender.mStrokeWidth.setMaximumValue( properties.value( u"width_varying_maximum_value"_s ).toDouble() );
849 if ( properties.contains( u"width_varying_use_absolute_value"_s ) )
850 symbolLayer->mLineRender.mStrokeWidth.setUseAbsoluteValue( properties.value( u"width_varying_use_absolute_value"_s ).toInt() );
851 if ( properties.contains( u"width_varying_minimum_width"_s ) )
852 symbolLayer->mLineRender.mStrokeWidth.setMinimumWidth( properties.value( u"width_varying_minimum_width"_s ).toDouble() );
853 if ( properties.contains( u"width_varying_maximum_width"_s ) )
854 symbolLayer->mLineRender.mStrokeWidth.setMaximumWidth( properties.value( u"width_varying_maximum_width"_s ).toDouble() );
855 if ( properties.contains( u"width_varying_ignore_out_of_range"_s ) )
856 symbolLayer->mLineRender.mStrokeWidth.setIgnoreOutOfRange( properties.value( u"width_varying_ignore_out_of_range"_s ).toInt() );
857 if ( properties.contains( u"width_varying_is_variable_width"_s ) )
858 symbolLayer->mLineRender.mStrokeWidth.setIsVariableWidth( properties.value( u"width_varying_is_variable_width"_s ).toInt() );
859
860 if ( properties.contains( u"single_color"_s ) )
861 symbolLayer->mLineRender.mStrokeColoring.setColor( QgsColorUtils::colorFromString( properties.value( u"single_color"_s ).toString() ) );
862 if ( properties.contains( u"color_ramp_shader"_s ) )
863 symbolLayer->mLineRender.mStrokeColoring.setColor( createColorRampShaderFromProperties( properties.value( u"color_ramp_shader"_s ) ) );
864 if ( properties.contains( u"coloring_method"_s ) )
865 symbolLayer->mLineRender.mStrokeColoring.setColoringMethod( static_cast<QgsInterpolatedLineColor::ColoringMethod>( properties.value( u"coloring_method"_s ).toInt() ) );
866
867 return symbolLayer;
868}
869
874
876{
877 QVariantMap props;
878
879 // Line width varying
880 props.insert( u"line_width"_s, QString::number( mLineRender.mStrokeWidth.fixedStrokeWidth() ) );
881 props.insert( u"line_width_unit"_s, QgsUnitTypes::encodeUnit( mLineRender.widthUnit() ) );
882 props.insert( u"width_varying_minimum_value"_s, mLineRender.mStrokeWidth.minimumValue() );
883 props.insert( u"width_varying_maximum_value"_s, mLineRender.mStrokeWidth.maximumValue() );
884 props.insert( u"width_varying_use_absolute_value"_s, mLineRender.mStrokeWidth.useAbsoluteValue() ? 1 : 0 );
885 props.insert( u"width_varying_minimum_width"_s, mLineRender.mStrokeWidth.minimumWidth() );
886 props.insert( u"width_varying_maximum_width"_s, mLineRender.mStrokeWidth.maximumWidth() );
887 props.insert( u"width_varying_ignore_out_of_range"_s, mLineRender.mStrokeWidth.ignoreOutOfRange() ? 1 : 0 );
888 props.insert( u"width_varying_is_variable_width"_s, mLineRender.mStrokeWidth.isVariableWidth() ? 1 : 0 );
889
890 // Color varying
891 props.insert( u"coloring_method"_s, mLineRender.mStrokeColoring.coloringMethod() );
892 props.insert( u"single_color"_s, QgsColorUtils::colorToString( mLineRender.mStrokeColoring.singleColor() ) );
893 props.insert( u"color_ramp_shader"_s, colorRampShaderProperties() );
894
895 return props;
896}
897
899{
901
902 startRender( context );
903 double min = std::min( mLineRender.interpolatedLineWidth().minimumValue(), mLineRender.interpolatedColor().colorRampShader().minimumValue() );
904 double max = std::max( mLineRender.interpolatedLineWidth().maximumValue(), mLineRender.interpolatedColor().colorRampShader().maximumValue() );
905
906 double totalLength = geometry.length();
907 if ( qgsDoubleNear( totalLength, 0 ) )
908 return;
909
910 double variation = ( max - min ) / totalLength;
911
912 QPolygonF points = geometry.asQPolygonF();
913 double lengthFromStart = 0;
914 for ( int i = 1; i < points.count(); ++i )
915 {
916 QPointF p1 = points.at( i - 1 );
917 QPointF p2 = points.at( i );
918
919 double v1 = min + variation * lengthFromStart;
920 QPointF vectDist = p2 - p1;
921 lengthFromStart += sqrt( pow( vectDist.x(), 2 ) + pow( vectDist.y(), 2 ) );
922 double v2 = min + variation * lengthFromStart;
923 mLineRender.renderInDeviceCoordinates( v1, v2, v1, v2, p1, p2, context.renderContext() );
924 }
925
926 renderPolyline( points, context );
927}
928
930{
931 switch ( mLineRender.interpolatedColor().coloringMethod() )
932 {
934 return mLineRender.interpolatedColor().singleColor();
936 return QColor();
937 }
939}
940
941
954
959
964
965void QgsInterpolatedLineSymbolLayer::setWidthUnit( Qgis::RenderUnit strokeWidthUnit ) // cppcheck-suppress duplInheritedMember
966{
967 mLineRender.mStrokeWidthUnit = strokeWidthUnit;
968}
969
970// cppcheck-suppress duplInheritedMember
972{
973 return mLineRender.widthUnit();
974}
975
977{
978 mLineRender.mStrokeWidth = interpolatedLineWidth;
979}
980
982{
983 return mLineRender.interpolatedLineWidth();
984}
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>( shaderVariantMap.value( u"color_ramp_shader_classification_mode"_s ).toInt() ) );
1065
1066 if ( shaderVariantMap.contains( u"color_ramp_shader_items_list"_s ) )
1067 {
1068 QVariant colorRampItemsVar = shaderVariantMap.value( u"color_ramp_shader_items_list"_s );
1069 if ( colorRampItemsVar.userType() == QMetaType::Type::QVariantList )
1070 {
1071 QVariantList itemVariantList = colorRampItemsVar.toList();
1072 QList<QgsColorRampShader::ColorRampItem> colorRampItemList;
1073 for ( const QVariant &itemVar : std::as_const( itemVariantList ) )
1074 {
1075 QgsColorRampShader::ColorRampItem item;
1076 if ( itemVar.userType() != QMetaType::Type::QVariantMap )
1077 continue;
1078 QVariantMap itemVarMap = itemVar.toMap();
1079 if ( !itemVarMap.contains( u"label"_s ) || !itemVarMap.contains( u"color"_s ) || !itemVarMap.contains( u"value"_s ) )
1080 continue;
1081
1082 item.label = itemVarMap.value( u"label"_s ).toString();
1083 item.color = QgsColorUtils::colorFromString( itemVarMap.value( u"color"_s ).toString() );
1084 item.value = itemVarMap.value( u"value"_s ).toDouble();
1085
1086 colorRampItemList.append( item );
1087 }
1088 colorRampShader.setColorRampItemList( colorRampItemList );
1089 }
1090 }
1091
1092 if ( shaderVariantMap.contains( u"color_ramp_shader_minimum_value"_s ) )
1093 colorRampShader.setMinimumValue( shaderVariantMap.value( u"color_ramp_shader_minimum_value"_s ).toDouble() );
1094 else
1095 colorRampShader.setMinimumValue( std::numeric_limits<double>::quiet_NaN() );
1096
1097 if ( shaderVariantMap.contains( u"color_ramp_shader_maximum_value"_s ) )
1098 colorRampShader.setMaximumValue( shaderVariantMap.value( u"color_ramp_shader_maximum_value"_s ).toDouble() );
1099 else
1100 colorRampShader.setMaximumValue( std::numeric_limits<double>::quiet_NaN() );
1101
1102 if ( shaderVariantMap.contains( u"color_ramp_shader_value_out_of_range"_s ) )
1103 colorRampShader.setClip( shaderVariantMap.value( u"color_ramp_shader_value_out_of_range"_s ).toInt() == 1 );
1104 if ( shaderVariantMap.contains( u"color_ramp_shader_label_precision"_s ) )
1105 colorRampShader.setLabelPrecision( shaderVariantMap.value( u"color_ramp_shader_label_precision"_s ).toInt() );
1106
1107 return colorRampShader;
1108}
1109
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 ) { return total + QgsSymbolLayerUtils::polylineLength( part ); } );
1135
1136 if ( qgsDoubleNear( totalLength, 0 ) )
1137 return;
1138
1139 double startValWidth = 0;
1140 double variationPerMapUnitWidth = 0;
1141 double startValColor = 0;
1142 double variationPerMapUnitColor = 0;
1143
1144 bool ok = true;
1145
1146 if ( mLineRender.interpolatedLineWidth().isVariableWidth() )
1147 {
1149 {
1151 if ( !ok )
1152 return;
1153 }
1154
1155 double endValWidth = 0;
1157 {
1158 endValWidth = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::Property::LineEndWidthValue, context.expressionContext(), 0, &ok );
1159 if ( !ok )
1160 return;
1161 }
1162
1163 variationPerMapUnitWidth = ( endValWidth - startValWidth ) / totalLength;
1164 }
1165
1166 if ( mLineRender.interpolatedColor().coloringMethod() == QgsInterpolatedLineColor::ColorRamp )
1167 {
1169 {
1170 startValColor = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::Property::LineStartColorValue, context.expressionContext(), 0, &ok );
1171 if ( !ok )
1172 return;
1173 }
1174
1175 double endValColor = 0;
1177 {
1178 endValColor = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::Property::LineEndColorValue, context.expressionContext(), 0, &ok );
1179 if ( !ok )
1180 return;
1181 }
1182
1183 variationPerMapUnitColor = ( endValColor - startValColor ) / totalLength;
1184 }
1185
1186 for ( const QPolygonF &poly : parts )
1187 {
1188 double lengthFromStart = 0;
1189 for ( int i = 1; i < poly.count(); ++i )
1190 {
1191 const QPointF p1 = poly.at( i - 1 );
1192 const QPointF p2 = poly.at( i );
1193
1194 const double v1c = startValColor + variationPerMapUnitColor * lengthFromStart;
1195 const double v1w = startValWidth + variationPerMapUnitWidth * lengthFromStart;
1196 lengthFromStart += QgsGeometryUtilsBase::distance2D( p1.x(), p1.y(), p2.x(), p2.y() );
1197 const double v2c = startValColor + variationPerMapUnitColor * lengthFromStart;
1198 const double v2w = startValWidth + variationPerMapUnitWidth * lengthFromStart;
1199 mLineRender.renderInDeviceCoordinates( v1c, v2c, v1w, v2w, p1, p2, context );
1200 }
1201 }
1202}
1203
1205{
1206 mLineRender.setSelected( context.selected() );
1207
1208 if ( points.empty() )
1209 return;
1210
1211 if ( mRenderingFeature )
1212 {
1213 // in the middle of rendering a possibly multi-part feature, so we collect all the parts and defer the actual rendering
1214 // until after we've received the final part
1215 mLineParts.append( points );
1216 }
1217 else
1218 {
1219 // not rendering a feature, so we can just render the polyline immediately
1220 render( { points }, context.renderContext() );
1221 }
1222}
1223
@ DisableFeatureClipping
If present, indicates that features should never be clipped to the map extent during rendering.
Definition qgis.h:963
@ CanCalculateMaskGeometryPerFeature
If present, indicates that mask geometry can safely be calculated per feature for the symbol layer....
Definition qgis.h:964
ShaderInterpolationMethod
Color ramp shader interpolation methods.
Definition qgis.h:1594
@ Exact
Assigns the color of the exact matching value in the color ramp item list.
Definition qgis.h:1597
@ Linear
Interpolates the color between two class breaks linearly.
Definition qgis.h:1595
@ Discrete
Assigns the color of the higher class for every pixel between two class breaks.
Definition qgis.h:1596
QFlags< SymbolLayerFlag > SymbolLayerFlags
Symbol layer flags.
Definition qgis.h:969
ShaderClassificationMethod
Color ramp shader classification methods.
Definition qgis.h:1609
RenderUnit
Rendering size units.
Definition qgis.h:5758
@ Line
Line symbol.
Definition qgis.h:673
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.
static std::unique_ptr< QgsSymbolLayer > create(const QVariantMap &properties)
Creates the symbol layer.
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.
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:168
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:164
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
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:8415
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:7743