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