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