Skip to content
Permalink
Browse files
[dxf] Fix broken coordinate transform when exporting features
to DXF, add tests

Fixes #43449
  • Loading branch information
nyalldawson committed Jun 7, 2021
1 parent eeee133 commit 65c02e024a767ccc57283ec29a9c1b6d6ef8003f
Showing with 78 additions and 3 deletions.
  1. +2 −2 src/core/dxf/qgsdxfexport.cpp
  2. +8 −1 src/core/dxf/qgsdxfexport.h
  3. +68 −0 tests/src/core/testqgsdxfexport.cpp
@@ -660,10 +660,10 @@ void QgsDxfExport::writeEntities()
continue;
}

QgsCoordinateTransform ct( mMapSettings.destinationCrs(), job->crs, mMapSettings.transformContext() );
const QgsCoordinateTransform ct( job->crs, mMapSettings.destinationCrs(), mMapSettings.transformContext() );

QgsFeatureRequest request = QgsFeatureRequest().setSubsetOfAttributes( job->attributes, job->fields ).setExpressionContext( job->renderContext.expressionContext() );
request.setFilterRect( ct.transform( mExtent ) );
request.setFilterRect( ct.transformBoundingBox( mExtent, QgsCoordinateTransform::ReverseTransform ) );

QgsFeatureIterator featureIt = job->featureSource.getFeatures( request );

@@ -585,13 +585,20 @@ class CORE_EXPORT QgsDxfExport : public QgsLabelSink
/**
* Writes geometry generator symbol layer
* \param ctx the symbol render context
* \param ct the coordinate transform
* \param ct coordinate transform from CRS of feature being added to destination DXF CRS
* \param layer the layer name
* \param symbolLayer the symbollayer to write to the dxf file
* \param allSymbolLayers if TRUE, all symbol layers of the subsymbol are written. If FALSE, only the first one is written
*/
void addGeometryGeneratorSymbolLayer( QgsSymbolRenderContext &ctx, const QgsCoordinateTransform &ct, const QString &layer, QgsSymbolLayer *symbolLayer, bool allSymbolLayers );

/**
* \param ctx
* \param ct coordinate transform from CRS of feature being added to destination DXF CRS
* \param layer
* \param symbolLayer
* \param symbol
*/
void addFeature( QgsSymbolRenderContext &ctx, const QgsCoordinateTransform &ct, const QString &layer, const QgsSymbolLayer *symbolLayer, const QgsSymbol *symbol );

//returns dxf palette index from symbol layer color
@@ -67,6 +67,7 @@ class TestQgsDxfExport : public QObject
void testCurveExport();
void testCurveExport_data();
void testDashedLine();
void testTransform();

private:
QgsVectorLayer *mPointLayer = nullptr;
@@ -1177,6 +1178,73 @@ void TestQgsDxfExport::testDashedLine()
, &debugInfo ), debugInfo.toUtf8().constData() );
}

void TestQgsDxfExport::testTransform()
{
std::unique_ptr<QgsSimpleLineSymbolLayer> symbolLayer = std::make_unique<QgsSimpleLineSymbolLayer>( QColor( 0, 0, 0 ) );
symbolLayer->setWidth( 0.11 );
symbolLayer->setCustomDashVector( { 0.5, 0.35 } );
symbolLayer->setCustomDashPatternUnit( QgsUnitTypes::RenderUnit::RenderMapUnits );
symbolLayer->setUseCustomDashPattern( true );

QgsLineSymbol *symbol = new QgsLineSymbol();
symbol->changeSymbolLayer( 0, symbolLayer.release() );

std::unique_ptr< QgsVectorLayer > vl = std::make_unique< QgsVectorLayer >( QStringLiteral( "Linestring?crs=epsg:2056" ), QString(), QStringLiteral( "memory" ) );
QgsGeometry g = QgsGeometry::fromWkt( QStringLiteral( "LineString (2689564.82757076947018504 1283554.68540272791869938, 2689565.52996697928756475 1283531.49185784510336816)" ) );
QgsFeature f;
f.setGeometry( g );
vl->dataProvider()->addFeatures( QgsFeatureList() << f );
g = QgsGeometry::fromWkt( QStringLiteral( "LineString( 2689550.41764387069270015 1283518.10608713980764151, 2689586.27526817657053471 1283519.37654714332893491 )" ) );
f.setGeometry( g );
vl->dataProvider()->addFeatures( QgsFeatureList() << f );

QgsSingleSymbolRenderer *renderer = new QgsSingleSymbolRenderer( symbol );
vl->setRenderer( renderer );

QgsDxfExport d;
d.addLayers( QList< QgsDxfExport::DxfLayer >() << QgsDxfExport::DxfLayer( vl.get() ) );
d.setSymbologyExport( QgsDxfExport::SymbologyExport::SymbolLayerSymbology );

QgsMapSettings mapSettings;
QSize size( 640, 480 );
mapSettings.setOutputSize( size );
mapSettings.setLayers( QList<QgsMapLayer *>() << vl.get() );
mapSettings.setOutputDpi( 96 );
mapSettings.setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) ) );

d.setMapSettings( mapSettings );
d.setSymbologyScale( 1000 );

QString file = getTempFileName( QStringLiteral( "line_transform" ) );
QFile dxfFile( file );
QCOMPARE( d.writeToFile( &dxfFile, QStringLiteral( "CP1252" ) ), QgsDxfExport::ExportResult::Success );
dxfFile.close();

std::unique_ptr< QgsVectorLayer > result = std::make_unique< QgsVectorLayer >( file, QStringLiteral( "res" ) );
QVERIFY( result->isValid() );
QCOMPARE( result->featureCount(), 2L );
QgsFeature f2;
QgsFeatureIterator it = result->getFeatures();
QVERIFY( it.nextFeature( f2 ) );
QCOMPARE( f2.geometry().asWkt( 0 ), QStringLiteral( "LineString (960884 6056508, 960884 6056473)" ) );
QVERIFY( it.nextFeature( f2 ) );
QCOMPARE( f2.geometry().asWkt( 0 ), QStringLiteral( "LineString (960862 6056454, 960915 6056455)" ) );

// export a subset via extent (this is in EPSG:3857 -- the destination crs
d.setExtent( QgsRectangle( 960858.48, 6056426.49, 960918.31, 6056467.93 ) );
QString file2 = getTempFileName( QStringLiteral( "line_transform2" ) );
QFile dxfFile2( file2 );
QCOMPARE( d.writeToFile( &dxfFile2, QStringLiteral( "CP1252" ) ), QgsDxfExport::ExportResult::Success );
dxfFile2.close();

result = std::make_unique< QgsVectorLayer >( file2, QStringLiteral( "res" ) );
QVERIFY( result->isValid() );
QCOMPARE( result->featureCount(), 1L );
it = result->getFeatures();
QVERIFY( it.nextFeature( f2 ) );
QCOMPARE( f2.geometry().asWkt( 0 ), QStringLiteral( "LineString (960862 6056454, 960915 6056455)" ) );
}

bool TestQgsDxfExport::fileContainsText( const QString &path, const QString &text, QString *debugInfo ) const
{
QStringList debugLines;

0 comments on commit 65c02e0

Please sign in to comment.