Skip to content

Commit 8bbac01

Browse files
committedMay 10, 2021
[ogr] Add support for embedded marker symbol conversion to QGIS symbols
1 parent f191404 commit 8bbac01

File tree

2 files changed

+241
-0
lines changed

2 files changed

+241
-0
lines changed
 

‎src/core/qgsogrutils.cpp

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@
2727
#include "qgsmultipolygon.h"
2828
#include "qgsmapinfosymbolconverter.h"
2929
#include "qgsfillsymbollayer.h"
30+
#include "qgsmarkersymbollayer.h"
3031
#include "qgssymbollayerutils.h"
32+
#include "qgsfontutils.h"
33+
#include "qgsmessagelog.h"
3134

3235
#include <QTextCodec>
3336
#include <QUuid>
@@ -1436,9 +1439,169 @@ std::unique_ptr<QgsSymbol> QgsOgrUtils::symbolFromStyleString( const QString &st
14361439
return std::make_unique< QgsFillSymbol >( layers );
14371440
};
14381441

1442+
auto convertSymbol = [&convertColor, &convertSize, string]( const QVariantMap & symbolStyle ) -> std::unique_ptr< QgsSymbol >
1443+
{
1444+
const QColor color = convertColor( symbolStyle.value( QStringLiteral( "c" ), QStringLiteral( "#000000" ) ).toString() );
1445+
1446+
double symbolSize = DEFAULT_SIMPLEMARKER_SIZE;
1447+
QgsUnitTypes::RenderUnit symbolSizeUnit = QgsUnitTypes::RenderMillimeters;
1448+
convertSize( symbolStyle.value( QStringLiteral( "s" ) ).toString(), symbolSize, symbolSizeUnit );
1449+
1450+
const double angle = symbolStyle.value( QStringLiteral( "a" ), QStringLiteral( "0" ) ).toDouble();
1451+
1452+
const QString id = symbolStyle.value( QStringLiteral( "id" ) ).toString();
1453+
1454+
std::unique_ptr< QgsMarkerSymbolLayer > markerLayer;
1455+
1456+
const thread_local QRegularExpression sFontId = QRegularExpression( QStringLiteral( "font-sym-(\\d+)" ) );
1457+
const QRegularExpressionMatch fontMatch = sFontId.match( id );
1458+
if ( fontMatch.hasMatch() )
1459+
{
1460+
const int symId = fontMatch.captured( 1 ).toInt();
1461+
const QStringList families = symbolStyle.value( QStringLiteral( "f" ), QString() ).toString().split( ',' );
1462+
1463+
bool familyFound = false;
1464+
QString fontFamily;
1465+
for ( const QString &family : std::as_const( families ) )
1466+
{
1467+
if ( QgsFontUtils::fontFamilyMatchOnSystem( family ) )
1468+
{
1469+
familyFound = true;
1470+
fontFamily = family;
1471+
break;
1472+
}
1473+
}
1474+
1475+
if ( familyFound )
1476+
{
1477+
std::unique_ptr< QgsFontMarkerSymbolLayer > fontMarker = std::make_unique< QgsFontMarkerSymbolLayer >( fontFamily, QChar( symId ), symbolSize );
1478+
fontMarker->setSizeUnit( symbolSizeUnit );
1479+
fontMarker->setAngle( -angle );
1480+
1481+
fontMarker->setColor( color );
1482+
1483+
const QColor strokeColor = convertColor( symbolStyle.value( QStringLiteral( "o" ), QString() ).toString() );
1484+
if ( strokeColor.isValid() )
1485+
{
1486+
fontMarker->setStrokeColor( strokeColor );
1487+
fontMarker->setStrokeWidth( 1 );
1488+
fontMarker->setStrokeWidthUnit( QgsUnitTypes::RenderPoints );
1489+
}
1490+
else
1491+
{
1492+
fontMarker->setStrokeWidth( 0 );
1493+
}
1494+
1495+
markerLayer = std::move( fontMarker );
1496+
}
1497+
else if ( !families.empty() )
1498+
{
1499+
// couldn't even find a matching font in the backup list
1500+
QgsMessageLog::logMessage( QObject::tr( "Font %1 not found on system" ).arg( families.at( 0 ) ) );
1501+
}
1502+
}
1503+
1504+
if ( !markerLayer )
1505+
{
1506+
const thread_local QRegularExpression sOgrId = QRegularExpression( QStringLiteral( "ogr-sym-(\\d+)" ) );
1507+
const QRegularExpressionMatch ogrMatch = sOgrId.match( id );
1508+
1509+
QgsSimpleMarkerSymbolLayerBase::Shape shape;
1510+
bool isFilled = true;
1511+
if ( ogrMatch.hasMatch() )
1512+
{
1513+
const int symId = ogrMatch.captured( 1 ).toInt();
1514+
switch ( symId )
1515+
{
1516+
case 0:
1517+
shape = QgsSimpleMarkerSymbolLayer::Shape::Cross;
1518+
break;
1519+
1520+
case 1:
1521+
shape = QgsSimpleMarkerSymbolLayer::Shape::Cross2;
1522+
break;
1523+
1524+
case 2:
1525+
isFilled = false;
1526+
shape = QgsSimpleMarkerSymbolLayer::Shape::Circle;
1527+
break;
1528+
1529+
case 3:
1530+
shape = QgsSimpleMarkerSymbolLayer::Shape::Circle;
1531+
break;
1532+
1533+
case 4:
1534+
isFilled = false;
1535+
shape = QgsSimpleMarkerSymbolLayer::Shape::Square;
1536+
break;
1537+
1538+
case 5:
1539+
shape = QgsSimpleMarkerSymbolLayer::Shape::Square;
1540+
break;
1541+
1542+
case 6:
1543+
isFilled = false;
1544+
shape = QgsSimpleMarkerSymbolLayer::Shape::Triangle;
1545+
break;
1546+
1547+
case 7:
1548+
shape = QgsSimpleMarkerSymbolLayer::Shape::Triangle;
1549+
break;
1550+
1551+
case 8:
1552+
isFilled = false;
1553+
shape = QgsSimpleMarkerSymbolLayer::Shape::Star;
1554+
break;
1555+
1556+
case 9:
1557+
shape = QgsSimpleMarkerSymbolLayer::Shape::Star;
1558+
break;
1559+
1560+
case 10:
1561+
shape = QgsSimpleMarkerSymbolLayer::Shape::Line;
1562+
break;
1563+
}
1564+
}
1565+
1566+
std::unique_ptr< QgsSimpleMarkerSymbolLayer > simpleMarker = std::make_unique< QgsSimpleMarkerSymbolLayer >( shape, symbolSize, -angle );
1567+
simpleMarker->setSizeUnit( symbolSizeUnit );
1568+
1569+
if ( isFilled && QgsSimpleMarkerSymbolLayer::shapeIsFilled( shape ) )
1570+
{
1571+
simpleMarker->setColor( color );
1572+
simpleMarker->setStrokeStyle( Qt::NoPen );
1573+
}
1574+
else
1575+
{
1576+
simpleMarker->setFillColor( QColor( 0, 0, 0, 0 ) );
1577+
simpleMarker->setStrokeColor( color );
1578+
}
1579+
1580+
const QColor strokeColor = convertColor( symbolStyle.value( QStringLiteral( "o" ), QString() ).toString() );
1581+
if ( strokeColor.isValid() )
1582+
{
1583+
simpleMarker->setStrokeColor( strokeColor );
1584+
simpleMarker->setStrokeStyle( Qt::SolidLine );
1585+
}
1586+
1587+
markerLayer = std::move( simpleMarker );
1588+
}
1589+
1590+
return std::make_unique< QgsMarkerSymbol >( QgsSymbolLayerList() << markerLayer.release() );
1591+
};
1592+
14391593
switch ( type )
14401594
{
14411595
case QgsSymbol::Marker:
1596+
if ( styles.contains( QStringLiteral( "symbol" ) ) )
1597+
{
1598+
const QVariantMap symbolStyle = styles.value( QStringLiteral( "symbol" ) ).toMap();
1599+
return convertSymbol( symbolStyle );
1600+
}
1601+
else
1602+
{
1603+
return nullptr;
1604+
}
14421605
break;
14431606

14441607
case QgsSymbol::Line:

‎tests/src/core/testqgsogrutils.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
#include "qgsogrproxytextcodec.h"
3131
#include "qgslinesymbollayer.h"
3232
#include "qgsfillsymbollayer.h"
33+
#include "qgsmarkersymbollayer.h"
34+
#include "qgsfontutils.h"
3335

3436
class TestQgsOgrUtils: public QObject
3537
{
@@ -635,6 +637,82 @@ void TestQgsOgrUtils::convertStyleString()
635637
QCOMPARE( qgis::down_cast<QgsSimpleFillSymbolLayer * >( symbol->symbolLayer( 0 ) )->brushStyle(), Qt::NoBrush );
636638
QCOMPARE( qgis::down_cast<QgsSimpleFillSymbolLayer * >( symbol->symbolLayer( 0 ) )->strokeStyle(), Qt::SolidLine );
637639
QCOMPARE( qgis::down_cast<QgsSimpleFillSymbolLayer * >( symbol->symbolLayer( 0 ) )->strokeColor().name(), QStringLiteral( "#ffff00" ) );
640+
641+
// symbol
642+
symbol = QgsOgrUtils::symbolFromStyleString( QStringLiteral( R"""(SYMBOL(a:0,c:#5050ff,s:36pt,id:"ogr-sym-5"))""" ), QgsSymbol::Marker );
643+
QVERIFY( symbol );
644+
QCOMPARE( symbol->symbolLayerCount(), 1 );
645+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->color().name(), QStringLiteral( "#5050ff" ) );
646+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->shape(), QgsSimpleMarkerSymbolLayer::Square );
647+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->size(), 36.0 );
648+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->angle(), 0.0 );
649+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->sizeUnit(), QgsUnitTypes::RenderPoints );
650+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->strokeStyle(), Qt::NoPen );
651+
symbol = QgsOgrUtils::symbolFromStyleString( QStringLiteral( R"""(SYMBOL(a:0,c:#5050ff,s:36pt,id:"ogr-sym-6"))""" ), QgsSymbol::Marker );
652+
QVERIFY( symbol );
653+
QCOMPARE( symbol->symbolLayerCount(), 1 );
654+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->color().alpha(), 0 );
655+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->strokeColor().name(), QStringLiteral( "#5050ff" ) );
656+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->shape(), QgsSimpleMarkerSymbolLayer::Triangle );
657+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->size(), 36.0 );
658+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->angle(), 0.0 );
659+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->sizeUnit(), QgsUnitTypes::RenderPoints );
660+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->strokeStyle(), Qt::SolidLine );
661+
symbol = QgsOgrUtils::symbolFromStyleString( QStringLiteral( R"""(SYMBOL(a:20,c:#5050ff,s:36pt,id:"ogr-sym-5"))""" ), QgsSymbol::Marker );
662+
QVERIFY( symbol );
663+
QCOMPARE( symbol->symbolLayerCount(), 1 );
664+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->color().name(), QStringLiteral( "#5050ff" ) );
665+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->shape(), QgsSimpleMarkerSymbolLayer::Square );
666+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->size(), 36.0 );
667+
// OGR symbol angles are opposite direction to qgis marker angles
668+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->angle(), -20.0 );
669+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->sizeUnit(), QgsUnitTypes::RenderPoints );
670+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->strokeStyle(), Qt::NoPen );
671+
symbol = QgsOgrUtils::symbolFromStyleString( QStringLiteral( R"""(SYMBOL(c:#5050ff,o:#3030ff,s:36pt,id:"ogr-sym-5"))""" ), QgsSymbol::Marker );
672+
QVERIFY( symbol );
673+
QCOMPARE( symbol->symbolLayerCount(), 1 );
674+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->color().name(), QStringLiteral( "#5050ff" ) );
675+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->shape(), QgsSimpleMarkerSymbolLayer::Square );
676+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->size(), 36.0 );
677+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->angle(), 0.0 );
678+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->sizeUnit(), QgsUnitTypes::RenderPoints );
679+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->strokeStyle(), Qt::SolidLine );
680+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->strokeColor().name(), QStringLiteral( "#3030ff" ) );
681+
682+
// font symbol
683+
QFont f = QgsFontUtils::getStandardTestFont();
684+
symbol = QgsOgrUtils::symbolFromStyleString( QStringLiteral( R"""(SYMBOL(c:#00FF00,s:12pt,id:"font-sym-75,ogr-sym-9",f:"%1"))""" ).arg( f.family() ), QgsSymbol::Marker );
685+
QVERIFY( symbol );
686+
QCOMPARE( symbol->symbolLayerCount(), 1 );
687+
QCOMPARE( qgis::down_cast<QgsFontMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->color().name(), QStringLiteral( "#00ff00" ) );
688+
QCOMPARE( qgis::down_cast<QgsFontMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->character(), QStringLiteral( "K" ) );
689+
QCOMPARE( qgis::down_cast<QgsFontMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->size(), 12.0 );
690+
QCOMPARE( qgis::down_cast<QgsFontMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->angle(), 0.0 );
691+
QCOMPARE( qgis::down_cast<QgsFontMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->sizeUnit(), QgsUnitTypes::RenderPoints );
692+
QCOMPARE( qgis::down_cast<QgsFontMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->strokeWidth(), 0 );
693+
694+
symbol = QgsOgrUtils::symbolFromStyleString( QStringLiteral( R"""(SYMBOL(a:20,c:#00FF00,o:#3030ff,s:12pt,id:"font-sym-75,ogr-sym-9",f:"%1"))""" ).arg( f.family() ), QgsSymbol::Marker );
695+
QVERIFY( symbol );
696+
QCOMPARE( symbol->symbolLayerCount(), 1 );
697+
QCOMPARE( qgis::down_cast<QgsFontMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->color().name(), QStringLiteral( "#00ff00" ) );
698+
QCOMPARE( qgis::down_cast<QgsFontMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->character(), QStringLiteral( "K" ) );
699+
QCOMPARE( qgis::down_cast<QgsFontMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->size(), 12.0 );
700+
QCOMPARE( qgis::down_cast<QgsFontMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->angle(), -20.0 );
701+
QCOMPARE( qgis::down_cast<QgsFontMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->sizeUnit(), QgsUnitTypes::RenderPoints );
702+
QCOMPARE( qgis::down_cast<QgsFontMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->strokeWidth(), 1 );
703+
QCOMPARE( qgis::down_cast<QgsFontMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->strokeWidthUnit(), QgsUnitTypes::RenderPoints );
704+
QCOMPARE( qgis::down_cast<QgsFontMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->strokeColor().name(), QStringLiteral( "#3030ff" ) );
705+
706+
// bad font name, should fallback to ogr symbol id
707+
symbol = QgsOgrUtils::symbolFromStyleString( QStringLiteral( R"""(SYMBOL(c:#00FF00,s:12pt,id:"font-sym-75,ogr-sym-9",f:"xxxxxx"))""" ), QgsSymbol::Marker );
708+
QVERIFY( symbol );
709+
QCOMPARE( symbol->symbolLayerCount(), 1 );
710+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->color().name(), QStringLiteral( "#00ff00" ) );
711+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->shape(), QgsSimpleMarkerSymbolLayer::Star );
712+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->size(), 12.0 );
713+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->angle(), 0.0 );
714+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->sizeUnit(), QgsUnitTypes::RenderPoints );
715+
QCOMPARE( qgis::down_cast<QgsSimpleMarkerSymbolLayer * >( symbol->symbolLayer( 0 ) )->strokeStyle(), Qt::NoPen );
638716
}
639717

640718
QGSTEST_MAIN( TestQgsOgrUtils )

0 commit comments

Comments
 (0)
Please sign in to comment.