mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-25 00:58:06 -05:00
Add dedicated conversion for MapInfo marker symbols
This commit is contained in:
parent
8bbac0145a
commit
94dc209e9e
@ -67,6 +67,15 @@ The caller takes ownership of the returned symbol.
|
||||
%Docstring
|
||||
Converts the MapInfo fill symbol with the specified ``identifier`` to a :py:class:`QgsFillSymbol`.
|
||||
|
||||
The caller takes ownership of the returned symbol.
|
||||
%End
|
||||
|
||||
static QgsMarkerSymbol *convertMarkerSymbol( int identifier, QgsMapInfoSymbolConversionContext &context, const QColor &color, double size, QgsUnitTypes::RenderUnit sizeUnit ) /Factory/;
|
||||
%Docstring
|
||||
Converts the MapInfo marker symbol with the specified ``identifier`` to a :py:class:`QgsMarkerSymbol`.
|
||||
|
||||
This method will convert a MapInfo "MapInfo 3.0 Compatible" symbol with a specific ``identifier`` to a :py:class:`QgsMarkerSymbol`.
|
||||
|
||||
The caller takes ownership of the returned symbol.
|
||||
%End
|
||||
|
||||
|
@ -1451,6 +1451,22 @@ std::unique_ptr<QgsSymbol> QgsOgrUtils::symbolFromStyleString( const QString &st
|
||||
|
||||
const QString id = symbolStyle.value( QStringLiteral( "id" ) ).toString();
|
||||
|
||||
// if the symbol is a mapinfo symbol, use dedicated converter for more accurate results
|
||||
const thread_local QRegularExpression sMapInfoId = QRegularExpression( QStringLiteral( "mapinfo-sym-(\\d+)" ) );
|
||||
const QRegularExpressionMatch match = sMapInfoId.match( id );
|
||||
if ( match.hasMatch() )
|
||||
{
|
||||
const int symbolId = match.captured( 1 ).toInt();
|
||||
QgsMapInfoSymbolConversionContext context;
|
||||
|
||||
// ogr interpretations of mapinfo symbol sizes are too large -- scale these down
|
||||
symbolSize *= 0.61;
|
||||
|
||||
std::unique_ptr<QgsSymbol> res( QgsMapInfoSymbolConverter::convertMarkerSymbol( symbolId, context, color, symbolSize, symbolSizeUnit ) );
|
||||
if ( res )
|
||||
return res;
|
||||
}
|
||||
|
||||
std::unique_ptr< QgsMarkerSymbolLayer > markerLayer;
|
||||
|
||||
const thread_local QRegularExpression sFontId = QRegularExpression( QStringLiteral( "font-sym-(\\d+)" ) );
|
||||
@ -1602,7 +1618,6 @@ std::unique_ptr<QgsSymbol> QgsOgrUtils::symbolFromStyleString( const QString &st
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
|
||||
case QgsSymbol::Line:
|
||||
if ( styles.contains( QStringLiteral( "pen" ) ) )
|
||||
|
@ -1386,3 +1386,172 @@ QgsFillSymbol *QgsMapInfoSymbolConverter::convertFillSymbol( int identifier, Qgs
|
||||
}
|
||||
return new QgsFillSymbol( layers );
|
||||
}
|
||||
|
||||
QgsMarkerSymbol *QgsMapInfoSymbolConverter::convertMarkerSymbol( int identifier, QgsMapInfoSymbolConversionContext &context, const QColor &color, double size, QgsUnitTypes::RenderUnit sizeUnit )
|
||||
{
|
||||
QgsSimpleMarkerSymbolLayerBase::Shape shape;
|
||||
bool isFilled = true;
|
||||
bool isNull = false;
|
||||
bool hasShadow = false;
|
||||
double angle = 0;
|
||||
QgsMarkerSymbolLayer::VerticalAnchorPoint vertAlign = QgsMarkerSymbolLayer::VCenter;
|
||||
QPointF shadowOffset;
|
||||
switch ( identifier )
|
||||
{
|
||||
case 31:
|
||||
// null symbol
|
||||
isNull = true;
|
||||
break;
|
||||
|
||||
case 32:
|
||||
shape = QgsSimpleMarkerSymbolLayer::Shape::Square;
|
||||
break;
|
||||
|
||||
case 33:
|
||||
shape = QgsSimpleMarkerSymbolLayer::Shape::Diamond;
|
||||
break;
|
||||
|
||||
case 34:
|
||||
shape = QgsSimpleMarkerSymbolLayer::Shape::Circle;
|
||||
break;
|
||||
|
||||
case 35:
|
||||
shape = QgsSimpleMarkerSymbolLayer::Shape::Star;
|
||||
break;
|
||||
|
||||
case 36:
|
||||
shape = QgsSimpleMarkerSymbolLayer::Shape::Triangle;
|
||||
break;
|
||||
|
||||
case 37:
|
||||
shape = QgsSimpleMarkerSymbolLayer::Shape::Triangle;
|
||||
angle = 180;
|
||||
break;
|
||||
|
||||
case 38:
|
||||
shape = QgsSimpleMarkerSymbolLayer::Shape::Square;
|
||||
isFilled = false;
|
||||
break;
|
||||
|
||||
case 39:
|
||||
shape = QgsSimpleMarkerSymbolLayer::Shape::Diamond;
|
||||
isFilled = false;
|
||||
break;
|
||||
|
||||
case 40:
|
||||
shape = QgsSimpleMarkerSymbolLayer::Shape::Circle;
|
||||
isFilled = false;
|
||||
break;
|
||||
|
||||
case 41:
|
||||
shape = QgsSimpleMarkerSymbolLayer::Shape::Star;
|
||||
isFilled = false;
|
||||
break;
|
||||
|
||||
case 42:
|
||||
shape = QgsSimpleMarkerSymbolLayer::Shape::Triangle;
|
||||
isFilled = false;
|
||||
break;
|
||||
|
||||
case 43:
|
||||
shape = QgsSimpleMarkerSymbolLayer::Shape::Triangle;
|
||||
angle = 180;
|
||||
isFilled = false;
|
||||
break;
|
||||
|
||||
case 44:
|
||||
shape = QgsSimpleMarkerSymbolLayer::Shape::Square;
|
||||
hasShadow = true;
|
||||
shadowOffset = QPointF( size * 0.1, size * 0.1 );
|
||||
break;
|
||||
|
||||
case 45:
|
||||
shape = QgsSimpleMarkerSymbolLayer::Shape::Triangle;
|
||||
shadowOffset = QPointF( size * 0.2, size * 0.1 );
|
||||
hasShadow = true;
|
||||
break;
|
||||
|
||||
case 46:
|
||||
shape = QgsSimpleMarkerSymbolLayer::Shape::Circle;
|
||||
shadowOffset = QPointF( size * 0.1, size * 0.1 );
|
||||
hasShadow = true;
|
||||
break;
|
||||
|
||||
case 47:
|
||||
shape = QgsSimpleMarkerSymbolLayer::Shape::Arrow;
|
||||
size *= 0.66666;
|
||||
angle = 45;
|
||||
vertAlign = QgsMarkerSymbolLayer::Top;
|
||||
break;
|
||||
|
||||
case 48:
|
||||
shape = QgsSimpleMarkerSymbolLayer::Shape::Arrow;
|
||||
size *= 0.66666;
|
||||
angle = 225;
|
||||
vertAlign = QgsMarkerSymbolLayer::Top;
|
||||
break;
|
||||
|
||||
case 49:
|
||||
shape = QgsSimpleMarkerSymbolLayer::Shape::Cross;
|
||||
break;
|
||||
|
||||
case 50:
|
||||
shape = QgsSimpleMarkerSymbolLayer::Shape::Cross2;
|
||||
break;
|
||||
|
||||
case 51:
|
||||
shape = QgsSimpleMarkerSymbolLayer::Shape::Cross;
|
||||
break;
|
||||
|
||||
default:
|
||||
context.pushWarning( QObject::tr( "The symbol is not supported in QGIS" ) );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr< QgsSimpleMarkerSymbolLayer > simpleMarker = std::make_unique< QgsSimpleMarkerSymbolLayer >( shape, size );
|
||||
simpleMarker->setSizeUnit( sizeUnit );
|
||||
simpleMarker->setAngle( angle );
|
||||
simpleMarker->setVerticalAnchorPoint( vertAlign );
|
||||
|
||||
if ( isNull )
|
||||
{
|
||||
simpleMarker->setFillColor( QColor( 0, 0, 0, 0 ) );
|
||||
simpleMarker->setStrokeStyle( Qt::NoPen );
|
||||
}
|
||||
if ( isFilled && QgsSimpleMarkerSymbolLayer::shapeIsFilled( shape ) )
|
||||
{
|
||||
simpleMarker->setColor( color );
|
||||
simpleMarker->setStrokeColor( QColor( 0, 0, 0 ) );
|
||||
simpleMarker->setStrokeWidth( 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
simpleMarker->setFillColor( QColor( 0, 0, 0, 0 ) );
|
||||
simpleMarker->setStrokeColor( color );
|
||||
}
|
||||
|
||||
QgsSymbolLayerList symbols;
|
||||
if ( hasShadow )
|
||||
{
|
||||
std::unique_ptr< QgsSimpleMarkerSymbolLayer > shadow( simpleMarker->clone() );
|
||||
shadow->setColor( QColor( 0, 0, 0 ) );
|
||||
shadow->setLocked( true );
|
||||
shadow->setOffset( shadowOffset );
|
||||
shadow->setOffsetUnit( sizeUnit );
|
||||
|
||||
symbols << shadow.release();
|
||||
symbols << simpleMarker.release();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( identifier == 51 )
|
||||
{
|
||||
std::unique_ptr< QgsSimpleMarkerSymbolLayer > second( simpleMarker->clone() );
|
||||
second->setShape( QgsSimpleMarkerSymbolLayer::Shape::Cross2 );
|
||||
symbols << second.release();
|
||||
}
|
||||
symbols << simpleMarker.release();
|
||||
}
|
||||
|
||||
return new QgsMarkerSymbol( symbols );
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
class QgsLineSymbol;
|
||||
class QgsFillSymbol;
|
||||
class QgsMarkerSymbol;
|
||||
|
||||
/**
|
||||
* Context for a MapInfo symbol conversion operation.
|
||||
@ -80,6 +81,15 @@ class CORE_EXPORT QgsMapInfoSymbolConverter
|
||||
*/
|
||||
static QgsFillSymbol *convertFillSymbol( int identifier, QgsMapInfoSymbolConversionContext &context, const QColor &foreColor, const QColor &backColor = QColor() ) SIP_FACTORY;
|
||||
|
||||
/**
|
||||
* Converts the MapInfo marker symbol with the specified \a identifier to a QgsMarkerSymbol.
|
||||
*
|
||||
* This method will convert a MapInfo "MapInfo 3.0 Compatible" symbol with a specific \a identifier to a QgsMarkerSymbol.
|
||||
*
|
||||
* The caller takes ownership of the returned symbol.
|
||||
*/
|
||||
static QgsMarkerSymbol *convertMarkerSymbol( int identifier, QgsMapInfoSymbolConversionContext &context, const QColor &color, double size, QgsUnitTypes::RenderUnit sizeUnit ) SIP_FACTORY;
|
||||
|
||||
};
|
||||
|
||||
#endif // QGSMAPINFOSYMBOLCONVERTER_H
|
||||
|
@ -37,12 +37,14 @@ from qgis.core import (QgsVectorLayer,
|
||||
QgsFeature,
|
||||
QgsGeometry
|
||||
)
|
||||
from qgis.testing import unittest
|
||||
from qgis.testing import unittest, start_app
|
||||
|
||||
from utilities import unitTestDataPath
|
||||
|
||||
TEST_DATA_DIR = unitTestDataPath()
|
||||
|
||||
start_app()
|
||||
|
||||
|
||||
class TestQgsEmbeddedSymbolRenderer(unittest.TestCase):
|
||||
|
||||
@ -174,10 +176,10 @@ class TestQgsEmbeddedSymbolRenderer(unittest.TestCase):
|
||||
renderchecker.setControlName('expected_embedded_mapinfo_lines')
|
||||
self.assertTrue(renderchecker.runTest('embedded_mapinfo_lines'))
|
||||
|
||||
def testMapFillLineSymbolConversion(self):
|
||||
def testMapInfoFillSymbolConversion(self):
|
||||
line_layer = QgsVectorLayer(TEST_DATA_DIR + '/mapinfo/fill_styles.TAB', 'Fills', 'ogr')
|
||||
|
||||
renderer = QgsEmbeddedSymbolRenderer(defaultSymbol=QgsLineSymbol.createSimple({}))
|
||||
renderer = QgsEmbeddedSymbolRenderer(defaultSymbol=QgsFillSymbol.createSimple({}))
|
||||
line_layer.setRenderer(renderer)
|
||||
|
||||
mapsettings = QgsMapSettings()
|
||||
@ -194,6 +196,26 @@ class TestQgsEmbeddedSymbolRenderer(unittest.TestCase):
|
||||
renderchecker.setControlName('expected_embedded_mapinfo_fills')
|
||||
self.assertTrue(renderchecker.runTest('embedded_mapinfo_fills'))
|
||||
|
||||
def testMapInfoMarkerSymbolConversion(self):
|
||||
line_layer = QgsVectorLayer(TEST_DATA_DIR + '/mapinfo/marker_styles.TAB', 'Marker', 'ogr')
|
||||
|
||||
renderer = QgsEmbeddedSymbolRenderer(defaultSymbol=QgsMarkerSymbol.createSimple({}))
|
||||
line_layer.setRenderer(renderer)
|
||||
|
||||
mapsettings = QgsMapSettings()
|
||||
mapsettings.setOutputSize(QSize(2000, 4000))
|
||||
mapsettings.setOutputDpi(96)
|
||||
mapsettings.setMagnificationFactor(2)
|
||||
mapsettings.setExtent(line_layer.extent().buffered(0.1))
|
||||
|
||||
mapsettings.setLayers([line_layer])
|
||||
|
||||
renderchecker = QgsMultiRenderChecker()
|
||||
renderchecker.setMapSettings(mapsettings)
|
||||
renderchecker.setControlPathPrefix('embedded')
|
||||
renderchecker.setControlName('expected_embedded_mapinfo_markers')
|
||||
self.assertTrue(renderchecker.runTest('embedded_mapinfo_markers'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
BIN
tests/testdata/mapinfo/marker_styles.DAT
vendored
Normal file
BIN
tests/testdata/mapinfo/marker_styles.DAT
vendored
Normal file
Binary file not shown.
BIN
tests/testdata/mapinfo/marker_styles.ID
vendored
Normal file
BIN
tests/testdata/mapinfo/marker_styles.ID
vendored
Normal file
Binary file not shown.
BIN
tests/testdata/mapinfo/marker_styles.MAP
vendored
Normal file
BIN
tests/testdata/mapinfo/marker_styles.MAP
vendored
Normal file
Binary file not shown.
8
tests/testdata/mapinfo/marker_styles.TAB
vendored
Normal file
8
tests/testdata/mapinfo/marker_styles.TAB
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
!table
|
||||
!version 300
|
||||
!charset WindowsLatin1
|
||||
|
||||
Definition Table
|
||||
Type NATIVE Charset "WindowsLatin1"
|
||||
Fields 1
|
||||
Field1 Char (10) ;
|
Loading…
x
Reference in New Issue
Block a user