23 mStrokeWidth = strokeWidth;
28 mStrokeColoring = strokeColoring;
33 mStrokeWidthUnit = strokeWidthUnit;
38 QPainter *painter = context.
painter();
41 painter->setRenderHint( QPainter::Antialiasing,
true );
45 if ( value1 > value2 )
47 std::swap( value1, value2 );
48 std::swap( point1, point2 );
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() );
58 QList<double> breakValues;
59 QList<QColor> breakColors;
60 QList<QLinearGradient> gradients;
62 mStrokeColoring.
graduatedColors( value1, value2, breakValues, breakColors, gradients );
64 if ( gradients.isEmpty() && !breakValues.empty() && !breakColors.isEmpty() )
66 Q_ASSERT( breakColors.count() == breakValues.count() );
67 for (
int i = 0; i < breakValues.count(); ++i )
69 double value = breakValues.at( i );
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 );
84 if ( !std::isnan( width1 ) || !std::isnan( width2 ) )
87 QBrush brush( Qt::SolidPattern );
90 startAngle = ( acos( -orthu.x() ) / M_PI ) * 180;
92 startAngle = 360 - startAngle;
94 bool outOfRange1 = std::isnan( width1 );
95 bool outOfRange2 = std::isnan( width2 );
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 );
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 );
119 if ( gradients.isEmpty() && breakValues.empty() && breakColors.count() == 1 )
121 double startAdjusting = 0;
123 adjustLine( value1, value1, value2, width1, startAdjusting );
126 double endAdjusting = 0;
128 adjustLine( value2, value1, value2, width2, endAdjusting );
130 QPointF pointStartAdjusted = p1 + dir * startAdjusting;
131 QPointF pointEndAdjusted = p2 - dir * endAdjusting;
134 double semiWidth1 = width1 / 2;
135 double semiWidth2 = width2 / 2;
137 varLine.append( pointStartAdjusted + orthu * semiWidth1 );
138 varLine.append( pointEndAdjusted + orthu * semiWidth2 );
139 varLine.append( pointEndAdjusted - orthu * semiWidth2 );
140 varLine.append( pointStartAdjusted - orthu * semiWidth1 );
142 QBrush brush( Qt::SolidPattern );
143 brush.setColor( breakColors.first() );
144 painter->setBrush( brush );
145 painter->setPen( pen );
148 pen.setBrush( brush );
150 painter->setPen( pen );
152 painter->drawPolygon( varLine );
154 else if ( !gradients.isEmpty() && !breakValues.isEmpty() && !breakColors.isEmpty() )
156 Q_ASSERT( breakColors.count() == breakValues.count() );
157 Q_ASSERT( breakColors.count() == gradients.count() + 1 );
159 for (
int i = 0; i < gradients.count(); ++i )
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 );
166 if ( std::isnan( w1 ) && std::isnan( w2 ) )
169 double firstAdjusting = 0;
170 if ( std::isnan( w1 ) )
171 adjustLine( firstValue, value1, value2, w1, firstAdjusting );
174 double secondAdjusting = 0;
175 if ( std::isnan( w2 ) )
176 adjustLine( secondValue, value1, value2, w2, secondAdjusting );
181 QPointF pointStart = p1 + dir * ( firstValue - value1 ) / ( value2 - value1 );
182 QPointF pointEnd = p1 + dir * ( secondValue - value1 ) / ( value2 - value1 );
184 QPointF pointStartAdjusted = pointStart + dir * firstAdjusting;
185 QPointF pointEndAdjusted = pointEnd - dir * secondAdjusting;
191 varLine.append( pointStartAdjusted + orthu * sw1 );
192 varLine.append( pointEndAdjusted + orthu * sw2 );
193 varLine.append( pointEndAdjusted - orthu * sw2 );
194 varLine.append( pointStartAdjusted - orthu * sw1 );
196 QLinearGradient gradient = gradients.at( i );
197 gradient.setStart( pointStart );
198 gradient.setFinalStop( pointEnd );
199 QBrush brush( gradient );
200 painter->setBrush( brush );
203 pen.setBrush( brush );
205 painter->setPen( pen );
207 painter->drawPolygon( varLine );
215 void QgsInterpolatedLineRenderer::adjustLine(
const double &value,
const double &value1,
const double &value2,
double &width,
double &adjusting )
const
219 adjusting = fabs( ( value - mStrokeWidth.
maximumValue() ) / ( value2 - value1 ) );
224 adjusting = fabs( ( value - mStrokeWidth.
minimumValue() ) / ( value2 - value1 ) );
231 return mMinimumValue;
237 mNeedUpdateFormula =
true;
242 return mMaximumValue;
248 mNeedUpdateFormula =
true;
253 return mMinimumWidth;
259 mNeedUpdateFormula =
true;
264 return mMaximumWidth;
270 mNeedUpdateFormula =
true;
275 if ( mIsWidthVariable )
277 if ( mNeedUpdateFormula )
278 updateLinearFormula();
280 if ( mUseAbsoluteValue )
281 value = std::fabs( value );
283 if ( value > mMaximumValue )
285 if ( mIgnoreOutOfRange )
286 return std::numeric_limits<double>::quiet_NaN();
288 return mMaximumWidth;
291 if ( value < mMinimumValue )
293 if ( mIgnoreOutOfRange )
294 return std::numeric_limits<double>::quiet_NaN();
296 return mMinimumWidth;
299 return ( value - mMinimumValue ) * mLinearCoef + mMinimumWidth;
309 QDomElement elem = doc.createElement( QStringLiteral(
"mesh-stroke-width" ) );
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 );
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();
339 return mUseAbsoluteValue;
354 return mIgnoreOutOfRange;
364 return mIsWidthVariable;
369 mIsWidthVariable = isWidthVarying;
374 mFixedWidth = fixedWidth;
377 void QgsInterpolatedLineWidth::updateLinearFormula()
const
379 if ( mMaximumWidth - mMinimumWidth != 0 )
380 mLinearCoef = ( mMaximumWidth - mMinimumWidth ) / ( mMaximumValue - mMinimumValue ) ;
383 mNeedUpdateFormula =
false;
409 mSingleColor =
color;
416 if ( mColorRampShader.
isEmpty() )
420 if ( mColorRampShader.
shade( magnitude, &r, &g, &b, &a ) )
421 return QColor( r, g, b, a );
423 return QColor( 0, 0, 0, 0 );
433 return mColoringMethod;
438 return mColorRampShader;
445 QDomElement elem = doc.createElement( QStringLiteral(
"mesh-stroke-color" ) );
448 elem.setAttribute( QStringLiteral(
"coloring-method" ), mColoringMethod );
449 elem.appendChild( mColorRampShader.
writeXml( doc ) );
458 QDomElement shaderElem = elem.firstChildElement( QStringLiteral(
"colorrampshader" ) );
459 mColorRampShader.
readXml( shaderElem );
463 elem.attribute( QStringLiteral(
"coloring-method" ) ).toInt() );
473 breakValues.append( value1 );
474 breakColors.append( mSingleColor );
475 breakValues.append( value2 );
476 breakColors.append( mSingleColor );
477 gradients.append( makeSimpleLinearGradient( mSingleColor, mSingleColor ) );
484 graduatedColorsInterpolated( value1, value2, breakValues, breakColors, gradients );
487 graduatedColorsDiscrete( value1, value2, breakValues, breakColors, gradients );
490 graduatedColorsExact( value1, value2, breakValues, breakColors, gradients );
496 QLinearGradient QgsInterpolatedLineColor::makeSimpleLinearGradient(
const QColor &color1,
const QColor &color2 )
const
498 QLinearGradient gradient;
499 gradient.setColorAt( 0, color1 );
500 gradient.setColorAt( 1, color2 );
505 int QgsInterpolatedLineColor::itemColorIndexInf(
double value )
const
507 QList<QgsColorRampShader::ColorRampItem> itemList = mColorRampShader.
colorRampItemList();
509 if ( itemList.isEmpty() || itemList.first().value > value )
513 itemList.removeLast();
515 if ( value > itemList.last().value )
516 return itemList.count() - 1;
518 int indSup = itemList.count() - 1;
523 if ( abs( indSup - indInf ) <= 1 )
526 int newInd = ( indInf + indSup ) / 2;
528 if ( itemList.at( newInd ).value == std::numeric_limits<double>::quiet_NaN() )
531 if ( itemList.at( newInd ).value <= value )
538 void QgsInterpolatedLineColor::graduatedColorsExact(
double value1,
double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients )
const
541 Q_ASSERT( breakValues.isEmpty() );
542 Q_ASSERT( breakColors.isEmpty() );
543 Q_ASSERT( gradients.isEmpty() );
545 const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.
colorRampItemList();
546 if ( itemList.isEmpty() )
549 int index = itemColorIndexInf( value1 );
550 if ( index < 0 || !
qgsDoubleNear( value1, itemList.at( index ).value ) )
556 breakColors.append( itemList.at( index ).color );
560 while ( index < itemList.count() && itemList.at( index ).value <= value2 )
562 breakValues.append( itemList.at( index ).value );
563 breakColors.append( itemList.at( index ).color );
568 void QgsInterpolatedLineColor::graduatedColorsInterpolated(
double value1,
double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients )
const
571 Q_ASSERT( breakValues.isEmpty() );
572 Q_ASSERT( breakColors.isEmpty() );
573 Q_ASSERT( gradients.isEmpty() );
576 const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.
colorRampItemList();
577 if ( itemList.empty() )
580 if ( itemList.count() == 1 )
582 breakColors.append( itemList.first().color );
586 if ( value2 <= itemList.first().value )
588 if ( !mColorRampShader.
clip() )
589 breakColors.append( itemList.first().color );
593 if ( value1 > itemList.last().value )
595 if ( !mColorRampShader.
clip() )
596 breakColors.append( itemList.last().color );
606 if ( mColorRampShader.
shade( value1, &r, &g, &b, &a ) )
607 color = QColor( r, g, b, a );
608 breakColors.append(
color );
613 int index = itemColorIndexInf( value1 );
616 QColor
color = itemList.first().color;
617 breakColors.append(
color );
618 if ( mColorRampShader.
clip() )
619 breakValues.append( itemList.first().value );
621 breakValues.append( value1 );
628 if ( mColorRampShader.
shade( value1, &r, &g, &b, &a ) )
629 color = QColor( r, g, b, a );
630 breakValues.append( value1 );
631 breakColors.append(
color );
636 while ( index < itemList.count() && itemList.at( index ).value < value2 )
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 ) );
647 QColor color1 = breakColors.last();
649 if ( value2 < itemList.last().value )
652 if ( mColorRampShader.
shade( value2, &r, &g, &b, &a ) )
653 color2 = QColor( r, g, b, a );
654 breakValues.append( value2 );
658 color2 = itemList.last().color;
659 if ( mColorRampShader.
clip() )
660 breakValues.append( itemList.last().value );
662 breakValues.append( value2 );
664 breakColors.append( color2 );
665 gradients.append( makeSimpleLinearGradient( color1, color2 ) );
669 void QgsInterpolatedLineColor::graduatedColorsDiscrete(
double value1,
double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients )
const
672 Q_ASSERT( breakValues.isEmpty() );
673 Q_ASSERT( breakColors.isEmpty() );
674 Q_ASSERT( gradients.isEmpty() );
676 const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.
colorRampItemList();
677 if ( itemList.empty() )
680 if ( itemList.count() == 1 )
682 breakColors.append( itemList.first().color );
686 double lastValue = itemList.at( itemList.count() - 2 ).value;
689 if ( value2 <= itemList.first().value )
691 breakColors.append( itemList.first().color );
695 if ( value1 > lastValue )
697 breakColors.append( itemList.last().color );
702 int index = itemColorIndexInf( value1 );
708 breakColors.append( itemList.at( index + 1 ).color );
714 breakValues.append( value1 );
715 breakColors.append( itemList.first().color );
719 QColor
color = itemList.at( index ).color;
720 breakValues.append( value1 );
721 breakColors.append(
color );
726 while ( index < ( itemList.count() - 1 ) && itemList.at( index ).value < value2 )
728 QColor
color = itemList.at( index ).color;
729 breakValues.append( itemList.at( index ).value );
730 breakColors.append(
color );
731 gradients.append( makeSimpleLinearGradient(
color,
color ) );
736 QColor lastColor = itemList.at( index ).color;
737 breakColors.append( lastColor );
738 breakValues.append( value2 );
739 gradients.append( makeSimpleLinearGradient( lastColor, lastColor ) );