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 ) );
A ramp shader will color a raster pixel based on a list of values ranges in a ramp.
QList< QgsColorRampShader::ColorRampItem > colorRampItemList() const
Returns the custom colormap.
bool isEmpty() const
Whether the color ramp contains any items.
Type colorRampType() const
Returns the color ramp type.
bool clip() const
Returns whether the shader will clip values which are out of range.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context=QgsReadWriteContext()) const
Writes configuration to a new DOM element.
bool shade(double value, int *returnRedValue, int *returnGreenValue, int *returnBlueValue, int *returnAlphaValue) const override
Generates and new RGB value based on one input value.
QgsColorRamp * sourceColorRamp() const
Returns the source color ramp.
@ Interpolated
Interpolates the color between two class breaks linearly.
@ Discrete
Assigns the color of the higher class for every pixel between two class breaks.
@ Exact
Assigns the color of the exact matching value in the color ramp item list.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context=QgsReadWriteContext())
Reads configuration from the given DOM element.
Class defining color to render mesh datasets.
QgsInterpolatedLineColor::ColoringMethod coloringMethod() const
Returns the coloring method used.
QgsColorRampShader colorRampShader() const
Returns the color ramp shader.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Reads configuration from the given DOM element.
QColor color(double magnitude) const
Returns the color corresponding to the magnitude.
void graduatedColors(double value1, double value2, QList< double > &breakValues, QList< QColor > &breakColors, QList< QLinearGradient > &gradients) const
Returns the break values, graduated colors and the associated gradients between two values.
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.
QgsInterpolatedLineColor()=default
Default constructor.
ColoringMethod
Defines how the color is defined.
@ ColorRamp
Render with a color ramp.
@ SingleColor
Render with a single color.
void setWidthUnit(const QgsUnitTypes::RenderUnit &strokeWidthUnit)
Sets the unit of the stroke width.
void setInterpolatedColor(const QgsInterpolatedLineColor &strokeColoring)
Sets the stroke color used to plot.
void setInterpolatedWidth(const QgsInterpolatedLineWidth &strokeWidth)
Sets the stroke width used to plot.
void render(double value1, double value2, QgsPointXY point1, QgsPointXY point2, QgsRenderContext &context) const
Render a line in the context between point1 and point2 with color and width that vary depending on va...
Represents a width than can vary depending on values.
void setFixedStrokeWidth(double fixedWidth)
Sets the fixed width.
double strokeWidth(double value) const
Returns the variable width depending on value, if not varying returns the fixed width.
void setUseAbsoluteValue(bool useAbsoluteValue)
Sets whether absolute value are used as input.
double minimumValue() const
Returns the minimum value used to defined the variable width.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Reads configuration from the given DOM element.
void setIgnoreOutOfRange(bool ignoreOutOfRange)
Sets whether the variable width ignores out of range value.
void setMaximumValue(double maximumValue)
Sets the maximum value used to defined the variable width.
bool useAbsoluteValue() const
Returns whether absolute value are used as input.
void setIsVariableWidth(bool isVariableWidth)
Returns whether the width is variable.
void setMinimumValue(double minimumValue)
Sets the minimum value used to defined the variable width.
double maximumWidth() const
Returns the maximum width used to defined the variable width.
void setMaximumWidth(double maximumWidth)
Sets the maximum width used to defined the variable width.
double maximumValue() const
Returns the maximum value used to defined the variable width.
void setMinimumWidth(double minimumWidth)
Sets the minimum width used to defined the variable width.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Writes configuration to a new DOM element.
bool ignoreOutOfRange() const
Returns whether the variable width ignores out of range value.
double minimumWidth() const
Returns the minimum width used to defined the variable width.
double fixedStrokeWidth() const
Returns the fixed width.
bool isVariableWidth() const
Returns whether the width is variable.
Perform transforms between map coordinates and device coordinates.
QgsPointXY transform(const QgsPointXY &p) const
Transform the point p from map (world) coordinates to device coordinates.
A class to represent a 2D point.
QPointF toQPointF() const
Converts a point to a QPointF.
The class is used as a container of context for various read/write operations on other objects.
Contains information about the context of a rendering operation.
QPainter * painter()
Returns the destination QPainter for the render operation.
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
Scoped object for saving and restoring a QPainter object's state.
static QColor decodeColor(const QString &str)
static QString encodeColor(const QColor &color)
RenderUnit
Rendering size units.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)