31 #include <QSvgRenderer>
34 #include <QDomDocument>
35 #include <QDomElement>
42 static void _fixQPictureDPI( QPainter *p )
48 p->scale(
static_cast< double >(
qt_defaultDpiX() ) / p->device()->logicalDpiX(),
49 static_cast< double >(
qt_defaultDpiY() ) / p->device()->logicalDpiY() );
62 QList< Shape > shapes;
146 QTransform transform;
149 if ( !hasDataDefinedSize )
159 double half = scaledSize / 2.0;
160 transform.scale( half, half );
166 transform.rotate(
mAngle );
193 bool hasDataDefinedSize =
false;
194 double scaledSize =
calculateSize( context, hasDataDefinedSize );
196 bool hasDataDefinedRotation =
false;
202 bool createdNewPath =
false;
209 if ( exprVal.isValid() )
220 createdNewPath =
true;
229 QTransform transform;
232 transform.translate( point.x() +
offset.x(), point.y() +
offset.y() );
235 if ( hasDataDefinedSize || createdNewPath )
244 double half = s / 2.0;
245 transform.scale( half, half );
249 transform.rotate(
angle );
257 polygon = transform.map(
mPolygon );
261 path = transform.map(
mPath );
263 draw( context, symbol, polygon, path );
268 bool hasDataDefinedSize =
false;
269 double scaledSize =
calculateSize( context, hasDataDefinedSize );
271 bool hasDataDefinedRotation =
false;
278 QTransform transform;
281 transform.translate( point.x() +
offset.x(), point.y() +
offset.y() );
284 transform.rotate(
angle );
286 return transform.mapRect( QRectF( -scaledSize / 2.0,
296 QString cleaned = name.toLower().trimmed();
298 if ( cleaned == QLatin1String(
"square" ) || cleaned == QLatin1String(
"rectangle" ) )
300 else if ( cleaned == QLatin1String(
"diamond" ) )
302 else if ( cleaned == QLatin1String(
"pentagon" ) )
304 else if ( cleaned == QLatin1String(
"hexagon" ) )
306 else if ( cleaned == QLatin1String(
"triangle" ) )
308 else if ( cleaned == QLatin1String(
"equilateral_triangle" ) )
310 else if ( cleaned == QLatin1String(
"star" ) || cleaned == QLatin1String(
"regular_star" ) )
312 else if ( cleaned == QLatin1String(
"arrow" ) )
314 else if ( cleaned == QLatin1String(
"circle" ) )
316 else if ( cleaned == QLatin1String(
"cross" ) )
318 else if ( cleaned == QLatin1String(
"cross_fill" ) )
320 else if ( cleaned == QLatin1String(
"cross2" ) || cleaned == QLatin1String(
"x" ) )
322 else if ( cleaned == QLatin1String(
"line" ) )
324 else if ( cleaned == QLatin1String(
"arrowhead" ) )
326 else if ( cleaned == QLatin1String(
"filled_arrowhead" ) )
328 else if ( cleaned == QLatin1String(
"semi_circle" ) )
330 else if ( cleaned == QLatin1String(
"third_circle" ) )
332 else if ( cleaned == QLatin1String(
"quarter_circle" ) )
334 else if ( cleaned == QLatin1String(
"quarter_square" ) )
336 else if ( cleaned == QLatin1String(
"half_square" ) )
338 else if ( cleaned == QLatin1String(
"diagonal_half_square" ) )
340 else if ( cleaned == QLatin1String(
"right_half_triangle" ) )
342 else if ( cleaned == QLatin1String(
"left_half_triangle" ) )
355 return QStringLiteral(
"square" );
357 return QStringLiteral(
"quarter_square" );
359 return QStringLiteral(
"half_square" );
361 return QStringLiteral(
"diagonal_half_square" );
363 return QStringLiteral(
"diamond" );
365 return QStringLiteral(
"pentagon" );
367 return QStringLiteral(
"hexagon" );
369 return QStringLiteral(
"triangle" );
371 return QStringLiteral(
"equilateral_triangle" );
373 return QStringLiteral(
"left_half_triangle" );
375 return QStringLiteral(
"right_half_triangle" );
377 return QStringLiteral(
"star" );
379 return QStringLiteral(
"arrow" );
381 return QStringLiteral(
"filled_arrowhead" );
383 return QStringLiteral(
"cross_fill" );
385 return QStringLiteral(
"circle" );
387 return QStringLiteral(
"cross" );
389 return QStringLiteral(
"cross2" );
391 return QStringLiteral(
"line" );
393 return QStringLiteral(
"arrowhead" );
395 return QStringLiteral(
"semi_circle" );
397 return QStringLiteral(
"third_circle" );
399 return QStringLiteral(
"quarter_circle" );
416 polygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 1, 1 ) ) );
420 polygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 0, 0 ) ) );
424 polygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 0, 1 ) ) );
428 polygon << QPointF( -1, -1 ) << QPointF( 1, 1 ) << QPointF( -1, 1 ) << QPointF( -1, -1 );
432 polygon << QPointF( -1, 0 ) << QPointF( 0, 1 )
433 << QPointF( 1, 0 ) << QPointF( 0, -1 ) << QPointF( -1, 0 );
443 polygon << QPointF( -0.9511, -0.3090 )
444 << QPointF( -0.5878, 0.8090 )
445 << QPointF( 0.5878, 0.8090 )
446 << QPointF( 0.9511, -0.3090 )
448 << QPointF( -0.9511, -0.3090 );
459 polygon << QPointF( -0.8660, -0.5 )
460 << QPointF( -0.8660, 0.5 )
462 << QPointF( 0.8660, 0.5 )
463 << QPointF( 0.8660, -0.5 )
465 << QPointF( -0.8660, -0.5 );
469 polygon << QPointF( -1, 1 ) << QPointF( 1, 1 ) << QPointF( 0, -1 ) << QPointF( -1, 1 );
477 polygon << QPointF( -0.8660, 0.5 )
478 << QPointF( 0.8660, 0.5 )
480 << QPointF( -0.8660, 0.5 );
484 polygon << QPointF( 0, 1 ) << QPointF( 1, 1 ) << QPointF( 0, -1 ) << QPointF( 0, 1 );
488 polygon << QPointF( -1, 1 ) << QPointF( 0, 1 ) << QPointF( 0, -1 ) << QPointF( -1, 1 );
493 double inner_r = std::cos(
DEG2RAD( 72.0 ) ) / std::cos(
DEG2RAD( 36.0 ) );
495 polygon << QPointF( inner_r * std::sin(
DEG2RAD( 324.0 ) ), - inner_r * std::cos(
DEG2RAD( 324.0 ) ) )
496 << QPointF( std::sin(
DEG2RAD( 288.0 ) ), - std::cos(
DEG2RAD( 288 ) ) )
497 << QPointF( inner_r * std::sin(
DEG2RAD( 252.0 ) ), - inner_r * std::cos(
DEG2RAD( 252.0 ) ) )
498 << QPointF( std::sin(
DEG2RAD( 216.0 ) ), - std::cos(
DEG2RAD( 216.0 ) ) )
499 << QPointF( 0, inner_r )
500 << QPointF( std::sin(
DEG2RAD( 144.0 ) ), - std::cos(
DEG2RAD( 144.0 ) ) )
501 << QPointF( inner_r * std::sin(
DEG2RAD( 108.0 ) ), - inner_r * std::cos(
DEG2RAD( 108.0 ) ) )
502 << QPointF( std::sin(
DEG2RAD( 72.0 ) ), - std::cos(
DEG2RAD( 72.0 ) ) )
503 << QPointF( inner_r * std::sin(
DEG2RAD( 36.0 ) ), - inner_r * std::cos(
DEG2RAD( 36.0 ) ) )
505 << QPointF( inner_r * std::sin(
DEG2RAD( 324.0 ) ), - inner_r * std::cos(
DEG2RAD( 324.0 ) ) );
510 polygon << QPointF( 0, -1 )
511 << QPointF( 0.5, -0.5 )
512 << QPointF( 0.25, -0.5 )
513 << QPointF( 0.25, 1 )
514 << QPointF( -0.25, 1 )
515 << QPointF( -0.25, -0.5 )
516 << QPointF( -0.5, -0.5 )
521 polygon << QPointF( 0, 0 ) << QPointF( -1, 1 ) << QPointF( -1, -1 ) << QPointF( 0, 0 );
525 polygon << QPointF( -1, -0.2 )
526 << QPointF( -1, -0.2 )
527 << QPointF( -1, 0.2 )
528 << QPointF( -0.2, 0.2 )
529 << QPointF( -0.2, 1 )
531 << QPointF( 0.2, 0.2 )
533 << QPointF( 1, -0.2 )
534 << QPointF( 0.2, -0.2 )
535 << QPointF( 0.2, -1 )
536 << QPointF( -0.2, -1 )
537 << QPointF( -0.2, -0.2 )
538 << QPointF( -1, -0.2 );
557 mPath = QPainterPath();
563 mPath.addEllipse( QRectF( -1, -1, 2, 2 ) );
567 mPath.arcTo( -1, -1, 2, 2, 0, 180 );
568 mPath.lineTo( 0, 0 );
572 mPath.arcTo( -1, -1, 2, 2, 90, 120 );
573 mPath.lineTo( 0, 0 );
577 mPath.arcTo( -1, -1, 2, 2, 90, 90 );
578 mPath.lineTo( 0, 0 );
582 mPath.moveTo( -1, 0 );
583 mPath.lineTo( 1, 0 );
584 mPath.moveTo( 0, -1 );
585 mPath.lineTo( 0, 1 );
589 mPath.moveTo( -1, -1 );
590 mPath.lineTo( 1, 1 );
591 mPath.moveTo( 1, -1 );
592 mPath.lineTo( -1, 1 );
596 mPath.moveTo( 0, -1 );
597 mPath.lineTo( 0, 1 );
601 mPath.moveTo( -1, -1 );
602 mPath.lineTo( 0, 0 );
603 mPath.lineTo( -1, 1 );
628 double scaledSize =
mSize;
632 if ( hasDataDefinedSize )
639 if ( hasDataDefinedSize && ok )
644 scaledSize = std::sqrt( scaledSize );
659 markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
660 offset = QPointF( offsetX, offsetY );
662 hasDataDefinedRotation =
false;
675 hasDataDefinedRotation =
true;
680 if ( hasDataDefinedRotation )
709 , mStrokeColor( strokeColor )
710 , mPenJoinStyle( penJoinStyle )
725 if ( props.contains( QStringLiteral(
"name" ) ) )
729 if ( props.contains( QStringLiteral(
"color" ) ) )
731 if ( props.contains( QStringLiteral(
"color_border" ) ) )
736 else if ( props.contains( QStringLiteral(
"outline_color" ) ) )
740 else if ( props.contains( QStringLiteral(
"line_color" ) ) )
744 if ( props.contains( QStringLiteral(
"joinstyle" ) ) )
748 if ( props.contains( QStringLiteral(
"size" ) ) )
749 size = props[QStringLiteral(
"size" )].toDouble();
750 if ( props.contains( QStringLiteral(
"angle" ) ) )
751 angle = props[QStringLiteral(
"angle" )].toDouble();
752 if ( props.contains( QStringLiteral(
"scale_method" ) ) )
756 if ( props.contains( QStringLiteral(
"offset" ) ) )
758 if ( props.contains( QStringLiteral(
"offset_unit" ) ) )
760 if ( props.contains( QStringLiteral(
"offset_map_unit_scale" ) ) )
762 if ( props.contains( QStringLiteral(
"size_unit" ) ) )
764 if ( props.contains( QStringLiteral(
"size_map_unit_scale" ) ) )
767 if ( props.contains( QStringLiteral(
"outline_style" ) ) )
771 else if ( props.contains( QStringLiteral(
"line_style" ) ) )
775 if ( props.contains( QStringLiteral(
"outline_width" ) ) )
777 m->
setStrokeWidth( props[QStringLiteral(
"outline_width" )].toDouble() );
779 else if ( props.contains( QStringLiteral(
"line_width" ) ) )
781 m->
setStrokeWidth( props[QStringLiteral(
"line_width" )].toDouble() );
783 if ( props.contains( QStringLiteral(
"outline_width_unit" ) ) )
787 if ( props.contains( QStringLiteral(
"line_width_unit" ) ) )
791 if ( props.contains( QStringLiteral(
"outline_width_map_unit_scale" ) ) )
796 if ( props.contains( QStringLiteral(
"horizontal_anchor_point" ) ) )
800 if ( props.contains( QStringLiteral(
"vertical_anchor_point" ) ) )
813 return QStringLiteral(
"SimpleMarker" );
820 QColor brushColor =
mColor;
826 mBrush = QBrush( brushColor );
827 mPen = QPen( penColor );
836 selBrushColor.setAlphaF( context.
opacity() );
837 selPenColor.setAlphaF( context.
opacity() );
859 mSelPen.setColor( selBrushColor );
891 scaledSize = ( std::abs( std::sin(
mAngle * M_PI / 180 ) ) + std::abs( std::cos(
mAngle * M_PI / 180 ) ) ) * scaledSize;
894 double pw =
static_cast< int >( std::round( ( (
qgsDoubleNear(
mPen.widthF(), 0.0 ) ? 1 :
mPen.widthF() * 4 ) + 1 ) ) ) / 2 * 2;
895 int imageSize = (
static_cast< int >( scaledSize ) + pw ) / 2 * 2 + 1;
896 double center = imageSize / 2.0;
902 mCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
909 p.setRenderHint( QPainter::Antialiasing );
910 p.setBrush( needsBrush ?
mBrush : Qt::NoBrush );
912 p.translate( QPointF( center, center ) );
920 mSelCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
924 p.setRenderHint( QPainter::Antialiasing );
925 p.setBrush( needsBrush ?
mSelBrush : Qt::NoBrush );
927 p.translate( QPointF( center, center ) );
938 p.setRenderHint( QPainter::Antialiasing );
939 p.fillRect( 0, 0, imageSize, imageSize, selColor );
940 p.setBrush( needsBrush ?
mBrush : Qt::NoBrush );
942 p.translate( QPointF( center, center ) );
1016 p->setBrush( Qt::NoBrush );
1020 if ( !polygon.isEmpty() )
1021 p->drawPolygon( polygon );
1023 p->drawPath( path );
1040 double s = img.width();
1042 bool hasDataDefinedSize =
false;
1043 double scaledSize =
calculateSize( context, hasDataDefinedSize );
1045 bool hasDataDefinedRotation =
false;
1050 p->drawImage( QRectF( point.x() - s / 2.0 +
offset.x(),
1051 point.y() - s / 2.0 +
offset.y(),
1066 map[QStringLiteral(
"size" )] = QString::number(
mSize );
1069 map[QStringLiteral(
"angle" )] = QString::number(
mAngle );
1075 map[QStringLiteral(
"outline_width" )] = QString::number(
mStrokeWidth );
1106 QDomElement graphicElem = doc.createElement( QStringLiteral(
"se:Graphic" ) );
1107 element.appendChild( graphicElem );
1116 double angle = props.value( QStringLiteral(
"angle" ), QStringLiteral(
"0" ) ).toDouble( &ok );
1119 angleFunc = QStringLiteral(
"%1 + %2" ).arg( props.value( QStringLiteral(
"angle" ), QStringLiteral(
"0" ) ) ).arg(
mAngle );
1134 Q_UNUSED( mmScaleFactor )
1135 Q_UNUSED( mapUnitScaleFactor )
1137 QString ogrType =
"3";
1138 if ( mName ==
"square" )
1142 else if ( mName ==
"triangle" )
1146 else if ( mName ==
"star" )
1150 else if ( mName ==
"circle" )
1154 else if ( mName ==
"cross" )
1158 else if ( mName ==
"x" || mName ==
"cross2" )
1162 else if ( mName ==
"line" )
1168 ogrString.append(
"SYMBOL(" );
1169 ogrString.append(
"id:" );
1170 ogrString.append(
'\"' );
1171 ogrString.append(
"ogr-sym-" );
1172 ogrString.append( ogrType );
1173 ogrString.append(
'\"' );
1174 ogrString.append(
",c:" );
1175 ogrString.append(
mColor.name() );
1176 ogrString.append(
",o:" );
1178 ogrString.append( QString(
",s:%1mm" ).arg(
mSize ) );
1179 ogrString.append(
')' );
1184 ogrString.append(
"PEN(" );
1185 ogrString.append(
"c:" );
1186 ogrString.append(
mColor.name() );
1187 ogrString.append(
",w:" );
1188 ogrString.append( QString::number(
mSize ) );
1189 ogrString.append(
"mm" );
1190 ogrString.append(
")" );
1198 QDomElement graphicElem = element.firstChildElement( QStringLiteral(
"Graphic" ) );
1199 if ( graphicElem.isNull() )
1202 QString name = QStringLiteral(
"square" );
1215 double d = angleFunc.toDouble( &ok );
1225 QString uom = element.attribute( QStringLiteral(
"uom" ) );
1251 p->drawPath(
mPath );
1264 if ( hasDataDefinedSize )
1285 size *= mmMapUnitScaleFactor;
1292 double halfSize =
size / 2.0;
1309 QColor pc =
mPen.color();
1310 QColor bc =
mBrush.color();
1330 QPointF off( offsetX, offsetY );
1359 t.translate( shift.x() + off.x(), shift.y() - off.y() );
1367 t.scale( halfSize, -halfSize );
1369 polygon = t.map( polygon );
1372 p.reserve( polygon.size() );
1373 for (
int i = 0; i < polygon.size(); i++ )
1378 if (
mBrush.style() != Qt::NoBrush )
1380 if (
mPen.style() != Qt::NoPen )
1385 shift += QPointF( off.x(), -off.y() );
1386 if (
mBrush.style() != Qt::NoBrush )
1388 if (
mPen.style() != Qt::NoPen )
1393 QPointF pt1 = t.map( QPointF( 0, -halfSize ) );
1394 QPointF pt2 = t.map( QPointF( 0, halfSize ) );
1396 if (
mPen.style() != Qt::NoPen )
1401 if (
mPen.style() != Qt::NoPen )
1403 QPointF pt1 = t.map( QPointF( -halfSize, 0 ) );
1404 QPointF pt2 = t.map( QPointF( halfSize, 0 ) );
1405 QPointF pt3 = t.map( QPointF( 0, -halfSize ) );
1406 QPointF pt4 = t.map( QPointF( 0, halfSize ) );
1414 if (
mPen.style() != Qt::NoPen )
1416 QPointF pt1 = t.map( QPointF( -halfSize, -halfSize ) );
1417 QPointF pt2 = t.map( QPointF( halfSize, halfSize ) );
1418 QPointF pt3 = t.map( QPointF( halfSize, -halfSize ) );
1419 QPointF pt4 = t.map( QPointF( -halfSize, halfSize ) );
1427 if (
mPen.style() != Qt::NoPen )
1429 QPointF pt1 = t.map( QPointF( -halfSize, halfSize ) );
1430 QPointF pt2 = t.map( QPointF( 0, 0 ) );
1431 QPointF pt3 = t.map( QPointF( -halfSize, -halfSize ) );
1510 symbolBounds.adjust( -penWidth / 2.0, -penWidth / 2.0,
1511 penWidth / 2.0, penWidth / 2.0 );
1513 return symbolBounds;
1560 if ( props.contains( QStringLiteral(
"name" ) ) )
1561 name = props[QStringLiteral(
"name" )];
1562 if ( props.contains( QStringLiteral(
"size" ) ) )
1563 size = props[QStringLiteral(
"size" )].toDouble();
1564 if ( props.contains( QStringLiteral(
"angle" ) ) )
1565 angle = props[QStringLiteral(
"angle" )].toDouble();
1566 if ( props.contains( QStringLiteral(
"scale_method" ) ) )
1570 if ( props.contains( QStringLiteral(
"offset" ) ) )
1572 if ( props.contains( QStringLiteral(
"offset_unit" ) ) )
1574 if ( props.contains( QStringLiteral(
"offset_map_unit_scale" ) ) )
1576 if ( props.contains( QStringLiteral(
"size_unit" ) ) )
1578 if ( props.contains( QStringLiteral(
"size_map_unit_scale" ) ) )
1580 if ( props.contains( QStringLiteral(
"horizontal_anchor_point" ) ) )
1584 if ( props.contains( QStringLiteral(
"vertical_anchor_point" ) ) )
1598 return QStringLiteral(
"FilledMarker" );
1623 map[QStringLiteral(
"size" )] = QString::number(
mSize );
1626 map[QStringLiteral(
"angle" )] = QString::number(
mAngle );
1682 attr.unite( mFill->usedAttributes( context ) );
1690 if ( mFill && mFill->hasDataDefinedProperties() )
1699 mFill->setColor(
c );
1704 return mFill ? mFill->color() :
mColor;
1720 p->setBrush( Qt::red );
1724 p->setBrush( Qt::NoBrush );
1726 p->setPen( Qt::black );
1728 if ( !polygon.isEmpty() )
1734 QPolygonF poly = path.toFillPolygon();
1754 mColor = QColor( 35, 35, 35 );
1767 if ( props.contains( QStringLiteral(
"name" ) ) )
1768 name = props[QStringLiteral(
"name" )];
1769 if ( props.contains( QStringLiteral(
"size" ) ) )
1770 size = props[QStringLiteral(
"size" )].toDouble();
1771 if ( props.contains( QStringLiteral(
"angle" ) ) )
1772 angle = props[QStringLiteral(
"angle" )].toDouble();
1773 if ( props.contains( QStringLiteral(
"scale_method" ) ) )
1779 if ( !props.contains( QStringLiteral(
"fill" ) ) && !props.contains( QStringLiteral(
"color" ) ) && !props.contains( QStringLiteral(
"outline" ) ) &&
1780 !props.contains( QStringLiteral(
"outline_color" ) ) && !props.contains( QStringLiteral(
"outline-width" ) ) && !props.contains( QStringLiteral(
"outline_width" ) ) )
1783 double fillOpacity = 1.0;
1784 double strokeOpacity = 1.0;
1786 bool hasFillParam =
false, hasFillOpacityParam =
false, hasStrokeParam =
false, hasStrokeWidthParam =
false, hasStrokeOpacityParam =
false;
1787 bool hasDefaultFillColor =
false, hasDefaultFillOpacity =
false, hasDefaultStrokeColor =
false, hasDefaultStrokeWidth =
false, hasDefaultStrokeOpacity =
false;
1789 hasFillOpacityParam, hasDefaultFillOpacity, fillOpacity,
1790 hasStrokeParam, hasDefaultStrokeColor,
strokeColor,
1791 hasStrokeWidthParam, hasDefaultStrokeWidth,
strokeWidth,
1792 hasStrokeOpacityParam, hasDefaultStrokeOpacity, strokeOpacity );
1793 if ( hasDefaultFillColor )
1797 if ( hasDefaultFillOpacity )
1800 c.setAlphaF( fillOpacity );
1803 if ( hasDefaultStrokeColor )
1807 if ( hasDefaultStrokeWidth )
1811 if ( hasDefaultStrokeOpacity )
1814 c.setAlphaF( strokeOpacity );
1819 if ( props.contains( QStringLiteral(
"size_unit" ) ) )
1821 if ( props.contains( QStringLiteral(
"size_map_unit_scale" ) ) )
1823 if ( props.contains( QStringLiteral(
"fixedAspectRatio" ) ) )
1825 if ( props.contains( QStringLiteral(
"offset" ) ) )
1827 if ( props.contains( QStringLiteral(
"offset_unit" ) ) )
1829 if ( props.contains( QStringLiteral(
"offset_map_unit_scale" ) ) )
1831 if ( props.contains( QStringLiteral(
"fill" ) ) )
1836 else if ( props.contains( QStringLiteral(
"color" ) ) )
1840 if ( props.contains( QStringLiteral(
"outline" ) ) )
1845 else if ( props.contains( QStringLiteral(
"outline_color" ) ) )
1849 else if ( props.contains( QStringLiteral(
"line_color" ) ) )
1854 if ( props.contains( QStringLiteral(
"outline-width" ) ) )
1857 m->
setStrokeWidth( props[QStringLiteral(
"outline-width" )].toDouble() );
1859 else if ( props.contains( QStringLiteral(
"outline_width" ) ) )
1861 m->
setStrokeWidth( props[QStringLiteral(
"outline_width" )].toDouble() );
1863 else if ( props.contains( QStringLiteral(
"line_width" ) ) )
1865 m->
setStrokeWidth( props[QStringLiteral(
"line_width" )].toDouble() );
1868 if ( props.contains( QStringLiteral(
"outline_width_unit" ) ) )
1872 else if ( props.contains( QStringLiteral(
"line_width_unit" ) ) )
1876 if ( props.contains( QStringLiteral(
"outline_width_map_unit_scale" ) ) )
1879 if ( props.contains( QStringLiteral(
"horizontal_anchor_point" ) ) )
1883 if ( props.contains( QStringLiteral(
"vertical_anchor_point" ) ) )
1897 QgsStringMap::iterator it =
properties.find( QStringLiteral(
"name" ) );
1910 QColor defaultFillColor, defaultStrokeColor;
1912 bool hasFillParam =
false, hasFillOpacityParam =
false, hasStrokeParam =
false, hasStrokeWidthParam =
false, hasStrokeOpacityParam =
false;
1913 bool hasDefaultFillColor =
false, hasDefaultFillOpacity =
false, hasDefaultStrokeColor =
false, hasDefaultStrokeWidth =
false, hasDefaultStrokeOpacity =
false;
1915 hasFillOpacityParam, hasDefaultFillOpacity, fillOpacity,
1916 hasStrokeParam, hasDefaultStrokeColor, defaultStrokeColor,
1917 hasStrokeWidthParam, hasDefaultStrokeWidth,
strokeWidth,
1918 hasStrokeOpacityParam, hasDefaultStrokeOpacity, strokeOpacity );
1920 double newFillOpacity = hasFillOpacityParam ?
fillColor().alphaF() : 1.0;
1921 double newStrokeOpacity = hasStrokeOpacityParam ?
strokeColor().alphaF() : 1.0;
1923 if ( hasDefaultFillColor )
1925 defaultFillColor.setAlphaF( newFillOpacity );
1928 if ( hasDefaultFillOpacity )
1931 c.setAlphaF( fillOpacity );
1934 if ( hasDefaultStrokeColor )
1936 defaultStrokeColor.setAlphaF( newStrokeOpacity );
1939 if ( hasDefaultStrokeWidth )
1943 if ( hasDefaultStrokeOpacity )
1946 c.setAlphaF( strokeOpacity );
1960 double widthScaleFactor = 3.465;
1963 mDefaultAspectRatio = svgViewbox.isValid() ? svgViewbox.height() / svgViewbox.width() : 0.0;
1971 if ( aPreservedAspectRatio && !par )
1975 else if ( !aPreservedAspectRatio && par )
1985 return QStringLiteral(
"SvgMarker" );
2005 bool hasDataDefinedSize =
false;
2006 double scaledSize = calculateSize( context, hasDataDefinedSize );
2010 if (
static_cast< int >(
size ) < 1 || 10000.0 <
size )
2017 bool hasDataDefinedAspectRatio =
false;
2020 QPointF outputOffset;
2022 calculateOffsetAndRotation( context, scaledSize, outputOffset,
angle );
2024 p->translate( point + outputOffset );
2060 bool fitsInCache =
true;
2061 bool usePict =
true;
2062 double hwRatio = 1.0;
2068 if ( fitsInCache && img.width() > 1 )
2074 QImage transparentImage = img.copy();
2076 p->drawImage( -transparentImage.width() / 2.0, -transparentImage.height() / 2.0, transparentImage );
2077 hwRatio =
static_cast< double >( transparentImage.height() ) /
static_cast< double >( transparentImage.width() );
2081 p->drawImage( -img.width() / 2.0, -img.height() / 2.0, img );
2082 hwRatio =
static_cast< double >( img.height() ) /
static_cast< double >( img.width() );
2087 if ( usePict || !fitsInCache )
2089 p->setOpacity( context.
opacity() );
2093 if ( pct.width() > 1 )
2096 _fixQPictureDPI( p );
2097 p->drawPicture( 0, 0, pct );
2099 hwRatio =
static_cast< double >( pct.height() ) /
static_cast< double >( pct.width() );
2107 if ( penWidth >
size / 20 )
2110 penWidth =
size / 20;
2112 double penOffset = penWidth / 2;
2113 pen.setWidth( penWidth );
2115 p->setBrush( Qt::NoBrush );
2116 double wSize =
size + penOffset;
2117 double hSize =
size * hwRatio + penOffset;
2118 p->drawRect( QRectF( -wSize / 2.0, -hSize / 2.0, wSize, hSize ) );
2126 p->setRenderHint( QPainter::Antialiasing );
2131 double QgsSvgMarkerSymbolLayer::calculateSize(
QgsSymbolRenderContext &context,
bool &hasDataDefinedSize )
const
2133 double scaledSize =
mSize;
2137 if ( hasDataDefinedSize )
2145 if ( hasDataDefinedSize )
2152 if ( hasDataDefinedSize && ok )
2157 scaledSize = std::sqrt( scaledSize );
2170 if ( !hasDataDefinedAspectRatio )
2180 double defaultHeight =
mSize * scaledAspectRatio;
2181 scaledAspectRatio = defaultHeight / scaledSize;
2184 double scaledHeight = scaledSize * scaledAspectRatio;
2191 if ( hasDataDefinedAspectRatio && ok )
2196 scaledHeight = sqrt( scaledHeight );
2203 scaledAspectRatio = scaledHeight / scaledSize;
2205 return scaledAspectRatio;
2208 void QgsSvgMarkerSymbolLayer::calculateOffsetAndRotation(
QgsSymbolRenderContext &context,
double scaledSize, QPointF &offset,
double &
angle )
const
2213 markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
2214 offset = QPointF( offsetX, offsetY );
2224 if ( hasDataDefinedRotation )
2250 map[QStringLiteral(
"name" )] =
mPath;
2251 map[QStringLiteral(
"size" )] = QString::number(
mSize );
2254 map[QStringLiteral(
"fixedAspectRatio" )] = QString::number(
mFixedAspectRatio );
2255 map[QStringLiteral(
"angle" )] = QString::number(
mAngle );
2262 map[QStringLiteral(
"outline_width" )] = QString::number(
mStrokeWidth );
2325 QDomElement graphicElem = doc.createElement( QStringLiteral(
"se:Graphic" ) );
2326 element.appendChild( graphicElem );
2336 double angle = props.value( QStringLiteral(
"angle" ), QStringLiteral(
"0" ) ).toDouble( &ok );
2339 angleFunc = QStringLiteral(
"%1 + %2" ).arg( props.value( QStringLiteral(
"angle" ), QStringLiteral(
"0" ) ) ).arg(
mAngle );
2357 QDomElement graphicElem = element.firstChildElement( QStringLiteral(
"Graphic" ) );
2358 if ( graphicElem.isNull() )
2361 QString
path, mimeType;
2368 QString uom = element.attribute( QStringLiteral(
"uom" ) );
2371 if ( mimeType != QLatin1String(
"image/svg+xml" ) )
2379 double d = angleFunc.toDouble( &ok );
2405 if ( hasDataDefinedSize )
2411 if ( hasDataDefinedSize && ok )
2425 size *= mmMapUnitScaleFactor;
2439 double offsetX =
offset.x();
2440 double offsetY =
offset.y();
2442 QPointF outputOffset( offsetX, offsetY );
2490 QSvgRenderer r( svgContent );
2497 QSizeF outSize( r.defaultSize() );
2498 outSize.scale(
size,
size, Qt::KeepAspectRatio );
2504 p.translate( r.defaultSize().width() / 2.0, r.defaultSize().height() / 2.0 );
2506 p.translate( -r.defaultSize().width() / 2.0, -r.defaultSize().height() / 2.0 );
2508 pd.
setShift( shift + QPointF( outputOffset.x(), -outputOffset.y() ) );
2509 pd.
setOutputSize( QRectF( -outSize.width() / 2.0, -outSize.height() / 2.0, outSize.width(), outSize.height() ) );
2518 bool hasDataDefinedSize =
false;
2519 double scaledSize = calculateSize( context, hasDataDefinedSize );
2523 if (
static_cast< int >( scaledSize ) < 1 || 10000.0 < scaledSize )
2528 QPointF outputOffset;
2530 calculateOffsetAndRotation( context, scaledSize, outputOffset,
angle );
2567 double scaledHeight = svgViewbox.isValid() ? scaledSize * svgViewbox.height() / svgViewbox.width() : scaledSize;
2572 transform.translate( point.x() + outputOffset.x(), point.y() + outputOffset.y() );
2575 transform.rotate(
angle );
2580 QRectF symbolBounds = transform.mapRect( QRectF( -scaledSize / 2.0,
2581 -scaledHeight / 2.0,
2589 return symbolBounds;
2613 if ( props.contains( QStringLiteral(
"imageFile" ) ) )
2614 path = props[QStringLiteral(
"imageFile" )];
2615 if ( props.contains( QStringLiteral(
"size" ) ) )
2616 size = props[QStringLiteral(
"size" )].toDouble();
2617 if ( props.contains( QStringLiteral(
"angle" ) ) )
2618 angle = props[QStringLiteral(
"angle" )].toDouble();
2619 if ( props.contains( QStringLiteral(
"scale_method" ) ) )
2624 if ( props.contains( QStringLiteral(
"alpha" ) ) )
2626 m->
setOpacity( props[QStringLiteral(
"alpha" )].toDouble() );
2629 if ( props.contains( QStringLiteral(
"size_unit" ) ) )
2631 if ( props.contains( QStringLiteral(
"size_map_unit_scale" ) ) )
2633 if ( props.contains( QStringLiteral(
"fixedAspectRatio" ) ) )
2636 if ( props.contains( QStringLiteral(
"offset" ) ) )
2638 if ( props.contains( QStringLiteral(
"offset_unit" ) ) )
2640 if ( props.contains( QStringLiteral(
"offset_map_unit_scale" ) ) )
2643 if ( props.contains( QStringLiteral(
"horizontal_anchor_point" ) ) )
2647 if ( props.contains( QStringLiteral(
"vertical_anchor_point" ) ) )
2660 QgsStringMap::iterator it =
properties.find( QStringLiteral(
"name" ) );
2679 if ( aPreservedAspectRatio && !par )
2683 else if ( !aPreservedAspectRatio && par )
2702 return QStringLiteral(
"RasterMarker" );
2718 if (
path.isEmpty() )
2722 double height = 0.0;
2724 bool hasDataDefinedSize =
false;
2725 double scaledSize = calculateSize( context, hasDataDefinedSize );
2727 bool hasDataDefinedAspectRatio =
false;
2730 QPointF outputOffset;
2737 if (
size.isEmpty() )
2740 width = ( scaledSize *
static_cast< double >(
size.width() ) ) / 100.0;
2741 height = ( scaledSize *
static_cast< double >(
size.height() ) ) / 100.0;
2744 if (
static_cast< int >( width ) < 1 || 10000.0 < width ||
static_cast< int >( height ) < 1 || 10000.0 < height )
2747 calculateOffsetAndRotation( context, width, height, outputOffset,
angle );
2757 if ( !
size.isNull() &&
size.isValid() &&
size.width() > 0 )
2759 height = width * (
static_cast< double >(
size.height() ) /
static_cast< double >(
size.width() ) );
2764 if (
static_cast< int >( width ) < 1 || 10000.0 < width )
2767 calculateOffsetAndRotation( context, scaledSize, scaledSize * ( height / width ), outputOffset,
angle );
2771 p->translate( point + outputOffset );
2787 if ( !img.isNull() )
2792 p->drawImage( -img.width() / 2.0, -img.height() / 2.0, img );
2798 double QgsRasterMarkerSymbolLayer::calculateSize(
QgsSymbolRenderContext &context,
bool &hasDataDefinedSize )
const
2800 double scaledSize =
mSize;
2804 if ( hasDataDefinedSize )
2812 if ( hasDataDefinedSize )
2819 if ( hasDataDefinedSize && ok )
2824 scaledSize = std::sqrt( scaledSize );
2837 if ( !hasDataDefinedAspectRatio )
2847 double defaultHeight =
mSize * scaledAspectRatio;
2848 scaledAspectRatio = defaultHeight / scaledSize;
2851 double scaledHeight = scaledSize * scaledAspectRatio;
2858 if ( hasDataDefinedAspectRatio && ok )
2863 scaledHeight = sqrt( scaledHeight );
2870 scaledAspectRatio = scaledHeight / scaledSize;
2872 return scaledAspectRatio;
2875 void QgsRasterMarkerSymbolLayer::calculateOffsetAndRotation(
QgsSymbolRenderContext &context,
double scaledWidth,
double scaledHeight, QPointF &offset,
double &
angle )
const
2880 markerOffset( context, scaledWidth, scaledHeight, offsetX, offsetY );
2881 offset = QPointF( offsetX, offsetY );
2891 if ( hasDataDefinedRotation )
2912 map[QStringLiteral(
"imageFile" )] =
mPath;
2913 map[QStringLiteral(
"size" )] = QString::number(
mSize );
2916 map[QStringLiteral(
"fixedAspectRatio" )] = QString::number(
mFixedAspectRatio );
2917 map[QStringLiteral(
"angle" )] = QString::number(
mAngle );
2918 map[QStringLiteral(
"alpha" )] = QString::number(
mOpacity );
2957 bool hasDataDefinedSize =
false;
2958 double scaledSize = calculateSize( context, hasDataDefinedSize );
2960 bool hasDataDefinedAspectRatio =
false;
2965 if (
static_cast< int >( scaledSize ) < 1 || 10000.0 < scaledSize )
2970 QPointF outputOffset;
2972 calculateOffsetAndRotation( context, scaledSize, scaledSize * ( height / width ), outputOffset,
angle );
2977 transform.translate( point.x() + outputOffset.x(), point.y() + outputOffset.y() );
2980 transform.rotate(
angle );
2982 QRectF symbolBounds = transform.mapRect( QRectF( -width / 2.0,
2987 return symbolBounds;
2999 mOrigSize = pointSize;
3018 if ( props.contains( QStringLiteral(
"font" ) ) )
3019 fontFamily = props[QStringLiteral(
"font" )];
3020 if ( props.contains( QStringLiteral(
"chr" ) ) && props[QStringLiteral(
"chr" )].length() > 0 )
3021 string = props[QStringLiteral(
"chr" )];
3022 if ( props.contains( QStringLiteral(
"size" ) ) )
3023 pointSize = props[QStringLiteral(
"size" )].toDouble();
3024 if ( props.contains( QStringLiteral(
"color" ) ) )
3026 if ( props.contains( QStringLiteral(
"angle" ) ) )
3027 angle = props[QStringLiteral(
"angle" )].toDouble();
3031 if ( props.contains( QStringLiteral(
"font_style" ) ) )
3032 m->
setFontStyle( props[QStringLiteral(
"font_style" )] );
3033 if ( props.contains( QStringLiteral(
"outline_color" ) ) )
3035 if ( props.contains( QStringLiteral(
"outline_width" ) ) )
3036 m->
setStrokeWidth( props[QStringLiteral(
"outline_width" )].toDouble() );
3037 if ( props.contains( QStringLiteral(
"offset" ) ) )
3039 if ( props.contains( QStringLiteral(
"offset_unit" ) ) )
3041 if ( props.contains( QStringLiteral(
"offset_map_unit_scale" ) ) )
3043 if ( props.contains( QStringLiteral(
"size_unit" ) ) )
3045 if ( props.contains( QStringLiteral(
"size_map_unit_scale" ) ) )
3047 if ( props.contains( QStringLiteral(
"outline_width_unit" ) ) )
3049 if ( props.contains( QStringLiteral(
"outline_width_map_unit_scale" ) ) )
3051 if ( props.contains( QStringLiteral(
"joinstyle" ) ) )
3053 if ( props.contains( QStringLiteral(
"horizontal_anchor_point" ) ) )
3055 if ( props.contains( QStringLiteral(
"vertical_anchor_point" ) ) )
3065 return QStringLiteral(
"FontMarker" );
3070 QColor brushColor =
mColor;
3071 QColor penColor = mStrokeColor;
3073 brushColor.setAlphaF(
mColor.alphaF() * context.
opacity() );
3074 penColor.setAlphaF( mStrokeColor.alphaF() * context.
opacity() );
3076 mBrush = QBrush( brushColor );
3077 mPen = QPen( penColor );
3078 mPen.setJoinStyle( mPenJoinStyle );
3081 mFont = QFont( mFontFamily );
3082 if ( !mFontStyle.isEmpty() )
3091 mFont.setPixelSize( std::max( 2,
static_cast< int >( std::round( sizePixels ) ) ) );
3092 mFontMetrics.reset(
new QFontMetrics( mFont ) );
3093 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
3094 mChrWidth = mFontMetrics->width( mString );
3096 mChrWidth = mFontMetrics->horizontalAdvance( mString );
3098 mChrOffset = QPointF( mChrWidth / 2.0, -mFontMetrics->ascent() / 2.0 );
3105 if ( mUseCachedPath )
3107 QPointF chrOffset = mChrOffset;
3109 QString charToRender = characterToRender( context, chrOffset, chrWidth );
3110 mCachedPath = QPainterPath();
3111 mCachedPath.addText( -chrOffset.x(), -chrOffset.y(), mFont, charToRender );
3120 QString QgsFontMarkerSymbolLayer::characterToRender(
QgsSymbolRenderContext &context, QPointF &charOffset,
double &charWidth )
3122 charOffset = mChrOffset;
3123 QString stringToRender = mString;
3128 if ( stringToRender != mString )
3130 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
3131 charWidth = mFontMetrics->width( stringToRender );
3133 charWidth = mFontMetrics->horizontalAdvance( stringToRender );
3135 charOffset = QPointF( charWidth / 2.0, -mFontMetrics->ascent() / 2.0 );
3138 return stringToRender;
3143 bool &hasDataDefinedRotation,
3145 double &
angle )
const
3150 markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
3151 offset = QPointF( offsetX, offsetY );
3167 if ( hasDataDefinedRotation )
3191 double scaledSize =
mSize;
3195 if ( hasDataDefinedSize )
3201 if ( hasDataDefinedSize && ok )
3206 scaledSize = std::sqrt( scaledSize );
3218 if ( !p || !mNonZeroFontSize )
3221 QTransform transform;
3224 QColor brushColor =
mColor;
3233 brushColor.setAlphaF( brushColor.alphaF() * context.
opacity() );
3235 mBrush.setColor( brushColor );
3237 QColor penColor = mStrokeColor;
3243 penColor.setAlphaF( penColor.alphaF() * context.
opacity() );
3267 p->setBrush( mBrush );
3270 mPen.setColor( penColor );
3271 mPen.setWidthF( penWidth );
3276 p->setPen( Qt::NoPen );
3283 mFont.setFamily( ok ?
fontFamily : mFontFamily );
3293 mFontMetrics.reset(
new QFontMetrics( mFont ) );
3296 QPointF chrOffset = mChrOffset;
3298 QString charToRender = characterToRender( context, chrOffset, chrWidth );
3300 double sizeToRender = calculateSize( context );
3302 bool hasDataDefinedRotation =
false;
3305 calculateOffsetAndRotation( context, sizeToRender, hasDataDefinedRotation,
offset,
angle );
3307 p->translate( point.x() +
offset.x(), point.y() +
offset.y() );
3310 transform.rotate(
angle );
3314 double s = sizeToRender / mOrigSize;
3315 transform.scale( s, s );
3318 if ( mUseCachedPath )
3320 p->drawPath( transform.map( mCachedPath ) );
3325 path.addText( -chrOffset.x(), -chrOffset.y(), mFont, charToRender );
3326 p->drawPath( transform.map( path ) );
3335 props[QStringLiteral(
"font" )] = mFontFamily;
3336 props[QStringLiteral(
"font_style" )] = mFontStyle;
3337 props[QStringLiteral(
"chr" )] = mString;
3338 props[QStringLiteral(
"size" )] = QString::number(
mSize );
3343 props[QStringLiteral(
"outline_width" )] = QString::number( mStrokeWidth );
3347 props[QStringLiteral(
"angle" )] = QString::number(
mAngle );
3380 QDomElement graphicElem = doc.createElement( QStringLiteral(
"se:Graphic" ) );
3381 element.appendChild( graphicElem );
3383 QString fontPath = QStringLiteral(
"ttf://%1" ).arg( mFontFamily );
3384 int markIndex = !mString.isEmpty() ? mString.at( 0 ).unicode() : 0;
3391 double angle = props.value( QStringLiteral(
"angle" ), QStringLiteral(
"0" ) ).toDouble( &ok );
3394 angleFunc = QStringLiteral(
"%1 + %2" ).arg( props.value( QStringLiteral(
"angle" ), QStringLiteral(
"0" ) ) ).arg(
mAngle );
3409 QPointF chrOffset = mChrOffset;
3410 double chrWidth = mChrWidth;
3412 ( void )characterToRender( context, chrOffset, chrWidth );
3414 if ( !mFontMetrics )
3415 mFontMetrics.reset(
new QFontMetrics( mFont ) );
3417 double scaledSize = calculateSize( context );
3420 chrWidth *= scaledSize / mOrigSize;
3423 bool hasDataDefinedRotation =
false;
3426 calculateOffsetAndRotation( context, scaledSize, hasDataDefinedRotation,
offset,
angle );
3432 transform.translate( point.x() +
offset.x(), point.y() +
offset.y() );
3435 transform.rotate(
angle );
3437 QRectF symbolBounds = transform.mapRect( QRectF( -chrWidth / 2.0,
3441 return symbolBounds;
3448 QDomElement graphicElem = element.firstChildElement( QStringLiteral(
"Graphic" ) );
3449 if ( graphicElem.isNull() )
3452 QString name, format;
3460 if ( !name.startsWith( QLatin1String(
"ttf://" ) ) || format != QLatin1String(
"ttf" ) )
3470 double d = angleFunc.toDouble( &ok );
3478 QString uom = element.attribute( QStringLiteral(
"uom" ) );