mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -04:00
Merge pull request #32770 from m-kuhn/dxf-symbol-fixes
Make the DXF renderer ready for background threading and fix symbology
This commit is contained in:
commit
cbe6150348
@ -34,6 +34,17 @@ Returns the layer
|
||||
%Docstring
|
||||
Returns the attribute index used to split into multiple layers.
|
||||
The attribute value is used for layer names.
|
||||
|
||||
.. seealso:: :py:func:`splitLayerAttribute`
|
||||
%End
|
||||
|
||||
QString splitLayerAttribute() const;
|
||||
%Docstring
|
||||
If the split layer attribute is set, the vector layer
|
||||
will be split into several dxf layers, one per each
|
||||
unique value.
|
||||
|
||||
.. versionadded:: 3.12
|
||||
%End
|
||||
|
||||
};
|
||||
@ -85,6 +96,8 @@ The attribute value is used for layer names.
|
||||
Constructor for QgsDxfExport.
|
||||
%End
|
||||
|
||||
~QgsDxfExport();
|
||||
|
||||
void setMapSettings( const QgsMapSettings &settings );
|
||||
%Docstring
|
||||
Set map settings and assign layer name attributes
|
||||
@ -471,6 +484,9 @@ Register name of layer for feature
|
||||
:param layer: dxf layer of feature
|
||||
%End
|
||||
|
||||
private:
|
||||
QgsDxfExport( const QgsDxfExport &other );
|
||||
QgsDxfExport &operator=( const QgsDxfExport & );
|
||||
};
|
||||
|
||||
QFlags<QgsDxfExport::Flag> operator|(QgsDxfExport::Flag f1, QFlags<QgsDxfExport::Flag> f2);
|
||||
|
@ -281,14 +281,13 @@ QList< QgsDxfExport::DxfLayer > QgsVectorLayerAndAttributeModel::layers() const
|
||||
QList< QgsDxfExport::DxfLayer > layers;
|
||||
QHash< QString, int > layerIdx;
|
||||
|
||||
const auto constMCheckedLeafs = mCheckedLeafs;
|
||||
for ( const QModelIndex &idx : constMCheckedLeafs )
|
||||
for ( const QModelIndex &idx : qgis::as_const( mCheckedLeafs ) )
|
||||
{
|
||||
QgsLayerTreeNode *node = index2node( idx );
|
||||
if ( QgsLayerTree::isGroup( node ) )
|
||||
{
|
||||
const auto constFindLayers = QgsLayerTree::toGroup( node )->findLayers();
|
||||
for ( QgsLayerTreeLayer *treeLayer : constFindLayers )
|
||||
const auto childLayers = QgsLayerTree::toGroup( node )->findLayers();
|
||||
for ( QgsLayerTreeLayer *treeLayer : childLayers )
|
||||
{
|
||||
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( treeLayer->layer() );
|
||||
Q_ASSERT( vl );
|
||||
|
@ -61,26 +61,11 @@
|
||||
|
||||
#include <QIODevice>
|
||||
|
||||
QgsDxfExport::QgsDxfExport( const QgsDxfExport &dxfExport )
|
||||
{
|
||||
*this = dxfExport;
|
||||
}
|
||||
QgsDxfExport::QgsDxfExport() = default;
|
||||
|
||||
QgsDxfExport &QgsDxfExport::operator=( const QgsDxfExport &dxfExport )
|
||||
QgsDxfExport::~QgsDxfExport()
|
||||
{
|
||||
mMapSettings = dxfExport.mMapSettings;
|
||||
mLayerNameAttribute = dxfExport.mLayerNameAttribute;
|
||||
mSymbologyScale = dxfExport.mSymbologyScale;
|
||||
mSymbologyExport = dxfExport.mSymbologyExport;
|
||||
mMapUnits = dxfExport.mMapUnits;
|
||||
mLayerTitleAsName = dxfExport.mLayerTitleAsName;
|
||||
mSymbolLayerCounter = 0; // internal counter
|
||||
mNextHandleId = 0;
|
||||
mBlockCounter = 0;
|
||||
mCrs = QgsCoordinateReferenceSystem();
|
||||
mFactor = dxfExport.mFactor;
|
||||
mForce2d = dxfExport.mForce2d;
|
||||
return *this;
|
||||
qDeleteAll( mJobs );
|
||||
}
|
||||
|
||||
void QgsDxfExport::setMapSettings( const QgsMapSettings &settings )
|
||||
@ -248,10 +233,12 @@ QgsDxfExport::ExportResult QgsDxfExport::writeToFile( QIODevice *d, const QStrin
|
||||
mMapSettings.setOutputDpi( dpi );
|
||||
|
||||
writeHeader( dxfEncoding( encoding ) );
|
||||
prepareRenderers();
|
||||
writeTables();
|
||||
writeBlocks();
|
||||
writeEntities();
|
||||
writeEndFile();
|
||||
stopRenderers();
|
||||
|
||||
return ExportResult::Success;
|
||||
}
|
||||
@ -560,7 +547,7 @@ void QgsDxfExport::writeBlocks()
|
||||
startSection();
|
||||
writeGroup( 2, QStringLiteral( "BLOCKS" ) );
|
||||
|
||||
const QStringList blockStrings = QStringList() << QStringLiteral( "*Model_Space" ) << QStringLiteral( "*Paper_Space" ) << QStringLiteral( "*Paper_Space0" );
|
||||
static const QStringList blockStrings = QStringList() << QStringLiteral( "*Model_Space" ) << QStringLiteral( "*Paper_Space" ) << QStringLiteral( "*Paper_Space0" );
|
||||
for ( const QString &block : blockStrings )
|
||||
{
|
||||
writeGroup( 0, QStringLiteral( "BLOCK" ) );
|
||||
@ -598,13 +585,11 @@ void QgsDxfExport::writeBlocks()
|
||||
|
||||
// if point symbol layer and no data defined properties: write block
|
||||
QgsSymbolRenderContext ctx( ct, QgsUnitTypes::RenderMapUnits, symbolLayer.second->opacity(), false, symbolLayer.second->renderHints(), nullptr );
|
||||
ml->startRender( ctx );
|
||||
|
||||
// markers with data defined properties are inserted inline
|
||||
if ( hasDataDefinedProperties( ml, symbolLayer.second ) )
|
||||
{
|
||||
continue;
|
||||
// ml->stopRender( ctx );
|
||||
}
|
||||
|
||||
QString block( QStringLiteral( "symbolLayer%1" ).arg( mBlockCounter++ ) );
|
||||
@ -637,7 +622,6 @@ void QgsDxfExport::writeBlocks()
|
||||
writeGroup( 100, QStringLiteral( "AcDbBlockEnd" ) );
|
||||
|
||||
mPointSymbolBlocks.insert( ml, block );
|
||||
ml->stopRender( ctx );
|
||||
}
|
||||
endSection();
|
||||
}
|
||||
@ -650,127 +634,36 @@ void QgsDxfExport::writeEntities()
|
||||
|
||||
mBlockHandle = QStringLiteral( "%1" ).arg( mBlockHandles[ QStringLiteral( "*Model_Space" )], 0, 16 );
|
||||
|
||||
QImage image( 10, 10, QImage::Format_ARGB32_Premultiplied );
|
||||
image.setDotsPerMeterX( 96 / 25.4 * 1000 );
|
||||
image.setDotsPerMeterY( 96 / 25.4 * 1000 );
|
||||
QPainter painter( &image );
|
||||
|
||||
QgsRenderContext ctx;
|
||||
ctx.setPainter( &painter );
|
||||
ctx.setRendererScale( mSymbologyScale );
|
||||
ctx.setExtent( mExtent );
|
||||
|
||||
ctx.setScaleFactor( 96.0 / 25.4 );
|
||||
ctx.setMapToPixel( QgsMapToPixel( 1.0 / mFactor, mExtent.center().x(), mExtent.center().y(), mExtent.width() * mFactor,
|
||||
mExtent.height() * mFactor, 0 ) );
|
||||
|
||||
ctx.expressionContext().appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
|
||||
ctx.expressionContext().appendScope( QgsExpressionContextUtils::globalScope() );
|
||||
|
||||
// label engine
|
||||
QgsDefaultLabelingEngine engine;
|
||||
engine.setMapSettings( mMapSettings );
|
||||
|
||||
// iterate through the maplayers
|
||||
const QList< QgsMapLayer *> layers = mMapSettings.layers();
|
||||
for ( QgsMapLayer *ml : layers )
|
||||
for ( DxfLayerJob *job : qgis::as_const( mJobs ) )
|
||||
{
|
||||
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml );
|
||||
if ( !vl || !layerIsScaleBasedVisible( vl ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
QgsMapLayerStyleOverride styleOverride( vl );
|
||||
if ( mMapSettings.layerStyleOverrides().contains( vl->id() ) )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "%1: apply override style" ).arg( vl->id() ) );
|
||||
styleOverride.setOverrideStyle( mMapSettings.layerStyleOverrides().value( vl->id() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "%1: no override style" ).arg( vl->id() ) );
|
||||
}
|
||||
|
||||
if ( !vl->renderer() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto scopePopper = [&ctx]( QgsExpressionContextScope * scope )
|
||||
{
|
||||
Q_UNUSED( scope )
|
||||
delete ctx.expressionContext().popScope();
|
||||
};
|
||||
std::unique_ptr<QgsExpressionContextScope, decltype( scopePopper ) > layerScope( QgsExpressionContextUtils::layerScope( ml ), scopePopper );
|
||||
ctx.expressionContext().appendScope( layerScope.get() );
|
||||
QgsSymbolRenderContext sctx( ctx, QgsUnitTypes::RenderMillimeters, 1.0, false, nullptr, nullptr );
|
||||
|
||||
std::unique_ptr< QgsFeatureRenderer > renderer( vl->renderer()->clone() );
|
||||
renderer->startRender( ctx, vl->fields() );
|
||||
|
||||
QSet<QString> attributes = renderer->usedAttributes( ctx );
|
||||
int attrIdx = mLayerNameAttribute.value( vl->id(), -1 );
|
||||
if ( vl->fields().exists( attrIdx ) )
|
||||
{
|
||||
QString layerAttr = vl->fields().at( attrIdx ).name();
|
||||
attributes << layerAttr;
|
||||
}
|
||||
|
||||
const QgsAbstractVectorLayerLabeling *labeling = vl->labelsEnabled() ? vl->labeling() : nullptr;
|
||||
QgsDxfLabelProvider *lp = nullptr;
|
||||
QgsDxfRuleBasedLabelProvider *rblp = nullptr;
|
||||
if ( const QgsRuleBasedLabeling *rbl = dynamic_cast<const QgsRuleBasedLabeling *>( labeling ) )
|
||||
{
|
||||
rblp = new QgsDxfRuleBasedLabelProvider( *rbl, vl, this );
|
||||
rblp->reinit( vl );
|
||||
engine.addProvider( rblp );
|
||||
|
||||
if ( !rblp->prepare( ctx, attributes ) )
|
||||
{
|
||||
engine.removeProvider( rblp );
|
||||
rblp = nullptr;
|
||||
}
|
||||
}
|
||||
else if ( labeling )
|
||||
{
|
||||
QgsPalLayerSettings settings = labeling->settings();
|
||||
lp = new QgsDxfLabelProvider( vl, QString(), this, &settings );
|
||||
engine.addProvider( lp );
|
||||
|
||||
if ( !lp->prepare( ctx, attributes ) )
|
||||
{
|
||||
engine.removeProvider( lp );
|
||||
lp = nullptr;
|
||||
}
|
||||
}
|
||||
QgsSymbolRenderContext sctx( mRenderContext, QgsUnitTypes::RenderMillimeters, 1.0, false, nullptr, nullptr );
|
||||
|
||||
if ( mSymbologyExport == QgsDxfExport::SymbolLayerSymbology &&
|
||||
( renderer->capabilities() & QgsFeatureRenderer::SymbolLevels ) &&
|
||||
renderer->usingSymbolLevels() )
|
||||
( job->renderer->capabilities() & QgsFeatureRenderer::SymbolLevels ) &&
|
||||
job->renderer->usingSymbolLevels() )
|
||||
{
|
||||
writeEntitiesSymbolLevels( vl );
|
||||
renderer->stopRender( ctx );
|
||||
writeEntitiesSymbolLevels( job );
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
QgsFeatureRequest freq = QgsFeatureRequest().setSubsetOfAttributes( attributes, vl->fields() ).setExpressionContext( ctx.expressionContext() );
|
||||
freq.setFilterRect( mMapSettings.mapToLayerCoordinates( vl, mExtent ) );
|
||||
QgsCoordinateTransform ct( mMapSettings.destinationCrs(), job->crs, mMapSettings.transformContext() );
|
||||
|
||||
QgsFeatureIterator featureIt = vl->getFeatures( freq );
|
||||
QgsFeatureRequest request = QgsFeatureRequest().setSubsetOfAttributes( job->attributes, job->fields ).setExpressionContext( job->expressionContext );
|
||||
request.setFilterRect( ct.transform( mExtent ) );
|
||||
|
||||
QgsCoordinateTransform ct = mMapSettings.layerTransform( vl );
|
||||
QgsFeatureIterator featureIt = job->featureSource.getFeatures( request );
|
||||
|
||||
QgsFeature fet;
|
||||
while ( featureIt.nextFeature( fet ) )
|
||||
{
|
||||
ctx.expressionContext().setFeature( fet );
|
||||
QString lName( dxfLayerName( attrIdx < 0 ? layerName( vl ) : fet.attribute( attrIdx ).toString() ) );
|
||||
mRenderContext.expressionContext().setFeature( fet );
|
||||
QString lName( dxfLayerName( job->splitLayerAttribute.isNull() ? job->layerTitle : fet.attribute( job->splitLayerAttribute ).toString() ) );
|
||||
|
||||
sctx.setFeature( &fet );
|
||||
|
||||
if ( !renderer->willRenderFeature( fet, ctx ) )
|
||||
if ( !job->renderer->willRenderFeature( fet, mRenderContext ) )
|
||||
continue;
|
||||
|
||||
if ( mSymbologyExport == NoSymbology )
|
||||
@ -779,7 +672,7 @@ void QgsDxfExport::writeEntities()
|
||||
}
|
||||
else
|
||||
{
|
||||
const QgsSymbolList symbolList = renderer->symbolsForFeature( fet, ctx );
|
||||
const QgsSymbolList symbolList = job->renderer->symbolsForFeature( fet, mRenderContext );
|
||||
bool hasSymbology = symbolList.size() > 0;
|
||||
|
||||
if ( hasSymbology && mSymbologyExport == QgsDxfExport::SymbolLayerSymbology ) // symbol layer symbology, but layer does not use symbol levels
|
||||
@ -823,55 +716,88 @@ void QgsDxfExport::writeEntities()
|
||||
}
|
||||
}
|
||||
|
||||
if ( lp )
|
||||
if ( job->labelProvider )
|
||||
{
|
||||
lp->registerDxfFeature( fet, ctx, lName );
|
||||
job->labelProvider->registerDxfFeature( fet, mRenderContext, lName );
|
||||
}
|
||||
else if ( rblp )
|
||||
else if ( job->ruleBasedLabelProvider )
|
||||
{
|
||||
rblp->registerDxfFeature( fet, ctx, lName );
|
||||
job->ruleBasedLabelProvider->registerDxfFeature( fet, mRenderContext, lName );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
renderer->stopRender( ctx );
|
||||
}
|
||||
|
||||
engine.run( ctx );
|
||||
QImage image( 10, 10, QImage::Format_ARGB32_Premultiplied );
|
||||
image.setDotsPerMeterX( 96 / 25.4 * 1000 );
|
||||
image.setDotsPerMeterY( 96 / 25.4 * 1000 );
|
||||
QPainter painter( &image );
|
||||
mRenderContext.setPainter( &painter );
|
||||
|
||||
mRenderContext.labelingEngine()->run( mRenderContext );
|
||||
|
||||
endSection();
|
||||
}
|
||||
|
||||
void QgsDxfExport::writeEntitiesSymbolLevels( QgsVectorLayer *layer )
|
||||
void QgsDxfExport::prepareRenderers()
|
||||
{
|
||||
if ( !layer )
|
||||
{
|
||||
return;
|
||||
}
|
||||
Q_ASSERT( mJobs.empty() ); // If this fails, stopRenderers() was not called after the last job
|
||||
|
||||
if ( !layer->renderer() )
|
||||
mRenderContext = QgsRenderContext();
|
||||
mRenderContext.setRendererScale( mSymbologyScale );
|
||||
mRenderContext.setExtent( mExtent );
|
||||
|
||||
mRenderContext.setScaleFactor( 96.0 / 25.4 );
|
||||
mRenderContext.setMapToPixel( QgsMapToPixel( 1.0 / mFactor, mExtent.center().x(), mExtent.center().y(), mExtent.width() * mFactor,
|
||||
mExtent.height() * mFactor, 0 ) );
|
||||
|
||||
mRenderContext.expressionContext().appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
|
||||
mRenderContext.expressionContext().appendScope( QgsExpressionContextUtils::globalScope() );
|
||||
|
||||
mLabelingEngine = qgis::make_unique<QgsDefaultLabelingEngine>();
|
||||
mLabelingEngine->setMapSettings( mMapSettings );
|
||||
mRenderContext.setLabelingEngine( mLabelingEngine.get() );
|
||||
|
||||
const QList< QgsMapLayer * > layers = mMapSettings.layers();
|
||||
for ( QgsMapLayer *ml : layers )
|
||||
{
|
||||
// TODO return error
|
||||
return;
|
||||
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml );
|
||||
if ( !vl )
|
||||
continue;
|
||||
|
||||
if ( !vl->renderer() )
|
||||
continue;
|
||||
|
||||
if ( !layerIsScaleBasedVisible( vl ) )
|
||||
continue;
|
||||
|
||||
QString splitLayerAttribute;
|
||||
int splitLayerAttributeIndex = mLayerNameAttribute.value( vl->id(), -1 );
|
||||
const QgsFields fields = vl->fields();
|
||||
if ( splitLayerAttributeIndex >= 0 && splitLayerAttributeIndex < fields.size() )
|
||||
splitLayerAttribute = fields.at( splitLayerAttributeIndex ).name();
|
||||
DxfLayerJob *job = new DxfLayerJob( vl, mMapSettings.layerStyleOverrides().value( vl->id() ), mRenderContext, this, splitLayerAttribute );
|
||||
mJobs.append( job );
|
||||
}
|
||||
std::unique_ptr< QgsFeatureRenderer > renderer( layer->renderer()->clone() );
|
||||
}
|
||||
|
||||
void QgsDxfExport::writeEntitiesSymbolLevels( DxfLayerJob *job )
|
||||
{
|
||||
QHash< QgsSymbol *, QList<QgsFeature> > features;
|
||||
|
||||
QgsRenderContext ctx = renderContext();
|
||||
ctx.expressionContext().appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) );
|
||||
const QList<QgsExpressionContextScope *> scopes = job->expressionContext.scopes();
|
||||
for ( QgsExpressionContextScope *scope : scopes )
|
||||
ctx.expressionContext().appendScope( new QgsExpressionContextScope( *scope ) );
|
||||
QgsSymbolRenderContext sctx( ctx, QgsUnitTypes::RenderMillimeters, 1.0, false, nullptr, nullptr );
|
||||
renderer->startRender( ctx, layer->fields() );
|
||||
|
||||
// get iterator
|
||||
QgsFeatureRequest req;
|
||||
if ( layer->wkbType() == QgsWkbTypes::NoGeometry )
|
||||
{
|
||||
req.setFlags( QgsFeatureRequest::NoGeometry );
|
||||
}
|
||||
req.setSubsetOfAttributes( renderer->usedAttributes( ctx ), layer->fields() );
|
||||
req.setFilterRect( mMapSettings.mapToLayerCoordinates( layer, mExtent ) );
|
||||
req.setSubsetOfAttributes( job->renderer->usedAttributes( ctx ), job->featureSource.fields() );
|
||||
QgsCoordinateTransform ct( mMapSettings.destinationCrs(), job->crs, mMapSettings.transformContext() );
|
||||
req.setFilterRect( ct.transform( mExtent ) );
|
||||
|
||||
QgsFeatureIterator fit = layer->getFeatures( req );
|
||||
QgsFeatureIterator fit = job->featureSource.getFeatures( req );
|
||||
|
||||
// fetch features
|
||||
QgsFeature fet;
|
||||
@ -879,7 +805,7 @@ void QgsDxfExport::writeEntitiesSymbolLevels( QgsVectorLayer *layer )
|
||||
while ( fit.nextFeature( fet ) )
|
||||
{
|
||||
ctx.expressionContext().setFeature( fet );
|
||||
featureSymbol = renderer->symbolForFeature( fet, ctx );
|
||||
featureSymbol = job->renderer->symbolForFeature( fet, ctx );
|
||||
if ( !featureSymbol )
|
||||
{
|
||||
continue;
|
||||
@ -895,7 +821,7 @@ void QgsDxfExport::writeEntitiesSymbolLevels( QgsVectorLayer *layer )
|
||||
|
||||
// find out order
|
||||
QgsSymbolLevelOrder levels;
|
||||
const QgsSymbolList symbols = renderer->symbols( ctx );
|
||||
const QgsSymbolList symbols = job->renderer->symbols( ctx );
|
||||
for ( QgsSymbol *symbol : symbols )
|
||||
{
|
||||
for ( int j = 0; j < symbol->symbolLayerCount(); j++ )
|
||||
@ -910,8 +836,6 @@ void QgsDxfExport::writeEntitiesSymbolLevels( QgsVectorLayer *layer )
|
||||
}
|
||||
}
|
||||
|
||||
QgsCoordinateTransform ct = mMapSettings.layerTransform( layer );
|
||||
|
||||
// export symbol layers and symbology
|
||||
for ( const QgsSymbolLevel &level : qgis::as_const( levels ) )
|
||||
{
|
||||
@ -928,11 +852,16 @@ void QgsDxfExport::writeEntitiesSymbolLevels( QgsVectorLayer *layer )
|
||||
for ( const QgsFeature &feature : featureList )
|
||||
{
|
||||
sctx.setFeature( &feature );
|
||||
addFeature( sctx, ct, layer->name(), levelIt.key()->symbolLayer( llayer ), levelIt.key() );
|
||||
addFeature( sctx, ct, job->layerName, levelIt.key()->symbolLayer( llayer ), levelIt.key() );
|
||||
}
|
||||
}
|
||||
}
|
||||
renderer->stopRender( ctx );
|
||||
}
|
||||
|
||||
void QgsDxfExport::stopRenderers()
|
||||
{
|
||||
qDeleteAll( mJobs );
|
||||
mJobs.clear();
|
||||
}
|
||||
|
||||
void QgsDxfExport::writeEndFile()
|
||||
@ -1803,9 +1732,7 @@ QRgb QgsDxfExport::createRgbEntry( qreal r, qreal g, qreal b )
|
||||
|
||||
QgsRenderContext QgsDxfExport::renderContext() const
|
||||
{
|
||||
QgsRenderContext context;
|
||||
context.setRendererScale( mSymbologyScale );
|
||||
return context;
|
||||
return mRenderContext;
|
||||
}
|
||||
|
||||
double QgsDxfExport::mapUnitScaleFactor( double scale, QgsUnitTypes::RenderUnit symbolUnits, QgsUnitTypes::DistanceUnit mapUnits, double mapUnitsPerPixel )
|
||||
@ -1861,35 +1788,20 @@ QList< QPair< QgsSymbolLayer *, QgsSymbol * > > QgsDxfExport::symbolLayers( QgsR
|
||||
{
|
||||
QList< QPair< QgsSymbolLayer *, QgsSymbol * > > symbolLayers;
|
||||
|
||||
const QList< QgsMapLayer * > layers = mMapSettings.layers();
|
||||
for ( QgsMapLayer *ml : layers )
|
||||
for ( DxfLayerJob *job : mJobs )
|
||||
{
|
||||
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml );
|
||||
if ( !vl )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const QgsSymbolList symbols = job->renderer->symbols( context );
|
||||
|
||||
// get renderer
|
||||
QgsFeatureRenderer *r = vl->renderer();
|
||||
if ( !r )
|
||||
for ( QgsSymbol *symbol : symbols )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// get all symbols
|
||||
QgsSymbolList symbols = r->symbols( context );
|
||||
QgsSymbolList::iterator symbolIt = symbols.begin();
|
||||
for ( ; symbolIt != symbols.end(); ++symbolIt )
|
||||
{
|
||||
int maxSymbolLayers = ( *symbolIt )->symbolLayerCount();
|
||||
int maxSymbolLayers = symbol->symbolLayerCount();
|
||||
if ( mSymbologyExport != SymbolLayerSymbology )
|
||||
{
|
||||
maxSymbolLayers = 1;
|
||||
}
|
||||
for ( int i = 0; i < maxSymbolLayers; ++i )
|
||||
{
|
||||
symbolLayers.append( qMakePair( ( *symbolIt )->symbolLayer( i ), *symbolIt ) );
|
||||
symbolLayers.append( qMakePair( symbol->symbolLayer( i ), symbol ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1900,8 +1812,7 @@ QList< QPair< QgsSymbolLayer *, QgsSymbol * > > QgsDxfExport::symbolLayers( QgsR
|
||||
void QgsDxfExport::writeDefaultLinetypes()
|
||||
{
|
||||
// continuous (Qt solid line)
|
||||
const QStringList blockStrings = QStringList() << QStringLiteral( "ByLayer" ) << QStringLiteral( "ByBlock" ) << QStringLiteral( "CONTINUOUS" );
|
||||
for ( const QString <ype : blockStrings )
|
||||
for ( const QString <ype : { QStringLiteral( "ByLayer" ), QStringLiteral( "ByBlock" ), QStringLiteral( "CONTINUOUS" ) } )
|
||||
{
|
||||
writeGroup( 0, QStringLiteral( "LTYPE" ) );
|
||||
writeHandle();
|
||||
@ -1983,10 +1894,9 @@ int QgsDxfExport::nLineTypes( const QList< QPair< QgsSymbolLayer *, QgsSymbol *
|
||||
void QgsDxfExport::writeLinetype( const QString &styleName, const QVector<qreal> &pattern, QgsUnitTypes::RenderUnit u )
|
||||
{
|
||||
double length = 0;
|
||||
QVector<qreal>::const_iterator dashIt = pattern.constBegin();
|
||||
for ( ; dashIt != pattern.constEnd(); ++dashIt )
|
||||
for ( qreal size : pattern )
|
||||
{
|
||||
length += ( *dashIt * mapUnitScaleFactor( mSymbologyScale, u, mMapUnits, mMapSettings.mapToPixel().mapUnitsPerPixel() ) );
|
||||
length += ( size * mapUnitScaleFactor( mSymbologyScale, u, mMapUnits, mMapSettings.mapToPixel().mapUnitsPerPixel() ) );
|
||||
}
|
||||
|
||||
writeGroup( 0, QStringLiteral( "LTYPE" ) );
|
||||
@ -2001,12 +1911,11 @@ void QgsDxfExport::writeLinetype( const QString &styleName, const QVector<qreal>
|
||||
writeGroup( 73, pattern.size() );
|
||||
writeGroup( 40, length );
|
||||
|
||||
dashIt = pattern.constBegin();
|
||||
bool isGap = false;
|
||||
for ( ; dashIt != pattern.constEnd(); ++dashIt )
|
||||
for ( qreal size : pattern )
|
||||
{
|
||||
// map units or mm?
|
||||
double segmentLength = ( isGap ? -*dashIt : *dashIt );
|
||||
double segmentLength = ( isGap ? -size : size );
|
||||
segmentLength *= mapUnitScaleFactor( mSymbologyScale, u, mMapUnits, mMapSettings.mapToPixel().mapUnitsPerPixel() );
|
||||
writeGroup( 49, segmentLength );
|
||||
writeGroup( 74, 0 );
|
||||
@ -2156,6 +2065,7 @@ bool QgsDxfExport::layerIsScaleBasedVisible( const QgsMapLayer *layer ) const
|
||||
|
||||
QString QgsDxfExport::layerName( const QString &id, const QgsFeature &f ) const
|
||||
{
|
||||
// TODO: make this thread safe
|
||||
const QList< QgsMapLayer * > layers = mMapSettings.layers();
|
||||
for ( QgsMapLayer *ml : layers )
|
||||
{
|
||||
@ -2378,3 +2288,15 @@ QgsCoordinateReferenceSystem QgsDxfExport::destinationCrs() const
|
||||
{
|
||||
return mCrs;
|
||||
}
|
||||
|
||||
QString QgsDxfExport::DxfLayer::splitLayerAttribute() const
|
||||
{
|
||||
QString splitLayerFieldName;
|
||||
const QgsFields fields = mLayer->fields();
|
||||
if ( mLayerOutputAttributeIndex >= 0 && mLayerOutputAttributeIndex < fields.size() )
|
||||
{
|
||||
splitLayerFieldName = fields.at( mLayerOutputAttributeIndex ).name();
|
||||
}
|
||||
|
||||
return splitLayerFieldName;
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ class QgsCurve;
|
||||
class QgsCurvePolygon;
|
||||
class QgsCircularString;
|
||||
class QgsCompoundCurve;
|
||||
struct DxfLayerJob;
|
||||
|
||||
#define DXF_HANDSEED 100
|
||||
#define DXF_HANDMAX 9999999
|
||||
@ -73,9 +74,18 @@ class CORE_EXPORT QgsDxfExport
|
||||
/**
|
||||
* Returns the attribute index used to split into multiple layers.
|
||||
* The attribute value is used for layer names.
|
||||
* \see splitLayerAttribute
|
||||
*/
|
||||
int layerOutputAttributeIndex() const {return mLayerOutputAttributeIndex;}
|
||||
|
||||
/**
|
||||
* If the split layer attribute is set, the vector layer
|
||||
* will be split into several dxf layers, one per each
|
||||
* unique value.
|
||||
* \since QGIS 3.12
|
||||
*/
|
||||
QString splitLayerAttribute() const;
|
||||
|
||||
private:
|
||||
QgsVectorLayer *mLayer = nullptr;
|
||||
int mLayerOutputAttributeIndex = -1;
|
||||
@ -135,9 +145,9 @@ class CORE_EXPORT QgsDxfExport
|
||||
/**
|
||||
* Constructor for QgsDxfExport.
|
||||
*/
|
||||
QgsDxfExport() = default;
|
||||
QgsDxfExport( const QgsDxfExport &dxfExport ) SIP_SKIP;
|
||||
QgsDxfExport &operator=( const QgsDxfExport &dxfExport );
|
||||
QgsDxfExport();
|
||||
|
||||
~QgsDxfExport();
|
||||
|
||||
/**
|
||||
* Set map settings and assign layer name attributes
|
||||
@ -493,6 +503,11 @@ class CORE_EXPORT QgsDxfExport
|
||||
void registerDxfLayer( const QString &layerId, QgsFeatureId fid, const QString &layer );
|
||||
|
||||
private:
|
||||
|
||||
#ifdef SIP_RUN
|
||||
QgsDxfExport( const QgsDxfExport &other );
|
||||
QgsDxfExport &operator=( const QgsDxfExport & );
|
||||
#endif
|
||||
//! Extent for export, only intersecting features are exported. If the extent is an empty rectangle, all features are exported
|
||||
QgsRectangle mExtent;
|
||||
//! Scale for symbology export (used if symbols units are mm)
|
||||
@ -512,10 +527,12 @@ class CORE_EXPORT QgsDxfExport
|
||||
|
||||
//AC1009
|
||||
void writeHeader( const QString &codepage );
|
||||
void prepareRenderers();
|
||||
void writeTables();
|
||||
void writeBlocks();
|
||||
void writeEntities();
|
||||
void writeEntitiesSymbolLevels( QgsVectorLayer *layer );
|
||||
void writeEntitiesSymbolLevels( DxfLayerJob *job );
|
||||
void stopRenderers();
|
||||
void writeEndFile();
|
||||
|
||||
void startSection();
|
||||
@ -581,6 +598,11 @@ class CORE_EXPORT QgsDxfExport
|
||||
void appendLineString( const QgsLineString &ls, QVector<QgsPoint> &points, QVector<double> &bulges );
|
||||
void appendCircularString( const QgsCircularString &cs, QVector<QgsPoint> &points, QVector<double> &bulges );
|
||||
void appendCompoundCurve( const QgsCompoundCurve &cc, QVector<QgsPoint> &points, QVector<double> &bulges );
|
||||
|
||||
QgsRenderContext mRenderContext;
|
||||
// Internal cache for layer related information required during rendering
|
||||
QList<DxfLayerJob *> mJobs;
|
||||
std::unique_ptr<QgsLabelingEngine> mLabelingEngine;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( QgsDxfExport::Flags )
|
||||
|
@ -15,6 +15,96 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsexpressioncontext.h"
|
||||
#include "qgsexpressioncontextutils.h"
|
||||
#include "qgsvectorlayerfeatureiterator.h"
|
||||
#include "qgsrenderer.h"
|
||||
#include "qgsvectorlayerlabeling.h"
|
||||
#include "qgsdxfpallabeling.h"
|
||||
|
||||
/**
|
||||
* Holds information about each layer in a DXF job.
|
||||
* This can be used for multithreading.
|
||||
*/
|
||||
struct DxfLayerJob
|
||||
{
|
||||
DxfLayerJob( QgsVectorLayer *vl, const QString &layerStyleOverride, QgsRenderContext &renderContext, QgsDxfExport *dxfExport, const QString &splitLayerAttribute )
|
||||
: styleOverride( vl )
|
||||
, expressionContext( renderContext.expressionContext() )
|
||||
, featureSource( vl )
|
||||
, dxfExport( dxfExport )
|
||||
, crs( vl->crs() )
|
||||
, layerName( vl->name() )
|
||||
, splitLayerAttribute( splitLayerAttribute )
|
||||
, layerTitle( vl->title().isEmpty() ? vl->name() : vl->title() )
|
||||
{
|
||||
fields = vl->fields();
|
||||
renderer.reset( vl->renderer()->clone() );
|
||||
expressionContext.appendScope( vl->createExpressionContextScope() );
|
||||
|
||||
if ( !layerStyleOverride.isNull() )
|
||||
{
|
||||
styleOverride.setOverrideStyle( layerStyleOverride );
|
||||
}
|
||||
|
||||
labeling.reset( vl->labelsEnabled() ? vl->labeling()->clone() : nullptr );
|
||||
|
||||
attributes = renderer->usedAttributes( renderContext );
|
||||
if ( !splitLayerAttribute.isNull() )
|
||||
{
|
||||
attributes << splitLayerAttribute;
|
||||
}
|
||||
|
||||
if ( labeling )
|
||||
{
|
||||
QgsLabelingEngine *labelingEngine = renderContext.labelingEngine();
|
||||
if ( const QgsRuleBasedLabeling *rbl = dynamic_cast<const QgsRuleBasedLabeling *>( labeling.get() ) )
|
||||
{
|
||||
ruleBasedLabelProvider = new QgsDxfRuleBasedLabelProvider( *rbl, vl, dxfExport );
|
||||
labelingEngine->addProvider( ruleBasedLabelProvider );
|
||||
|
||||
if ( !ruleBasedLabelProvider->prepare( renderContext, attributes ) )
|
||||
{
|
||||
labelingEngine->removeProvider( ruleBasedLabelProvider );
|
||||
ruleBasedLabelProvider = nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsPalLayerSettings settings = labeling->settings();
|
||||
labelProvider = new QgsDxfLabelProvider( vl, QString(), dxfExport, &settings );
|
||||
labelingEngine->addProvider( labelProvider );
|
||||
|
||||
if ( !labelProvider->prepare( renderContext, attributes ) )
|
||||
{
|
||||
labelingEngine->removeProvider( labelProvider );
|
||||
labelProvider = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This will need to be started in a separate thread, if threaded somewhere else to
|
||||
renderer->startRender( renderContext, fields );
|
||||
};
|
||||
|
||||
QgsFields fields;
|
||||
QgsMapLayerStyleOverride styleOverride;
|
||||
QgsExpressionContext expressionContext;
|
||||
QgsVectorLayerFeatureSource featureSource;
|
||||
std::unique_ptr< QgsFeatureRenderer > renderer;
|
||||
std::unique_ptr<QgsAbstractVectorLayerLabeling> labeling;
|
||||
QgsDxfExport *dxfExport = nullptr;
|
||||
QgsCoordinateReferenceSystem crs;
|
||||
QString layerName;
|
||||
QgsDxfLabelProvider *labelProvider = nullptr;
|
||||
QgsDxfRuleBasedLabelProvider *ruleBasedLabelProvider = nullptr;
|
||||
QString splitLayerAttribute;
|
||||
QString layerTitle;
|
||||
QSet<QString> attributes;
|
||||
};
|
||||
|
||||
// dxf color palette
|
||||
static int sDxfColors[][3] =
|
||||
{
|
||||
|
@ -44,6 +44,7 @@ QgsDxfRuleBasedLabelProvider::QgsDxfRuleBasedLabelProvider( const QgsRuleBasedLa
|
||||
: QgsRuleBasedLabelProvider( rules, layer, false )
|
||||
, mDxfExport( dxf )
|
||||
{
|
||||
mRules->rootRule()->createSubProviders( layer, mSubProviders, this );
|
||||
}
|
||||
|
||||
void QgsDxfRuleBasedLabelProvider::reinit( QgsVectorLayer *layer )
|
||||
|
@ -78,8 +78,9 @@ class QgsDxfRuleBasedLabelProvider : public QgsRuleBasedLabelProvider
|
||||
/**
|
||||
* Reinitialize the subproviders with QgsDxfLabelProviders
|
||||
* \param layer layer
|
||||
* \deprecated since QGIS 3.12
|
||||
*/
|
||||
void reinit( QgsVectorLayer *layer );
|
||||
Q_DECL_DEPRECATED void reinit( QgsVectorLayer *layer );
|
||||
|
||||
/**
|
||||
* Re-implementation that writes to DXF file instead of drawing with QPainter
|
||||
|
@ -489,7 +489,7 @@ class CORE_EXPORT QgsRenderContext
|
||||
* Assign new labeling engine
|
||||
* \note not available in Python bindings
|
||||
*/
|
||||
void setLabelingEngine( QgsLabelingEngine *engine2 ) { mLabelingEngine = engine2; } SIP_SKIP
|
||||
void setLabelingEngine( QgsLabelingEngine *engine ) { mLabelingEngine = engine; } SIP_SKIP
|
||||
|
||||
/**
|
||||
* Sets the \a color to use when rendering selected features.
|
||||
|
@ -38,8 +38,8 @@ namespace QgsWms
|
||||
|
||||
// Write output
|
||||
QgsRenderer renderer( context );
|
||||
QgsDxfExport dxf = renderer.getDxf();
|
||||
std::unique_ptr<QgsDxfExport> dxf = renderer.getDxf();
|
||||
response.setHeader( "Content-Type", "application/dxf" );
|
||||
dxf.writeToFile( response.io(), parameters.dxfCodec() );
|
||||
dxf->writeToFile( response.io(), parameters.dxfCodec() );
|
||||
}
|
||||
} // namespace QgsWms
|
||||
|
@ -804,7 +804,7 @@ namespace QgsWms
|
||||
return image.release();
|
||||
}
|
||||
|
||||
QgsDxfExport QgsRenderer::getDxf()
|
||||
std::unique_ptr<QgsDxfExport> QgsRenderer::getDxf()
|
||||
{
|
||||
// init layer restorer before doing anything
|
||||
std::unique_ptr<QgsLayerRestorer> restorer;
|
||||
@ -838,14 +838,14 @@ namespace QgsWms
|
||||
}
|
||||
|
||||
// add layers to dxf
|
||||
QgsDxfExport dxf;
|
||||
dxf.setExtent( mWmsParameters.bboxAsRectangle() );
|
||||
dxf.addLayers( dxfLayers );
|
||||
dxf.setLayerTitleAsName( mWmsParameters.dxfUseLayerTitleAsName() );
|
||||
dxf.setSymbologyExport( mWmsParameters.dxfMode() );
|
||||
std::unique_ptr<QgsDxfExport> dxf = qgis::make_unique<QgsDxfExport>();
|
||||
dxf->setExtent( mWmsParameters.bboxAsRectangle() );
|
||||
dxf->addLayers( dxfLayers );
|
||||
dxf->setLayerTitleAsName( mWmsParameters.dxfUseLayerTitleAsName() );
|
||||
dxf->setSymbologyExport( mWmsParameters.dxfMode() );
|
||||
if ( mWmsParameters.dxfFormatOptions().contains( QgsWmsParameters::DxfFormatOption::SCALE ) )
|
||||
{
|
||||
dxf.setSymbologyScale( mWmsParameters.dxfScale() );
|
||||
dxf->setSymbologyScale( mWmsParameters.dxfScale() );
|
||||
}
|
||||
|
||||
return dxf;
|
||||
|
@ -124,7 +124,7 @@ namespace QgsWms
|
||||
* \returns the map as DXF data
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
QgsDxfExport getDxf();
|
||||
std::unique_ptr<QgsDxfExport> getDxf();
|
||||
|
||||
/**
|
||||
* Returns printed page as binary
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "qgslabelingengine.h"
|
||||
#include "qgssinglesymbolrenderer.h"
|
||||
#include "qgsvectorlayerlabeling.h"
|
||||
#include "qgslinesymbollayer.h"
|
||||
#include <QTemporaryFile>
|
||||
|
||||
Q_DECLARE_METATYPE( QgsDxfExport::HAlign )
|
||||
@ -49,7 +50,7 @@ class TestQgsDxfExport : public QObject
|
||||
void testPolygons();
|
||||
void testMultiSurface();
|
||||
void testMtext();
|
||||
void testMTextNoSymbology(); //tests if label export works if layer has vector renderer type 'no symbols'
|
||||
void testMtext_data();
|
||||
void testMTextEscapeSpaces();
|
||||
void testText();
|
||||
void testTextAlign();
|
||||
@ -57,6 +58,7 @@ class TestQgsDxfExport : public QObject
|
||||
void testGeometryGeneratorExport();
|
||||
void testCurveExport();
|
||||
void testCurveExport_data();
|
||||
void testDashedLine();
|
||||
|
||||
private:
|
||||
QgsVectorLayer *mPointLayer = nullptr;
|
||||
@ -71,7 +73,6 @@ class TestQgsDxfExport : public QObject
|
||||
QString getTempFileName( const QString &file ) const;
|
||||
|
||||
bool fileContainsText( const QString &path, const QString &text, QString *debugInfo = nullptr ) const;
|
||||
bool testMtext( QgsVectorLayer *vlayer, const QString &tempFileName ) const;
|
||||
};
|
||||
|
||||
void TestQgsDxfExport::initTestCase()
|
||||
@ -264,12 +265,98 @@ void TestQgsDxfExport::testMultiSurface()
|
||||
|
||||
void TestQgsDxfExport::testMtext()
|
||||
{
|
||||
QVERIFY( testMtext( mPointLayer, QStringLiteral( "mtext_dxf" ) ) );
|
||||
QFETCH( QgsVectorLayer *, layer );
|
||||
QFETCH( QString, layerName );
|
||||
|
||||
QVERIFY( layer );
|
||||
|
||||
QgsProject::instance()->addMapLayer( layer );
|
||||
|
||||
QgsPalLayerSettings settings;
|
||||
settings.fieldName = QStringLiteral( "Class" );
|
||||
QgsTextFormat format;
|
||||
format.setFont( QgsFontUtils::getStandardTestFont( QStringLiteral( "Bold" ) ).family() );
|
||||
format.setSize( 12 );
|
||||
format.setNamedStyle( QStringLiteral( "Bold" ) );
|
||||
format.setColor( QColor( 200, 0, 200 ) );
|
||||
settings.setFormat( format );
|
||||
layer->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) );
|
||||
layer->setLabelsEnabled( true );
|
||||
|
||||
QgsDxfExport d;
|
||||
d.addLayers( QList< QgsDxfExport::DxfLayer >() << QgsDxfExport::DxfLayer( layer ) );
|
||||
|
||||
QgsMapSettings mapSettings;
|
||||
QSize size( 640, 480 );
|
||||
mapSettings.setOutputSize( size );
|
||||
mapSettings.setExtent( layer->extent() );
|
||||
mapSettings.setLayers( QList<QgsMapLayer *>() << layer );
|
||||
mapSettings.setOutputDpi( 96 );
|
||||
mapSettings.setDestinationCrs( layer->crs() );
|
||||
|
||||
d.setMapSettings( mapSettings );
|
||||
d.setSymbologyScale( 1000 );
|
||||
d.setSymbologyExport( QgsDxfExport::FeatureSymbology );
|
||||
|
||||
QString file = getTempFileName( layerName );
|
||||
QFile dxfFile( file );
|
||||
QCOMPARE( d.writeToFile( &dxfFile, QStringLiteral( "CP1252" ) ), QgsDxfExport::ExportResult::Success );
|
||||
dxfFile.close();
|
||||
|
||||
QString debugInfo;
|
||||
QVERIFY2( fileContainsText( file, "MTEXT\n"
|
||||
" 5\n"
|
||||
"**no check**\n"
|
||||
"100\n"
|
||||
"AcDbEntity\n"
|
||||
"100\n"
|
||||
"AcDbMText\n"
|
||||
" 8\n"
|
||||
"points\n"
|
||||
"420\n"
|
||||
"**no check**\n"
|
||||
" 10\n"
|
||||
"**no check**\n"
|
||||
" 20\n"
|
||||
"**no check**\n"
|
||||
" 1\n"
|
||||
"\\fQGIS Vera Sans|i0|b1;\\H3.81136;Biplane\n"
|
||||
" 50\n"
|
||||
"0.0\n"
|
||||
" 41\n"
|
||||
"**no check**\n"
|
||||
" 71\n"
|
||||
" 7\n"
|
||||
" 7\n"
|
||||
"STANDARD\n"
|
||||
" 0", &debugInfo ), debugInfo.toUtf8().constData() );
|
||||
|
||||
|
||||
QgsProject::instance()->removeMapLayer( layer );
|
||||
}
|
||||
|
||||
void TestQgsDxfExport::testMTextNoSymbology()
|
||||
void TestQgsDxfExport::testMtext_data()
|
||||
{
|
||||
QVERIFY( testMtext( mPointLayerNoSymbols, QStringLiteral( "text_no_symbology_dxf" ) ) );
|
||||
QTest::addColumn<QgsVectorLayer *>( "layer" );
|
||||
QTest::addColumn<QString>( "layerName" );
|
||||
|
||||
QString filename = QStringLiteral( TEST_DATA_DIR ) + "/points.shp";
|
||||
|
||||
QgsVectorLayer *pointLayer = new QgsVectorLayer( filename, QStringLiteral( "points" ), QStringLiteral( "ogr" ) );
|
||||
QVERIFY( pointLayer->isValid() );
|
||||
|
||||
QTest::newRow( "MText" )
|
||||
<< pointLayer
|
||||
<< QStringLiteral( "mtext_dxf" );
|
||||
|
||||
QgsVectorLayer *pointLayerNoSymbols = new QgsVectorLayer( filename, QStringLiteral( "points" ), QStringLiteral( "ogr" ) );
|
||||
QVERIFY( pointLayerNoSymbols->isValid() );
|
||||
pointLayerNoSymbols->setRenderer( new QgsNullSymbolRenderer() );
|
||||
pointLayerNoSymbols->addExpressionField( QStringLiteral( "'A text with spaces'" ), QgsField( QStringLiteral( "Spacestest" ), QVariant::String ) );
|
||||
|
||||
QTest::newRow( "MText No Symbology" )
|
||||
<< pointLayerNoSymbols
|
||||
<< QStringLiteral( "mtext_no_symbology_dxf" );
|
||||
}
|
||||
|
||||
void TestQgsDxfExport::testMTextEscapeSpaces()
|
||||
@ -304,7 +391,8 @@ void TestQgsDxfExport::testMTextEscapeSpaces()
|
||||
QFile dxfFile( file );
|
||||
QCOMPARE( d.writeToFile( &dxfFile, QStringLiteral( "CP1252" ) ), QgsDxfExport::ExportResult::Success );
|
||||
dxfFile.close();
|
||||
QVERIFY( fileContainsText( file, "\\fQGIS Vera Sans|i0|b1;\\H3.81136;A\\~text\\~with\\~spaces" ) );
|
||||
QString debugInfo;
|
||||
QVERIFY2( fileContainsText( file, "\\fQGIS Vera Sans|i0|b1;\\H3.81136;A\\~text\\~with\\~spaces", &debugInfo ), debugInfo.toUtf8().constData() );
|
||||
}
|
||||
|
||||
void TestQgsDxfExport::testText()
|
||||
@ -436,7 +524,7 @@ void TestQgsDxfExport::testTextAlign()
|
||||
QString debugInfo;
|
||||
QVERIFY2( fileContainsText( file, QStringLiteral( "TEXT\n"
|
||||
" 5\n"
|
||||
"89\n"
|
||||
"**no check**\n"
|
||||
"100\n"
|
||||
"AcDbEntity\n"
|
||||
"100\n"
|
||||
@ -519,76 +607,6 @@ void TestQgsDxfExport::testTextAlign_data()
|
||||
<< QStringLiteral( "Half" );
|
||||
}
|
||||
|
||||
bool TestQgsDxfExport::testMtext( QgsVectorLayer *vlayer, const QString &tempFileName ) const
|
||||
{
|
||||
if ( !vlayer )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QgsPalLayerSettings settings;
|
||||
settings.fieldName = QStringLiteral( "Class" );
|
||||
QgsTextFormat format;
|
||||
format.setFont( QgsFontUtils::getStandardTestFont( QStringLiteral( "Bold" ) ).family() );
|
||||
format.setSize( 12 );
|
||||
format.setNamedStyle( QStringLiteral( "Bold" ) );
|
||||
format.setColor( QColor( 200, 0, 200 ) );
|
||||
settings.setFormat( format );
|
||||
vlayer->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) );
|
||||
vlayer->setLabelsEnabled( true );
|
||||
|
||||
QgsDxfExport d;
|
||||
d.addLayers( QList< QgsDxfExport::DxfLayer >() << QgsDxfExport::DxfLayer( vlayer ) );
|
||||
|
||||
QgsMapSettings mapSettings;
|
||||
QSize size( 640, 480 );
|
||||
mapSettings.setOutputSize( size );
|
||||
mapSettings.setExtent( vlayer->extent() );
|
||||
mapSettings.setLayers( QList<QgsMapLayer *>() << vlayer );
|
||||
mapSettings.setOutputDpi( 96 );
|
||||
mapSettings.setDestinationCrs( vlayer->crs() );
|
||||
|
||||
d.setMapSettings( mapSettings );
|
||||
d.setSymbologyScale( 1000 );
|
||||
d.setSymbologyExport( QgsDxfExport::FeatureSymbology );
|
||||
|
||||
QString file = getTempFileName( tempFileName );
|
||||
QFile dxfFile( file );
|
||||
if ( d.writeToFile( &dxfFile, QStringLiteral( "CP1252" ) ) != QgsDxfExport::ExportResult::Success )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
dxfFile.close();
|
||||
|
||||
|
||||
return ( fileContainsText( file, "MTEXT\n"
|
||||
" 5\n"
|
||||
"**no check**\n"
|
||||
"100\n"
|
||||
"AcDbEntity\n"
|
||||
"100\n"
|
||||
"AcDbMText\n"
|
||||
" 8\n"
|
||||
"points\n"
|
||||
"420\n"
|
||||
"**no check**\n"
|
||||
" 10\n"
|
||||
"**no check**\n"
|
||||
" 20\n"
|
||||
"**no check**\n"
|
||||
" 1\n"
|
||||
"\\fQGIS Vera Sans|i0|b1;\\H3.81136;Biplane\n"
|
||||
" 50\n"
|
||||
"0.0\n"
|
||||
" 41\n"
|
||||
"**no check**\n"
|
||||
" 71\n"
|
||||
" 7\n"
|
||||
" 7\n"
|
||||
"STANDARD\n"
|
||||
" 0" ) );
|
||||
}
|
||||
|
||||
void TestQgsDxfExport::testGeometryGeneratorExport()
|
||||
{
|
||||
QgsDxfExport d;
|
||||
@ -747,6 +765,127 @@ void TestQgsDxfExport::testCurveExport_data()
|
||||
|
||||
}
|
||||
|
||||
void TestQgsDxfExport::testDashedLine()
|
||||
{
|
||||
std::unique_ptr<QgsSimpleLineSymbolLayer> symbolLayer = qgis::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 = qgis::make_unique< QgsVectorLayer >( QStringLiteral( "CompoundCurve?crs=epsg:2056" ), QString(), QStringLiteral( "memory" ) );
|
||||
QgsGeometry g = QgsGeometry::fromWkt( "CompoundCurve ((2689563.84200000017881393 1283531.23699999996460974, 2689563.42499999981373549 1283537.55499999993480742, 2689563.19900000002235174 1283540.52399999997578561, 2689562.99800000013783574 1283543.42999999993480742, 2689562.66900000022724271 1283548.56000000005587935, 2689562.43399999989196658 1283555.287999999942258))" );
|
||||
QgsFeature f;
|
||||
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.setExtent( vl->extent() );
|
||||
mapSettings.setLayers( QList<QgsMapLayer *>() << vl.get() );
|
||||
mapSettings.setOutputDpi( 96 );
|
||||
mapSettings.setDestinationCrs( vl->crs() );
|
||||
|
||||
d.setMapSettings( mapSettings );
|
||||
d.setSymbologyScale( 1000 );
|
||||
|
||||
QString file = getTempFileName( "dashed_line_dxf" );
|
||||
QFile dxfFile( file );
|
||||
QCOMPARE( d.writeToFile( &dxfFile, QStringLiteral( "CP1252" ) ), QgsDxfExport::ExportResult::Success );
|
||||
dxfFile.close();
|
||||
|
||||
QString debugInfo;
|
||||
|
||||
// Make sure the style definition for the dashed line is there
|
||||
QVERIFY2( fileContainsText( file,
|
||||
"LTYPE\n"
|
||||
" 5\n"
|
||||
"6c\n"
|
||||
"100\n"
|
||||
"AcDbSymbolTableRecord\n"
|
||||
"100\n"
|
||||
"AcDbLinetypeTableRecord\n"
|
||||
" 2\n"
|
||||
"symbolLayer0\n"
|
||||
" 70\n"
|
||||
" 64\n"
|
||||
" 3\n"
|
||||
"\n"
|
||||
" 72\n"
|
||||
" 65\n"
|
||||
" 73\n"
|
||||
" 2\n"
|
||||
" 40\n"
|
||||
"REGEX ^0\\.8[0-9]*\n"
|
||||
" 49\n"
|
||||
"0.5\n"
|
||||
" 74\n"
|
||||
" 0\n"
|
||||
" 49\n"
|
||||
"REGEX ^-0\\.3[0-9]*\n"
|
||||
" 74\n"
|
||||
" 0", &debugInfo ), debugInfo.toUtf8().constData() );
|
||||
|
||||
// Make sure that the polyline references the style symbolLayer0
|
||||
QVERIFY2( fileContainsText( file,
|
||||
"LWPOLYLINE\n"
|
||||
" 5\n"
|
||||
"83\n"
|
||||
" 8\n"
|
||||
"0\n"
|
||||
"100\n"
|
||||
"AcDbEntity\n"
|
||||
"100\n"
|
||||
"AcDbPolyline\n"
|
||||
" 6\n"
|
||||
"symbolLayer0\n"
|
||||
"420\n"
|
||||
" 0\n"
|
||||
" 90\n"
|
||||
" 6\n"
|
||||
" 70\n"
|
||||
" 0\n"
|
||||
" 43\n"
|
||||
"0.11\n"
|
||||
" 10\n"
|
||||
"REGEX ^2689563.84[0-9]*\n"
|
||||
" 20\n"
|
||||
"REGEX ^1283531.23[0-9]*\n"
|
||||
" 10\n"
|
||||
"REGEX ^2689563.42[0-9]*\n"
|
||||
" 20\n"
|
||||
"REGEX ^1283537.55[0-9]*\n"
|
||||
" 10\n"
|
||||
"REGEX ^2689563.19[0-9]*\n"
|
||||
" 20\n"
|
||||
"REGEX ^1283540.52[0-9]*\n"
|
||||
" 10\n"
|
||||
"REGEX ^2689562.99[0-9]*\n"
|
||||
" 20\n"
|
||||
"REGEX ^1283543.42[0-9]*\n"
|
||||
" 10\n"
|
||||
"REGEX ^2689562.66[0-9]*\n"
|
||||
" 20\n"
|
||||
"REGEX ^1283548.56[0-9]*\n"
|
||||
" 10\n"
|
||||
"REGEX ^2689562.43[0-9]*\n"
|
||||
" 20\n"
|
||||
"REGEX ^1283555.28[0-9]*\n"
|
||||
" 0\n"
|
||||
"ENDSEC"
|
||||
, &debugInfo ), debugInfo.toUtf8().constData() );
|
||||
}
|
||||
|
||||
bool TestQgsDxfExport::fileContainsText( const QString &path, const QString &text, QString *debugInfo ) const
|
||||
{
|
||||
QStringList debugLines;
|
||||
|
@ -86,13 +86,13 @@ void TestQgsServerWmsDxf::use_title_as_layername_true()
|
||||
context.setParameters( parameters );
|
||||
|
||||
QgsWms::QgsRenderer renderer( context );
|
||||
QgsDxfExport exporter = renderer.getDxf();
|
||||
std::unique_ptr<QgsDxfExport> exporter = renderer.getDxf();
|
||||
|
||||
const QString name = exporter.layerName( vl );
|
||||
QCOMPARE( exporter.layerName( vl ), QString( "testlayer \u00E8\u00E9" ) );
|
||||
const QString name = exporter->layerName( vl );
|
||||
QCOMPARE( exporter->layerName( vl ), QString( "testlayer \u00E8\u00E9" ) );
|
||||
|
||||
const QgsFeature ft = vl->getFeature( 1 );
|
||||
QCOMPARE( exporter.layerName( vl->id(), ft ), QString( "two" ) );
|
||||
QCOMPARE( exporter->layerName( vl->id(), ft ), QString( "two" ) );
|
||||
}
|
||||
|
||||
void TestQgsServerWmsDxf::use_title_as_layername_false()
|
||||
@ -135,13 +135,13 @@ void TestQgsServerWmsDxf::use_title_as_layername_false()
|
||||
context.setParameters( parameters );
|
||||
|
||||
QgsWms::QgsRenderer renderer( context );
|
||||
QgsDxfExport exporter = renderer.getDxf();
|
||||
std::unique_ptr<QgsDxfExport> exporter = renderer.getDxf();
|
||||
|
||||
const QString name = exporter.layerName( vl );
|
||||
QCOMPARE( exporter.layerName( vl ), QString( "A test vector layer" ) );
|
||||
const QString name = exporter->layerName( vl );
|
||||
QCOMPARE( exporter->layerName( vl ), QString( "A test vector layer" ) );
|
||||
|
||||
const QgsFeature ft = vl->getFeature( 1 );
|
||||
QCOMPARE( exporter.layerName( vl->id(), ft ), QString( "A test vector layer" ) );
|
||||
QCOMPARE( exporter->layerName( vl->id(), ft ), QString( "A test vector layer" ) );
|
||||
}
|
||||
|
||||
QGSTEST_MAIN( TestQgsServerWmsDxf )
|
||||
|
Loading…
x
Reference in New Issue
Block a user