29using namespace Qt::StringLiterals;
33 mStrokeWidth = strokeWidth;
43 mStrokeColoring = strokeColoring;
48 return mStrokeColoring;
53 mStrokeWidthUnit = strokeWidthUnit;
58 return mStrokeWidthUnit;
63 QPainter *painter = context.
painter();
67 QPointF dir = p2 - p1;
68 double length = sqrt( pow( dir.x(), 2 ) + pow( dir.y(), 2 ) );
69 QPointF diru = dir / length;
70 QPointF orthu = QPointF( -diru.y(), diru.x() );
72 QList<double> breakValues;
73 QList<QColor> breakColors;
74 QList<QLinearGradient> gradients;
76 mStrokeColoring.graduatedColors( valueColor1, valueColor2, breakValues, breakColors, gradients );
79 if ( gradients.isEmpty() && !breakValues.empty() && !breakColors.isEmpty() )
81 Q_ASSERT( breakColors.count() == breakValues.count() );
82 for (
int i = 0; i < breakValues.count(); ++i )
84 const bool widthIsInverted { valueWidth1 > valueWidth2 };
85 const double value = breakValues.at( i );
86 const double width = context.
convertToPainterUnits( mStrokeWidth.strokeWidth( widthIsInverted ? mStrokeWidth.maximumValue() - value : value ), mStrokeWidthUnit );
87 QPen pen( mSelected ? selectedColor : breakColors.at( i ) );
88 pen.setWidthF( width );
89 pen.setCapStyle( Qt::PenCapStyle::RoundCap );
90 painter->setPen( pen );
91 const QPointF point = p1 + dir * ( value - valueColor1 ) / ( valueColor2 - valueColor1 );
92 painter->drawPoint( point );
97 double width1 = mStrokeWidth.strokeWidth( valueWidth1 );
98 double width2 = mStrokeWidth.strokeWidth( valueWidth2 );
100 if ( !std::isnan( width1 ) && !std::isnan( width2 ) )
103 QBrush brush( Qt::SolidPattern );
106 startAngle = ( acos( -orthu.x() ) / M_PI ) * 180;
108 startAngle = 360 - startAngle;
110 bool outOfRange1 = std::isnan( width1 );
111 bool outOfRange2 = std::isnan( width2 );
116 QRectF capBox1( p1.x() - width1 / 2, p1.y() - width1 / 2, width1, width1 );
117 brush.setColor( mSelected ? selectedColor : mStrokeColoring.color( valueColor1 ) );
118 painter->setBrush( brush );
119 pen.setBrush( brush );
120 painter->setPen( pen );
121 painter->drawPie( capBox1, ( startAngle - 1 ) * 16, 182 * 16 );
127 QRectF capBox2( p2.x() - width2 / 2, p2.y() - width2 / 2, width2, width2 );
128 brush.setColor( mSelected ? selectedColor : mStrokeColoring.color( valueColor2 ) );
129 pen.setBrush( brush );
130 painter->setBrush( brush );
131 painter->setPen( pen );
132 painter->drawPie( capBox2, ( startAngle + 179 ) * 16, 182 * 16 );
135 if ( ( gradients.isEmpty() && breakValues.empty() && breakColors.count() == 1 ) || mSelected )
137 double startAdjusting = 0;
139 adjustLine( valueColor1, valueColor1, valueColor2, width1, startAdjusting );
142 double endAdjusting = 0;
144 adjustLine( valueColor2, valueColor1, valueColor2, width2, endAdjusting );
146 QPointF pointStartAdjusted = p1 + dir * startAdjusting;
147 QPointF pointEndAdjusted = p2 - dir * endAdjusting;
150 double semiWidth1 = width1 / 2;
151 double semiWidth2 = width2 / 2;
153 varLine.append( pointStartAdjusted + orthu * semiWidth1 );
154 varLine.append( pointEndAdjusted + orthu * semiWidth2 );
155 varLine.append( pointEndAdjusted - orthu * semiWidth2 );
156 varLine.append( pointStartAdjusted - orthu * semiWidth1 );
158 QBrush brush( Qt::SolidPattern );
159 brush.setColor( mSelected ? selectedColor : breakColors.first() );
160 painter->setBrush( brush );
161 painter->setPen( pen );
164 pen.setBrush( brush );
166 painter->setPen( pen );
168 painter->drawPolygon( varLine );
171 else if ( !gradients.isEmpty() && !breakValues.isEmpty() && !breakColors.isEmpty() )
173 Q_ASSERT( breakColors.count() == breakValues.count() );
174 Q_ASSERT( breakColors.count() == gradients.count() + 1 );
175 double widthColorVariationValueRatio = ( valueWidth2 - valueWidth1 ) / ( valueColor2 - valueColor1 );
177 for (
int i = 0; i < gradients.count(); ++i )
179 double firstValue = breakValues.at( i );
180 double secondValue = breakValues.at( i + 1 );
181 double w1 = mStrokeWidth.strokeWidth( widthColorVariationValueRatio * ( firstValue - valueColor1 ) + valueWidth1 );
182 double w2 = mStrokeWidth.strokeWidth( widthColorVariationValueRatio * ( secondValue - valueColor1 ) + valueWidth1 );
184 if ( std::isnan( w1 ) && std::isnan( w2 ) )
187 double firstAdjusting = 0;
188 if ( std::isnan( w1 ) )
189 adjustLine( firstValue, valueColor1, valueColor2, w1, firstAdjusting );
192 double secondAdjusting = 0;
193 if ( std::isnan( w2 ) )
194 adjustLine( secondValue, valueColor1, valueColor2, w2, secondAdjusting );
199 QPointF pointStart = p1 + dir * ( firstValue - valueColor1 ) / ( valueColor2 - valueColor1 );
200 QPointF pointEnd = p1 + dir * ( secondValue - valueColor1 ) / ( valueColor2 - valueColor1 );
202 QPointF pointStartAdjusted = pointStart + dir * firstAdjusting;
203 QPointF pointEndAdjusted = pointEnd - dir * secondAdjusting;
209 varLine.append( pointStartAdjusted + orthu * sw1 );
210 varLine.append( pointEndAdjusted + orthu * sw2 );
211 varLine.append( pointEndAdjusted - orthu * sw2 );
212 varLine.append( pointStartAdjusted - orthu * sw1 );
214 QLinearGradient gradient = gradients.at( i );
215 gradient.setStart( pointStart );
216 gradient.setFinalStop( pointEnd );
217 QBrush brush( gradient );
218 painter->setBrush( brush );
221 pen.setBrush( brush );
223 painter->setPen( pen );
225 painter->drawPolygon( varLine );
240 if ( value1 > value2 )
242 std::swap( value1, value2 );
243 std::swap( point1, point2 );
259 if ( valueColor1 > valueColor2 )
261 std::swap( valueColor1, valueColor2 );
262 std::swap( valueWidth1, valueWidth2 );
263 std::swap( point1, point2 );
274 mSelected = selected;
277void QgsInterpolatedLineRenderer::adjustLine(
const double value,
const double value1,
const double value2,
double &width,
double &adjusting )
const
281 adjusting = fabs( ( value - mStrokeWidth.
maximumValue() ) / ( value2 - value1 ) );
286 adjusting = fabs( ( value - mStrokeWidth.minimumValue() ) / ( value2 - value1 ) );
287 width = mStrokeWidth.minimumWidth();
293 return mMinimumValue;
299 mNeedUpdateFormula =
true;
304 return mMaximumValue;
310 mNeedUpdateFormula =
true;
315 return mMinimumWidth;
321 mNeedUpdateFormula =
true;
326 return mMaximumWidth;
332 mNeedUpdateFormula =
true;
337 if ( mIsWidthVariable )
339 if ( mNeedUpdateFormula )
340 updateLinearFormula();
342 if ( mUseAbsoluteValue )
343 value = std::fabs( value );
345 if ( value > mMaximumValue )
347 if ( mIgnoreOutOfRange )
348 return std::numeric_limits<double>::quiet_NaN();
350 return mMaximumWidth;
353 if ( value < mMinimumValue )
355 if ( mIgnoreOutOfRange )
356 return std::numeric_limits<double>::quiet_NaN();
358 return mMinimumWidth;
361 return ( value - mMinimumValue ) * mLinearCoef + mMinimumWidth;
369 QDomElement elem = doc.createElement( u
"mesh-stroke-width"_s );
371 elem.setAttribute( u
"width-varying"_s, mIsWidthVariable ? 1 : 0 );
372 elem.setAttribute( u
"fixed-width"_s, mFixedWidth );
373 elem.setAttribute( u
"minimum-value"_s, mMinimumValue );
374 elem.setAttribute( u
"maximum-value"_s, mMaximumValue );
375 elem.setAttribute( u
"minimum-width"_s, mMinimumWidth );
376 elem.setAttribute( u
"maximum-width"_s, mMaximumWidth );
377 elem.setAttribute( u
"ignore-out-of-range"_s, mIgnoreOutOfRange ? 1 : 0 );
378 elem.setAttribute( u
"use-absolute-value"_s, mUseAbsoluteValue ? 1 : 0 );
385 mIsWidthVariable = elem.attribute( u
"width-varying"_s ).toInt();
386 mFixedWidth = elem.attribute( u
"fixed-width"_s ).toDouble();
387 mMinimumValue = elem.attribute( u
"minimum-value"_s ).toDouble();
388 mMaximumValue = elem.attribute( u
"maximum-value"_s ).toDouble();
389 mMinimumWidth = elem.attribute( u
"minimum-width"_s ).toDouble();
390 mMaximumWidth = elem.attribute( u
"maximum-width"_s ).toDouble();
391 mIgnoreOutOfRange = elem.attribute( u
"ignore-out-of-range"_s ).toInt();
392 mUseAbsoluteValue = elem.attribute( u
"use-absolute-value"_s ).toInt();
397 return mUseAbsoluteValue;
412 return mIgnoreOutOfRange;
422 return mIsWidthVariable;
427 mIsWidthVariable = isWidthVarying;
432 mFixedWidth = fixedWidth;
435void QgsInterpolatedLineWidth::updateLinearFormula()
const
438 mLinearCoef = ( mMaximumWidth - mMinimumWidth ) / ( mMaximumValue - mMinimumValue ) ;
441 mNeedUpdateFormula =
false;
446 mColorRampShader.setMinimumValue( std::numeric_limits<double>::quiet_NaN() );
447 mColorRampShader.setMaximumValue( std::numeric_limits<double>::quiet_NaN() );
459 mColorRampShader.setMinimumValue( std::numeric_limits<double>::quiet_NaN() );
460 mColorRampShader.setMaximumValue( std::numeric_limits<double>::quiet_NaN() );
466 if ( ( mColorRampShader.sourceColorRamp() ) )
474 mSingleColor =
color;
479 QgsColorRamp *lSourceColorRamp = mColorRampShader.sourceColorRamp();
480 if ( mColoringMethod ==
ColorRamp && lSourceColorRamp )
482 if ( mColorRampShader.isEmpty() )
483 return lSourceColorRamp->
color( 0 );
486 if ( mColorRampShader.shade( magnitude, &r, &g, &b, &a ) )
487 return QColor( r, g, b, a );
489 return QColor( 0, 0, 0, 0 );
499 return mColoringMethod;
504 return mColorRampShader;
514 QDomElement elem = doc.createElement( u
"mesh-stroke-color"_s );
517 elem.setAttribute( u
"coloring-method"_s, mColoringMethod );
518 elem.appendChild( mColorRampShader.writeXml( doc ) );
525 QDomElement shaderElem = elem.firstChildElement( u
"colorrampshader"_s );
526 mColorRampShader.
readXml( shaderElem );
530 elem.attribute( u
"coloring-method"_s ).toInt() );
540 breakColors.append( mSingleColor );
544 switch ( mColorRampShader.colorRampType() )
547 graduatedColorsInterpolated( value1, value2, breakValues, breakColors, gradients );
550 graduatedColorsDiscrete( value1, value2, breakValues, breakColors, gradients );
553 graduatedColorsExact( value1, value2, breakValues, breakColors, gradients );
564QLinearGradient QgsInterpolatedLineColor::makeSimpleLinearGradient(
const QColor &color1,
const QColor &color2 )
const
566 QLinearGradient gradient;
567 gradient.setColorAt( 0, color1 );
568 gradient.setColorAt( 1, color2 );
573int QgsInterpolatedLineColor::itemColorIndexInf(
double value )
const
575 QList<QgsColorRampShader::ColorRampItem> itemList = mColorRampShader.colorRampItemList();
577 if ( itemList.isEmpty() || itemList.first().value > value )
581 itemList.removeLast();
583 if ( value > itemList.last().value )
584 return itemList.count() - 1;
586 int indSup = itemList.count() - 1;
591 if ( abs( indSup - indInf ) <= 1 )
594 int newInd = ( indInf + indSup ) / 2;
596 if ( std::isnan( itemList.at( newInd ).value ) )
599 if ( itemList.at( newInd ).value <= value )
606void QgsInterpolatedLineColor::graduatedColorsExact(
double value1,
double value2, QList<double> &breakValues, QList<QColor> &breakColors,
const QList<QLinearGradient> &gradients )
const
609 Q_ASSERT( breakValues.isEmpty() );
610 Q_ASSERT( breakColors.isEmpty() );
611 Q_ASSERT( gradients.isEmpty() );
613 const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.colorRampItemList();
614 if ( itemList.isEmpty() )
617 int index = itemColorIndexInf( value1 );
618 if ( index < 0 || !
qgsDoubleNear( value1, itemList.at( index ).value ) )
624 breakColors.append( itemList.at( index ).color );
628 while ( index < itemList.count() && itemList.at( index ).value <= value2 )
630 breakValues.append( itemList.at( index ).value );
631 breakColors.append( itemList.at( index ).color );
636void QgsInterpolatedLineColor::graduatedColorsInterpolated(
double value1,
double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients )
const
639 Q_ASSERT( breakValues.isEmpty() );
640 Q_ASSERT( breakColors.isEmpty() );
641 Q_ASSERT( gradients.isEmpty() );
644 const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.colorRampItemList();
645 if ( itemList.empty() )
648 if ( itemList.count() == 1 )
650 breakColors.append( itemList.first().color );
654 if ( value2 <= itemList.first().value )
656 if ( !mColorRampShader.clip() )
657 breakColors.append( itemList.first().color );
661 if ( value1 > itemList.last().value )
663 if ( !mColorRampShader.clip() )
664 breakColors.append( itemList.last().color );
674 if ( mColorRampShader.shade( value1, &r, &g, &b, &a ) )
675 color = QColor( r, g, b, a );
676 breakColors.append(
color );
681 int index = itemColorIndexInf( value1 );
684 QColor
color = itemList.first().color;
685 breakColors.append(
color );
686 if ( mColorRampShader.clip() )
687 breakValues.append( itemList.first().value );
689 breakValues.append( value1 );
696 if ( mColorRampShader.shade( value1, &r, &g, &b, &a ) )
697 color = QColor( r, g, b, a );
698 breakValues.append( value1 );
699 breakColors.append(
color );
704 while ( index < itemList.count() && itemList.at( index ).value < value2 )
706 QColor color1 = breakColors.last();
707 QColor color2 = itemList.at( index ).color;
708 breakValues.append( itemList.at( index ).value );
709 breakColors.append( color2 );
710 gradients.append( makeSimpleLinearGradient( color1, color2 ) );
715 QColor color1 = breakColors.last();
717 if ( value2 < itemList.last().value )
720 if ( mColorRampShader.shade( value2, &r, &g, &b, &a ) )
721 color2 = QColor( r, g, b, a );
722 breakValues.append( value2 );
726 color2 = itemList.last().color;
727 if ( mColorRampShader.clip() )
728 breakValues.append( itemList.last().value );
730 breakValues.append( value2 );
732 breakColors.append( color2 );
733 gradients.append( makeSimpleLinearGradient( color1, color2 ) );
737void QgsInterpolatedLineColor::graduatedColorsDiscrete(
double value1,
double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients )
const
740 Q_ASSERT( breakValues.isEmpty() );
741 Q_ASSERT( breakColors.isEmpty() );
742 Q_ASSERT( gradients.isEmpty() );
744 const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.colorRampItemList();
745 if ( itemList.empty() )
748 if ( itemList.count() == 1 )
750 breakColors.append( itemList.first().color );
754 double lastValue = itemList.at( itemList.count() - 2 ).value;
757 if ( value2 <= itemList.first().value )
759 breakColors.append( itemList.first().color );
763 if ( value1 > lastValue )
765 breakColors.append( itemList.last().color );
770 int index = itemColorIndexInf( value1 );
776 breakColors.append( itemList.at( index + 1 ).color );
782 breakValues.append( value1 );
783 breakColors.append( itemList.first().color );
787 QColor
color = itemList.at( index ).color;
788 breakValues.append( value1 );
789 breakColors.append(
color );
794 while ( index < ( itemList.count() - 1 ) && itemList.at( index ).value < value2 )
796 QColor
color = itemList.at( index ).color;
797 breakValues.append( itemList.at( index ).value );
798 breakColors.append(
color );
799 gradients.append( makeSimpleLinearGradient(
color,
color ) );
804 QColor lastColor = itemList.at( index ).color;
805 breakColors.append( lastColor );
806 breakValues.append( value2 );
807 gradients.append( makeSimpleLinearGradient( lastColor, lastColor ) );
831 std::unique_ptr<QgsInterpolatedLineSymbolLayer> symbolLayer;
832 symbolLayer = std::make_unique<QgsInterpolatedLineSymbolLayer>( );
834 if (
properties.contains( u
"start_width_expression"_s ) )
836 if (
properties.contains( u
"end_width_expression"_s ) )
839 if (
properties.contains( u
"start_color_expression"_s ) )
841 if (
properties.contains( u
"end_color_expression"_s ) )
845 symbolLayer->mLineRender.mStrokeWidth.setFixedStrokeWidth(
properties.value( u
"line_width"_s ).toDouble() ) ;
846 if (
properties.contains( u
"line_width_unit"_s ) )
848 if (
properties.contains( u
"width_varying_minimum_value"_s ) )
849 symbolLayer->mLineRender.mStrokeWidth.setMinimumValue(
properties.value( u
"width_varying_minimum_value"_s ).toDouble() );
850 if (
properties.contains( u
"width_varying_maximum_value"_s ) )
851 symbolLayer->mLineRender.mStrokeWidth.setMaximumValue(
properties.value( u
"width_varying_maximum_value"_s ).toDouble() );
852 if (
properties.contains( u
"width_varying_use_absolute_value"_s ) )
853 symbolLayer->mLineRender.mStrokeWidth.setUseAbsoluteValue(
properties.value( u
"width_varying_use_absolute_value"_s ).toInt() );
854 if (
properties.contains( u
"width_varying_minimum_width"_s ) )
855 symbolLayer->mLineRender.mStrokeWidth.setMinimumWidth(
properties.value( u
"width_varying_minimum_width"_s ).toDouble() );
856 if (
properties.contains( u
"width_varying_maximum_width"_s ) )
857 symbolLayer->mLineRender.mStrokeWidth.setMaximumWidth(
properties.value( u
"width_varying_maximum_width"_s ).toDouble() );
858 if (
properties.contains( u
"width_varying_ignore_out_of_range"_s ) )
859 symbolLayer->mLineRender.mStrokeWidth.setIgnoreOutOfRange(
properties.value( u
"width_varying_ignore_out_of_range"_s ).toInt() );
860 if (
properties.contains( u
"width_varying_is_variable_width"_s ) )
861 symbolLayer->mLineRender.mStrokeWidth.setIsVariableWidth(
properties.value( u
"width_varying_is_variable_width"_s ).toInt() );
863 if (
properties.contains( u
"single_color"_s ) )
865 if (
properties.contains( u
"color_ramp_shader"_s ) )
866 symbolLayer->mLineRender.mStrokeColoring.setColor( createColorRampShaderFromProperties(
properties.value( u
"color_ramp_shader"_s ) ) );
867 if (
properties.contains( u
"coloring_method"_s ) )
868 symbolLayer->mLineRender.mStrokeColoring.setColoringMethod(
871 return symbolLayer.release();
886 props.insert( u
"line_width"_s, QString::number( mLineRender.mStrokeWidth.fixedStrokeWidth() ) );
888 props.insert( u
"width_varying_minimum_value"_s, mLineRender.mStrokeWidth.minimumValue() );
889 props.insert( u
"width_varying_maximum_value"_s, mLineRender.mStrokeWidth.maximumValue() );
890 props.insert( u
"width_varying_use_absolute_value"_s, mLineRender.mStrokeWidth.useAbsoluteValue() ? 1 : 0 );
891 props.insert( u
"width_varying_minimum_width"_s, mLineRender.mStrokeWidth.minimumWidth() );
892 props.insert( u
"width_varying_maximum_width"_s, mLineRender.mStrokeWidth.maximumWidth() );
893 props.insert( u
"width_varying_ignore_out_of_range"_s, mLineRender.mStrokeWidth.ignoreOutOfRange() ? 1 : 0 );
894 props.insert( u
"width_varying_is_variable_width"_s, mLineRender.mStrokeWidth.isVariableWidth() ? 1 : 0 );
897 props.insert( u
"coloring_method"_s, mLineRender.mStrokeColoring.coloringMethod() );
899 props.insert( u
"color_ramp_shader"_s, colorRampShaderProperties() );
910 double min = std::min( mLineRender.interpolatedLineWidth().minimumValue(), mLineRender.interpolatedColor().colorRampShader().minimumValue() );
911 double max = std::max( mLineRender.interpolatedLineWidth().maximumValue(), mLineRender.interpolatedColor().colorRampShader().maximumValue() );
913 double totalLength = geometry.
length();
917 double variation = ( max - min ) / totalLength;
920 double lengthFromStart = 0;
921 for (
int i = 1; i < points.count(); ++i )
923 QPointF p1 = points.at( i - 1 );
924 QPointF p2 = points.at( i );
926 double v1 = min + variation * lengthFromStart;
927 QPointF vectDist = p2 - p1;
928 lengthFromStart += sqrt( pow( vectDist.x(), 2 ) + pow( vectDist.y(), 2 ) );
929 double v2 = min + variation * lengthFromStart;
930 mLineRender.renderInDeviceCoordinates( v1, v2, v1, v2, p1, p2, context.
renderContext() );
939 switch ( mLineRender.interpolatedColor().coloringMethod() )
942 return mLineRender.interpolatedColor().singleColor();
952 if ( start.isEmpty() )
975 mLineRender.mStrokeWidthUnit = strokeWidthUnit;
982 mLineRender.mStrokeWidth = interpolatedLineWidth;
989 if ( start.isEmpty() )
1012 mLineRender.setInterpolatedColor( interpolatedLineColor );
1017 return mLineRender.interpolatedColor();
1020QVariant QgsInterpolatedLineSymbolLayer::colorRampShaderProperties()
const
1027 props.insert( u
"color_ramp_shader_type"_s,
static_cast< int >( colorRampShader.
colorRampType() ) );
1028 props.insert( u
"color_ramp_shader_classification_mode"_s,
static_cast< int >( colorRampShader.
classificationMode() ) );
1029 QVariantList colorRampItemListVariant;
1031 const QList<QgsColorRampShader::ColorRampItem> colorRampItemList = colorRampShader.
colorRampItemList();
1034 QVariantMap itemVar;
1035 itemVar[u
"label"_s] = item.label;
1037 itemVar[u
"value"_s] = item.value;
1038 colorRampItemListVariant.append( itemVar );
1040 props.insert( u
"color_ramp_shader_items_list"_s, colorRampItemListVariant );
1042 props.insert( u
"color_ramp_shader_minimum_value"_s, colorRampShader.
minimumValue() );
1043 props.insert( u
"color_ramp_shader_maximum_value"_s, colorRampShader.
maximumValue() );
1044 props.insert( u
"color_ramp_shader_value_out_of_range"_s, colorRampShader.
clip() ? 1 : 0 );
1045 props.insert( u
"color_ramp_shader_label_precision"_s, colorRampShader.
labelPrecision() );
1050QgsColorRampShader QgsInterpolatedLineSymbolLayer::createColorRampShaderFromProperties(
const QVariant &properties )
1052 QgsColorRampShader colorRampShader;
1054 if (
properties.userType() != QMetaType::Type::QVariantMap )
1055 return colorRampShader;
1057 QVariantMap shaderVariantMap =
properties.toMap();
1059 if ( shaderVariantMap.contains( u
"color_ramp_source"_s ) )
1062 if ( shaderVariantMap.contains( u
"color_ramp_shader_type"_s ) )
1064 if ( shaderVariantMap.contains( u
"color_ramp_shader_classification_mode"_s ) )
1066 shaderVariantMap.value( u
"color_ramp_shader_classification_mode"_s ).toInt() ) );
1068 if ( shaderVariantMap.contains( u
"color_ramp_shader_items_list"_s ) )
1070 QVariant colorRampItemsVar = shaderVariantMap.value( u
"color_ramp_shader_items_list"_s );
1071 if ( colorRampItemsVar.userType() == QMetaType::Type::QVariantList )
1073 QVariantList itemVariantList = colorRampItemsVar.toList();
1074 QList<QgsColorRampShader::ColorRampItem> colorRampItemList;
1075 for (
const QVariant &itemVar : std::as_const( itemVariantList ) )
1077 QgsColorRampShader::ColorRampItem item;
1078 if ( itemVar.userType() != QMetaType::Type::QVariantMap )
1080 QVariantMap itemVarMap = itemVar.toMap();
1081 if ( !itemVarMap.contains( u
"label"_s ) || !itemVarMap.contains( u
"color"_s ) || !itemVarMap.contains( u
"value"_s ) )
1084 item.
label = itemVarMap.value( u
"label"_s ).toString();
1086 item.
value = itemVarMap.value( u
"value"_s ).toDouble();
1088 colorRampItemList.append( item );
1094 if ( shaderVariantMap.contains( u
"color_ramp_shader_minimum_value"_s ) )
1095 colorRampShader.
setMinimumValue( shaderVariantMap.value( u
"color_ramp_shader_minimum_value"_s ).toDouble() );
1097 colorRampShader.
setMinimumValue( std::numeric_limits<double>::quiet_NaN() );
1099 if ( shaderVariantMap.contains( u
"color_ramp_shader_maximum_value"_s ) )
1100 colorRampShader.
setMaximumValue( shaderVariantMap.value( u
"color_ramp_shader_maximum_value"_s ).toDouble() );
1102 colorRampShader.
setMaximumValue( std::numeric_limits<double>::quiet_NaN() );
1104 if ( shaderVariantMap.contains( u
"color_ramp_shader_value_out_of_range"_s ) )
1105 colorRampShader.
setClip( shaderVariantMap.value( u
"color_ramp_shader_value_out_of_range"_s ).toInt() == 1 );
1106 if ( shaderVariantMap.contains( u
"color_ramp_shader_label_precision"_s ) )
1107 colorRampShader.
setLabelPrecision( shaderVariantMap.value( u
"color_ramp_shader_label_precision"_s ).toInt() );
1109 return colorRampShader;
1117 mRenderingFeature =
true;
1123 mRenderingFeature =
false;
1125 if ( mLineParts.empty() )
1128 render( mLineParts, context );
1132void QgsInterpolatedLineSymbolLayer::render(
const QVector< QPolygonF > &parts,
QgsRenderContext &context )
1134 const double totalLength = std::accumulate( parts.begin(), parts.end(), 0.0, [](
double total,
const QPolygonF & part )
1136 return total + QgsSymbolLayerUtils::polylineLength( part );
1142 double startValWidth = 0;
1143 double variationPerMapUnitWidth = 0;
1144 double startValColor = 0;
1145 double variationPerMapUnitColor = 0;
1158 double endValWidth = 0;
1166 variationPerMapUnitWidth = ( endValWidth - startValWidth ) / totalLength;
1178 double endValColor = 0;
1186 variationPerMapUnitColor = ( endValColor - startValColor ) / totalLength;
1189 for (
const QPolygonF &poly : parts )
1191 double lengthFromStart = 0;
1192 for (
int i = 1; i < poly.count(); ++i )
1194 const QPointF p1 = poly.at( i - 1 );
1195 const QPointF p2 = poly.at( i );
1197 const double v1c = startValColor + variationPerMapUnitColor * lengthFromStart;
1198 const double v1w = startValWidth + variationPerMapUnitWidth * lengthFromStart;
1200 const double v2c = startValColor + variationPerMapUnitColor * lengthFromStart;
1201 const double v2w = startValWidth + variationPerMapUnitWidth * lengthFromStart;
1202 mLineRender.renderInDeviceCoordinates( v1c, v2c, v1w, v2w, p1, p2, context );
1209 mLineRender.setSelected( context.
selected() );
1211 if ( points.empty() )
1214 if ( mRenderingFeature )
1218 mLineParts.append( points );
@ DisableFeatureClipping
If present, indicates that features should never be clipped to the map extent during rendering.
@ CanCalculateMaskGeometryPerFeature
If present, indicates that mask geometry can safely be calculated per feature for the symbol layer....
ShaderInterpolationMethod
Color ramp shader interpolation methods.
@ Exact
Assigns the color of the exact matching value in the color ramp item list.
@ Linear
Interpolates the color between two class breaks linearly.
@ Discrete
Assigns the color of the higher class for every pixel between two class breaks.
QFlags< SymbolLayerFlag > SymbolLayerFlags
Symbol layer flags.
ShaderClassificationMethod
Color ramp shader classification methods.
RenderUnit
Rendering size units.
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.
Qgis::ShaderClassificationMethod classificationMode() const
Returns the classification mode.
Qgis::ShaderInterpolationMethod colorRampType() const
Returns the color ramp interpolation method.
void setSourceColorRamp(QgsColorRamp *colorramp)
Set the source color ramp.
void setClassificationMode(Qgis::ShaderClassificationMethod classificationMode)
Sets the classification mode.
QList< QgsColorRampShader::ColorRampItem > colorRampItemList() const
Returns the custom color map.
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.
QgsColorRamp * sourceColorRamp() const
Returns the source color ramp.
void setColorRampType(Qgis::ShaderInterpolationMethod colorRampType)
Sets the color ramp interpolation method.
void setColorRampItemList(const QList< QgsColorRampShader::ColorRampItem > &list)
Sets a custom color map.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context=QgsReadWriteContext())
Reads configuration from the given DOM element.
Abstract base class for color ramps.
virtual QColor color(double value) const =0
Returns the color corresponding to a specified value.
static QColor colorFromString(const QString &string)
Decodes a string into a color value.
static QString colorToString(const QColor &color)
Encodes a color into a string value.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
static double distance2D(double x1, double y1, double x2, double y2)
Returns the 2D distance between (x1, y1) and (x2, y2).
A geometry is the spatial representation of a feature.
QPolygonF asQPolygonF() const
Returns contents of the geometry as a QPolygonF.
double length() const
Returns the planar, 2-dimensional length of geometry.
Defines color interpolation for rendering 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...
Qgis::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(Qgis::RenderUnit strokeWidthUnit)
Sets the unit of the stroke width.
Q_DECL_DEPRECATED QString endValueExpressionForWidth() const
Returns the expression related to the end extremity value for width.
QColor color() const override
Returns the "representative" color of the symbol layer.
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::RenderUnit widthUnit() const
Returns the width unit.
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.
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.
QgsInterpolatedLineSymbolLayer()
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.
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...
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.
void setWidthUnit(Qgis::RenderUnit strokeWidthUnit)
Sets the width unit.
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 that 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.
QgsLineSymbolLayer(const QgsLineSymbolLayer &other)=delete
Perform transforms between map coordinates and device coordinates.
QgsPointXY transform(const QgsPointXY &p) const
Transforms a point p from map (world) coordinates to device coordinates.
QPointF toQPointF() const
Converts a point to a QPointF.
bool isActive(int key) const final
Returns true if the collection contains an active property with the specified key.
A store for object properties.
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.
A container for the context for various read/write operations on objects.
Contains information about the context of a rendering operation.
double convertToPainterUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
QPainter * painter()
Returns the destination QPainter for the render operation.
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
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...
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.
static QgsStyle * defaultStyle(bool initialize=true)
Returns the default application-wide style.
static QVariant colorRampToVariant(const QString &name, QgsColorRamp *ramp)
Saves a color ramp to a QVariantMap, wrapped in a QVariant.
static std::unique_ptr< QgsColorRamp > loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
void copyDataDefinedProperties(QgsSymbolLayer *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
@ LineEndColorValue
End line color for interpolated line renderer.
@ LineStartColorValue
Start line color for interpolated line renderer.
@ LineEndWidthValue
End line width for interpolated line renderer.
@ LineStartWidthValue
Start line width for interpolated line renderer.
void copyPaintEffect(QgsSymbolLayer *destLayer) const
Copies paint effect of this layer to another symbol layer.
virtual Qgis::SymbolLayerFlags flags() const
Returns flags which control the symbol layer's behavior.
QgsPropertyCollection mDataDefinedProperties
QgsSymbolLayer(const QgsSymbolLayer &other)
Encapsulates the context in which a symbol is being rendered.
bool selected() const
Returns true if symbols should be rendered using the selected symbol coloring and style.
const QgsLegendPatchShape * patchShape() const
Returns the symbol patch shape, to use if rendering symbol preview icons.
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
static Q_INVOKABLE Qgis::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
static Q_INVOKABLE QString encodeUnit(Qgis::DistanceUnit unit)
Encodes a distance unit to a string.
#define BUILTIN_UNREACHABLE
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).