QGIS API Documentation  3.21.0-Master (5b68dc587e)
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  else if ( !gradients.isEmpty() && !breakValues.isEmpty() && !breakColors.isEmpty() )
163  {
164  Q_ASSERT( breakColors.count() == breakValues.count() );
165  Q_ASSERT( breakColors.count() == gradients.count() + 1 );
166  double widthColorVariationValueRatio = ( valueWidth2 - valueWidth1 ) / ( valueColor2 - valueColor1 );
167 
168  for ( int i = 0; i < gradients.count(); ++i )
169  {
170  double firstValue = breakValues.at( i );
171  double secondValue = breakValues.at( i + 1 );
172  double w1 = mStrokeWidth.strokeWidth( widthColorVariationValueRatio * ( firstValue - valueColor1 ) + valueWidth1 );
173  double w2 = mStrokeWidth.strokeWidth( widthColorVariationValueRatio * ( secondValue - valueColor1 ) + valueWidth1 );
174 
175  if ( std::isnan( w1 ) && std::isnan( w2 ) )
176  continue;
177 
178  double firstAdjusting = 0;
179  if ( std::isnan( w1 ) )
180  adjustLine( firstValue, valueColor1, valueColor2, w1, firstAdjusting );
181 
182 
183  double secondAdjusting = 0;
184  if ( std::isnan( w2 ) )
185  adjustLine( secondValue, valueColor1, valueColor2, w2, secondAdjusting );
186 
187  w1 = context.convertToPainterUnits( w1, mStrokeWidthUnit );
188  w2 = context.convertToPainterUnits( w2, mStrokeWidthUnit ) ;
189 
190  QPointF pointStart = p1 + dir * ( firstValue - valueColor1 ) / ( valueColor2 - valueColor1 );
191  QPointF pointEnd = p1 + dir * ( secondValue - valueColor1 ) / ( valueColor2 - valueColor1 );
192 
193  QPointF pointStartAdjusted = pointStart + dir * firstAdjusting;
194  QPointF pointEndAdjusted = pointEnd - dir * secondAdjusting;
195 
196  QPolygonF varLine;
197  double sw1 = w1 / 2;
198  double sw2 = w2 / 2;
199 
200  varLine.append( pointStartAdjusted + orthu * sw1 );
201  varLine.append( pointEndAdjusted + orthu * sw2 );
202  varLine.append( pointEndAdjusted - orthu * sw2 );
203  varLine.append( pointStartAdjusted - orthu * sw1 );
204 
205  QLinearGradient gradient = gradients.at( i );
206  gradient.setStart( pointStart );
207  gradient.setFinalStop( pointEnd );
208  QBrush brush( gradient );
209  painter->setBrush( brush );
210 
211  QPen pen;
212  pen.setBrush( brush );
213  pen.setWidthF( 0 );
214  painter->setPen( pen );
215 
216  painter->drawPolygon( varLine );
217  }
218  }
219  }
220  }
221 }
222 
223 
224 void QgsInterpolatedLineRenderer::render( double value1, double value2, const QgsPointXY &pt1, const QgsPointXY &pt2, QgsRenderContext &context ) const
225 {
226  const QgsMapToPixel &mapToPixel = context.mapToPixel();
227 
228  QgsPointXY point1 = pt1;
229  QgsPointXY point2 = pt2;
230 
231  if ( value1 > value2 )
232  {
233  std::swap( value1, value2 );
234  std::swap( point1, point2 );
235  }
236 
237  QPointF p1 = mapToPixel.transform( point1 ).toQPointF();
238  QPointF p2 = mapToPixel.transform( point2 ).toQPointF();
239 
240  renderInDeviceCoordinates( value1, value2, value1, value2, p1, p2, context );
241 }
242 
243 void QgsInterpolatedLineRenderer::render( double valueColor1, double valueColor2, double valueWidth1, double valueWidth2, const QgsPointXY &pt1, const QgsPointXY &pt2, QgsRenderContext &context ) const
244 {
245  const QgsMapToPixel &mapToPixel = context.mapToPixel();
246 
247  QgsPointXY point1 = pt1;
248  QgsPointXY point2 = pt2;
249 
250  if ( valueColor1 > valueColor2 )
251  {
252  std::swap( valueColor1, valueColor2 );
253  std::swap( valueWidth1, valueWidth2 );
254  std::swap( point1, point2 );
255  }
256 
257  QPointF p1 = mapToPixel.transform( point1 ).toQPointF();
258  QPointF p2 = mapToPixel.transform( point2 ).toQPointF();
259 
260  renderInDeviceCoordinates( valueColor1, valueColor2, valueWidth1, valueWidth2, p1, p2, context );
261 }
262 
264 {
265  mSelected = selected;
266 }
267 
268 void QgsInterpolatedLineRenderer::adjustLine( const double value, const double value1, const double value2, double &width, double &adjusting ) const
269 {
270  if ( value > mStrokeWidth.maximumValue() )
271  {
272  adjusting = fabs( ( value - mStrokeWidth.maximumValue() ) / ( value2 - value1 ) );
273  width = mStrokeWidth.maximumWidth();
274  }
275  else
276  {
277  adjusting = fabs( ( value - mStrokeWidth.minimumValue() ) / ( value2 - value1 ) );
278  width = mStrokeWidth.minimumWidth();
279  }
280 }
281 
283 {
284  return mMinimumValue;
285 }
286 
287 void QgsInterpolatedLineWidth::setMinimumValue( double minimumValue )
288 {
289  mMinimumValue = minimumValue;
290  mNeedUpdateFormula = true;
291 }
292 
294 {
295  return mMaximumValue;
296 }
297 
298 void QgsInterpolatedLineWidth::setMaximumValue( double maximumValue )
299 {
300  mMaximumValue = maximumValue;
301  mNeedUpdateFormula = true;
302 }
303 
305 {
306  return mMinimumWidth;
307 }
308 
309 void QgsInterpolatedLineWidth::setMinimumWidth( double minimumWidth )
310 {
311  mMinimumWidth = minimumWidth;
312  mNeedUpdateFormula = true;
313 }
314 
316 {
317  return mMaximumWidth;
318 }
319 
320 void QgsInterpolatedLineWidth::setMaximumWidth( double maximumWidth )
321 {
322  mMaximumWidth = maximumWidth;
323  mNeedUpdateFormula = true;
324 }
325 
326 double QgsInterpolatedLineWidth::strokeWidth( double value ) const
327 {
328  if ( mIsWidthVariable )
329  {
330  if ( mNeedUpdateFormula )
331  updateLinearFormula();
332 
333  if ( mUseAbsoluteValue )
334  value = std::fabs( value );
335 
336  if ( value > mMaximumValue )
337  {
338  if ( mIgnoreOutOfRange )
339  return std::numeric_limits<double>::quiet_NaN();
340  else
341  return mMaximumWidth;
342  }
343 
344  if ( value < mMinimumValue )
345  {
346  if ( mIgnoreOutOfRange )
347  return std::numeric_limits<double>::quiet_NaN();
348  else
349  return mMinimumWidth;
350  }
351 
352  return ( value - mMinimumValue ) * mLinearCoef + mMinimumWidth;
353  }
354  else
355  return fixedStrokeWidth();
356 }
357 
358 QDomElement QgsInterpolatedLineWidth::writeXml( QDomDocument &doc, const QgsReadWriteContext & ) const
359 {
360  QDomElement elem = doc.createElement( QStringLiteral( "mesh-stroke-width" ) );
361 
362  elem.setAttribute( QStringLiteral( "width-varying" ), mIsWidthVariable ? 1 : 0 );
363  elem.setAttribute( QStringLiteral( "fixed-width" ), mFixedWidth );
364  elem.setAttribute( QStringLiteral( "minimum-value" ), mMinimumValue );
365  elem.setAttribute( QStringLiteral( "maximum-value" ), mMaximumValue );
366  elem.setAttribute( QStringLiteral( "minimum-width" ), mMinimumWidth );
367  elem.setAttribute( QStringLiteral( "maximum-width" ), mMaximumWidth );
368  elem.setAttribute( QStringLiteral( "ignore-out-of-range" ), mIgnoreOutOfRange ? 1 : 0 );
369  elem.setAttribute( QStringLiteral( "use-absolute-value" ), mUseAbsoluteValue ? 1 : 0 );
370 
371  return elem;
372 }
373 
374 void QgsInterpolatedLineWidth::readXml( const QDomElement &elem, const QgsReadWriteContext & )
375 {
376  mIsWidthVariable = elem.attribute( QStringLiteral( "width-varying" ) ).toInt();
377  mFixedWidth = elem.attribute( QStringLiteral( "fixed-width" ) ).toDouble();
378  mMinimumValue = elem.attribute( QStringLiteral( "minimum-value" ) ).toDouble();
379  mMaximumValue = elem.attribute( QStringLiteral( "maximum-value" ) ).toDouble();
380  mMinimumWidth = elem.attribute( QStringLiteral( "minimum-width" ) ).toDouble();
381  mMaximumWidth = elem.attribute( QStringLiteral( "maximum-width" ) ).toDouble();
382  mIgnoreOutOfRange = elem.attribute( QStringLiteral( "ignore-out-of-range" ) ).toInt();
383  mUseAbsoluteValue = elem.attribute( QStringLiteral( "use-absolute-value" ) ).toInt();
384 }
385 
387 {
388  return mUseAbsoluteValue;
389 }
390 
392 {
393  mUseAbsoluteValue = useAbsoluteValue;
394 }
395 
397 {
398  return mFixedWidth;
399 }
400 
402 {
403  return mIgnoreOutOfRange;
404 }
405 
407 {
408  mIgnoreOutOfRange = ignoreOutOfRange;
409 }
410 
412 {
413  return mIsWidthVariable;
414 }
415 
417 {
418  mIsWidthVariable = isWidthVarying;
419 }
420 
422 {
423  mFixedWidth = fixedWidth;
424 }
425 
426 void QgsInterpolatedLineWidth::updateLinearFormula() const
427 {
428  if ( !qgsDoubleNear( mMaximumWidth, mMinimumWidth ) )
429  mLinearCoef = ( mMaximumWidth - mMinimumWidth ) / ( mMaximumValue - mMinimumValue ) ;
430  else
431  mLinearCoef = 0;
432  mNeedUpdateFormula = false;
433 }
434 
436 {
437  mColorRampShader.setMinimumValue( std::numeric_limits<double>::quiet_NaN() );
438  mColorRampShader.setMaximumValue( std::numeric_limits<double>::quiet_NaN() );
439 }
440 
442 {
444 }
445 
447 {
448  setColor( color );
449  mColoringMethod = SingleColor;
450  mColorRampShader.setMinimumValue( std::numeric_limits<double>::quiet_NaN() );
451  mColorRampShader.setMaximumValue( std::numeric_limits<double>::quiet_NaN() );
452 }
453 
455 {
456  mColorRampShader = colorRampShader;
457  if ( ( mColorRampShader.sourceColorRamp() ) )
458  mColoringMethod = ColorRamp;
459  else
460  mColoringMethod = SingleColor;
461 }
462 
463 void QgsInterpolatedLineColor::setColor( const QColor &color )
464 {
465  mSingleColor = color;
466 }
467 
468 QColor QgsInterpolatedLineColor::color( double magnitude ) const
469 {
470  QgsColorRamp *lSourceColorRamp = mColorRampShader.sourceColorRamp();
471  if ( mColoringMethod == ColorRamp && lSourceColorRamp )
472  {
473  if ( mColorRampShader.isEmpty() )
474  return lSourceColorRamp->color( 0 );
475 
476  int r, g, b, a;
477  if ( mColorRampShader.shade( magnitude, &r, &g, &b, &a ) )
478  return QColor( r, g, b, a );
479  else
480  return QColor( 0, 0, 0, 0 );
481  }
482  else
483  {
484  return mSingleColor;
485  }
486 }
487 
489 {
490  return mColoringMethod;
491 }
492 
494 {
495  return mColorRampShader;
496 }
497 
499 {
500  return mSingleColor;
501 }
502 
503 QDomElement QgsInterpolatedLineColor::writeXml( QDomDocument &doc, const QgsReadWriteContext & ) const
504 {
505  QDomElement elem = doc.createElement( QStringLiteral( "mesh-stroke-color" ) );
506 
507  elem.setAttribute( QStringLiteral( "single-color" ), QgsSymbolLayerUtils::encodeColor( mSingleColor ) );
508  elem.setAttribute( QStringLiteral( "coloring-method" ), mColoringMethod );
509  elem.appendChild( mColorRampShader.writeXml( doc ) );
510 
511  return elem;
512 }
513 
514 void QgsInterpolatedLineColor::readXml( const QDomElement &elem, const QgsReadWriteContext & )
515 {
516  QDomElement shaderElem = elem.firstChildElement( QStringLiteral( "colorrampshader" ) );
517  mColorRampShader.readXml( shaderElem );
518 
519  mSingleColor = QgsSymbolLayerUtils::decodeColor( elem.attribute( QStringLiteral( "single-color" ) ) );
520  mColoringMethod = static_cast<QgsInterpolatedLineColor::ColoringMethod>(
521  elem.attribute( QStringLiteral( "coloring-method" ) ).toInt() );
522 }
523 
524 void QgsInterpolatedLineColor::graduatedColors( double value1, double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients ) const
525 {
526  breakValues.clear();
527  breakColors.clear();
528  gradients.clear();
529  if ( mColoringMethod == SingleColor )
530  {
531  breakColors.append( mSingleColor );
532  return;
533  }
534 
535  switch ( mColorRampShader.colorRampType() )
536  {
538  graduatedColorsInterpolated( value1, value2, breakValues, breakColors, gradients );
539  break;
541  graduatedColorsDiscrete( value1, value2, breakValues, breakColors, gradients );
542  break;
544  graduatedColorsExact( value1, value2, breakValues, breakColors, gradients );
545  break;
546  }
547 
548 }
549 
551 {
552  mColoringMethod = coloringMethod;
553 }
554 
555 QLinearGradient QgsInterpolatedLineColor::makeSimpleLinearGradient( const QColor &color1, const QColor &color2 ) const
556 {
557  QLinearGradient gradient;
558  gradient.setColorAt( 0, color1 );
559  gradient.setColorAt( 1, color2 );
560 
561  return gradient;
562 }
563 
564 int QgsInterpolatedLineColor::itemColorIndexInf( double value ) const
565 {
566  QList<QgsColorRampShader::ColorRampItem> itemList = mColorRampShader.colorRampItemList();
567 
568  if ( itemList.isEmpty() || itemList.first().value > value )
569  return -1;
570 
571  if ( mColorRampShader.colorRampType() == QgsColorRampShader::Discrete )
572  itemList.removeLast(); //remove the inf value
573 
574  if ( value > itemList.last().value )
575  return itemList.count() - 1;
576 
577  int indSup = itemList.count() - 1;
578  int indInf = 0;
579 
580  while ( true )
581  {
582  if ( abs( indSup - indInf ) <= 1 ) //always indSup>indInf, but abs to prevent infinity loop
583  return indInf;
584 
585  int newInd = ( indInf + indSup ) / 2;
586 
587  if ( std::isnan( itemList.at( newInd ).value ) )
588  return -1;
589 
590  if ( itemList.at( newInd ).value <= value )
591  indInf = newInd;
592  else
593  indSup = newInd;
594  }
595 }
596 
597 void QgsInterpolatedLineColor::graduatedColorsExact( double value1, double value2, QList<double> &breakValues, QList<QColor> &breakColors, const QList<QLinearGradient> &gradients ) const
598 {
599  Q_ASSERT( mColorRampShader.colorRampType() == QgsColorRampShader::Exact );
600  Q_ASSERT( breakValues.isEmpty() );
601  Q_ASSERT( breakColors.isEmpty() );
602  Q_ASSERT( gradients.isEmpty() );
603 
604  const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.colorRampItemList();
605  if ( itemList.isEmpty() )
606  return;
607 
608  int index = itemColorIndexInf( value1 );
609  if ( index < 0 || !qgsDoubleNear( value1, itemList.at( index ).value ) )
610  index++;
611 
612  if ( qgsDoubleNear( value1, value2 ) && qgsDoubleNear( value1, itemList.at( index ).value ) )
613  {
614  //the two value are the same and are equal to the value in the item list --> render only one color
615  breakColors.append( itemList.at( index ).color );
616  return;
617  }
618 
619  while ( index < itemList.count() && itemList.at( index ).value <= value2 )
620  {
621  breakValues.append( itemList.at( index ).value );
622  breakColors.append( itemList.at( index ).color );
623  index++;
624  }
625 }
626 
627 void QgsInterpolatedLineColor::graduatedColorsInterpolated( double value1, double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients ) const
628 {
629  Q_ASSERT( mColorRampShader.colorRampType() == QgsColorRampShader::Interpolated );
630  Q_ASSERT( breakValues.isEmpty() );
631  Q_ASSERT( breakColors.isEmpty() );
632  Q_ASSERT( gradients.isEmpty() );
633 
634 
635  const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.colorRampItemList();
636  if ( itemList.empty() )
637  return;
638 
639  if ( itemList.count() == 1 )
640  {
641  breakColors.append( itemList.first().color );
642  return;
643  }
644 
645  if ( value2 <= itemList.first().value ) // completely out of range and less
646  {
647  if ( !mColorRampShader.clip() )
648  breakColors.append( itemList.first().color ); // render only the first color in the whole range if not clipped
649  return;
650  }
651 
652  if ( value1 > itemList.last().value ) // completely out of range and greater
653  {
654  if ( !mColorRampShader.clip() )
655  breakColors.append( itemList.last().color ); // render only the last color in the whole range if not clipped
656  return;
657  }
658 
659  if ( qgsDoubleNear( value1, value2 ) )
660  {
661  // the two values are the same
662  // --> render only one color
663  int r, g, b, a;
664  QColor color;
665  if ( mColorRampShader.shade( value1, &r, &g, &b, &a ) )
666  color = QColor( r, g, b, a );
667  breakColors.append( color );
668  return;
669  }
670 
671  // index of the inf value of the interval where value1 is in the color ramp shader
672  int index = itemColorIndexInf( value1 );
673  if ( index < 0 ) // value1 out of range
674  {
675  QColor color = itemList.first().color;
676  breakColors.append( color );
677  if ( mColorRampShader.clip() ) // The first value/color returned is the first of the item list
678  breakValues.append( itemList.first().value );
679  else // The first value/color returned is the first color of the item list and value1
680  breakValues.append( value1 );
681  }
682  else
683  {
684  // shade the color
685  int r, g, b, a;
686  QColor color;
687  if ( mColorRampShader.shade( value1, &r, &g, &b, &a ) )
688  color = QColor( r, g, b, a );
689  breakValues.append( value1 );
690  breakColors.append( color );
691  }
692 
693  index++; // increment the index before go through the intervals
694 
695  while ( index < itemList.count() && itemList.at( index ).value < value2 )
696  {
697  QColor color1 = breakColors.last();
698  QColor color2 = itemList.at( index ).color;
699  breakValues.append( itemList.at( index ).value );
700  breakColors.append( color2 );
701  gradients.append( makeSimpleLinearGradient( color1, color2 ) );
702  index++;
703  }
704 
705  // close the lists with value2 or last item if >value2
706  QColor color1 = breakColors.last();
707  QColor color2;
708  if ( value2 < itemList.last().value )
709  {
710  int r, g, b, a;
711  if ( mColorRampShader.shade( value2, &r, &g, &b, &a ) )
712  color2 = QColor( r, g, b, a );
713  breakValues.append( value2 );
714  }
715  else
716  {
717  color2 = itemList.last().color;
718  if ( mColorRampShader.clip() )
719  breakValues.append( itemList.last().value );
720  else
721  breakValues.append( value2 );
722  }
723  breakColors.append( color2 );
724  gradients.append( makeSimpleLinearGradient( color1, color2 ) );
725 }
726 
727 
728 void QgsInterpolatedLineColor::graduatedColorsDiscrete( double value1, double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients ) const
729 {
730  Q_ASSERT( mColorRampShader.colorRampType() == QgsColorRampShader::Discrete );
731  Q_ASSERT( breakValues.isEmpty() );
732  Q_ASSERT( breakColors.isEmpty() );
733  Q_ASSERT( gradients.isEmpty() );
734 
735  const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.colorRampItemList();
736  if ( itemList.empty() )
737  return;
738 
739  if ( itemList.count() == 1 )
740  {
741  breakColors.append( itemList.first().color );
742  return;
743  }
744 
745  double lastValue = itemList.at( itemList.count() - 2 ).value;
746 
747 
748  if ( value2 <= itemList.first().value ) // completely out of range and less
749  {
750  breakColors.append( itemList.first().color ); // render only the first color in the whole range
751  return;
752  }
753 
754  if ( value1 > lastValue ) // completely out of range and greater
755  {
756  breakColors.append( itemList.last().color ); // render only the last color in the whole range
757  return;
758  }
759 
760  // index of the inf value of the interval where value1 is in the color ramp shader
761  int index = itemColorIndexInf( value1 );
762 
763  if ( qgsDoubleNear( value1, value2 ) )
764  {
765  // the two values are the same and are equal to the value in the item list
766  // --> render only one color, the sup one
767  breakColors.append( itemList.at( index + 1 ).color );
768  return;
769  }
770 
771  if ( index < 0 ) // value1 out of range
772  {
773  breakValues.append( value1 );
774  breakColors.append( itemList.first().color );
775  }
776  else // append the first value with corresponding color
777  {
778  QColor color = itemList.at( index ).color;
779  breakValues.append( value1 );
780  breakColors.append( color );
781  }
782 
783  index++; // increment the index before go through the intervals
784 
785  while ( index < ( itemList.count() - 1 ) && itemList.at( index ).value < value2 )
786  {
787  QColor color = itemList.at( index ).color;
788  breakValues.append( itemList.at( index ).value );
789  breakColors.append( color );
790  gradients.append( makeSimpleLinearGradient( color, color ) );
791  index++;
792  }
793 
794  // add value2 to close
795  QColor lastColor = itemList.at( index ).color;
796  breakColors.append( lastColor );
797  breakValues.append( value2 );
798  gradients.append( makeSimpleLinearGradient( lastColor, lastColor ) );
799 
800 }
801 
802 QString QgsInterpolatedLineSymbolLayer::layerType() const {return QStringLiteral( "InterpolatedLine" );}
803 
805 {
806 }
807 
809 {
810 }
811 
813 {
816  copyPaintEffect( l );
817  return l;
818 }
819 
821 {
822  std::unique_ptr<QgsInterpolatedLineSymbolLayer> symbolLayer;
823  symbolLayer.reset( new QgsInterpolatedLineSymbolLayer() );
824 
825  if ( properties.contains( QStringLiteral( "start_width_expression" ) ) )
826  symbolLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyLineStartWidthValue, QgsProperty::fromExpression( properties.value( QStringLiteral( "start_width_expression" ) ).toString() ) );
827  if ( properties.contains( QStringLiteral( "end_width_expression" ) ) )
828  symbolLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyLineEndWidthValue, QgsProperty::fromExpression( properties.value( QStringLiteral( "end_width_expression" ) ).toString() ) );
829 
830  if ( properties.contains( QStringLiteral( "start_color_expression" ) ) )
831  symbolLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyLineStartColorValue, QgsProperty::fromExpression( properties.value( QStringLiteral( "start_color_expression" ) ).toString() ) );
832  if ( properties.contains( QStringLiteral( "end_color_expression" ) ) )
833  symbolLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyLineEndColorValue, QgsProperty::fromExpression( properties.value( QStringLiteral( "end_color_expression" ) ).toString() ) );
834 
835  if ( properties.contains( QStringLiteral( "line_width" ) ) )
836  symbolLayer->mLineRender.mStrokeWidth.setFixedStrokeWidth( properties.value( QStringLiteral( "line_width" ) ).toDouble() ) ;
837  if ( properties.contains( QStringLiteral( "line_width_unit" ) ) )
838  symbolLayer->mLineRender.setWidthUnit( QgsUnitTypes::decodeRenderUnit( properties.value( QStringLiteral( "line_width_unit" ) ).toString() ) );
839  if ( properties.contains( QStringLiteral( "width_varying_minimum_value" ) ) )
840  symbolLayer->mLineRender.mStrokeWidth.setMinimumValue( properties.value( QStringLiteral( "width_varying_minimum_value" ) ).toDouble() );
841  if ( properties.contains( QStringLiteral( "width_varying_maximum_value" ) ) )
842  symbolLayer->mLineRender.mStrokeWidth.setMaximumValue( properties.value( QStringLiteral( "width_varying_maximum_value" ) ).toDouble() );
843  if ( properties.contains( QStringLiteral( "width_varying_use_absolute_value" ) ) )
844  symbolLayer->mLineRender.mStrokeWidth.setUseAbsoluteValue( properties.value( QStringLiteral( "width_varying_use_absolute_value" ) ).toInt() );
845  if ( properties.contains( QStringLiteral( "width_varying_minimum_width" ) ) )
846  symbolLayer->mLineRender.mStrokeWidth.setMinimumWidth( properties.value( QStringLiteral( "width_varying_minimum_width" ) ).toDouble() );
847  if ( properties.contains( QStringLiteral( "width_varying_maximum_width" ) ) )
848  symbolLayer->mLineRender.mStrokeWidth.setMaximumWidth( properties.value( QStringLiteral( "width_varying_maximum_width" ) ).toDouble() );
849  if ( properties.contains( QStringLiteral( "width_varying_ignore_out_of_range" ) ) )
850  symbolLayer->mLineRender.mStrokeWidth.setIgnoreOutOfRange( properties.value( QStringLiteral( "width_varying_ignore_out_of_range" ) ).toInt() );
851  if ( properties.contains( QStringLiteral( "width_varying_is_variable_width" ) ) )
852  symbolLayer->mLineRender.mStrokeWidth.setIsVariableWidth( properties.value( QStringLiteral( "width_varying_is_variable_width" ) ).toInt() );
853 
854  if ( properties.contains( QStringLiteral( "single_color" ) ) )
855  symbolLayer->mLineRender.mStrokeColoring.setColor( QgsSymbolLayerUtils::decodeColor( properties.value( QStringLiteral( "single_color" ) ).toString() ) );
856  if ( properties.contains( QStringLiteral( "color_ramp_shader" ) ) )
857  symbolLayer->mLineRender.mStrokeColoring.setColor( createColorRampShaderFromProperties( properties.value( QStringLiteral( "color_ramp_shader" ) ) ) );
858  if ( properties.contains( QStringLiteral( "coloring_method" ) ) )
859  symbolLayer->mLineRender.mStrokeColoring.setColoringMethod(
860  static_cast<QgsInterpolatedLineColor::ColoringMethod>( properties.value( QStringLiteral( "coloring_method" ) ).toInt() ) );
861 
862  return symbolLayer.release();
863 }
864 
865 Qgis::SymbolLayerFlags QgsInterpolatedLineSymbolLayer::flags() const
866 {
868 }
869 
871 {
872  QVariantMap props;
873 
874  // Line width varying
875  props.insert( QStringLiteral( "line_width" ), QString::number( mLineRender.mStrokeWidth.fixedStrokeWidth() ) );
876  props.insert( QStringLiteral( "line_width_unit" ), QgsUnitTypes::encodeUnit( mLineRender.widthUnit() ) );
877  props.insert( QStringLiteral( "width_varying_minimum_value" ), mLineRender.mStrokeWidth.minimumValue() );
878  props.insert( QStringLiteral( "width_varying_maximum_value" ), mLineRender.mStrokeWidth.maximumValue() );
879  props.insert( QStringLiteral( "width_varying_use_absolute_value" ), mLineRender.mStrokeWidth.useAbsoluteValue() ? 1 : 0 );
880  props.insert( QStringLiteral( "width_varying_minimum_width" ), mLineRender.mStrokeWidth.minimumWidth() );
881  props.insert( QStringLiteral( "width_varying_maximum_width" ), mLineRender.mStrokeWidth.maximumWidth() );
882  props.insert( QStringLiteral( "width_varying_ignore_out_of_range" ), mLineRender.mStrokeWidth.ignoreOutOfRange() ? 1 : 0 );
883  props.insert( QStringLiteral( "width_varying_is_variable_width" ), mLineRender.mStrokeWidth.isVariableWidth() ? 1 : 0 );
884 
885  // Color varying
886  props.insert( QStringLiteral( "coloring_method" ), mLineRender.mStrokeColoring.coloringMethod() );
887  props.insert( QStringLiteral( "single_color" ), QgsSymbolLayerUtils::encodeColor( mLineRender.mStrokeColoring.singleColor() ) );
888  props.insert( QStringLiteral( "color_ramp_shader" ), colorRampShaderProperties() );
889 
890  return props;
891 }
892 
894 {
895  QgsGeometry geometry = context.patchShape() ? context.patchShape()->geometry()
897 
898  startRender( context );
899  double min = std::min( mLineRender.interpolatedLineWidth().minimumValue(), mLineRender.interpolatedColor().colorRampShader().minimumValue() );
900  double max = std::max( mLineRender.interpolatedLineWidth().maximumValue(), mLineRender.interpolatedColor().colorRampShader().maximumValue() );
901 
902  double totalLength = geometry.length();
903  if ( qgsDoubleNear( totalLength, 0 ) )
904  return;
905 
906  double variation = ( max - min ) / totalLength;
907 
908  QPolygonF points = geometry.asQPolygonF();
909  double lengthFromStart = 0;
910  for ( int i = 1; i < points.count(); ++i )
911  {
912  QPointF p1 = points.at( i - 1 );
913  QPointF p2 = points.at( i );
914 
915  double v1 = min + variation * lengthFromStart;
916  QPointF vectDist = p2 - p1;
917  lengthFromStart += sqrt( pow( vectDist.x(), 2 ) + pow( vectDist.y(), 2 ) );
918  double v2 = min + variation * lengthFromStart;
919  mLineRender.renderInDeviceCoordinates( v1, v2, v1, v2, p1, p2, context.renderContext() );
920  }
921 
922  renderPolyline( points, context );
923 }
924 
925 
926 void QgsInterpolatedLineSymbolLayer::setExpressionsStringForWidth( const QString &start, const QString &end )
927 {
928  if ( start.isEmpty() )
930  else
932 
933  if ( end.isEmpty() )
935  else
937 }
938 
940 {
942 }
943 
945 {
947 }
948 
950 {
951  mLineRender.mStrokeWidthUnit = strokeWidthUnit;
952 }
953 
955 
957 {
958  mLineRender.mStrokeWidth = interpolatedLineWidth;
959 }
960 
962 
963 void QgsInterpolatedLineSymbolLayer::setExpressionsStringForColor( const QString &start, const QString &end )
964 {
965  if ( start.isEmpty() )
967  else
969 
970  if ( end.isEmpty() )
972  else
974 }
975 
977 {
979 }
980 
982 {
984 }
985 
987 {
988  mLineRender.setInterpolatedColor( interpolatedLineColor );
989 }
990 
992 {
993  return mLineRender.interpolatedColor();
994 }
995 
996 QVariant QgsInterpolatedLineSymbolLayer::colorRampShaderProperties() const
997 {
998  const QgsColorRampShader &colorRampShader = mLineRender.mStrokeColoring.colorRampShader();
999 
1000  QVariantMap props;
1001  if ( colorRampShader.sourceColorRamp() )
1002  props.insert( QStringLiteral( "color_ramp_source" ), QgsSymbolLayerUtils::colorRampToVariant( QString(), colorRampShader.sourceColorRamp() ) );
1003  props.insert( QStringLiteral( "color_ramp_shader_type" ), colorRampShader.colorRampType() );
1004  props.insert( QStringLiteral( "color_ramp_shader_classification_mode" ), colorRampShader.classificationMode() );
1005  QVariantList colorRampItemListVariant;
1006 
1007  const QList<QgsColorRampShader::ColorRampItem> colorRampItemList = colorRampShader.colorRampItemList();
1008  for ( const QgsColorRampShader::ColorRampItem &item : colorRampItemList )
1009  {
1010  QVariantMap itemVar;
1011  itemVar[QStringLiteral( "label" )] = item.label;
1012  itemVar[QStringLiteral( "color" )] = QgsSymbolLayerUtils::encodeColor( item.color );
1013  itemVar[QStringLiteral( "value" )] = item.value;
1014  colorRampItemListVariant.append( itemVar );
1015  }
1016  props.insert( QStringLiteral( "color_ramp_shader_items_list" ), colorRampItemListVariant );
1017 
1018  props.insert( QStringLiteral( "color_ramp_shader_minimum_value" ), colorRampShader.minimumValue() );
1019  props.insert( QStringLiteral( "color_ramp_shader_maximum_value" ), colorRampShader.maximumValue() );
1020  props.insert( QStringLiteral( "color_ramp_shader_value_out_of_range" ), colorRampShader.clip() ? 1 : 0 );
1021  props.insert( QStringLiteral( "color_ramp_shader_label_precision" ), colorRampShader.labelPrecision() );
1022 
1023  return props;
1024 }
1025 
1026 QgsColorRampShader QgsInterpolatedLineSymbolLayer::createColorRampShaderFromProperties( const QVariant &properties )
1027 {
1028  QgsColorRampShader colorRampShader;
1029 
1030  if ( properties.type() != QVariant::Map )
1031  return colorRampShader;
1032 
1033  QVariantMap shaderVariantMap = properties.toMap();
1034 
1035  if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_source" ) ) )
1036  colorRampShader.setSourceColorRamp( QgsSymbolLayerUtils::loadColorRamp( shaderVariantMap.value( QStringLiteral( "color_ramp_source" ) ) ) );
1037 
1038  if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_type" ) ) )
1039  colorRampShader.setColorRampType( static_cast<QgsColorRampShader::Type>( shaderVariantMap.value( QStringLiteral( "color_ramp_shader_type" ) ).toInt() ) );
1040  if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_classification_mode" ) ) )
1041  colorRampShader.setClassificationMode( static_cast<QgsColorRampShader::ClassificationMode>(
1042  shaderVariantMap.value( QStringLiteral( "color_ramp_shader_classification_mode" ) ).toInt() ) );
1043 
1044  if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_items_list" ) ) )
1045  {
1046  QVariant colorRampItemsVar = shaderVariantMap.value( QStringLiteral( "color_ramp_shader_items_list" ) );
1047  if ( colorRampItemsVar.type() == QVariant::List )
1048  {
1049  QVariantList itemVariantList = colorRampItemsVar.toList();
1050  QList<QgsColorRampShader::ColorRampItem> colorRampItemList;
1051  for ( const QVariant &itemVar : std::as_const( itemVariantList ) )
1052  {
1054  if ( itemVar.type() != QVariant::Map )
1055  continue;
1056  QVariantMap itemVarMap = itemVar.toMap();
1057  if ( !itemVarMap.contains( QStringLiteral( "label" ) ) || !itemVarMap.contains( QStringLiteral( "color" ) ) || !itemVarMap.contains( QStringLiteral( "value" ) ) )
1058  continue;
1059 
1060  item.label = itemVarMap.value( QStringLiteral( "label" ) ).toString();
1061  item.color = QgsSymbolLayerUtils::decodeColor( itemVarMap.value( QStringLiteral( "color" ) ).toString() );
1062  item.value = itemVarMap.value( QStringLiteral( "value" ) ).toDouble();
1063 
1064  colorRampItemList.append( item );
1065  }
1066  colorRampShader.setColorRampItemList( colorRampItemList );
1067  }
1068  }
1069 
1070  if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_minimum_value" ) ) )
1071  colorRampShader.setMinimumValue( shaderVariantMap.value( QStringLiteral( "color_ramp_shader_minimum_value" ) ).toDouble() );
1072  else
1073  colorRampShader.setMinimumValue( std::numeric_limits<double>::quiet_NaN() );
1074 
1075  if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_maximum_value" ) ) )
1076  colorRampShader.setMaximumValue( shaderVariantMap.value( QStringLiteral( "color_ramp_shader_maximum_value" ) ).toDouble() );
1077  else
1078  colorRampShader.setMaximumValue( std::numeric_limits<double>::quiet_NaN() );
1079 
1080  if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_value_out_of_range" ) ) )
1081  colorRampShader.setClip( shaderVariantMap.value( QStringLiteral( "color_ramp_shader_value_out_of_range" ) ).toInt() == 1 );
1082  if ( shaderVariantMap.contains( QStringLiteral( "color_ramp_shader_label_precision" ) ) )
1083  colorRampShader.setLabelPrecision( shaderVariantMap.value( QStringLiteral( "color_ramp_shader_label_precision" ) ).toInt() );
1084 
1085  return colorRampShader;
1086 }
1087 
1089 
1090 
1092 {
1093  mRenderingFeature = true;
1094  mLineParts.clear();
1095 }
1096 
1098 {
1099  mRenderingFeature = false;
1100 
1101  if ( mLineParts.empty() )
1102  return;
1103 
1104  render( mLineParts, context );
1105  mLineParts.clear();
1106 }
1107 
1108 void QgsInterpolatedLineSymbolLayer::render( const QVector< QPolygonF > &parts, QgsRenderContext &context )
1109 {
1110  const double totalLength = std::accumulate( parts.begin(), parts.end(), 0.0, []( double total, const QPolygonF & part )
1111  {
1112  return total + QgsSymbolLayerUtils::polylineLength( part );
1113  } );
1114 
1115  if ( qgsDoubleNear( totalLength, 0 ) )
1116  return;
1117 
1118  double startValWidth = 0;
1119  double variationPerMapUnitWidth = 0;
1120  double startValColor = 0;
1121  double variationPerMapUnitColor = 0;
1122 
1123  bool ok = true;
1124 
1125  if ( mLineRender.interpolatedLineWidth().isVariableWidth() )
1126  {
1128  {
1130  if ( !ok )
1131  return;
1132  }
1133 
1134  double endValWidth = 0;
1136  {
1138  if ( !ok )
1139  return;
1140  }
1141 
1142  variationPerMapUnitWidth = ( endValWidth - startValWidth ) / totalLength;
1143  }
1144 
1146  {
1148  {
1150  if ( !ok )
1151  return;
1152  }
1153 
1154  double endValColor = 0;
1156  {
1158  if ( !ok )
1159  return;
1160  }
1161 
1162  variationPerMapUnitColor = ( endValColor - startValColor ) / totalLength;
1163  }
1164 
1165  for ( const QPolygonF &poly : parts )
1166  {
1167  double lengthFromStart = 0;
1168  for ( int i = 1; i < poly.count(); ++i )
1169  {
1170  const QPointF p1 = poly.at( i - 1 );
1171  const QPointF p2 = poly.at( i );
1172 
1173  const double v1c = startValColor + variationPerMapUnitColor * lengthFromStart;
1174  const double v1w = startValWidth + variationPerMapUnitWidth * lengthFromStart;
1175  lengthFromStart += std::sqrt( ( p1.x() - p2.x() ) * ( p1.x() - p2.x() ) + ( p1.y() - p2.y() ) * ( p1.y() - p2.y() ) );
1176  const double v2c = startValColor + variationPerMapUnitColor * lengthFromStart;
1177  const double v2w = startValWidth + variationPerMapUnitWidth * lengthFromStart;
1178  mLineRender.renderInDeviceCoordinates( v1c, v2c, v1w, v2w, p1, p2, context );
1179  }
1180  }
1181 }
1182 
1184 {
1185  mLineRender.setSelected( context.selected() );
1186 
1187  if ( points.empty() )
1188  return;
1189 
1190  if ( mRenderingFeature )
1191  {
1192  // in the middle of rendering a possibly multi-part feature, so we collect all the parts and defer the actual rendering
1193  // until after we've received the final part
1194  mLineParts.append( points );
1195  }
1196  else
1197  {
1198  // not rendering a feature, so we can just render the polyline immediately
1199  render( { points }, context.renderContext() );
1200  }
1201 }
1202 
1204 {
1205  return symbol && symbol->type() == Qgis::SymbolType::Line;
1206 }
1207 
1209 {
1210  return true;
1211 }
@ 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:124
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:1234