23 mStrokeWidth = strokeWidth;
28 mStrokeColoring = strokeColoring;
33 mStrokeWidthUnit = strokeWidthUnit;
38 QPainter *painter = context.
painter();
44 if ( value1 > value2 )
46 std::swap( value1, value2 );
47 std::swap( point1, point2 );
52 QPointF dir = p2 - p1;
53 double length = sqrt( pow( dir.x(), 2 ) + pow( dir.y(), 2 ) );
54 QPointF diru = dir / length;
55 QPointF orthu = QPointF( -diru.y(), diru.x() );
57 QList<double> breakValues;
58 QList<QColor> breakColors;
59 QList<QLinearGradient> gradients;
61 mStrokeColoring.
graduatedColors( value1, value2, breakValues, breakColors, gradients );
63 if ( gradients.isEmpty() && !breakValues.empty() && !breakColors.isEmpty() )
65 Q_ASSERT( breakColors.count() == breakValues.count() );
66 for (
int i = 0; i < breakValues.count(); ++i )
68 double value = breakValues.at( i );
70 QPen pen( breakColors.at( i ) );
71 pen.setWidthF( width );
72 pen.setCapStyle( Qt::PenCapStyle::RoundCap );
73 painter->setPen( pen );
74 QPointF point = p1 + dir * ( value - value1 ) / ( value2 - value1 );
75 painter->drawPoint( point );
83 if ( !std::isnan( width1 ) || !std::isnan( width2 ) )
86 QBrush brush( Qt::SolidPattern );
89 startAngle = ( acos( -orthu.x() ) / M_PI ) * 180;
91 startAngle = 360 - startAngle;
93 bool outOfRange1 = std::isnan( width1 );
94 bool outOfRange2 = std::isnan( width2 );
99 QRectF capBox1( p1.x() - width1 / 2, p1.y() - width1 / 2, width1, width1 );
100 brush.setColor( mStrokeColoring.
color( value1 ) );
101 painter->setBrush( brush );
102 pen.setBrush( brush );
103 painter->setPen( pen );
104 painter->drawPie( capBox1, ( startAngle - 1 ) * 16, 182 * 16 );
110 QRectF capBox2( p2.x() - width2 / 2, p2.y() - width2 / 2, width2, width2 );
111 brush.setColor( mStrokeColoring.
color( value2 ) );
112 pen.setBrush( brush );
113 painter->setBrush( brush );
114 painter->setPen( pen );
115 painter->drawPie( capBox2, ( startAngle + 179 ) * 16, 182 * 16 );
118 if ( gradients.isEmpty() && breakValues.empty() && breakColors.count() == 1 )
120 double startAdjusting = 0;
122 adjustLine( value1, value1, value2, width1, startAdjusting );
125 double endAdjusting = 0;
127 adjustLine( value2, value1, value2, width2, endAdjusting );
129 QPointF pointStartAdjusted = p1 + dir * startAdjusting;
130 QPointF pointEndAdjusted = p2 - dir * endAdjusting;
133 double semiWidth1 = width1 / 2;
134 double semiWidth2 = width2 / 2;
136 varLine.append( pointStartAdjusted + orthu * semiWidth1 );
137 varLine.append( pointEndAdjusted + orthu * semiWidth2 );
138 varLine.append( pointEndAdjusted - orthu * semiWidth2 );
139 varLine.append( pointStartAdjusted - orthu * semiWidth1 );
141 QBrush brush( Qt::SolidPattern );
142 brush.setColor( breakColors.first() );
143 painter->setBrush( brush );
144 painter->setPen( pen );
147 pen.setBrush( brush );
149 painter->setPen( pen );
151 painter->drawPolygon( varLine );
153 else if ( !gradients.isEmpty() && !breakValues.isEmpty() && !breakColors.isEmpty() )
155 Q_ASSERT( breakColors.count() == breakValues.count() );
156 Q_ASSERT( breakColors.count() == gradients.count() + 1 );
158 for (
int i = 0; i < gradients.count(); ++i )
160 double firstValue = breakValues.at( i );
161 double secondValue = breakValues.at( i + 1 );
162 double w1 = mStrokeWidth.
strokeWidth( firstValue );
163 double w2 = mStrokeWidth.
strokeWidth( secondValue );
165 if ( std::isnan( w1 ) && std::isnan( w2 ) )
168 double firstAdjusting = 0;
169 if ( std::isnan( w1 ) )
170 adjustLine( firstValue, value1, value2, w1, firstAdjusting );
173 double secondAdjusting = 0;
174 if ( std::isnan( w2 ) )
175 adjustLine( secondValue, value1, value2, w2, secondAdjusting );
180 QPointF pointStart = p1 + dir * ( firstValue - value1 ) / ( value2 - value1 );
181 QPointF pointEnd = p1 + dir * ( secondValue - value1 ) / ( value2 - value1 );
183 QPointF pointStartAdjusted = pointStart + dir * firstAdjusting;
184 QPointF pointEndAdjusted = pointEnd - dir * secondAdjusting;
190 varLine.append( pointStartAdjusted + orthu * sw1 );
191 varLine.append( pointEndAdjusted + orthu * sw2 );
192 varLine.append( pointEndAdjusted - orthu * sw2 );
193 varLine.append( pointStartAdjusted - orthu * sw1 );
195 QLinearGradient gradient = gradients.at( i );
196 gradient.setStart( pointStart );
197 gradient.setFinalStop( pointEnd );
198 QBrush brush( gradient );
199 painter->setBrush( brush );
202 pen.setBrush( brush );
204 painter->setPen( pen );
206 painter->drawPolygon( varLine );
213 void QgsInterpolatedLineRenderer::adjustLine(
const double &value,
const double &value1,
const double &value2,
double &width,
double &adjusting )
const
217 adjusting = fabs( ( value - mStrokeWidth.
maximumValue() ) / ( value2 - value1 ) );
222 adjusting = fabs( ( value - mStrokeWidth.
minimumValue() ) / ( value2 - value1 ) );
229 return mMinimumValue;
235 mNeedUpdateFormula =
true;
240 return mMaximumValue;
246 mNeedUpdateFormula =
true;
251 return mMinimumWidth;
257 mNeedUpdateFormula =
true;
262 return mMaximumWidth;
268 mNeedUpdateFormula =
true;
273 if ( mIsWidthVariable )
275 if ( mNeedUpdateFormula )
276 updateLinearFormula();
278 if ( mUseAbsoluteValue )
279 value = std::fabs( value );
281 if ( value > mMaximumValue )
283 if ( mIgnoreOutOfRange )
284 return std::numeric_limits<double>::quiet_NaN();
286 return mMaximumWidth;
289 if ( value < mMinimumValue )
291 if ( mIgnoreOutOfRange )
292 return std::numeric_limits<double>::quiet_NaN();
294 return mMinimumWidth;
297 return ( value - mMinimumValue ) * mLinearCoef + mMinimumWidth;
307 QDomElement elem = doc.createElement( QStringLiteral(
"mesh-stroke-width" ) );
309 elem.setAttribute( QStringLiteral(
"width-varying" ), mIsWidthVariable ? 1 : 0 );
310 elem.setAttribute( QStringLiteral(
"fixed-width" ), mFixedWidth );
311 elem.setAttribute( QStringLiteral(
"minimum-value" ), mMinimumValue );
312 elem.setAttribute( QStringLiteral(
"maximum-value" ), mMaximumValue );
313 elem.setAttribute( QStringLiteral(
"minimum-width" ), mMinimumWidth );
314 elem.setAttribute( QStringLiteral(
"maximum-width" ), mMaximumWidth );
315 elem.setAttribute( QStringLiteral(
"ignore-out-of-range" ), mIgnoreOutOfRange ? 1 : 0 );
316 elem.setAttribute( QStringLiteral(
"use-absolute-value" ), mUseAbsoluteValue ? 1 : 0 );
325 mIsWidthVariable = elem.attribute( QStringLiteral(
"width-varying" ) ).toInt();
326 mFixedWidth = elem.attribute( QStringLiteral(
"fixed-width" ) ).toDouble();
327 mMinimumValue = elem.attribute( QStringLiteral(
"minimum-value" ) ).toDouble();
328 mMaximumValue = elem.attribute( QStringLiteral(
"maximum-value" ) ).toDouble();
329 mMinimumWidth = elem.attribute( QStringLiteral(
"minimum-width" ) ).toDouble();
330 mMaximumWidth = elem.attribute( QStringLiteral(
"maximum-width" ) ).toDouble();
331 mIgnoreOutOfRange = elem.attribute( QStringLiteral(
"ignore-out-of-range" ) ).toInt();
332 mUseAbsoluteValue = elem.attribute( QStringLiteral(
"use-absolute-value" ) ).toInt();
337 return mUseAbsoluteValue;
352 return mIgnoreOutOfRange;
362 return mIsWidthVariable;
367 mIsWidthVariable = isWidthVarying;
372 mFixedWidth = fixedWidth;
375 void QgsInterpolatedLineWidth::updateLinearFormula()
const
377 if ( mMaximumWidth - mMinimumWidth != 0 )
378 mLinearCoef = ( mMaximumWidth - mMinimumWidth ) / ( mMaximumValue - mMinimumValue ) ;
381 mNeedUpdateFormula =
false;
407 mSingleColor =
color;
414 if ( mColorRampShader.
isEmpty() )
415 return lSourceColorRamp->color( 0 );
418 if ( mColorRampShader.
shade( magnitude, &r, &g, &b, &a ) )
419 return QColor( r, g, b, a );
421 return QColor( 0, 0, 0, 0 );
431 return mColoringMethod;
436 return mColorRampShader;
443 QDomElement elem = doc.createElement( QStringLiteral(
"mesh-stroke-color" ) );
446 elem.setAttribute( QStringLiteral(
"coloring-method" ), mColoringMethod );
447 elem.appendChild( mColorRampShader.
writeXml( doc ) );
456 QDomElement shaderElem = elem.firstChildElement( QStringLiteral(
"colorrampshader" ) );
457 mColorRampShader.
readXml( shaderElem );
461 elem.attribute( QStringLiteral(
"coloring-method" ) ).toInt() );
471 breakValues.append( value1 );
472 breakColors.append( mSingleColor );
473 breakValues.append( value2 );
474 breakColors.append( mSingleColor );
475 gradients.append( makeSimpleLinearGradient( mSingleColor, mSingleColor ) );
482 graduatedColorsInterpolated( value1, value2, breakValues, breakColors, gradients );
485 graduatedColorsDiscrete( value1, value2, breakValues, breakColors, gradients );
488 graduatedColorsExact( value1, value2, breakValues, breakColors, gradients );
494 QLinearGradient QgsInterpolatedLineColor::makeSimpleLinearGradient(
const QColor &color1,
const QColor &color2 )
const
496 QLinearGradient gradient;
497 gradient.setColorAt( 0, color1 );
498 gradient.setColorAt( 1, color2 );
503 int QgsInterpolatedLineColor::itemColorIndexInf(
double value )
const
505 QList<QgsColorRampShader::ColorRampItem> itemList = mColorRampShader.
colorRampItemList();
507 if ( itemList.isEmpty() || itemList.first().value > value )
511 itemList.removeLast();
513 if ( value > itemList.last().value )
514 return itemList.count() - 1;
516 int indSup = itemList.count() - 1;
521 if ( abs( indSup - indInf ) <= 1 )
524 int newInd = ( indInf + indSup ) / 2;
526 if ( itemList.at( newInd ).value == std::numeric_limits<double>::quiet_NaN() )
529 if ( itemList.at( newInd ).value <= value )
536 void QgsInterpolatedLineColor::graduatedColorsExact(
double value1,
double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients )
const
539 Q_ASSERT( breakValues.isEmpty() );
540 Q_ASSERT( breakColors.isEmpty() );
541 Q_ASSERT( gradients.isEmpty() );
543 const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.
colorRampItemList();
544 if ( itemList.isEmpty() )
547 int index = itemColorIndexInf( value1 );
548 if ( index < 0 || !
qgsDoubleNear( value1, itemList.at( index ).value ) )
554 breakColors.append( itemList.at( index ).color );
558 while ( index < itemList.count() && itemList.at( index ).value <= value2 )
560 breakValues.append( itemList.at( index ).value );
561 breakColors.append( itemList.at( index ).color );
566 void QgsInterpolatedLineColor::graduatedColorsInterpolated(
double value1,
double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients )
const
569 Q_ASSERT( breakValues.isEmpty() );
570 Q_ASSERT( breakColors.isEmpty() );
571 Q_ASSERT( gradients.isEmpty() );
574 const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.
colorRampItemList();
575 if ( itemList.empty() )
578 if ( itemList.count() == 1 )
580 breakColors.append( itemList.first().color );
584 if ( value2 <= itemList.first().value )
586 if ( !mColorRampShader.
clip() )
587 breakColors.append( itemList.first().color );
591 if ( value1 > itemList.last().value )
593 if ( !mColorRampShader.
clip() )
594 breakColors.append( itemList.last().color );
604 if ( mColorRampShader.
shade( value1, &r, &g, &b, &a ) )
605 color = QColor( r, g, b, a );
606 breakColors.append(
color );
611 int index = itemColorIndexInf( value1 );
614 QColor
color = itemList.first().color;
615 breakColors.append(
color );
616 if ( mColorRampShader.
clip() )
617 breakValues.append( itemList.first().value );
619 breakValues.append( value1 );
626 if ( mColorRampShader.
shade( value1, &r, &g, &b, &a ) )
627 color = QColor( r, g, b, a );
628 breakValues.append( value1 );
629 breakColors.append(
color );
634 while ( index < itemList.count() && itemList.at( index ).value < value2 )
636 QColor color1 = breakColors.last();
637 QColor color2 = itemList.at( index ).color;
638 breakValues.append( itemList.at( index ).value );
639 breakColors.append( color2 );
640 gradients.append( makeSimpleLinearGradient( color1, color2 ) );
645 QColor color1 = breakColors.last();
647 if ( value2 < itemList.last().value )
650 if ( mColorRampShader.
shade( value2, &r, &g, &b, &a ) )
651 color2 = QColor( r, g, b, a );
652 breakValues.append( value2 );
656 color2 = itemList.last().color;
657 if ( mColorRampShader.
clip() )
658 breakValues.append( itemList.last().value );
660 breakValues.append( value2 );
662 breakColors.append( color2 );
663 gradients.append( makeSimpleLinearGradient( color1, color2 ) );
667 void QgsInterpolatedLineColor::graduatedColorsDiscrete(
double value1,
double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients )
const
670 Q_ASSERT( breakValues.isEmpty() );
671 Q_ASSERT( breakColors.isEmpty() );
672 Q_ASSERT( gradients.isEmpty() );
674 const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.
colorRampItemList();
675 if ( itemList.empty() )
678 if ( itemList.count() == 1 )
680 breakColors.append( itemList.first().color );
684 double lastValue = itemList.at( itemList.count() - 2 ).value;
687 if ( value2 <= itemList.first().value )
689 breakColors.append( itemList.first().color );
693 if ( value1 > lastValue )
695 breakColors.append( itemList.last().color );
700 int index = itemColorIndexInf( value1 );
706 breakColors.append( itemList.at( index + 1 ).color );
712 breakValues.append( value1 );
713 breakColors.append( itemList.first().color );
717 QColor
color = itemList.at( index ).color;
718 breakValues.append( value1 );
719 breakColors.append(
color );
724 while ( index < ( itemList.count() - 1 ) && itemList.at( index ).value < value2 )
726 QColor
color = itemList.at( index ).color;
727 breakValues.append( itemList.at( index ).value );
728 breakColors.append(
color );
729 gradients.append( makeSimpleLinearGradient(
color,
color ) );
734 QColor lastColor = itemList.at( index ).color;
735 breakColors.append( lastColor );
736 breakValues.append( value2 );
737 gradients.append( makeSimpleLinearGradient( lastColor, lastColor ) );