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 );
170 else if ( !gradients.isEmpty() && !breakValues.isEmpty() && !breakColors.isEmpty() )
172 Q_ASSERT( breakColors.count() == breakValues.count() );
173 Q_ASSERT( breakColors.count() == gradients.count() + 1 );
174 double widthColorVariationValueRatio = ( valueWidth2 - valueWidth1 ) / ( valueColor2 - valueColor1 );
176 for (
int i = 0; i < gradients.count(); ++i )
178 double firstValue = breakValues.at( i );
179 double secondValue = breakValues.at( i + 1 );
180 double w1 = mStrokeWidth.strokeWidth( widthColorVariationValueRatio * ( firstValue - valueColor1 ) + valueWidth1 );
181 double w2 = mStrokeWidth.strokeWidth( widthColorVariationValueRatio * ( secondValue - valueColor1 ) + valueWidth1 );
183 if ( std::isnan( w1 ) && std::isnan( w2 ) )
186 double firstAdjusting = 0;
187 if ( std::isnan( w1 ) )
188 adjustLine( firstValue, valueColor1, valueColor2, w1, firstAdjusting );
191 double secondAdjusting = 0;
192 if ( std::isnan( w2 ) )
193 adjustLine( secondValue, valueColor1, valueColor2, w2, secondAdjusting );
198 QPointF pointStart = p1 + dir * ( firstValue - valueColor1 ) / ( valueColor2 - valueColor1 );
199 QPointF pointEnd = p1 + dir * ( secondValue - valueColor1 ) / ( valueColor2 - valueColor1 );
201 QPointF pointStartAdjusted = pointStart + dir * firstAdjusting;
202 QPointF pointEndAdjusted = pointEnd - dir * secondAdjusting;
208 varLine.append( pointStartAdjusted + orthu * sw1 );
209 varLine.append( pointEndAdjusted + orthu * sw2 );
210 varLine.append( pointEndAdjusted - orthu * sw2 );
211 varLine.append( pointStartAdjusted - orthu * sw1 );
213 QLinearGradient gradient = gradients.at( i );
214 gradient.setStart( pointStart );
215 gradient.setFinalStop( pointEnd );
216 QBrush brush( gradient );
217 painter->setBrush( brush );
220 pen.setBrush( brush );
222 painter->setPen( pen );
224 painter->drawPolygon( varLine );
239 if ( value1 > value2 )
241 std::swap( value1, value2 );
242 std::swap( point1, point2 );
258 if ( valueColor1 > valueColor2 )
260 std::swap( valueColor1, valueColor2 );
261 std::swap( valueWidth1, valueWidth2 );
262 std::swap( point1, point2 );
273 mSelected = selected;
276void QgsInterpolatedLineRenderer::adjustLine(
const double value,
const double value1,
const double value2,
double &width,
double &adjusting )
const
280 adjusting = fabs( ( value - mStrokeWidth.
maximumValue() ) / ( value2 - value1 ) );
285 adjusting = fabs( ( value - mStrokeWidth.minimumValue() ) / ( value2 - value1 ) );
286 width = mStrokeWidth.minimumWidth();
292 return mMinimumValue;
298 mNeedUpdateFormula =
true;
303 return mMaximumValue;
309 mNeedUpdateFormula =
true;
314 return mMinimumWidth;
320 mNeedUpdateFormula =
true;
325 return mMaximumWidth;
331 mNeedUpdateFormula =
true;
336 if ( mIsWidthVariable )
338 if ( mNeedUpdateFormula )
339 updateLinearFormula();
341 if ( mUseAbsoluteValue )
342 value = std::fabs( value );
344 if ( value > mMaximumValue )
346 if ( mIgnoreOutOfRange )
347 return std::numeric_limits<double>::quiet_NaN();
349 return mMaximumWidth;
352 if ( value < mMinimumValue )
354 if ( mIgnoreOutOfRange )
355 return std::numeric_limits<double>::quiet_NaN();
357 return mMinimumWidth;
360 return ( value - mMinimumValue ) * mLinearCoef + mMinimumWidth;
368 QDomElement elem = doc.createElement( u
"mesh-stroke-width"_s );
370 elem.setAttribute( u
"width-varying"_s, mIsWidthVariable ? 1 : 0 );
371 elem.setAttribute( u
"fixed-width"_s, mFixedWidth );
372 elem.setAttribute( u
"minimum-value"_s, mMinimumValue );
373 elem.setAttribute( u
"maximum-value"_s, mMaximumValue );
374 elem.setAttribute( u
"minimum-width"_s, mMinimumWidth );
375 elem.setAttribute( u
"maximum-width"_s, mMaximumWidth );
376 elem.setAttribute( u
"ignore-out-of-range"_s, mIgnoreOutOfRange ? 1 : 0 );
377 elem.setAttribute( u
"use-absolute-value"_s, mUseAbsoluteValue ? 1 : 0 );
384 mIsWidthVariable = elem.attribute( u
"width-varying"_s ).toInt();
385 mFixedWidth = elem.attribute( u
"fixed-width"_s ).toDouble();
386 mMinimumValue = elem.attribute( u
"minimum-value"_s ).toDouble();
387 mMaximumValue = elem.attribute( u
"maximum-value"_s ).toDouble();
388 mMinimumWidth = elem.attribute( u
"minimum-width"_s ).toDouble();
389 mMaximumWidth = elem.attribute( u
"maximum-width"_s ).toDouble();
390 mIgnoreOutOfRange = elem.attribute( u
"ignore-out-of-range"_s ).toInt();
391 mUseAbsoluteValue = elem.attribute( u
"use-absolute-value"_s ).toInt();
396 return mUseAbsoluteValue;
411 return mIgnoreOutOfRange;
421 return mIsWidthVariable;
426 mIsWidthVariable = isWidthVarying;
431 mFixedWidth = fixedWidth;
434void QgsInterpolatedLineWidth::updateLinearFormula()
const
437 mLinearCoef = ( mMaximumWidth - mMinimumWidth ) / ( mMaximumValue - mMinimumValue );
440 mNeedUpdateFormula =
false;
445 mColorRampShader.setMinimumValue( std::numeric_limits<double>::quiet_NaN() );
446 mColorRampShader.setMaximumValue( std::numeric_limits<double>::quiet_NaN() );
458 mColorRampShader.setMinimumValue( std::numeric_limits<double>::quiet_NaN() );
459 mColorRampShader.setMaximumValue( std::numeric_limits<double>::quiet_NaN() );
465 if ( ( mColorRampShader.sourceColorRamp() ) )
473 mSingleColor =
color;
478 QgsColorRamp *lSourceColorRamp = mColorRampShader.sourceColorRamp();
479 if ( mColoringMethod ==
ColorRamp && lSourceColorRamp )
481 if ( mColorRampShader.isEmpty() )
482 return lSourceColorRamp->
color( 0 );
485 if ( mColorRampShader.shade( magnitude, &r, &g, &b, &a ) )
486 return QColor( r, g, b, a );
488 return QColor( 0, 0, 0, 0 );
498 return mColoringMethod;
503 return mColorRampShader;
513 QDomElement elem = doc.createElement( u
"mesh-stroke-color"_s );
516 elem.setAttribute( u
"coloring-method"_s, mColoringMethod );
517 elem.appendChild( mColorRampShader.writeXml( doc ) );
524 QDomElement shaderElem = elem.firstChildElement( u
"colorrampshader"_s );
525 mColorRampShader.
readXml( shaderElem );
538 breakColors.append( mSingleColor );
542 switch ( mColorRampShader.colorRampType() )
545 graduatedColorsInterpolated( value1, value2, breakValues, breakColors, gradients );
548 graduatedColorsDiscrete( value1, value2, breakValues, breakColors, gradients );
551 graduatedColorsExact( value1, value2, breakValues, breakColors, gradients );
561QLinearGradient QgsInterpolatedLineColor::makeSimpleLinearGradient(
const QColor &color1,
const QColor &color2 )
const
563 QLinearGradient gradient;
564 gradient.setColorAt( 0, color1 );
565 gradient.setColorAt( 1, color2 );
570int QgsInterpolatedLineColor::itemColorIndexInf(
double value )
const
572 QList<QgsColorRampShader::ColorRampItem> itemList = mColorRampShader.colorRampItemList();
574 if ( itemList.isEmpty() || itemList.first().value > value )
578 itemList.removeLast();
580 if ( value > itemList.last().value )
581 return itemList.count() - 1;
583 int indSup = itemList.count() - 1;
588 if ( abs( indSup - indInf ) <= 1 )
591 int newInd = ( indInf + indSup ) / 2;
593 if ( std::isnan( itemList.at( newInd ).value ) )
596 if ( itemList.at( newInd ).value <= value )
603void QgsInterpolatedLineColor::graduatedColorsExact(
double value1,
double value2, QList<double> &breakValues, QList<QColor> &breakColors,
const QList<QLinearGradient> &gradients )
const
606 Q_ASSERT( breakValues.isEmpty() );
607 Q_ASSERT( breakColors.isEmpty() );
608 Q_ASSERT( gradients.isEmpty() );
610 const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.colorRampItemList();
611 if ( itemList.isEmpty() )
614 int index = itemColorIndexInf( value1 );
615 if ( index < 0 || !
qgsDoubleNear( value1, itemList.at( index ).value ) )
621 breakColors.append( itemList.at( index ).color );
625 while ( index < itemList.count() && itemList.at( index ).value <= value2 )
627 breakValues.append( itemList.at( index ).value );
628 breakColors.append( itemList.at( index ).color );
633void QgsInterpolatedLineColor::graduatedColorsInterpolated(
double value1,
double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients )
const
636 Q_ASSERT( breakValues.isEmpty() );
637 Q_ASSERT( breakColors.isEmpty() );
638 Q_ASSERT( gradients.isEmpty() );
641 const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.colorRampItemList();
642 if ( itemList.empty() )
645 if ( itemList.count() == 1 )
647 breakColors.append( itemList.first().color );
651 if ( value2 <= itemList.first().value )
653 if ( !mColorRampShader.clip() )
654 breakColors.append( itemList.first().color );
658 if ( value1 > itemList.last().value )
660 if ( !mColorRampShader.clip() )
661 breakColors.append( itemList.last().color );
671 if ( mColorRampShader.shade( value1, &r, &g, &b, &a ) )
672 color = QColor( r, g, b, a );
673 breakColors.append(
color );
678 int index = itemColorIndexInf( value1 );
681 QColor
color = itemList.first().color;
682 breakColors.append(
color );
683 if ( mColorRampShader.clip() )
684 breakValues.append( itemList.first().value );
686 breakValues.append( value1 );
693 if ( mColorRampShader.shade( value1, &r, &g, &b, &a ) )
694 color = QColor( r, g, b, a );
695 breakValues.append( value1 );
696 breakColors.append(
color );
701 while ( index < itemList.count() && itemList.at( index ).value < value2 )
703 QColor color1 = breakColors.last();
704 QColor color2 = itemList.at( index ).color;
705 breakValues.append( itemList.at( index ).value );
706 breakColors.append( color2 );
707 gradients.append( makeSimpleLinearGradient( color1, color2 ) );
712 QColor color1 = breakColors.last();
714 if ( value2 < itemList.last().value )
717 if ( mColorRampShader.shade( value2, &r, &g, &b, &a ) )
718 color2 = QColor( r, g, b, a );
719 breakValues.append( value2 );
723 color2 = itemList.last().color;
724 if ( mColorRampShader.clip() )
725 breakValues.append( itemList.last().value );
727 breakValues.append( value2 );
729 breakColors.append( color2 );
730 gradients.append( makeSimpleLinearGradient( color1, color2 ) );
734void QgsInterpolatedLineColor::graduatedColorsDiscrete(
double value1,
double value2, QList<double> &breakValues, QList<QColor> &breakColors, QList<QLinearGradient> &gradients )
const
737 Q_ASSERT( breakValues.isEmpty() );
738 Q_ASSERT( breakColors.isEmpty() );
739 Q_ASSERT( gradients.isEmpty() );
741 const QList<QgsColorRampShader::ColorRampItem> &itemList = mColorRampShader.colorRampItemList();
742 if ( itemList.empty() )
745 if ( itemList.count() == 1 )
747 breakColors.append( itemList.first().color );
751 double lastValue = itemList.at( itemList.count() - 2 ).value;
754 if ( value2 <= itemList.first().value )
756 breakColors.append( itemList.first().color );
760 if ( value1 > lastValue )
762 breakColors.append( itemList.last().color );
767 int index = itemColorIndexInf( value1 );
773 breakColors.append( itemList.at( index + 1 ).color );
779 breakValues.append( value1 );
780 breakColors.append( itemList.first().color );
784 QColor
color = itemList.at( index ).color;
785 breakValues.append( value1 );
786 breakColors.append(
color );
791 while ( index < ( itemList.count() - 1 ) && itemList.at( index ).value < value2 )
793 QColor
color = itemList.at( index ).color;
794 breakValues.append( itemList.at( index ).value );
795 breakColors.append(
color );
796 gradients.append( makeSimpleLinearGradient(
color,
color ) );
801 QColor lastColor = itemList.at( index ).color;
802 breakColors.append( lastColor );
803 breakValues.append( value2 );
804 gradients.append( makeSimpleLinearGradient( lastColor, lastColor ) );
809 return u
"InterpolatedLine"_s;
827 std::unique_ptr<QgsInterpolatedLineSymbolLayer> symbolLayer;
828 symbolLayer = std::make_unique<QgsInterpolatedLineSymbolLayer>();
830 if (
properties.contains( u
"start_width_expression"_s ) )
832 if (
properties.contains( u
"end_width_expression"_s ) )
835 if (
properties.contains( u
"start_color_expression"_s ) )
837 if (
properties.contains( u
"end_color_expression"_s ) )
841 symbolLayer->mLineRender.mStrokeWidth.setFixedStrokeWidth(
properties.value( u
"line_width"_s ).toDouble() );
842 if (
properties.contains( u
"line_width_unit"_s ) )
844 if (
properties.contains( u
"width_varying_minimum_value"_s ) )
845 symbolLayer->mLineRender.mStrokeWidth.setMinimumValue(
properties.value( u
"width_varying_minimum_value"_s ).toDouble() );
846 if (
properties.contains( u
"width_varying_maximum_value"_s ) )
847 symbolLayer->mLineRender.mStrokeWidth.setMaximumValue(
properties.value( u
"width_varying_maximum_value"_s ).toDouble() );
848 if (
properties.contains( u
"width_varying_use_absolute_value"_s ) )
849 symbolLayer->mLineRender.mStrokeWidth.setUseAbsoluteValue(
properties.value( u
"width_varying_use_absolute_value"_s ).toInt() );
850 if (
properties.contains( u
"width_varying_minimum_width"_s ) )
851 symbolLayer->mLineRender.mStrokeWidth.setMinimumWidth(
properties.value( u
"width_varying_minimum_width"_s ).toDouble() );
852 if (
properties.contains( u
"width_varying_maximum_width"_s ) )
853 symbolLayer->mLineRender.mStrokeWidth.setMaximumWidth(
properties.value( u
"width_varying_maximum_width"_s ).toDouble() );
854 if (
properties.contains( u
"width_varying_ignore_out_of_range"_s ) )
855 symbolLayer->mLineRender.mStrokeWidth.setIgnoreOutOfRange(
properties.value( u
"width_varying_ignore_out_of_range"_s ).toInt() );
856 if (
properties.contains( u
"width_varying_is_variable_width"_s ) )
857 symbolLayer->mLineRender.mStrokeWidth.setIsVariableWidth(
properties.value( u
"width_varying_is_variable_width"_s ).toInt() );
859 if (
properties.contains( u
"single_color"_s ) )
861 if (
properties.contains( u
"color_ramp_shader"_s ) )
862 symbolLayer->mLineRender.mStrokeColoring.setColor( createColorRampShaderFromProperties(
properties.value( u
"color_ramp_shader"_s ) ) );
863 if (
properties.contains( u
"coloring_method"_s ) )
866 return symbolLayer.release();
879 props.insert( u
"line_width"_s, QString::number( mLineRender.mStrokeWidth.fixedStrokeWidth() ) );
881 props.insert( u
"width_varying_minimum_value"_s, mLineRender.mStrokeWidth.minimumValue() );
882 props.insert( u
"width_varying_maximum_value"_s, mLineRender.mStrokeWidth.maximumValue() );
883 props.insert( u
"width_varying_use_absolute_value"_s, mLineRender.mStrokeWidth.useAbsoluteValue() ? 1 : 0 );
884 props.insert( u
"width_varying_minimum_width"_s, mLineRender.mStrokeWidth.minimumWidth() );
885 props.insert( u
"width_varying_maximum_width"_s, mLineRender.mStrokeWidth.maximumWidth() );
886 props.insert( u
"width_varying_ignore_out_of_range"_s, mLineRender.mStrokeWidth.ignoreOutOfRange() ? 1 : 0 );
887 props.insert( u
"width_varying_is_variable_width"_s, mLineRender.mStrokeWidth.isVariableWidth() ? 1 : 0 );
890 props.insert( u
"coloring_method"_s, mLineRender.mStrokeColoring.coloringMethod() );
892 props.insert( u
"color_ramp_shader"_s, colorRampShaderProperties() );
902 double min = std::min( mLineRender.interpolatedLineWidth().minimumValue(), mLineRender.interpolatedColor().colorRampShader().minimumValue() );
903 double max = std::max( mLineRender.interpolatedLineWidth().maximumValue(), mLineRender.interpolatedColor().colorRampShader().maximumValue() );
905 double totalLength = geometry.
length();
909 double variation = ( max - min ) / totalLength;
912 double lengthFromStart = 0;
913 for (
int i = 1; i < points.count(); ++i )
915 QPointF p1 = points.at( i - 1 );
916 QPointF p2 = points.at( i );
918 double v1 = min + variation * lengthFromStart;
919 QPointF vectDist = p2 - p1;
920 lengthFromStart += sqrt( pow( vectDist.x(), 2 ) + pow( vectDist.y(), 2 ) );
921 double v2 = min + variation * lengthFromStart;
922 mLineRender.renderInDeviceCoordinates( v1, v2, v1, v2, p1, p2, context.
renderContext() );
930 switch ( mLineRender.interpolatedColor().coloringMethod() )
933 return mLineRender.interpolatedColor().singleColor();
943 if ( start.isEmpty() )
966 mLineRender.mStrokeWidthUnit = strokeWidthUnit;
972 return mLineRender.widthUnit();
977 mLineRender.mStrokeWidth = interpolatedLineWidth;
982 return mLineRender.interpolatedLineWidth();
987 if ( start.isEmpty() )
1010 mLineRender.setInterpolatedColor( interpolatedLineColor );
1015 return mLineRender.interpolatedColor();
1018QVariant QgsInterpolatedLineSymbolLayer::colorRampShaderProperties()
const
1025 props.insert( u
"color_ramp_shader_type"_s,
static_cast< int >( colorRampShader.
colorRampType() ) );
1026 props.insert( u
"color_ramp_shader_classification_mode"_s,
static_cast< int >( colorRampShader.
classificationMode() ) );
1027 QVariantList colorRampItemListVariant;
1029 const QList<QgsColorRampShader::ColorRampItem> colorRampItemList = colorRampShader.
colorRampItemList();
1032 QVariantMap itemVar;
1033 itemVar[u
"label"_s] = item.label;
1035 itemVar[u
"value"_s] = item.value;
1036 colorRampItemListVariant.append( itemVar );
1038 props.insert( u
"color_ramp_shader_items_list"_s, colorRampItemListVariant );
1040 props.insert( u
"color_ramp_shader_minimum_value"_s, colorRampShader.
minimumValue() );
1041 props.insert( u
"color_ramp_shader_maximum_value"_s, colorRampShader.
maximumValue() );
1042 props.insert( u
"color_ramp_shader_value_out_of_range"_s, colorRampShader.
clip() ? 1 : 0 );
1043 props.insert( u
"color_ramp_shader_label_precision"_s, colorRampShader.
labelPrecision() );
1048QgsColorRampShader QgsInterpolatedLineSymbolLayer::createColorRampShaderFromProperties(
const QVariant &properties )
1050 QgsColorRampShader colorRampShader;
1052 if (
properties.userType() != QMetaType::Type::QVariantMap )
1053 return colorRampShader;
1055 QVariantMap shaderVariantMap =
properties.toMap();
1057 if ( shaderVariantMap.contains( u
"color_ramp_source"_s ) )
1060 if ( shaderVariantMap.contains( u
"color_ramp_shader_type"_s ) )
1062 if ( shaderVariantMap.contains( u
"color_ramp_shader_classification_mode"_s ) )
1065 if ( shaderVariantMap.contains( u
"color_ramp_shader_items_list"_s ) )
1067 QVariant colorRampItemsVar = shaderVariantMap.value( u
"color_ramp_shader_items_list"_s );
1068 if ( colorRampItemsVar.userType() == QMetaType::Type::QVariantList )
1070 QVariantList itemVariantList = colorRampItemsVar.toList();
1071 QList<QgsColorRampShader::ColorRampItem> colorRampItemList;
1072 for (
const QVariant &itemVar : std::as_const( itemVariantList ) )
1074 QgsColorRampShader::ColorRampItem item;
1075 if ( itemVar.userType() != QMetaType::Type::QVariantMap )
1077 QVariantMap itemVarMap = itemVar.toMap();
1078 if ( !itemVarMap.contains( u
"label"_s ) || !itemVarMap.contains( u
"color"_s ) || !itemVarMap.contains( u
"value"_s ) )
1081 item.
label = itemVarMap.value( u
"label"_s ).toString();
1083 item.
value = itemVarMap.value( u
"value"_s ).toDouble();
1085 colorRampItemList.append( item );
1091 if ( shaderVariantMap.contains( u
"color_ramp_shader_minimum_value"_s ) )
1092 colorRampShader.
setMinimumValue( shaderVariantMap.value( u
"color_ramp_shader_minimum_value"_s ).toDouble() );
1094 colorRampShader.
setMinimumValue( std::numeric_limits<double>::quiet_NaN() );
1096 if ( shaderVariantMap.contains( u
"color_ramp_shader_maximum_value"_s ) )
1097 colorRampShader.
setMaximumValue( shaderVariantMap.value( u
"color_ramp_shader_maximum_value"_s ).toDouble() );
1099 colorRampShader.
setMaximumValue( std::numeric_limits<double>::quiet_NaN() );
1101 if ( shaderVariantMap.contains( u
"color_ramp_shader_value_out_of_range"_s ) )
1102 colorRampShader.
setClip( shaderVariantMap.value( u
"color_ramp_shader_value_out_of_range"_s ).toInt() == 1 );
1103 if ( shaderVariantMap.contains( u
"color_ramp_shader_label_precision"_s ) )
1104 colorRampShader.
setLabelPrecision( shaderVariantMap.value( u
"color_ramp_shader_label_precision"_s ).toInt() );
1106 return colorRampShader;
1116 mRenderingFeature =
true;
1122 mRenderingFeature =
false;
1124 if ( mLineParts.empty() )
1127 render( mLineParts, context );
1131void QgsInterpolatedLineSymbolLayer::render(
const QVector< QPolygonF > &parts,
QgsRenderContext &context )
1133 const double totalLength = std::accumulate( parts.begin(), parts.end(), 0.0, [](
double total,
const QPolygonF &part ) { return total + QgsSymbolLayerUtils::polylineLength( part ); } );
1138 double startValWidth = 0;
1139 double variationPerMapUnitWidth = 0;
1140 double startValColor = 0;
1141 double variationPerMapUnitColor = 0;
1154 double endValWidth = 0;
1162 variationPerMapUnitWidth = ( endValWidth - startValWidth ) / totalLength;
1174 double endValColor = 0;
1182 variationPerMapUnitColor = ( endValColor - startValColor ) / totalLength;
1185 for (
const QPolygonF &poly : parts )
1187 double lengthFromStart = 0;
1188 for (
int i = 1; i < poly.count(); ++i )
1190 const QPointF p1 = poly.at( i - 1 );
1191 const QPointF p2 = poly.at( i );
1193 const double v1c = startValColor + variationPerMapUnitColor * lengthFromStart;
1194 const double v1w = startValWidth + variationPerMapUnitWidth * lengthFromStart;
1196 const double v2c = startValColor + variationPerMapUnitColor * lengthFromStart;
1197 const double v2w = startValWidth + variationPerMapUnitWidth * lengthFromStart;
1198 mLineRender.renderInDeviceCoordinates( v1c, v2c, v1w, v2w, p1, p2, context );
1205 mLineRender.setSelected( context.
selected() );
1207 if ( points.empty() )
1210 if ( mRenderingFeature )
1214 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 copyCommonProperties(QgsSymbolLayer *destLayer) const
Copies all common base class properties from 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.
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).