40 #include <QSvgRenderer>
41 #include <QDomDocument>
42 #include <QDomElement>
50 Qt::PenJoinStyle penJoinStyle )
51 : mBrushStyle( style )
52 , mStrokeColor( strokeColor )
53 , mStrokeStyle( strokeStyle )
54 , mStrokeWidth( strokeWidth )
55 , mPenJoinStyle( penJoinStyle )
91 void QgsSimpleFillSymbolLayer::applyDataDefinedSymbology(
QgsSymbolRenderContext &context, QBrush &brush, QPen &pen, QPen &selPen )
107 if ( exprVal.isValid() )
119 double width = exprVal.toDouble( &ok );
123 pen.setWidthF( width );
124 selPen.setWidthF( width );
160 if ( props.contains( QStringLiteral(
"color" ) ) )
162 if ( props.contains( QStringLiteral(
"style" ) ) )
164 if ( props.contains( QStringLiteral(
"color_border" ) ) )
169 else if ( props.contains( QStringLiteral(
"outline_color" ) ) )
173 else if ( props.contains( QStringLiteral(
"line_color" ) ) )
178 if ( props.contains( QStringLiteral(
"style_border" ) ) )
183 else if ( props.contains( QStringLiteral(
"outline_style" ) ) )
187 else if ( props.contains( QStringLiteral(
"line_style" ) ) )
191 if ( props.contains( QStringLiteral(
"width_border" ) ) )
194 strokeWidth = props[QStringLiteral(
"width_border" )].toDouble();
196 else if ( props.contains( QStringLiteral(
"outline_width" ) ) )
198 strokeWidth = props[QStringLiteral(
"outline_width" )].toDouble();
200 else if ( props.contains( QStringLiteral(
"line_width" ) ) )
202 strokeWidth = props[QStringLiteral(
"line_width" )].toDouble();
204 if ( props.contains( QStringLiteral(
"offset" ) ) )
206 if ( props.contains( QStringLiteral(
"joinstyle" ) ) )
211 if ( props.contains( QStringLiteral(
"border_width_unit" ) ) )
215 else if ( props.contains( QStringLiteral(
"outline_width_unit" ) ) )
219 else if ( props.contains( QStringLiteral(
"line_width_unit" ) ) )
223 if ( props.contains( QStringLiteral(
"offset_unit" ) ) )
226 if ( props.contains( QStringLiteral(
"border_width_map_unit_scale" ) ) )
228 if ( props.contains( QStringLiteral(
"offset_map_unit_scale" ) ) )
231 sl->restoreOldDataDefinedProperties( props );
239 return QStringLiteral(
"SimpleFill" );
251 selColor.setAlphaF( context.
opacity() );
301 #ifndef QT_NO_PRINTER
302 if (
mBrush.style() == Qt::SolidPattern ||
mBrush.style() == Qt::NoBrush || !
dynamic_cast<QPrinter *
>( p->device() ) )
309 #ifndef QT_NO_PRINTER
316 p->setPen( Qt::NoPen );
320 p->setBrush( Qt::NoBrush );
338 map[QStringLiteral(
"outline_width" )] = QString::number(
mStrokeWidth );
366 QDomElement symbolizerElem = doc.createElement( QStringLiteral(
"se:PolygonSymbolizer" ) );
367 if ( !props.value( QStringLiteral(
"uom" ), QString() ).isEmpty() )
368 symbolizerElem.setAttribute( QStringLiteral(
"uom" ), props.value( QStringLiteral(
"uom" ), QString() ) );
369 element.appendChild( symbolizerElem );
377 QDomElement fillElem = doc.createElement( QStringLiteral(
"se:Fill" ) );
378 symbolizerElem.appendChild( fillElem );
385 QDomElement strokeElem = doc.createElement( QStringLiteral(
"se:Stroke" ) );
386 symbolizerElem.appendChild( strokeElem );
401 symbolStyle.append(
';' );
410 Qt::BrushStyle fillStyle;
414 QDomElement fillElem = element.firstChildElement( QStringLiteral(
"Fill" ) );
417 QDomElement strokeElem = element.firstChildElement( QStringLiteral(
"Stroke" ) );
423 QString uom = element.attribute( QStringLiteral(
"uom" ), QString() );
429 sl->setOutputUnit( QgsUnitTypes::RenderUnit::RenderPixels );
438 return penBleed + offsetBleed;
499 : mGradientColorType( colorType )
500 , mGradientType( gradientType )
501 , mCoordinateMode( coordinateMode )
502 , mGradientSpread( spread )
503 , mReferencePoint1( QPointF( 0.5, 0 ) )
504 , mReferencePoint2( QPointF( 0.5, 1 ) )
525 bool refPoint1IsCentroid =
false;
527 bool refPoint2IsCentroid =
false;
532 if ( props.contains( QStringLiteral(
"type" ) ) )
533 type =
static_cast< GradientType >( props[QStringLiteral(
"type" )].toInt() );
534 if ( props.contains( QStringLiteral(
"coordinate_mode" ) ) )
536 if ( props.contains( QStringLiteral(
"spread" ) ) )
538 if ( props.contains( QStringLiteral(
"color_type" ) ) )
539 colorType =
static_cast< GradientColorType >( props[QStringLiteral(
"color_type" )].toInt() );
540 if ( props.contains( QStringLiteral(
"gradient_color" ) ) )
545 else if ( props.contains( QStringLiteral(
"color" ) ) )
549 if ( props.contains( QStringLiteral(
"gradient_color2" ) ) )
554 if ( props.contains( QStringLiteral(
"reference_point1" ) ) )
556 if ( props.contains( QStringLiteral(
"reference_point1_iscentroid" ) ) )
557 refPoint1IsCentroid = props[QStringLiteral(
"reference_point1_iscentroid" )].toInt();
558 if ( props.contains( QStringLiteral(
"reference_point2" ) ) )
560 if ( props.contains( QStringLiteral(
"reference_point2_iscentroid" ) ) )
561 refPoint2IsCentroid = props[QStringLiteral(
"reference_point2_iscentroid" )].toInt();
562 if ( props.contains( QStringLiteral(
"angle" ) ) )
563 angle = props[QStringLiteral(
"angle" )].toDouble();
565 if ( props.contains( QStringLiteral(
"offset" ) ) )
582 if ( props.contains( QStringLiteral(
"offset_unit" ) ) )
584 if ( props.contains( QStringLiteral(
"offset_map_unit_scale" ) ) )
587 sl->setReferencePoint1IsCentroid( refPoint1IsCentroid );
589 sl->setReferencePoint2IsCentroid( refPoint2IsCentroid );
590 sl->setAngle(
angle );
592 sl->setColorRamp( gradientRamp );
594 sl->restoreOldDataDefinedProperties( props );
607 return QStringLiteral(
"GradientFill" );
610 void QgsGradientFillSymbolLayer::applyDataDefinedSymbology(
QgsSymbolRenderContext &context,
const QPolygonF &points )
653 if ( currentType == QObject::tr(
"linear" ) )
657 else if ( currentType == QObject::tr(
"radial" ) )
661 else if ( currentType == QObject::tr(
"conical" ) )
675 if ( currentCoordMode == QObject::tr(
"feature" ) )
679 else if ( currentCoordMode == QObject::tr(
"viewport" ) )
693 if ( currentSpread == QObject::tr(
"pad" ) )
697 else if ( currentSpread == QObject::tr(
"repeat" ) )
701 else if ( currentSpread == QObject::tr(
"reflect" ) )
748 if ( refPoint1IsCentroid || refPoint2IsCentroid )
753 QRectF bbox = points.boundingRect();
754 double centroidX = ( centroid.x() - bbox.left() ) / bbox.width();
755 double centroidY = ( centroid.y() - bbox.top() ) / bbox.height();
757 if ( refPoint1IsCentroid )
759 refPoint1X = centroidX;
760 refPoint1Y = centroidY;
762 if ( refPoint2IsCentroid )
764 refPoint2X = centroidX;
765 refPoint2Y = centroidY;
771 spread, QPointF( refPoint1X, refPoint1Y ), QPointF( refPoint2X, refPoint2Y ),
angle );
774 QPointF QgsGradientFillSymbolLayer::rotateReferencePoint( QPointF refPoint,
double angle )
779 QLineF refLine = QLineF( QPointF( 0.5, 0.5 ), refPoint );
781 refLine.setAngle( refLine.angle() +
angle );
783 QPointF rotatedReferencePoint = refLine.p2();
785 if ( rotatedReferencePoint.x() > 1 )
786 rotatedReferencePoint.setX( 1 );
787 if ( rotatedReferencePoint.x() < 0 )
788 rotatedReferencePoint.setX( 0 );
789 if ( rotatedReferencePoint.y() > 1 )
790 rotatedReferencePoint.setY( 1 );
791 if ( rotatedReferencePoint.y() < 0 )
792 rotatedReferencePoint.setY( 0 );
794 return rotatedReferencePoint;
798 const QColor &color,
const QColor &color2, GradientColorType gradientColorType,
800 GradientCoordinateMode coordinateMode, GradientSpread gradientSpread,
801 QPointF referencePoint1, QPointF referencePoint2,
const double angle )
806 QColor fillColor2 =
color2;
807 fillColor2.setAlphaF( context.
opacity() * fillColor2.alphaF() );
818 gradient = QLinearGradient( rotatedReferencePoint1, rotatedReferencePoint2 );
821 gradient = QRadialGradient( rotatedReferencePoint1, QLineF( rotatedReferencePoint1, rotatedReferencePoint2 ).length() );
824 gradient = QConicalGradient( rotatedReferencePoint1, QLineF( rotatedReferencePoint1, rotatedReferencePoint2 ).
angle() );
830 gradient.setCoordinateMode( QGradient::ObjectBoundingMode );
833 gradient.setCoordinateMode( QGradient::StretchToDeviceMode );
839 gradient.setSpread( QGradient::PadSpread );
842 gradient.setSpread( QGradient::ReflectSpread );
845 gradient.setSpread( QGradient::RepeatSpread );
861 gradient.setColorAt( 1.0, fillColor2 );
865 brush = QBrush( gradient );
872 selColor.setAlphaF( context.
opacity() );
889 applyDataDefinedSymbology( context, points );
892 p->setPen( Qt::NoPen );
926 map[QStringLiteral(
"type" )] = QString::number(
mGradientType );
927 map[QStringLiteral(
"coordinate_mode" )] = QString::number(
mCoordinateMode );
933 map[QStringLiteral(
"angle" )] = QString::number(
mAngle );
939 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
995 int blurRadius,
bool useWholeShape,
double maxDistance )
996 : mBlurRadius( blurRadius )
997 , mUseWholeShape( useWholeShape )
998 , mMaxDistance( maxDistance )
999 , mColorType( colorType )
1018 if ( props.contains( QStringLiteral(
"color_type" ) ) )
1022 if ( props.contains( QStringLiteral(
"shapeburst_color" ) ) )
1027 else if ( props.contains( QStringLiteral(
"color" ) ) )
1032 if ( props.contains( QStringLiteral(
"shapeburst_color2" ) ) )
1037 else if ( props.contains( QStringLiteral(
"gradient_color2" ) ) )
1041 if ( props.contains( QStringLiteral(
"blur_radius" ) ) )
1043 blurRadius = props[QStringLiteral(
"blur_radius" )].toInt();
1045 if ( props.contains( QStringLiteral(
"use_whole_shape" ) ) )
1047 useWholeShape = props[QStringLiteral(
"use_whole_shape" )].toInt();
1049 if ( props.contains( QStringLiteral(
"max_distance" ) ) )
1051 maxDistance = props[QStringLiteral(
"max_distance" )].toDouble();
1053 if ( props.contains( QStringLiteral(
"offset" ) ) )
1072 if ( props.contains( QStringLiteral(
"offset_unit" ) ) )
1076 if ( props.contains( QStringLiteral(
"distance_unit" ) ) )
1080 if ( props.contains( QStringLiteral(
"offset_map_unit_scale" ) ) )
1084 if ( props.contains( QStringLiteral(
"distance_map_unit_scale" ) ) )
1088 if ( props.contains( QStringLiteral(
"ignore_rings" ) ) )
1090 sl->setIgnoreRings( props[QStringLiteral(
"ignore_rings" )].toInt() );
1094 sl->setColorRamp( gradientRamp );
1097 sl->restoreOldDataDefinedProperties( props );
1099 return sl.release();
1104 return QStringLiteral(
"ShapeburstFill" );
1109 if ( mGradientRamp.get() == ramp )
1112 mGradientRamp.reset( ramp );
1115 void QgsShapeburstFillSymbolLayer::applyDataDefinedSymbology(
QgsSymbolRenderContext &context, QColor &color, QColor &color2,
int &blurRadius,
bool &useWholeShape,
1116 double &maxDistance,
bool &ignoreRings )
1173 selColor.setAlphaF( context.
opacity() );
1174 mSelBrush = QBrush( selColor );
1193 p->setBrush( mSelBrush );
1194 QPointF
offset = mOffset;
1229 int outputPixelMaxDist = 0;
1237 std::unique_ptr< QgsGradientColorRamp > twoColorGradientRamp;
1240 twoColorGradientRamp = qgis::make_unique< QgsGradientColorRamp >( color1,
color2 );
1244 p->setPen( QPen( Qt::NoPen ) );
1249 int pointsWidth =
static_cast< int >( std::round( points.boundingRect().width() ) );
1250 int pointsHeight =
static_cast< int >( std::round( points.boundingRect().height() ) );
1251 int imWidth = pointsWidth + ( sideBuffer * 2 );
1252 int imHeight = pointsHeight + ( sideBuffer * 2 );
1253 std::unique_ptr< QImage > fillImage = qgis::make_unique< QImage >( imWidth,
1254 imHeight, QImage::Format_ARGB32_Premultiplied );
1255 if ( fillImage->isNull() )
1262 std::unique_ptr< QImage > alphaImage = qgis::make_unique< QImage >( fillImage->width(), fillImage->height(), QImage::Format_ARGB32_Premultiplied );
1263 if ( alphaImage->isNull() )
1272 fillImage->fill( Qt::black );
1275 alphaImage->fill( Qt::transparent );
1278 QPainter imgPainter;
1279 imgPainter.begin( alphaImage.get() );
1280 imgPainter.setRenderHint( QPainter::Antialiasing,
true );
1281 imgPainter.setBrush( QBrush( Qt::white ) );
1282 imgPainter.setPen( QPen( Qt::black ) );
1283 imgPainter.translate( -points.boundingRect().left() + sideBuffer, - points.boundingRect().top() + sideBuffer );
1289 imgPainter.begin( fillImage.get() );
1292 imgPainter.drawImage( 0, 0, *alphaImage );
1299 imgPainter.setBrush( QBrush( Qt::white ) );
1300 imgPainter.setPen( QPen( Qt::black ) );
1301 imgPainter.translate( -points.boundingRect().left() + sideBuffer, - points.boundingRect().top() + sideBuffer );
1307 double *dtArray = distanceTransform( fillImage.get(), context.
renderContext() );
1327 imgPainter.begin( fillImage.get() );
1328 imgPainter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
1329 imgPainter.drawImage( 0, 0, *alphaImage );
1337 QPointF
offset = mOffset;
1354 p->drawImage( points.boundingRect().left() - sideBuffer, points.boundingRect().top() - sideBuffer, *fillImage );
1365 void QgsShapeburstFillSymbolLayer::distanceTransform1d(
double *f,
int n,
int *v,
double *z,
double *d )
1371 for (
int q = 1; q <= n - 1; q++ )
1373 double s = ( ( f[q] + q * q ) - ( f[v[k]] + ( v[k] * v[k] ) ) ) / ( 2 * q - 2 * v[k] );
1377 s = ( ( f[q] + q * q ) - ( f[v[k]] + ( v[k] * v[k] ) ) ) / ( 2 * q - 2 * v[k] );
1386 for (
int q = 0; q <= n - 1; q++ )
1388 while ( z[k + 1] < q )
1390 d[q] = ( q - v[k] ) * ( q - v[k] ) + f[v[k]];
1395 void QgsShapeburstFillSymbolLayer::distanceTransform2d(
double *im,
int width,
int height,
QgsRenderContext &context )
1397 int maxDimension = std::max( width, height );
1398 double *f =
new double[ maxDimension ];
1399 int *v =
new int[ maxDimension ];
1400 double *z =
new double[ maxDimension + 1 ];
1401 double *d =
new double[ maxDimension ];
1404 for (
int x = 0; x < width; x++ )
1409 for (
int y = 0; y < height; y++ )
1411 f[y] = im[ x + y * width ];
1413 distanceTransform1d( f, height, v, z, d );
1414 for (
int y = 0; y < height; y++ )
1416 im[ x + y * width ] = d[y];
1421 for (
int y = 0; y < height; y++ )
1426 for (
int x = 0; x < width; x++ )
1428 f[x] = im[ x + y * width ];
1430 distanceTransform1d( f, width, v, z, d );
1431 for (
int x = 0; x < width; x++ )
1433 im[ x + y * width ] = d[x];
1444 double *QgsShapeburstFillSymbolLayer::distanceTransform( QImage *im,
QgsRenderContext &context )
1446 int width = im->width();
1447 int height = im->height();
1449 double *dtArray =
new double[width * height];
1454 for (
int heightIndex = 0; heightIndex < height; ++heightIndex )
1459 const QRgb *scanLine =
reinterpret_cast< const QRgb *
>( im->constScanLine( heightIndex ) );
1460 for (
int widthIndex = 0; widthIndex < width; ++widthIndex )
1462 tmpRgb = scanLine[widthIndex];
1463 if ( qRed( tmpRgb ) == 0 )
1471 dtArray[ idx ] =
INF;
1478 distanceTransform2d( dtArray, width, height, context );
1483 void QgsShapeburstFillSymbolLayer::dtArrayToQImage(
double *array, QImage *im,
QgsColorRamp *ramp,
QgsRenderContext &context,
bool useWholeShape,
int maxPixelDistance )
1485 int width = im->width();
1486 int height = im->height();
1489 double maxDistanceValue;
1494 double dtMaxValue = array[0];
1495 for (
int i = 1; i < ( width * height ); ++i )
1497 if ( array[i] > dtMaxValue )
1499 dtMaxValue = array[i];
1504 maxDistanceValue = std::sqrt( dtMaxValue );
1509 maxDistanceValue = maxPixelDistance;
1514 double squaredVal = 0;
1517 for (
int heightIndex = 0; heightIndex < height; ++heightIndex )
1522 QRgb *scanLine =
reinterpret_cast< QRgb *
>( im->scanLine( heightIndex ) );
1523 for (
int widthIndex = 0; widthIndex < width; ++widthIndex )
1526 squaredVal = array[idx];
1529 if ( maxDistanceValue > 0 )
1531 pixVal = squaredVal > 0 ? std::min( ( std::sqrt( squaredVal ) / maxDistanceValue ), 1.0 ) : 0;
1540 scanLine[widthIndex] = qPremultiply( ramp->
color( pixVal ).rgba() );
1551 map[QStringLiteral(
"color_type" )] = QString::number( mColorType );
1552 map[QStringLiteral(
"blur_radius" )] = QString::number( mBlurRadius );
1553 map[QStringLiteral(
"use_whole_shape" )] = QString::number( mUseWholeShape );
1554 map[QStringLiteral(
"max_distance" )] = QString::number( mMaxDistance );
1557 map[QStringLiteral(
"ignore_rings" )] = QString::number( mIgnoreRings );
1561 if ( mGradientRamp )
1563 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
1564 map.unite( mGradientRamp->properties() );
1566 map.insert( mGradientRamp->properties() );
1575 std::unique_ptr< QgsShapeburstFillSymbolLayer > sl = qgis::make_unique< QgsShapeburstFillSymbolLayer >(
mColor, mColor2, mColorType, mBlurRadius, mUseWholeShape, mMaxDistance );
1576 if ( mGradientRamp )
1578 sl->setColorRamp( mGradientRamp->clone() );
1580 sl->setDistanceUnit( mDistanceUnit );
1581 sl->setDistanceMapUnitScale( mDistanceMapUnitScale );
1582 sl->setIgnoreRings( mIgnoreRings );
1583 sl->setOffset( mOffset );
1584 sl->setOffsetUnit( mOffsetUnit );
1585 sl->setOffsetMapUnitScale( mOffsetMapUnitScale );
1588 return sl.release();
1593 double offsetBleed = context.
convertToPainterUnits( std::max( std::fabs( mOffset.x() ), std::fabs( mOffset.y() ) ), mOffsetUnit, mOffsetMapUnitScale );
1599 mDistanceUnit = unit;
1605 if ( mDistanceUnit == mOffsetUnit )
1607 return mDistanceUnit;
1614 mDistanceMapUnitScale = scale;
1615 mOffsetMapUnitScale = scale;
1620 if ( mDistanceMapUnitScale == mOffsetMapUnitScale )
1622 return mDistanceMapUnitScale;
1646 p->setPen( QPen( Qt::NoPen ) );
1648 QTransform bkTransform =
mBrush.transform();
1652 QTransform t =
mBrush.transform();
1653 t.translate( leftCorner.x(), leftCorner.y() );
1654 mBrush.setTransform( t );
1659 QPointF leftCorner = points.boundingRect().topLeft();
1660 QTransform t =
mBrush.transform();
1661 t.translate( leftCorner.x(), leftCorner.y() );
1662 mBrush.setTransform( t );
1668 p->setBrush( QBrush( selColor ) );
1674 QTransform t =
mBrush.transform();
1676 mBrush.setTransform( t );
1685 for (
auto ringIt = rings->constBegin(); ringIt != rings->constEnd(); ++ringIt )
1692 mBrush.setTransform( bkTransform );
1744 double subLayerBleed =
mStroke->symbolLayer( 0 )->estimateMaxBleed( context );
1745 return subLayerBleed;
1766 return QColor( Qt::black );
1773 return Qt::SolidLine;
1777 return Qt::SolidLine;
1781 return mStroke->dxfPenStyle();
1790 attr.unite(
mStroke->usedAttributes( context ) );
1813 , mPatternWidth( width )
1817 mColor = QColor( 255, 255, 255 );
1823 , mPatternWidth( width )
1824 , mSvgData( svgData )
1829 mColor = QColor( 255, 255, 255 );
1831 setDefaultSvgParams();
1837 mPatternWidthUnit = unit;
1838 mSvgStrokeWidthUnit = unit;
1840 mStroke->setOutputUnit( unit );
1846 if ( mPatternWidthUnit != unit || mSvgStrokeWidthUnit != unit ||
mStrokeWidthUnit != unit )
1856 mPatternWidthMapUnitScale = scale;
1857 mSvgStrokeWidthMapUnitScale = scale;
1864 mPatternWidthMapUnitScale == mSvgStrokeWidthMapUnitScale &&
1867 return mPatternWidthMapUnitScale;
1877 mSvgFilePath = svgPath;
1878 setDefaultSvgParams();
1888 if (
properties.contains( QStringLiteral(
"width" ) ) )
1890 width =
properties[QStringLiteral(
"width" )].toDouble();
1892 if (
properties.contains( QStringLiteral(
"svgFile" ) ) )
1896 if (
properties.contains( QStringLiteral(
"angle" ) ) )
1901 std::unique_ptr< QgsSVGFillSymbolLayer > symbolLayer;
1904 symbolLayer = qgis::make_unique< QgsSVGFillSymbolLayer >(
svgFilePath, width,
angle );
1908 if (
properties.contains( QStringLiteral(
"data" ) ) )
1910 data = QByteArray::fromHex(
properties[QStringLiteral(
"data" )].toLocal8Bit() );
1912 symbolLayer = qgis::make_unique< QgsSVGFillSymbolLayer >( data, width,
angle );
1916 if (
properties.contains( QStringLiteral(
"svgFillColor" ) ) )
1921 else if (
properties.contains( QStringLiteral(
"color" ) ) )
1925 if (
properties.contains( QStringLiteral(
"svgOutlineColor" ) ) )
1930 else if (
properties.contains( QStringLiteral(
"outline_color" ) ) )
1934 else if (
properties.contains( QStringLiteral(
"line_color" ) ) )
1938 if (
properties.contains( QStringLiteral(
"svgOutlineWidth" ) ) )
1941 symbolLayer->setSvgStrokeWidth(
properties[QStringLiteral(
"svgOutlineWidth" )].toDouble() );
1943 else if (
properties.contains( QStringLiteral(
"outline_width" ) ) )
1945 symbolLayer->setSvgStrokeWidth(
properties[QStringLiteral(
"outline_width" )].toDouble() );
1947 else if (
properties.contains( QStringLiteral(
"line_width" ) ) )
1949 symbolLayer->setSvgStrokeWidth(
properties[QStringLiteral(
"line_width" )].toDouble() );
1953 if (
properties.contains( QStringLiteral(
"pattern_width_unit" ) ) )
1957 if (
properties.contains( QStringLiteral(
"pattern_width_map_unit_scale" ) ) )
1961 if (
properties.contains( QStringLiteral(
"svg_outline_width_unit" ) ) )
1965 if (
properties.contains( QStringLiteral(
"svg_outline_width_map_unit_scale" ) ) )
1969 if (
properties.contains( QStringLiteral(
"outline_width_unit" ) ) )
1973 if (
properties.contains( QStringLiteral(
"outline_width_map_unit_scale" ) ) )
1978 symbolLayer->restoreOldDataDefinedProperties(
properties );
1980 return symbolLayer.release();
1985 QgsStringMap::iterator it =
properties.find( QStringLiteral(
"svgFile" ) );
1997 return QStringLiteral(
"SVGFill" );
2000 void QgsSVGFillSymbolLayer::applyPattern( QBrush &brush,
const QString &svgFilePath,
double patternWidth,
QgsUnitTypes::RenderUnit patternWidthUnit,
2001 const QColor &svgFillColor,
const QColor &svgStrokeColor,
double svgStrokeWidth,
2005 if ( mSvgViewBox.isNull() )
2012 if (
static_cast< int >( size ) < 1.0 || 10000.0 < size )
2014 brush.setTextureImage( QImage() );
2018 bool fitsInCache =
true;
2026 double hwRatio = 1.0;
2027 if ( patternPict.width() > 0 )
2029 hwRatio =
static_cast< double >( patternPict.height() ) /
static_cast< double >( patternPict.width() );
2031 patternImage = QImage(
static_cast< int >( size ),
static_cast< int >( size * hwRatio ), QImage::Format_ARGB32_Premultiplied );
2032 patternImage.fill( 0 );
2034 QPainter p( &patternImage );
2035 p.drawPicture( QPointF( size / 2, size * hwRatio / 2 ), patternPict );
2038 QTransform brushTransform;
2041 QImage transparentImage = patternImage.copy();
2043 brush.setTextureImage( transparentImage );
2047 brush.setTextureImage( patternImage );
2049 brush.setTransform( brushTransform );
2056 applyPattern(
mBrush, mSvgFilePath, mPatternWidth, mPatternWidthUnit,
mColor, mSvgStrokeColor, mSvgStrokeWidth, mSvgStrokeWidthUnit, context, mPatternWidthMapUnitScale, mSvgStrokeWidthMapUnitScale );
2075 if ( !mSvgFilePath.isEmpty() )
2077 map.insert( QStringLiteral(
"svgFile" ), mSvgFilePath );
2081 map.insert( QStringLiteral(
"data" ), QString( mSvgData.toHex() ) );
2084 map.insert( QStringLiteral(
"width" ), QString::number( mPatternWidth ) );
2085 map.insert( QStringLiteral(
"angle" ), QString::number(
mAngle ) );
2090 map.insert( QStringLiteral(
"outline_width" ), QString::number( mSvgStrokeWidth ) );
2104 std::unique_ptr< QgsSVGFillSymbolLayer > clonedLayer;
2105 if ( !mSvgFilePath.isEmpty() )
2107 clonedLayer = qgis::make_unique< QgsSVGFillSymbolLayer >( mSvgFilePath, mPatternWidth,
mAngle );
2108 clonedLayer->setSvgFillColor(
mColor );
2109 clonedLayer->setSvgStrokeColor( mSvgStrokeColor );
2110 clonedLayer->setSvgStrokeWidth( mSvgStrokeWidth );
2114 clonedLayer = qgis::make_unique< QgsSVGFillSymbolLayer >( mSvgData, mPatternWidth,
mAngle );
2117 clonedLayer->setPatternWidthUnit( mPatternWidthUnit );
2118 clonedLayer->setPatternWidthMapUnitScale( mPatternWidthMapUnitScale );
2119 clonedLayer->setSvgStrokeWidthUnit( mSvgStrokeWidthUnit );
2120 clonedLayer->setSvgStrokeWidthMapUnitScale( mSvgStrokeWidthMapUnitScale );
2126 clonedLayer->setSubSymbol(
mStroke->clone() );
2130 return clonedLayer.release();
2135 QDomElement symbolizerElem = doc.createElement( QStringLiteral(
"se:PolygonSymbolizer" ) );
2136 if ( !props.value( QStringLiteral(
"uom" ), QString() ).isEmpty() )
2137 symbolizerElem.setAttribute( QStringLiteral(
"uom" ), props.value( QStringLiteral(
"uom" ), QString() ) );
2138 element.appendChild( symbolizerElem );
2142 QDomElement fillElem = doc.createElement( QStringLiteral(
"se:Fill" ) );
2143 symbolizerElem.appendChild( fillElem );
2145 QDomElement graphicFillElem = doc.createElement( QStringLiteral(
"se:GraphicFill" ) );
2146 fillElem.appendChild( graphicFillElem );
2148 QDomElement graphicElem = doc.createElement( QStringLiteral(
"se:Graphic" ) );
2149 graphicFillElem.appendChild( graphicElem );
2151 if ( !mSvgFilePath.isEmpty() )
2162 symbolizerElem.appendChild( doc.createComment( QStringLiteral(
"SVG from data not implemented yet" ) ) );
2168 double angle = props.value( QStringLiteral(
"angle" ), QStringLiteral(
"0" ) ).toDouble( &ok );
2171 angleFunc = QStringLiteral(
"%1 + %2" ).arg( props.value( QStringLiteral(
"angle" ), QStringLiteral(
"0" ) ) ).arg(
mAngle );
2184 mStroke->toSld( doc, element, props );
2190 QString path, mimeType;
2192 Qt::PenStyle penStyle;
2193 double size, strokeWidth;
2195 QDomElement fillElem = element.firstChildElement( QStringLiteral(
"Fill" ) );
2196 if ( fillElem.isNull() )
2199 QDomElement graphicFillElem = fillElem.firstChildElement( QStringLiteral(
"GraphicFill" ) );
2200 if ( graphicFillElem.isNull() )
2203 QDomElement graphicElem = graphicFillElem.firstChildElement( QStringLiteral(
"Graphic" ) );
2204 if ( graphicElem.isNull() )
2210 if ( mimeType != QLatin1String(
"image/svg+xml" ) )
2215 QString uom = element.attribute( QStringLiteral(
"uom" ) );
2224 double d = angleFunc.toDouble( &ok );
2229 std::unique_ptr< QgsSVGFillSymbolLayer > sl = qgis::make_unique< QgsSVGFillSymbolLayer >( path, size,
angle );
2230 sl->setOutputUnit( QgsUnitTypes::RenderUnit::RenderPixels );
2233 sl->setSvgStrokeWidth( strokeWidth );
2236 QDomElement strokeElem = element.firstChildElement( QStringLiteral(
"Stroke" ) );
2237 if ( !strokeElem.isNull() )
2248 return sl.release();
2266 double width = mPatternWidth;
2272 QString svgFile = mSvgFilePath;
2291 double strokeWidth = mSvgStrokeWidth;
2298 mSvgStrokeWidthUnit, context, mPatternWidthMapUnitScale, mSvgStrokeWidthMapUnitScale );
2302 void QgsSVGFillSymbolLayer::storeViewBox()
2304 if ( !mSvgData.isEmpty() )
2306 QSvgRenderer r( mSvgData );
2309 mSvgViewBox = r.viewBoxF();
2314 mSvgViewBox = QRectF();
2317 void QgsSVGFillSymbolLayer::setDefaultSvgParams()
2319 if ( mSvgFilePath.isEmpty() )
2324 bool hasFillParam, hasFillOpacityParam, hasStrokeParam, hasStrokeWidthParam, hasStrokeOpacityParam;
2325 bool hasDefaultFillColor, hasDefaultFillOpacity, hasDefaultStrokeColor, hasDefaultStrokeWidth, hasDefaultStrokeOpacity;
2326 QColor defaultFillColor, defaultStrokeColor;
2327 double defaultStrokeWidth, defaultFillOpacity, defaultStrokeOpacity;
2329 hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
2330 hasStrokeParam, hasDefaultStrokeColor, defaultStrokeColor,
2331 hasStrokeWidthParam, hasDefaultStrokeWidth, defaultStrokeWidth,
2332 hasStrokeOpacityParam, hasDefaultStrokeOpacity, defaultStrokeOpacity );
2334 double newFillOpacity = hasFillOpacityParam ?
mColor.alphaF() : 1.0;
2335 double newStrokeOpacity = hasStrokeOpacityParam ? mSvgStrokeColor.alphaF() : 1.0;
2337 if ( hasDefaultFillColor )
2339 mColor = defaultFillColor;
2340 mColor.setAlphaF( newFillOpacity );
2342 if ( hasDefaultFillOpacity )
2344 mColor.setAlphaF( defaultFillOpacity );
2346 if ( hasDefaultStrokeColor )
2348 mSvgStrokeColor = defaultStrokeColor;
2349 mSvgStrokeColor.setAlphaF( newStrokeOpacity );
2351 if ( hasDefaultStrokeOpacity )
2353 mSvgStrokeColor.setAlphaF( defaultStrokeOpacity );
2355 if ( hasDefaultStrokeWidth )
2357 mSvgStrokeWidth = defaultStrokeWidth;
2383 return mFillLineSymbol ? mFillLineSymbol->
color() :
mColor;
2388 delete mFillLineSymbol;
2403 delete mFillLineSymbol;
2404 mFillLineSymbol = lineSymbol;
2415 return mFillLineSymbol;
2421 if ( mFillLineSymbol )
2443 mDistanceUnit = unit;
2444 mLineWidthUnit = unit;
2451 if ( mDistanceUnit != unit || mLineWidthUnit != unit || mOffsetUnit != unit )
2461 mDistanceMapUnitScale = scale;
2462 mLineWidthMapUnitScale = scale;
2463 mOffsetMapUnitScale = scale;
2469 mDistanceMapUnitScale == mLineWidthMapUnitScale &&
2470 mLineWidthMapUnitScale == mOffsetMapUnitScale )
2472 return mDistanceMapUnitScale;
2479 std::unique_ptr< QgsLinePatternFillSymbolLayer > patternLayer = qgis::make_unique< QgsLinePatternFillSymbolLayer >();
2485 QColor
color( Qt::black );
2488 if (
properties.contains( QStringLiteral(
"lineangle" ) ) )
2493 else if (
properties.contains( QStringLiteral(
"angle" ) ) )
2497 patternLayer->setLineAngle(
lineAngle );
2499 if (
properties.contains( QStringLiteral(
"distance" ) ) )
2503 patternLayer->setDistance(
distance );
2505 if (
properties.contains( QStringLiteral(
"linewidth" ) ) )
2510 else if (
properties.contains( QStringLiteral(
"outline_width" ) ) )
2514 else if (
properties.contains( QStringLiteral(
"line_width" ) ) )
2518 patternLayer->setLineWidth(
lineWidth );
2520 if (
properties.contains( QStringLiteral(
"color" ) ) )
2524 else if (
properties.contains( QStringLiteral(
"outline_color" ) ) )
2528 else if (
properties.contains( QStringLiteral(
"line_color" ) ) )
2532 patternLayer->setColor(
color );
2534 if (
properties.contains( QStringLiteral(
"offset" ) ) )
2538 patternLayer->setOffset(
offset );
2541 if (
properties.contains( QStringLiteral(
"distance_unit" ) ) )
2545 if (
properties.contains( QStringLiteral(
"distance_map_unit_scale" ) ) )
2549 if (
properties.contains( QStringLiteral(
"line_width_unit" ) ) )
2553 else if (
properties.contains( QStringLiteral(
"outline_width_unit" ) ) )
2557 if (
properties.contains( QStringLiteral(
"line_width_map_unit_scale" ) ) )
2561 if (
properties.contains( QStringLiteral(
"offset_unit" ) ) )
2565 if (
properties.contains( QStringLiteral(
"offset_map_unit_scale" ) ) )
2569 if (
properties.contains( QStringLiteral(
"outline_width_unit" ) ) )
2573 if (
properties.contains( QStringLiteral(
"outline_width_map_unit_scale" ) ) )
2578 patternLayer->restoreOldDataDefinedProperties(
properties );
2580 return patternLayer.release();
2585 return QStringLiteral(
"LinePatternFill" );
2588 void QgsLinePatternFillSymbolLayer::applyPattern(
const QgsSymbolRenderContext &context, QBrush &brush,
double lineAngle,
double distance )
2590 mBrush.setTextureImage( QImage() );
2592 if ( !mFillLineSymbol )
2597 std::unique_ptr< QgsLineSymbol > fillLineSymbol( mFillLineSymbol->
clone() );
2598 if ( !fillLineSymbol )
2613 outputPixelOffset = std::fmod( outputPixelOffset, outputPixelDist );
2614 if ( outputPixelOffset > outputPixelDist / 2.0 )
2615 outputPixelOffset -= outputPixelDist;
2619 double outputPixelBleed = 0;
2620 double outputPixelInterval = 0;
2621 for (
int i = 0; i < fillLineSymbol->symbolLayerCount(); i++ )
2625 outputPixelBleed = std::max( outputPixelBleed, outputPixelLayerBleed );
2628 if ( markerLineLayer )
2637 outputPixelInterval = std::max( outputPixelInterval, outputPixelLayerInterval );
2641 if ( outputPixelInterval > 0 )
2645 double intervalScale = std::round( outputPixelInterval ) / outputPixelInterval;
2646 outputPixelInterval = std::round( outputPixelInterval );
2648 for (
int i = 0; i < fillLineSymbol->symbolLayerCount(); i++ )
2653 if ( markerLineLayer )
2667 height = outputPixelDist;
2668 width = outputPixelInterval > 0 ? outputPixelInterval : height;
2672 width = outputPixelDist;
2673 height = outputPixelInterval > 0 ? outputPixelInterval : width;
2677 height = outputPixelDist / std::cos(
lineAngle * M_PI / 180 );
2678 width = outputPixelDist / std::sin(
lineAngle * M_PI / 180 );
2681 lineAngle = 180 * std::atan2(
static_cast< double >( height ),
static_cast< double >( width ) ) / M_PI;
2687 height = std::abs( height );
2688 width = std::abs( width );
2690 outputPixelDist = std::abs( height * std::cos(
lineAngle * M_PI / 180 ) );
2694 int offsetHeight =
static_cast< int >( std::round( outputPixelOffset / std::cos(
lineAngle * M_PI / 180 ) ) );
2695 outputPixelOffset = offsetHeight * std::cos(
lineAngle * M_PI / 180 );
2704 int bufferMulti =
static_cast< int >( std::max( std::ceil( outputPixelBleed / width ), std::ceil( outputPixelBleed / width ) ) );
2708 bufferMulti = std::max( bufferMulti, 1 );
2710 int xBuffer = width * bufferMulti;
2711 int yBuffer = height * bufferMulti;
2712 int innerWidth = width;
2713 int innerHeight = height;
2714 width += 2 * xBuffer;
2715 height += 2 * yBuffer;
2718 if ( width > 10000 || height > 10000 || width == 0 || height == 0 )
2723 QImage patternImage( width, height, QImage::Format_ARGB32 );
2724 patternImage.fill( 0 );
2726 QPointF p1, p2, p3, p4, p5, p6;
2729 p1 = QPointF( 0, yBuffer );
2730 p2 = QPointF( width, yBuffer );
2731 p3 = QPointF( 0, yBuffer + innerHeight );
2732 p4 = QPointF( width, yBuffer + innerHeight );
2736 p1 = QPointF( xBuffer, height );
2737 p2 = QPointF( xBuffer, 0 );
2738 p3 = QPointF( xBuffer + innerWidth, height );
2739 p4 = QPointF( xBuffer + innerWidth, 0 );
2743 dx = outputPixelDist * std::cos( ( 90 -
lineAngle ) * M_PI / 180.0 );
2744 dy = outputPixelDist * std::sin( ( 90 -
lineAngle ) * M_PI / 180.0 );
2745 p1 = QPointF( 0, height );
2746 p2 = QPointF( width, 0 );
2747 p3 = QPointF( -dx, height - dy );
2748 p4 = QPointF( width - dx, -dy );
2749 p5 = QPointF( dx, height + dy );
2750 p6 = QPointF( width + dx, dy );
2754 dx = outputPixelDist * std::cos( ( 90 -
lineAngle ) * M_PI / 180.0 );
2755 dy = outputPixelDist * std::sin( ( 90 -
lineAngle ) * M_PI / 180.0 );
2756 p1 = QPointF( width, 0 );
2757 p2 = QPointF( 0, height );
2758 p3 = QPointF( width - dx, -dy );
2759 p4 = QPointF( -dx, height - dy );
2760 p5 = QPointF( width + dx, dy );
2761 p6 = QPointF( dx, height + dy );
2765 dy = outputPixelDist * std::cos( ( 180 -
lineAngle ) * M_PI / 180 );
2766 dx = outputPixelDist * std::sin( ( 180 -
lineAngle ) * M_PI / 180 );
2767 p1 = QPointF( 0, 0 );
2768 p2 = QPointF( width, height );
2769 p5 = QPointF( dx, -dy );
2770 p6 = QPointF( width + dx, height - dy );
2771 p3 = QPointF( -dx, dy );
2772 p4 = QPointF( width - dx, height + dy );
2776 dy = outputPixelDist * std::cos( ( 180 -
lineAngle ) * M_PI / 180 );
2777 dx = outputPixelDist * std::sin( ( 180 -
lineAngle ) * M_PI / 180 );
2778 p1 = QPointF( width, height );
2779 p2 = QPointF( 0, 0 );
2780 p5 = QPointF( width + dx, height - dy );
2781 p6 = QPointF( dx, -dy );
2782 p3 = QPointF( width - dx, height + dy );
2783 p4 = QPointF( -dx, dy );
2790 p3 = QPointF( tempPt.x(), tempPt.y() );
2792 p4 = QPointF( tempPt.x(), tempPt.y() );
2794 p5 = QPointF( tempPt.x(), tempPt.y() );
2796 p6 = QPointF( tempPt.x(), tempPt.y() );
2800 p1 = QPointF( tempPt.x(), tempPt.y() );
2802 p2 = QPointF( tempPt.x(), tempPt.y() );
2805 QPainter p( &patternImage );
2809 p.setRenderHint( QPainter::Antialiasing,
false );
2810 QPen pen( QColor( Qt::black ) );
2811 pen.setWidthF( 0.1 );
2812 pen.setCapStyle( Qt::FlatCap );
2817 QPolygon polygon = QPolygon() << QPoint( 0, 0 ) << QPoint( width - 1, 0 ) << QPoint( width - 1, height - 1 ) << QPoint( 0, height - 1 ) << QPoint( 0, 0 );
2818 p.drawPolygon( polygon );
2820 polygon = QPolygon() << QPoint( xBuffer, yBuffer ) << QPoint( width - xBuffer - 1, yBuffer ) << QPoint( width - xBuffer - 1, height - yBuffer - 1 ) << QPoint( xBuffer, height - yBuffer - 1 ) << QPoint( xBuffer, yBuffer );
2821 p.drawPolygon( polygon );
2827 p.setRenderHint( QPainter::Antialiasing,
true );
2838 fillLineSymbol->startRender( lineRenderContext, context.
fields() );
2840 QVector<QPolygonF> polygons;
2841 polygons.append( QPolygonF() << p1 << p2 );
2842 polygons.append( QPolygonF() << p3 << p4 );
2845 polygons.append( QPolygonF() << p5 << p6 );
2848 for (
const QPolygonF &polygon : qgis::as_const( polygons ) )
2850 fillLineSymbol->renderPolyline( polygon, context.
feature(), lineRenderContext, -1, context.
selected() );
2853 fillLineSymbol->stopRender( lineRenderContext );
2857 patternImage = patternImage.copy( xBuffer, yBuffer, patternImage.width() - 2 * xBuffer, patternImage.height() - 2 * yBuffer );
2862 QImage transparentImage = patternImage.copy();
2864 brush.setTextureImage( transparentImage );
2868 brush.setTextureImage( patternImage );
2871 QTransform brushTransform;
2872 brush.setTransform( brushTransform );
2877 applyPattern( context,
mBrush, mLineAngle, mDistance );
2879 if ( mFillLineSymbol )
2887 if ( mFillLineSymbol )
2896 map.insert( QStringLiteral(
"angle" ), QString::number( mLineAngle ) );
2897 map.insert( QStringLiteral(
"distance" ), QString::number( mDistance ) );
2898 map.insert( QStringLiteral(
"line_width" ), QString::number( mLineWidth ) );
2900 map.insert( QStringLiteral(
"offset" ), QString::number( mOffset ) );
2915 if ( mFillLineSymbol )
2926 QDomElement symbolizerElem = doc.createElement( QStringLiteral(
"se:PolygonSymbolizer" ) );
2927 if ( !props.value( QStringLiteral(
"uom" ), QString() ).isEmpty() )
2928 symbolizerElem.setAttribute( QStringLiteral(
"uom" ), props.value( QStringLiteral(
"uom" ), QString() ) );
2929 element.appendChild( symbolizerElem );
2934 QDomElement fillElem = doc.createElement( QStringLiteral(
"se:Fill" ) );
2935 symbolizerElem.appendChild( fillElem );
2937 QDomElement graphicFillElem = doc.createElement( QStringLiteral(
"se:GraphicFill" ) );
2938 fillElem.appendChild( graphicFillElem );
2940 QDomElement graphicElem = doc.createElement( QStringLiteral(
"se:Graphic" ) );
2941 graphicFillElem.appendChild( graphicElem );
2944 QColor lineColor = mFillLineSymbol ? mFillLineSymbol->
color() : QColor();
2945 double lineWidth = mFillLineSymbol ? mFillLineSymbol->
width() : 0.0;
2953 double angle = props.value( QStringLiteral(
"angle" ), QStringLiteral(
"0" ) ).toDouble( &ok );
2956 angleFunc = QStringLiteral(
"%1 + %2" ).arg( props.value( QStringLiteral(
"angle" ), QStringLiteral(
"0" ) ) ).arg( mLineAngle );
2960 angleFunc = QString::number(
angle + mLineAngle );
2965 QPointF lineOffset( std::sin( mLineAngle ) * mOffset, std::cos( mLineAngle ) * mOffset );
2972 QString featureStyle;
2973 featureStyle.append(
"Brush(" );
2974 featureStyle.append( QStringLiteral(
"fc:%1" ).arg(
mColor.name() ) );
2975 featureStyle.append( QStringLiteral(
",bc:%1" ).arg( QLatin1String(
"#00000000" ) ) );
2976 featureStyle.append(
",id:\"ogr-brush-2\"" );
2977 featureStyle.append( QStringLiteral(
",a:%1" ).arg( mLineAngle ) );
2978 featureStyle.append( QStringLiteral(
",s:%1" ).arg( mLineWidth * widthScaleFactor ) );
2979 featureStyle.append(
",dx:0mm" );
2980 featureStyle.append( QStringLiteral(
",dy:%1mm" ).arg( mDistance * widthScaleFactor ) );
2981 featureStyle.append(
')' );
2982 return featureStyle;
3013 Qt::PenStyle lineStyle;
3015 QDomElement fillElem = element.firstChildElement( QStringLiteral(
"Fill" ) );
3016 if ( fillElem.isNull() )
3019 QDomElement graphicFillElem = fillElem.firstChildElement( QStringLiteral(
"GraphicFill" ) );
3020 if ( graphicFillElem.isNull() )
3023 QDomElement graphicElem = graphicFillElem.firstChildElement( QStringLiteral(
"Graphic" ) );
3024 if ( graphicElem.isNull() )
3030 if ( name != QLatin1String(
"horline" ) )
3038 double d = angleFunc.toDouble( &ok );
3047 offset = std::sqrt( std::pow( vectOffset.x(), 2 ) + std::pow( vectOffset.y(), 2 ) );
3050 QString uom = element.attribute( QStringLiteral(
"uom" ) );
3054 std::unique_ptr< QgsLinePatternFillSymbolLayer > sl = qgis::make_unique< QgsLinePatternFillSymbolLayer >();
3055 sl->setOutputUnit( QgsUnitTypes::RenderUnit::RenderPixels );
3056 sl->setColor( lineColor );
3058 sl->setLineAngle(
angle );
3060 sl->setDistance( size );
3063 QDomElement strokeElem = element.firstChildElement( QStringLiteral(
"Stroke" ) );
3064 if ( !strokeElem.isNull() )
3075 return sl.release();
3152 std::unique_ptr< QgsPointPatternFillSymbolLayer > layer = qgis::make_unique< QgsPointPatternFillSymbolLayer >();
3153 if (
properties.contains( QStringLiteral(
"distance_x" ) ) )
3155 layer->setDistanceX(
properties[QStringLiteral(
"distance_x" )].toDouble() );
3157 if (
properties.contains( QStringLiteral(
"distance_y" ) ) )
3159 layer->setDistanceY(
properties[QStringLiteral(
"distance_y" )].toDouble() );
3161 if (
properties.contains( QStringLiteral(
"displacement_x" ) ) )
3163 layer->setDisplacementX(
properties[QStringLiteral(
"displacement_x" )].toDouble() );
3165 if (
properties.contains( QStringLiteral(
"displacement_y" ) ) )
3167 layer->setDisplacementY(
properties[QStringLiteral(
"displacement_y" )].toDouble() );
3169 if (
properties.contains( QStringLiteral(
"offset_x" ) ) )
3171 layer->setOffsetX(
properties[QStringLiteral(
"offset_x" )].toDouble() );
3173 if (
properties.contains( QStringLiteral(
"offset_y" ) ) )
3175 layer->setOffsetY(
properties[QStringLiteral(
"offset_y" )].toDouble() );
3178 if (
properties.contains( QStringLiteral(
"distance_x_unit" ) ) )
3182 if (
properties.contains( QStringLiteral(
"distance_x_map_unit_scale" ) ) )
3186 if (
properties.contains( QStringLiteral(
"distance_y_unit" ) ) )
3190 if (
properties.contains( QStringLiteral(
"distance_y_map_unit_scale" ) ) )
3194 if (
properties.contains( QStringLiteral(
"displacement_x_unit" ) ) )
3198 if (
properties.contains( QStringLiteral(
"displacement_x_map_unit_scale" ) ) )
3202 if (
properties.contains( QStringLiteral(
"displacement_y_unit" ) ) )
3206 if (
properties.contains( QStringLiteral(
"displacement_y_map_unit_scale" ) ) )
3210 if (
properties.contains( QStringLiteral(
"offset_x_unit" ) ) )
3214 if (
properties.contains( QStringLiteral(
"offset_x_map_unit_scale" ) ) )
3218 if (
properties.contains( QStringLiteral(
"offset_y_unit" ) ) )
3222 if (
properties.contains( QStringLiteral(
"offset_y_map_unit_scale" ) ) )
3227 if (
properties.contains( QStringLiteral(
"outline_width_unit" ) ) )
3231 if (
properties.contains( QStringLiteral(
"outline_width_map_unit_scale" ) ) )
3236 layer->restoreOldDataDefinedProperties(
properties );
3238 return layer.release();
3243 return QStringLiteral(
"PointPatternFill" );
3246 void QgsPointPatternFillSymbolLayer::applyPattern(
const QgsSymbolRenderContext &context, QBrush &brush,
double distanceX,
double distanceY,
3247 double displacementX,
double displacementY,
double offsetX,
double offsetY )
3257 if ( width > 10000 || height > 10000 )
3260 brush.setTextureImage( img );
3264 QImage patternImage( width, height, QImage::Format_ARGB32 );
3265 patternImage.fill( 0 );
3266 if ( patternImage.isNull() )
3268 brush.setTextureImage( QImage() );
3273 QPainter p( &patternImage );
3294 for (
double currentX = -width; currentX <= width * 2.0; currentX += width )
3296 for (
double currentY = -height; currentY <= height * 2.0; currentY += height )
3305 for (
double currentX = -width; currentX <= width * 2.0; currentX += width )
3307 for (
double currentY = -height / 2.0; currentY <= height * 2.0; currentY += height )
3313 for (
double currentX = -width / 2.0; currentX <= width * 2.0; currentX += width )
3315 for (
double currentY = -height; currentY <= height * 2.0; currentY += height / 2.0 )
3317 mMarkerSymbol->
renderPoint( QPointF( currentX + widthOffset + ( std::fmod( currentY, height ) != 0 ? displacementPixelX : 0 ), currentY + heightOffset - displacementPixelY ), context.
feature(), pointRenderContext );
3326 QImage transparentImage = patternImage.copy();
3328 brush.setTextureImage( transparentImage );
3332 brush.setTextureImage( patternImage );
3334 QTransform brushTransform;
3335 brush.setTransform( brushTransform );
3344 if ( mRenderUsingMarkers )
3362 if ( mRenderUsingMarkers )
3375 if ( !mRenderUsingMarkers )
3437 p->setPen( QPen( Qt::NoPen ) );
3442 p->setBrush( QBrush( selColor ) );
3449 path.addPolygon( points );
3452 for (
const QPolygonF &ring : *rings )
3454 path.addPolygon( ring );
3457 p->setClipPath( path, Qt::IntersectClip );
3459 const double left = points.boundingRect().left();
3460 const double top = points.boundingRect().top();
3461 const double right = points.boundingRect().right();
3462 const double bottom = points.boundingRect().bottom();
3469 bool alternateColumn =
false;
3470 int currentCol = -3;
3471 for (
double currentX = ( std::floor( left / width ) - 2 ) * width; currentX <= right + 2 * width; currentX += width, alternateColumn = !alternateColumn )
3473 if ( needsExpressionContext )
3476 bool alternateRow =
false;
3477 const double columnX = currentX + widthOffset;
3478 int currentRow = -3;
3479 for (
double currentY = ( std::floor( top / height ) - 2 ) * height; currentY <= bottom + 2 * height; currentY += height, alternateRow = !alternateRow )
3481 double y = currentY + heightOffset;
3484 x += displacementPixelX;
3486 if ( !alternateColumn )
3487 y -= displacementPixelY;
3489 if ( needsExpressionContext )
3506 for (
auto ringIt = rings->constBegin(); ringIt != rings->constEnd(); ++ringIt )
3517 map.insert( QStringLiteral(
"distance_x" ), QString::number(
mDistanceX ) );
3518 map.insert( QStringLiteral(
"distance_y" ), QString::number(
mDistanceY ) );
3519 map.insert( QStringLiteral(
"displacement_x" ), QString::number(
mDisplacementX ) );
3520 map.insert( QStringLiteral(
"displacement_y" ), QString::number(
mDisplacementY ) );
3521 map.insert( QStringLiteral(
"offset_x" ), QString::number(
mOffsetX ) );
3522 map.insert( QStringLiteral(
"offset_y" ), QString::number(
mOffsetY ) );
3556 QDomElement symbolizerElem = doc.createElement( QStringLiteral(
"se:PolygonSymbolizer" ) );
3557 if ( !props.value( QStringLiteral(
"uom" ), QString() ).isEmpty() )
3558 symbolizerElem.setAttribute( QStringLiteral(
"uom" ), props.value( QStringLiteral(
"uom" ), QString() ) );
3559 element.appendChild( symbolizerElem );
3564 QDomElement fillElem = doc.createElement( QStringLiteral(
"se:Fill" ) );
3565 symbolizerElem.appendChild( fillElem );
3567 QDomElement graphicFillElem = doc.createElement( QStringLiteral(
"se:GraphicFill" ) );
3568 fillElem.appendChild( graphicFillElem );
3575 symbolizerElem.appendChild( distanceElem );
3581 QString errorMsg = QStringLiteral(
"MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( layer->
layerType() );
3582 graphicFillElem.appendChild( doc.createComment( errorMsg ) );
3708 std::unique_ptr< QgsCentroidFillSymbolLayer > sl = qgis::make_unique< QgsCentroidFillSymbolLayer >();
3710 if (
properties.contains( QStringLiteral(
"point_on_surface" ) ) )
3711 sl->setPointOnSurface(
properties[QStringLiteral(
"point_on_surface" )].toInt() != 0 );
3712 if (
properties.contains( QStringLiteral(
"point_on_all_parts" ) ) )
3713 sl->setPointOnAllParts(
properties[QStringLiteral(
"point_on_all_parts" )].toInt() != 0 );
3714 if (
properties.contains( QStringLiteral(
"clip_points" ) ) )
3715 sl->setClipPoints(
properties[QStringLiteral(
"clip_points" )].toInt() != 0 );
3716 if (
properties.contains( QStringLiteral(
"clip_on_current_part_only" ) ) )
3717 sl->setClipOnCurrentPartOnly(
properties[QStringLiteral(
"clip_on_current_part_only" )].toInt() != 0 );
3719 sl->restoreOldDataDefinedProperties(
properties );
3721 return sl.release();
3726 return QStringLiteral(
"CentroidFill" );
3757 part.exterior = points;
3759 part.rings = *rings;
3765 mCurrentParts << part;
3777 mCurrentParts.clear();
3783 render( context, mCurrentParts, feature,
false );
3786 void QgsCentroidFillSymbolLayer::render(
QgsRenderContext &context,
const QVector<QgsCentroidFillSymbolLayer::Part> &parts,
const QgsFeature &feature,
bool selected )
3795 QVector< QgsGeometry > geometryParts;
3796 geometryParts.reserve( parts.size() );
3797 QPainterPath globalPath;
3800 int maxAreaPartIdx = 0;
3802 for (
int i = 0; i < parts.size(); i++ )
3804 const Part part = parts[i];
3807 if ( !geom.
isNull() && !part.rings.empty() )
3809 QgsPolygon *poly = qgsgeometry_cast< QgsPolygon * >( geom.
get() );
3813 int area = poly->
area();
3815 if ( area > maxArea )
3825 globalPath.addPolygon( part.exterior );
3826 for (
const QPolygonF &ring : part.rings )
3828 globalPath.addPolygon( ring );
3833 for (
int i = 0; i < parts.size(); i++ )
3838 const Part part = parts[i];
3846 path.addPolygon( part.exterior );
3847 for (
const QPolygonF &ring : part.rings )
3849 path.addPolygon( ring );
3858 context.
painter()->setClipPath( path );
3862 mMarker->renderPoint( centroid, feature.
isValid() ? &feature :
nullptr, context, -1, selected );
3874 map[QStringLiteral(
"point_on_surface" )] = QString::number(
mPointOnSurface );
3875 map[QStringLiteral(
"point_on_all_parts" )] = QString::number(
mPointOnAllParts );
3876 map[QStringLiteral(
"clip_points" )] = QString::number(
mClipPoints );
3883 std::unique_ptr< QgsCentroidFillSymbolLayer > x = qgis::make_unique< QgsCentroidFillSymbolLayer >();
3886 x->setSubSymbol(
mMarker->clone() );
3901 mMarker->toSld( doc, element, props );
3912 std::unique_ptr< QgsMarkerSymbol > marker(
new QgsMarkerSymbol( layers ) );
3914 std::unique_ptr< QgsCentroidFillSymbolLayer > sl = qgis::make_unique< QgsCentroidFillSymbolLayer >();
3915 sl->setSubSymbol( marker.release() );
3916 sl->setPointOnAllParts(
false );
3917 return sl.release();
3944 attributes.unite(
mMarker->usedAttributes( context ) );
3962 mMarker->setOutputUnit( unit );
3979 mMarker->setMapUnitScale( scale );
3987 return mMarker->mapUnitScale();
3997 , mImageFilePath( imageFilePath )
4011 if (
properties.contains( QStringLiteral(
"imageFile" ) ) )
4013 imagePath =
properties[QStringLiteral(
"imageFile" )];
4015 if (
properties.contains( QStringLiteral(
"coordinate_mode" ) ) )
4019 if (
properties.contains( QStringLiteral(
"alpha" ) ) )
4021 alpha =
properties[QStringLiteral(
"alpha" )].toDouble();
4023 if (
properties.contains( QStringLiteral(
"offset" ) ) )
4027 if (
properties.contains( QStringLiteral(
"angle" ) ) )
4031 if (
properties.contains( QStringLiteral(
"width" ) ) )
4035 std::unique_ptr< QgsRasterFillSymbolLayer > symbolLayer = qgis::make_unique< QgsRasterFillSymbolLayer >( imagePath );
4036 symbolLayer->setCoordinateMode( mode );
4037 symbolLayer->setOpacity( alpha );
4038 symbolLayer->setOffset(
offset );
4039 symbolLayer->setAngle(
angle );
4040 symbolLayer->setWidth(
width );
4041 if (
properties.contains( QStringLiteral(
"offset_unit" ) ) )
4045 if (
properties.contains( QStringLiteral(
"offset_map_unit_scale" ) ) )
4049 if (
properties.contains( QStringLiteral(
"width_unit" ) ) )
4053 if (
properties.contains( QStringLiteral(
"width_map_unit_scale" ) ) )
4058 symbolLayer->restoreOldDataDefinedProperties(
properties );
4060 return symbolLayer.release();
4065 QgsStringMap::iterator it =
properties.find( QStringLiteral(
"imageFile" ) );
4069 it.value() = pathResolver.
writePath( it.value() );
4071 it.value() = pathResolver.
readPath( it.value() );
4083 return QStringLiteral(
"RasterFill" );
4094 QPointF
offset = mOffset;
4110 if ( mCoordinateMode ==
Feature )
4112 QRectF boundingRect = points.boundingRect();
4113 mBrush.setTransform(
mBrush.transform().translate( boundingRect.left() -
mBrush.transform().dx(),
4114 boundingRect.top() -
mBrush.transform().dy() ) );
4126 applyPattern(
mBrush, mImageFilePath, mWidth, mOpacity, context );
4137 map[QStringLiteral(
"imageFile" )] = mImageFilePath;
4138 map[QStringLiteral(
"coordinate_mode" )] = QString::number( mCoordinateMode );
4139 map[QStringLiteral(
"alpha" )] = QString::number( mOpacity );
4143 map[QStringLiteral(
"angle" )] = QString::number(
mAngle );
4144 map[QStringLiteral(
"width" )] = QString::number( mWidth );
4152 std::unique_ptr< QgsRasterFillSymbolLayer > sl = qgis::make_unique< QgsRasterFillSymbolLayer >( mImageFilePath );
4153 sl->setCoordinateMode( mCoordinateMode );
4154 sl->setOpacity( mOpacity );
4155 sl->setOffset( mOffset );
4156 sl->setOffsetUnit( mOffsetUnit );
4157 sl->setOffsetMapUnitScale( mOffsetMapUnitScale );
4159 sl->setWidth( mWidth );
4160 sl->setWidthUnit( mWidthUnit );
4161 sl->setWidthMapUnitScale( mWidthMapUnitScale );
4164 return sl.release();
4169 return context.
convertToPainterUnits( std::max( std::fabs( mOffset.x() ), std::fabs( mOffset.y() ) ), mOffsetUnit, mOffsetMapUnitScale );
4174 mImageFilePath = imagePath;
4179 mCoordinateMode = mode;
4197 if ( !hasWidthExpression && !hasAngleExpression && !hasOpacityExpression && !hasFileExpression )
4203 if ( hasAngleExpression )
4211 if ( !hasWidthExpression && !hasOpacityExpression && !hasFileExpression )
4216 double width = mWidth;
4217 if ( hasWidthExpression )
4223 if ( hasOpacityExpression )
4228 QString file = mImageFilePath;
4229 if ( hasFileExpression )
4242 void QgsRasterFillSymbolLayer::applyPattern( QBrush &brush,
const QString &imageFilePath,
const double width,
const double alpha,
const QgsSymbolRenderContext &context )
4255 if ( size.isEmpty() )
4258 size.setWidth( (
width * size.width() ) / 100.0 );
4261 if (
static_cast< int >( size.width() ) < 1 || 10000.0 < size.width() )
4265 size.setHeight( 0 );
4273 brush.setTextureImage( img );
4282 : mCountMethod( method )
4283 , mPointCount( pointCount )
4284 , mDensityArea( densityArea )
4293 const int pointCount =
properties.value( QStringLiteral(
"point_count" ), QStringLiteral(
"10" ) ).toInt();
4294 const double densityArea =
properties.value( QStringLiteral(
"density_area" ), QStringLiteral(
"250.0" ) ).toDouble();
4296 unsigned long seed = 0;
4297 if (
properties.contains( QStringLiteral(
"seed" ) ) )
4303 std::random_device rd;
4304 std::mt19937 mt(
seed == 0 ? rd() :
seed );
4305 std::uniform_int_distribution<> uniformDist( 1, 999999999 );
4306 seed = uniformDist( mt );
4311 if (
properties.contains( QStringLiteral(
"density_area_unit" ) ) )
4313 if (
properties.contains( QStringLiteral(
"density_area_unit_scale" ) ) )
4316 if (
properties.contains( QStringLiteral(
"clip_points" ) ) )
4318 sl->setClipPoints(
properties[QStringLiteral(
"clip_points" )].toInt() );
4321 return sl.release();
4326 return QStringLiteral(
"RandomMarkerFill" );
4331 mMarker->setColor(
color );
4337 return mMarker ? mMarker->color() :
mColor;
4342 mMarker->setOpacity( context.
opacity() );
4354 part.exterior = points;
4356 part.rings = *rings;
4358 if ( mRenderingFeature )
4362 mCurrentParts << part;
4371 void QgsRandomMarkerFillSymbolLayer::render(
QgsRenderContext &context,
const QVector<QgsRandomMarkerFillSymbolLayer::Part> &parts,
const QgsFeature &feature,
bool selected )
4380 QVector< QgsGeometry > geometryParts;
4381 geometryParts.reserve( parts.size() );
4384 for (
const Part &part : parts )
4387 if ( !geom.
isNull() && !part.rings.empty() )
4389 QgsPolygon *poly = qgsgeometry_cast< QgsPolygon * >( geom.
get() );
4390 for (
const QPolygonF &ring : part.rings )
4397 geom = geom.
buffer( 0, 0 );
4399 geometryParts << geom;
4403 path.addPolygon( part.exterior );
4404 for (
const QPolygonF &ring : part.rings )
4406 path.addPolygon( ring );
4416 context.
painter()->setClipPath( path );
4420 int count = mPointCount;
4427 switch ( mCountMethod )
4439 count = std::max( 0.0, std::ceil( count * ( geom.
area() /
densityArea ) ) );
4446 unsigned long seed = mSeed;
4457 std::sort( randomPoints.begin(), randomPoints.end(), [](
const QgsPointXY & a,
const QgsPointXY & b )->bool
4459 return a.y() < b.y();
4467 for (
const QgsPointXY &p : qgis::as_const( randomPoints ) )
4469 if ( needsExpressionContext )
4471 mMarker->renderPoint( QPointF( p.x(), p.y() ), feature.
isValid() ? &feature :
nullptr, context, -1, selected );
4483 map.insert( QStringLiteral(
"count_method" ), QString::number(
static_cast< int >( mCountMethod ) ) );
4484 map.insert( QStringLiteral(
"point_count" ), QString::number( mPointCount ) );
4485 map.insert( QStringLiteral(
"density_area" ), QString::number( mDensityArea ) );
4488 map.insert( QStringLiteral(
"seed" ), QString::number( mSeed ) );
4489 map.insert( QStringLiteral(
"clip_points" ), QString::number( mClipPoints ) );
4495 std::unique_ptr< QgsRandomMarkerFillSymbolLayer > res = qgis::make_unique< QgsRandomMarkerFillSymbolLayer >( mPointCount, mCountMethod, mDensityArea, mSeed );
4498 res->setDensityAreaUnit( mDensityAreaUnit );
4499 res->setDensityAreaUnitScale( mDensityAreaUnitScale );
4500 res->mClipPoints = mClipPoints;
4501 res->setSubSymbol( mMarker->clone() );
4504 return res.release();
4509 return mMarker.get();
4521 mColor = mMarker->color();
4530 attributes.unite( mMarker->usedAttributes( context ) );
4539 if ( mMarker && mMarker->hasDataDefinedProperties() )
4576 return mCountMethod;
4581 mCountMethod = method;
4586 return mDensityArea;
4591 mDensityArea = area;
4596 mRenderingFeature =
true;
4597 mCurrentParts.clear();
4602 mRenderingFeature =
false;
4603 render( context, mCurrentParts, feature,
false );
4611 mMarker->setOutputUnit( unit );
4619 return mMarker->outputUnit();
4628 mMarker->setMapUnitScale( scale );
4636 return mMarker->mapUnitScale();