QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsinterpolatedlinerenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsinterpolatedlinerenderer.cpp
3  --------------------------------------
4  Date : April 2020
5  Copyright : (C) 2020 by Vincent Cloarec
6  Email : vcloarec at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include <QPainter>
17 
19 #include "qgssymbollayerutils.h"
20 
22 {
23  mStrokeWidth = strokeWidth;
24 }
25 
27 {
28  mStrokeColoring = strokeColoring;
29 }
30 
32 {
33  mStrokeWidthUnit = strokeWidthUnit;
34 }
35 
36 void QgsInterpolatedLineRenderer::render( double value1, double value2, QgsPointXY point1, QgsPointXY point2, QgsRenderContext &context ) const
37 {
38  QPainter *painter = context.painter();
39  QgsScopedQPainterState painterState( painter );
40  context.setPainterFlagsUsingContext( painter );
41 
42  const QgsMapToPixel &mapToPixel = context.mapToPixel();
43 
44  if ( value1 > value2 )
45  {
46  std::swap( value1, value2 );
47  std::swap( point1, point2 );
48  }
49 
50  QPointF p1 = mapToPixel.transform( point1 ).toQPointF();
51  QPointF p2 = mapToPixel.transform( point2 ).toQPointF();
52  QPointF dir = p2 - p1;
53  double length = sqrt( pow( dir.x(), 2 ) + pow( dir.y(), 2 ) );
54  QPointF diru = dir / length;
55  QPointF orthu = QPointF( -diru.y(), diru.x() );
56 
57  QList<double> breakValues;
58  QList<QColor> breakColors;
59  QList<QLinearGradient> gradients;
60 
61  mStrokeColoring.graduatedColors( value1, value2, breakValues, breakColors, gradients );
62 
63  if ( gradients.isEmpty() && !breakValues.empty() && !breakColors.isEmpty() ) //exact colors to render
64  {
65  Q_ASSERT( breakColors.count() == breakValues.count() );
66  for ( int i = 0; i < breakValues.count(); ++i )
67  {
68  double value = breakValues.at( i );
69  double width = context.convertToPainterUnits( mStrokeWidth.strokeWidth( value ), mStrokeWidthUnit );
70  QPen pen( breakColors.at( i ) );
71  pen.setWidthF( width );
72  pen.setCapStyle( Qt::PenCapStyle::RoundCap );
73  painter->setPen( pen );
74  QPointF point = p1 + dir * ( value - value1 ) / ( value2 - value1 );
75  painter->drawPoint( point );
76  }
77  }
78  else
79  {
80  double width1 = mStrokeWidth.strokeWidth( value1 );
81  double width2 = mStrokeWidth.strokeWidth( value2 );
82 
83  if ( !std::isnan( width1 ) || !std::isnan( width2 ) ) // the two widths on extremity are not out of range and ignored
84  {
85  //Draw line cap
86  QBrush brush( Qt::SolidPattern );
87  QPen pen;
88  int startAngle;
89  startAngle = ( acos( -orthu.x() ) / M_PI ) * 180;
90  if ( orthu.y() < 0 )
91  startAngle = 360 - startAngle;
92 
93  bool outOfRange1 = std::isnan( width1 );
94  bool outOfRange2 = std::isnan( width2 );
95 
96  if ( !outOfRange1 )
97  {
98  width1 = context.convertToPainterUnits( width1, mStrokeWidthUnit );
99  QRectF capBox1( p1.x() - width1 / 2, p1.y() - width1 / 2, width1, width1 );
100  brush.setColor( mStrokeColoring.color( value1 ) );
101  painter->setBrush( brush );
102  pen.setBrush( brush );
103  painter->setPen( pen );
104  painter->drawPie( capBox1, ( startAngle - 1 ) * 16, 182 * 16 );
105  }
106 
107  if ( !outOfRange2 )
108  {
109  width2 = context.convertToPainterUnits( width2, mStrokeWidthUnit ) ;
110  QRectF capBox2( p2.x() - width2 / 2, p2.y() - width2 / 2, width2, width2 );
111  brush.setColor( mStrokeColoring.color( value2 ) );
112  pen.setBrush( brush );
113  painter->setBrush( brush );
114  painter->setPen( pen );
115  painter->drawPie( capBox2, ( startAngle + 179 ) * 16, 182 * 16 );
116  }
117 
118  if ( gradients.isEmpty() && breakValues.empty() && breakColors.count() == 1 ) //only one color to render
119  {
120  double startAdjusting = 0;
121  if ( outOfRange1 )
122  adjustLine( value1, value1, value2, width1, startAdjusting );
123 
124 
125  double endAdjusting = 0;
126  if ( outOfRange2 )
127  adjustLine( value2, value1, value2, width2, endAdjusting );
128 
129  QPointF pointStartAdjusted = p1 + dir * startAdjusting;
130  QPointF pointEndAdjusted = p2 - dir * endAdjusting;
131 
132  QPolygonF varLine;
133  double semiWidth1 = width1 / 2;
134  double semiWidth2 = width2 / 2;
135 
136  varLine.append( pointStartAdjusted + orthu * semiWidth1 );
137  varLine.append( pointEndAdjusted + orthu * semiWidth2 );
138  varLine.append( pointEndAdjusted - orthu * semiWidth2 );
139  varLine.append( pointStartAdjusted - orthu * semiWidth1 );
140 
141  QBrush brush( Qt::SolidPattern );
142  brush.setColor( breakColors.first() );
143  painter->setBrush( brush );
144  painter->setPen( pen );
145 
146  QPen pen;
147  pen.setBrush( brush );
148  pen.setWidthF( 0 );
149  painter->setPen( pen );
150 
151  painter->drawPolygon( varLine );
152  }
153  else if ( !gradients.isEmpty() && !breakValues.isEmpty() && !breakColors.isEmpty() )
154  {
155  Q_ASSERT( breakColors.count() == breakValues.count() );
156  Q_ASSERT( breakColors.count() == gradients.count() + 1 );
157 
158  for ( int i = 0; i < gradients.count(); ++i )
159  {
160  double firstValue = breakValues.at( i );
161  double secondValue = breakValues.at( i + 1 );
162  double w1 = mStrokeWidth.strokeWidth( firstValue );
163  double w2 = mStrokeWidth.strokeWidth( secondValue );
164 
165  if ( std::isnan( w1 ) && std::isnan( w2 ) )
166  continue;
167 
168  double firstAdjusting = 0;
169  if ( std::isnan( w1 ) )
170  adjustLine( firstValue, value1, value2, w1, firstAdjusting );
171 
172 
173  double secondAdjusting = 0;
174  if ( std::isnan( w2 ) )
175  adjustLine( secondValue, value1, value2, w2, secondAdjusting );
176 
177  w1 = context.convertToPainterUnits( w1, mStrokeWidthUnit );
178  w2 = context.convertToPainterUnits( w2, mStrokeWidthUnit ) ;
179 
180  QPointF pointStart = p1 + dir * ( firstValue - value1 ) / ( value2 - value1 );
181  QPointF pointEnd = p1 + dir * ( secondValue - value1 ) / ( value2 - value1 );
182 
183  QPointF pointStartAdjusted = pointStart + dir * firstAdjusting;
184  QPointF pointEndAdjusted = pointEnd - dir * secondAdjusting;
185 
186  QPolygonF varLine;
187  double sw1 = w1 / 2;
188  double sw2 = w2 / 2;
189 
190  varLine.append( pointStartAdjusted + orthu * sw1 );
191  varLine.append( pointEndAdjusted + orthu * sw2 );
192  varLine.append( pointEndAdjusted - orthu * sw2 );
193  varLine.append( pointStartAdjusted - orthu * sw1 );
194 
195  QLinearGradient gradient = gradients.at( i );
196  gradient.setStart( pointStart );
197  gradient.setFinalStop( pointEnd );
198  QBrush brush( gradient );
199  painter->setBrush( brush );
200 
201  QPen pen;
202  pen.setBrush( brush );
203  pen.setWidthF( 0 );
204  painter->setPen( pen );
205 
206  painter->drawPolygon( varLine );
207  }
208  }
209  }
210  }
211 }
212 
213 void QgsInterpolatedLineRenderer::adjustLine( const double &value, const double &value1, const double &value2, double &width, double &adjusting ) const
214 {
215  if ( value > mStrokeWidth.maximumValue() )
216  {
217  adjusting = fabs( ( value - mStrokeWidth.maximumValue() ) / ( value2 - value1 ) );
218  width = mStrokeWidth.maximumWidth();
219  }
220  else
221  {
222  adjusting = fabs( ( value - mStrokeWidth.minimumValue() ) / ( value2 - value1 ) );
223  width = mStrokeWidth.minimumWidth();
224  }
225 }
226 
228 {
229  return mMinimumValue;
230 }
231 
232 void QgsInterpolatedLineWidth::setMinimumValue( double minimumValue )
233 {
234  mMinimumValue = minimumValue;
235  mNeedUpdateFormula = true;
236 }
237 
239 {
240  return mMaximumValue;
241 }
242 
243 void QgsInterpolatedLineWidth::setMaximumValue( double maximumValue )
244 {
245  mMaximumValue = maximumValue;
246  mNeedUpdateFormula = true;
247 }
248 
250 {
251  return mMinimumWidth;
252 }
253 
254 void QgsInterpolatedLineWidth::setMinimumWidth( double minimumWidth )
255 {
256  mMinimumWidth = minimumWidth;
257  mNeedUpdateFormula = true;
258 }
259 
261 {
262  return mMaximumWidth;
263 }
264 
265 void QgsInterpolatedLineWidth::setMaximumWidth( double maximumWidth )
266 {
267  mMaximumWidth = maximumWidth;
268  mNeedUpdateFormula = true;
269 }
270 
271 double QgsInterpolatedLineWidth::strokeWidth( double value ) const
272 {
273  if ( mIsWidthVariable )
274  {
275  if ( mNeedUpdateFormula )
276  updateLinearFormula();
277 
278  if ( mUseAbsoluteValue )
279  value = std::fabs( value );
280 
281  if ( value > mMaximumValue )
282  {
283  if ( mIgnoreOutOfRange )
284  return std::numeric_limits<double>::quiet_NaN();
285  else
286  return mMaximumWidth;
287  }
288 
289  if ( value < mMinimumValue )
290  {
291  if ( mIgnoreOutOfRange )
292  return std::numeric_limits<double>::quiet_NaN();
293  else
294  return mMinimumWidth;
295  }
296 
297  return ( value - mMinimumValue ) * mLinearCoef + mMinimumWidth;
298  }
299  else
300  return fixedStrokeWidth();
301 }
302 
303 QDomElement QgsInterpolatedLineWidth::writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const
304 {
305  Q_UNUSED( context );
306 
307  QDomElement elem = doc.createElement( QStringLiteral( "mesh-stroke-width" ) );
308 
309  elem.setAttribute( QStringLiteral( "width-varying" ), mIsWidthVariable ? 1 : 0 );
310  elem.setAttribute( QStringLiteral( "fixed-width" ), mFixedWidth );
311  elem.setAttribute( QStringLiteral( "minimum-value" ), mMinimumValue );
312  elem.setAttribute( QStringLiteral( "maximum-value" ), mMaximumValue );
313  elem.setAttribute( QStringLiteral( "minimum-width" ), mMinimumWidth );
314  elem.setAttribute( QStringLiteral( "maximum-width" ), mMaximumWidth );
315  elem.setAttribute( QStringLiteral( "ignore-out-of-range" ), mIgnoreOutOfRange ? 1 : 0 );
316  elem.setAttribute( QStringLiteral( "use-absolute-value" ), mUseAbsoluteValue ? 1 : 0 );
317 
318  return elem;
319 }
320 
321 void QgsInterpolatedLineWidth::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
322 {
323  Q_UNUSED( context );
324 
325  mIsWidthVariable = elem.attribute( QStringLiteral( "width-varying" ) ).toInt();
326  mFixedWidth = elem.attribute( QStringLiteral( "fixed-width" ) ).toDouble();
327  mMinimumValue = elem.attribute( QStringLiteral( "minimum-value" ) ).toDouble();
328  mMaximumValue = elem.attribute( QStringLiteral( "maximum-value" ) ).toDouble();
329  mMinimumWidth = elem.attribute( QStringLiteral( "minimum-width" ) ).toDouble();
330  mMaximumWidth = elem.attribute( QStringLiteral( "maximum-width" ) ).toDouble();
331  mIgnoreOutOfRange = elem.attribute( QStringLiteral( "ignore-out-of-range" ) ).toInt();
332  mUseAbsoluteValue = elem.attribute( QStringLiteral( "use-absolute-value" ) ).toInt();
333 }
334 
336 {
337  return mUseAbsoluteValue;
338 }
339 
341 {
342  mUseAbsoluteValue = useAbsoluteValue;
343 }
344 
346 {
347  return mFixedWidth;
348 }
349 
351 {
352  return mIgnoreOutOfRange;
353 }
354 
356 {
357  mIgnoreOutOfRange = ignoreOutOfRange;
358 }
359 
361 {
362  return mIsWidthVariable;
363 }
364 
366 {
367  mIsWidthVariable = isWidthVarying;
368 }
369 
371 {
372  mFixedWidth = fixedWidth;
373 }
374 
375 void QgsInterpolatedLineWidth::updateLinearFormula() const
376 {
377  if ( mMaximumWidth - mMinimumWidth != 0 )
378  mLinearCoef = ( mMaximumWidth - mMinimumWidth ) / ( mMaximumValue - mMinimumValue ) ;
379  else
380  mLinearCoef = 0;
381  mNeedUpdateFormula = false;
382 }
383 
385 {
387 }
388 
390 {
391  setColor( color );
392  mColoringMethod = SingleColor;
393 }
394 
396 {
397  mColorRampShader = colorRampShader;
398  if ( ( mColorRampShader.sourceColorRamp() ) )
399  mColoringMethod = ColorRamp;
400  else
401  mColoringMethod = SingleColor;
402 }
403 
404 void QgsInterpolatedLineColor::setColor( const QColor &color )
405 {
406  mColorRampShader = QgsColorRampShader();
407  mSingleColor = color;
408 }
409 
410 QColor QgsInterpolatedLineColor::color( double magnitude ) const
411 {
412  if ( auto *lSourceColorRamp = mColorRampShader.sourceColorRamp() )
413  {
414  if ( mColorRampShader.isEmpty() )
415  return lSourceColorRamp->color( 0 );
416 
417  int r, g, b, a;
418  if ( mColorRampShader.shade( magnitude, &r, &g, &b, &a ) )
419  return QColor( r, g, b, a );
420  else
421  return QColor( 0, 0, 0, 0 );
422  }
423  else
424  {
425  return mSingleColor;
426  }
427 }
428 
430 {
431  return mColoringMethod;
432 }
433 
435 {
436  return mColorRampShader;
437 }
438 
439 QDomElement QgsInterpolatedLineColor::writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const
440 {
441  Q_UNUSED( context );
442 
443  QDomElement elem = doc.createElement( QStringLiteral( "mesh-stroke-color" ) );
444 
445  elem.setAttribute( QStringLiteral( "single-color" ), QgsSymbolLayerUtils::encodeColor( mSingleColor ) );
446  elem.setAttribute( QStringLiteral( "coloring-method" ), mColoringMethod );
447  elem.appendChild( mColorRampShader.writeXml( doc ) );
448 
449  return elem;
450 }
451 
452 void QgsInterpolatedLineColor::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
453 {
454  Q_UNUSED( context );
455 
456  QDomElement shaderElem = elem.firstChildElement( QStringLiteral( "colorrampshader" ) );
457  mColorRampShader.readXml( shaderElem );
458 
459  mSingleColor = QgsSymbolLayerUtils::decodeColor( elem.attribute( QStringLiteral( "single-color" ) ) );
460  mColoringMethod = static_cast<QgsInterpolatedLineColor::ColoringMethod>(
461  elem.attribute( QStringLiteral( "coloring-method" ) ).toInt() );
462 }
463 
464 void QgsInterpolatedLineColor::graduatedColors( double value1, double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients ) const
465 {
466  breakValues.clear();
467  breakColors.clear();
468  gradients.clear();
469  if ( mColoringMethod == SingleColor )
470  {
471  breakValues.append( value1 );
472  breakColors.append( mSingleColor );
473  breakValues.append( value2 );
474  breakColors.append( mSingleColor );
475  gradients.append( makeSimpleLinearGradient( mSingleColor, mSingleColor ) );
476  return;
477  }
478 
479  switch ( mColorRampShader.colorRampType() )
480  {
482  graduatedColorsInterpolated( value1, value2, breakValues, breakColors, gradients );
483  break;
485  graduatedColorsDiscrete( value1, value2, breakValues, breakColors, gradients );
486  break;
488  graduatedColorsExact( value1, value2, breakValues, breakColors, gradients );
489  break;
490  }
491 
492 }
493 
494 QLinearGradient QgsInterpolatedLineColor::makeSimpleLinearGradient( const QColor &color1, const QColor &color2 ) const
495 {
496  QLinearGradient gradient;
497  gradient.setColorAt( 0, color1 );
498  gradient.setColorAt( 1, color2 );
499 
500  return gradient;
501 }
502 
503 int QgsInterpolatedLineColor::itemColorIndexInf( double value ) const
504 {
505  QList<QgsColorRampShader::ColorRampItem> itemList = mColorRampShader.colorRampItemList();
506 
507  if ( itemList.isEmpty() || itemList.first().value > value )
508  return -1;
509 
510  if ( mColorRampShader.colorRampType() == QgsColorRampShader::Discrete )
511  itemList.removeLast(); //remove the inf value
512 
513  if ( value > itemList.last().value )
514  return itemList.count() - 1;
515 
516  int indSup = itemList.count() - 1;
517  int indInf = 0;
518 
519  while ( true )
520  {
521  if ( abs( indSup - indInf ) <= 1 ) //always indSup>indInf, but abs to prevent infinity loop
522  return indInf;
523 
524  int newInd = ( indInf + indSup ) / 2;
525 
526  if ( itemList.at( newInd ).value == std::numeric_limits<double>::quiet_NaN() )
527  return -1;
528 
529  if ( itemList.at( newInd ).value <= value )
530  indInf = newInd;
531  else
532  indSup = newInd;
533  }
534 }
535 
536 void QgsInterpolatedLineColor::graduatedColorsExact( double value1, double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients ) const
537 {
538  Q_ASSERT( mColorRampShader.colorRampType() == QgsColorRampShader::Exact );
539  Q_ASSERT( breakValues.isEmpty() );
540  Q_ASSERT( breakColors.isEmpty() );
541  Q_ASSERT( gradients.isEmpty() );
542 
543  const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.colorRampItemList();
544  if ( itemList.isEmpty() )
545  return;
546 
547  int index = itemColorIndexInf( value1 );
548  if ( index < 0 || !qgsDoubleNear( value1, itemList.at( index ).value ) )
549  index++;
550 
551  if ( qgsDoubleNear( value1, value2 ) && qgsDoubleNear( value1, itemList.at( index ).value ) )
552  {
553  //the two value are the same and are equal to the value in the item list --> render only one color
554  breakColors.append( itemList.at( index ).color );
555  return;
556  }
557 
558  while ( index < itemList.count() && itemList.at( index ).value <= value2 )
559  {
560  breakValues.append( itemList.at( index ).value );
561  breakColors.append( itemList.at( index ).color );
562  index++;
563  }
564 }
565 
566 void QgsInterpolatedLineColor::graduatedColorsInterpolated( double value1, double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients ) const
567 {
568  Q_ASSERT( mColorRampShader.colorRampType() == QgsColorRampShader::Interpolated );
569  Q_ASSERT( breakValues.isEmpty() );
570  Q_ASSERT( breakColors.isEmpty() );
571  Q_ASSERT( gradients.isEmpty() );
572 
573 
574  const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.colorRampItemList();
575  if ( itemList.empty() )
576  return;
577 
578  if ( itemList.count() == 1 )
579  {
580  breakColors.append( itemList.first().color );
581  return;
582  }
583 
584  if ( value2 <= itemList.first().value ) // completely out of range and less
585  {
586  if ( !mColorRampShader.clip() )
587  breakColors.append( itemList.first().color ); // render only the first color in the whole range if not clipped
588  return;
589  }
590 
591  if ( value1 > itemList.last().value ) // completely out of range and greater
592  {
593  if ( !mColorRampShader.clip() )
594  breakColors.append( itemList.last().color ); // render only the last color in the whole range if not clipped
595  return;
596  }
597 
598  if ( qgsDoubleNear( value1, value2 ) )
599  {
600  // the two values are the same
601  // --> render only one color
602  int r, g, b, a;
603  QColor color;
604  if ( mColorRampShader.shade( value1, &r, &g, &b, &a ) )
605  color = QColor( r, g, b, a );
606  breakColors.append( color );
607  return;
608  }
609 
610  // index of the inf value of the interval where value1 is in the color ramp shader
611  int index = itemColorIndexInf( value1 );
612  if ( index < 0 ) // value1 out of range
613  {
614  QColor color = itemList.first().color;
615  breakColors.append( color );
616  if ( mColorRampShader.clip() ) // The first value/color returned is the first of the item list
617  breakValues.append( itemList.first().value );
618  else // The first value/color returned is the first color of the item list and value1
619  breakValues.append( value1 );
620  }
621  else
622  {
623  // shade the color
624  int r, g, b, a;
625  QColor color;
626  if ( mColorRampShader.shade( value1, &r, &g, &b, &a ) )
627  color = QColor( r, g, b, a );
628  breakValues.append( value1 );
629  breakColors.append( color );
630  }
631 
632  index++; // increment the index before go through the intervals
633 
634  while ( index < itemList.count() && itemList.at( index ).value < value2 )
635  {
636  QColor color1 = breakColors.last();
637  QColor color2 = itemList.at( index ).color;
638  breakValues.append( itemList.at( index ).value );
639  breakColors.append( color2 );
640  gradients.append( makeSimpleLinearGradient( color1, color2 ) );
641  index++;
642  }
643 
644  // close the lists with value2 or last item if >value2
645  QColor color1 = breakColors.last();
646  QColor color2;
647  if ( value2 < itemList.last().value )
648  {
649  int r, g, b, a;
650  if ( mColorRampShader.shade( value2, &r, &g, &b, &a ) )
651  color2 = QColor( r, g, b, a );
652  breakValues.append( value2 );
653  }
654  else
655  {
656  color2 = itemList.last().color;
657  if ( mColorRampShader.clip() )
658  breakValues.append( itemList.last().value );
659  else
660  breakValues.append( value2 );
661  }
662  breakColors.append( color2 );
663  gradients.append( makeSimpleLinearGradient( color1, color2 ) );
664 }
665 
666 
667 void QgsInterpolatedLineColor::graduatedColorsDiscrete( double value1, double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients ) const
668 {
669  Q_ASSERT( mColorRampShader.colorRampType() == QgsColorRampShader::Discrete );
670  Q_ASSERT( breakValues.isEmpty() );
671  Q_ASSERT( breakColors.isEmpty() );
672  Q_ASSERT( gradients.isEmpty() );
673 
674  const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.colorRampItemList();
675  if ( itemList.empty() )
676  return;
677 
678  if ( itemList.count() == 1 )
679  {
680  breakColors.append( itemList.first().color );
681  return;
682  }
683 
684  double lastValue = itemList.at( itemList.count() - 2 ).value;
685 
686 
687  if ( value2 <= itemList.first().value ) // completely out of range and less
688  {
689  breakColors.append( itemList.first().color ); // render only the first color in the whole range
690  return;
691  }
692 
693  if ( value1 > lastValue ) // completely out of range and greater
694  {
695  breakColors.append( itemList.last().color ); // render only the last color in the whole range
696  return;
697  }
698 
699  // index of the inf value of the interval where value1 is in the color ramp shader
700  int index = itemColorIndexInf( value1 );
701 
702  if ( qgsDoubleNear( value1, value2 ) )
703  {
704  // the two values are the same and are equal to the value in the item list
705  // --> render only one color, the sup one
706  breakColors.append( itemList.at( index + 1 ).color );
707  return;
708  }
709 
710  if ( index < 0 ) // value1 out of range
711  {
712  breakValues.append( value1 );
713  breakColors.append( itemList.first().color );
714  }
715  else // append the first value with corresponding color
716  {
717  QColor color = itemList.at( index ).color;
718  breakValues.append( value1 );
719  breakColors.append( color );
720  }
721 
722  index++; // increment the index before go through the intervals
723 
724  while ( index < ( itemList.count() - 1 ) && itemList.at( index ).value < value2 )
725  {
726  QColor color = itemList.at( index ).color;
727  breakValues.append( itemList.at( index ).value );
728  breakColors.append( color );
729  gradients.append( makeSimpleLinearGradient( color, color ) );
730  index++;
731  }
732 
733  // add value2 to close
734  QColor lastColor = itemList.at( index ).color;
735  breakColors.append( lastColor );
736  breakValues.append( value2 );
737  gradients.append( makeSimpleLinearGradient( lastColor, lastColor ) );
738 
739 }
QgsInterpolatedLineWidth::readXml
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Reads configuration from the given DOM element.
Definition: qgsinterpolatedlinerenderer.cpp:321
QgsInterpolatedLineColor::writeXml
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Writes configuration to a new DOM element.
Definition: qgsinterpolatedlinerenderer.cpp:439
QgsSymbolLayerUtils::encodeColor
static QString encodeColor(const QColor &color)
Definition: qgssymbollayerutils.cpp:52
QgsRenderContext::convertToPainterUnits
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
Definition: qgsrendercontext.cpp:318
QgsRenderContext::setPainterFlagsUsingContext
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
Definition: qgsrendercontext.cpp:143
QgsRenderContext::mapToPixel
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
Definition: qgsrendercontext.h:325
QgsUnitTypes::RenderUnit
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:167
QgsReadWriteContext
The class is used as a container of context for various read/write operations on other objects.
Definition: qgsreadwritecontext.h:35
QgsInterpolatedLineColor::setColor
void setColor(const QgsColorRampShader &colorRampShader)
Sets the color ramp to define the coloring.
Definition: qgsinterpolatedlinerenderer.cpp:395
QgsInterpolatedLineRenderer::setInterpolatedColor
void setInterpolatedColor(const QgsInterpolatedLineColor &strokeColoring)
Sets the stroke color used to plot.
Definition: qgsinterpolatedlinerenderer.cpp:26
QgsInterpolatedLineColor::SingleColor
@ SingleColor
Render with a single color.
Definition: qgsinterpolatedlinerenderer.h:44
QgsColorRampShader::writeXml
QDomElement writeXml(QDomDocument &doc) const
Writes configuration to a new DOM element.
Definition: qgscolorrampshader.cpp:502
QgsColorRampShader::isEmpty
bool isEmpty() const
Whether the color ramp contains any items.
Definition: qgscolorrampshader.cpp:105
QgsInterpolatedLineWidth::strokeWidth
double strokeWidth(double value) const
Returns the variable width depending on value, if not varying returns the fixed width.
Definition: qgsinterpolatedlinerenderer.cpp:271
qgssymbollayerutils.h
QgsInterpolatedLineColor::ColoringMethod
ColoringMethod
Defines how the color is defined.
Definition: qgsinterpolatedlinerenderer.h:42
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:58
QgsInterpolatedLineWidth::setIgnoreOutOfRange
void setIgnoreOutOfRange(bool ignoreOutOfRange)
Sets whether the variable width ignores out of range value.
Definition: qgsinterpolatedlinerenderer.cpp:355
QgsPointXY::toQPointF
QPointF toQPointF() const
Converts a point to a QPointF.
Definition: qgspointxy.h:154
QgsInterpolatedLineColor::coloringMethod
QgsInterpolatedLineColor::ColoringMethod coloringMethod() const
Returns the coloring method used.
Definition: qgsinterpolatedlinerenderer.cpp:429
QgsInterpolatedLineWidth::fixedStrokeWidth
double fixedStrokeWidth() const
Returns the fixed width.
Definition: qgsinterpolatedlinerenderer.cpp:345
QgsInterpolatedLineWidth::setIsVariableWidth
void setIsVariableWidth(bool isVariableWidth)
Returns whether the width is variable.
Definition: qgsinterpolatedlinerenderer.cpp:365
QgsSymbolLayerUtils::decodeColor
static QColor decodeColor(const QString &str)
Definition: qgssymbollayerutils.cpp:57
QgsInterpolatedLineWidth::setUseAbsoluteValue
void setUseAbsoluteValue(bool useAbsoluteValue)
Sets whether absolute value are used as input.
Definition: qgsinterpolatedlinerenderer.cpp:340
QgsColorRampShader
A ramp shader will color a raster pixel based on a list of values ranges in a ramp.
Definition: qgscolorrampshader.h:40
QgsInterpolatedLineWidth::writeXml
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Writes configuration to a new DOM element.
Definition: qgsinterpolatedlinerenderer.cpp:303
QgsInterpolatedLineRenderer::setInterpolatedWidth
void setInterpolatedWidth(const QgsInterpolatedLineWidth &strokeWidth)
Sets the stroke width used to plot.
Definition: qgsinterpolatedlinerenderer.cpp:21
QgsInterpolatedLineWidth::minimumValue
double minimumValue() const
Returns the minimum value used to defined the variable width.
Definition: qgsinterpolatedlinerenderer.cpp:227
QgsInterpolatedLineColor::ColorRamp
@ ColorRamp
Render with a color ramp.
Definition: qgsinterpolatedlinerenderer.h:46
QgsColorRampShader::Discrete
@ Discrete
Assigns the color of the higher class for every pixel between two class breaks.
Definition: qgscolorrampshader.h:48
QgsInterpolatedLineWidth::setMinimumValue
void setMinimumValue(double minimumValue)
Sets the minimum value used to defined the variable width.
Definition: qgsinterpolatedlinerenderer.cpp:232
QgsInterpolatedLineWidth::setMinimumWidth
void setMinimumWidth(double minimumWidth)
Sets the minimum width used to defined the variable width.
Definition: qgsinterpolatedlinerenderer.cpp:254
QgsColorRampShader::sourceColorRamp
QgsColorRamp * sourceColorRamp() const
Returns the source color ramp.
Definition: qgscolorrampshader.cpp:126
QgsColorRampShader::Exact
@ Exact
Assigns the color of the exact matching value in the color ramp item list.
Definition: qgscolorrampshader.h:49
QgsInterpolatedLineWidth
Represents a width than can vary depending on values.
Definition: qgsinterpolatedlinerenderer.h:111
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:315
QgsInterpolatedLineColor::graduatedColors
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.
Definition: qgsinterpolatedlinerenderer.cpp:464
QgsInterpolatedLineColor
Class defining color to render mesh datasets.
Definition: qgsinterpolatedlinerenderer.h:35
QgsScopedQPainterState
Scoped object for saving and restoring a QPainter object's state.
Definition: qgsrendercontext.h:1120
QgsColorRampShader::readXml
void readXml(const QDomElement &elem)
Reads configuration from the given DOM element.
Definition: qgscolorrampshader.cpp:533
QgsInterpolatedLineColor::color
QColor color(double magnitude) const
Returns the color corresponding to the magnitude.
Definition: qgsinterpolatedlinerenderer.cpp:410
QgsInterpolatedLineWidth::ignoreOutOfRange
bool ignoreOutOfRange() const
Returns whether the variable width ignores out of range value.
Definition: qgsinterpolatedlinerenderer.cpp:350
QgsMapToPixel::transform
QgsPointXY transform(const QgsPointXY &p) const
Transform the point from map (world) coordinates to device coordinates.
Definition: qgsmaptopixel.cpp:217
QgsInterpolatedLineColor::colorRampShader
QgsColorRampShader colorRampShader() const
Returns the color ramp shader.
Definition: qgsinterpolatedlinerenderer.cpp:434
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:44
QgsColorRampShader::colorRampItemList
QList< QgsColorRampShader::ColorRampItem > colorRampItemList() const
Returns the custom colormap.
Definition: qgscolorrampshader.h:105
QgsColorRampShader::colorRampType
Type colorRampType() const
Returns the color ramp type.
Definition: qgscolorrampshader.h:108
QgsInterpolatedLineColor::readXml
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Reads configuration from the given DOM element.
Definition: qgsinterpolatedlinerenderer.cpp:452
QgsInterpolatedLineWidth::useAbsoluteValue
bool useAbsoluteValue() const
Returns whether absolute value are used as input.
Definition: qgsinterpolatedlinerenderer.cpp:335
QgsInterpolatedLineWidth::setMaximumValue
void setMaximumValue(double maximumValue)
Sets the maximum value used to defined the variable width.
Definition: qgsinterpolatedlinerenderer.cpp:243
QgsInterpolatedLineRenderer::setWidthUnit
void setWidthUnit(const QgsUnitTypes::RenderUnit &strokeWidthUnit)
Sets the unit of the stroke width.
Definition: qgsinterpolatedlinerenderer.cpp:31
QgsMapToPixel
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:38
QgsColorRampShader::shade
bool shade(double value, int *returnRedValue, int *returnGreenValue, int *returnBlueValue, int *returnAlphaValue) const override
Generates and new RGB value based on one input value.
Definition: qgscolorrampshader.cpp:321
QgsColorRampShader::clip
bool clip() const
Returns whether the shader will clip values which are out of range.
Definition: qgscolorrampshader.h:200
QgsInterpolatedLineColor::QgsInterpolatedLineColor
QgsInterpolatedLineColor()=default
Default constructor.
qgsinterpolatedlinerenderer.h
QgsInterpolatedLineWidth::setMaximumWidth
void setMaximumWidth(double maximumWidth)
Sets the maximum width used to defined the variable width.
Definition: qgsinterpolatedlinerenderer.cpp:265
QgsRenderContext::painter
QPainter * painter()
Returns the destination QPainter for the render operation.
Definition: qgsrendercontext.h:179
QgsColorRampShader::Interpolated
@ Interpolated
Interpolates the color between two class breaks linearly.
Definition: qgscolorrampshader.h:47
QgsInterpolatedLineWidth::minimumWidth
double minimumWidth() const
Returns the minimum width used to defined the variable width.
Definition: qgsinterpolatedlinerenderer.cpp:249
QgsInterpolatedLineWidth::maximumWidth
double maximumWidth() const
Returns the maximum width used to defined the variable width.
Definition: qgsinterpolatedlinerenderer.cpp:260
QgsInterpolatedLineWidth::maximumValue
double maximumValue() const
Returns the maximum value used to defined the variable width.
Definition: qgsinterpolatedlinerenderer.cpp:238
QgsInterpolatedLineWidth::setFixedStrokeWidth
void setFixedStrokeWidth(double fixedWidth)
Sets the fixed width.
Definition: qgsinterpolatedlinerenderer.cpp:370
QgsInterpolatedLineWidth::isVariableWidth
bool isVariableWidth() const
Returns whether the width is variable.
Definition: qgsinterpolatedlinerenderer.cpp:360
QgsInterpolatedLineRenderer::render
void render(double value1, double value2, QgsPointXY point1, QgsPointXY point2, QgsRenderContext &context) const
Render a line in the context between point1 and point2 with color and width that vary depending on va...
Definition: qgsinterpolatedlinerenderer.cpp:36