Port dxf export improvements to QGIS 3

This commit is contained in:
Marco Hugentobler 2018-06-05 16:24:09 +02:00 committed by Nyall Dawson
parent aa47dbef10
commit 18f0af8c23
9 changed files with 152 additions and 45 deletions

View File

@ -397,10 +397,21 @@ Write mtext (MTEXT)
.. versionadded:: 2.15
%End
static double mapUnitScaleFactor( double scale, QgsUnitTypes::RenderUnit symbolUnits, QgsUnitTypes::DistanceUnit mapUnits );
static double mapUnitScaleFactor( double scaleDenominator, QgsUnitTypes::RenderUnit symbolUnits, QgsUnitTypes::DistanceUnit mapUnits, double mapUnitsPerPixel = 1.0 );
%Docstring
Calculates a scaling factor to convert from map units to a specified symbol unit.
The ``scale`` parameter indicates the scale denominator, e.g. 1000.0 for a 1:1000 map.
Returns scale factor for conversion to map units
@param scaleDenominator the map scale denominator
@param symbolUnits the symbol output units
@param mapUnits the map units
@param mapUnitsPerPixel Map units per pixel*
%End
void clipValueToMapUnitScale( double &value, const QgsMapUnitScale &scale, double pixelToMMFactor ) const;
%Docstring
Clips value to scale minimum/maximum
@param value the value to clip
@param scale the scale dependent minimum/maximum values
@param pixelToMMFactor pixels per mm*
%End
static QString dxfLayerName( const QString &name );

View File

@ -930,7 +930,7 @@ void QgsDxfExport::writeBlocks()
writeGroup( 1, QLatin1String( "" ) );
// maplayer 0 -> block receives layer from INSERT statement
ml->writeDxf( *this, mapUnitScaleFactor( mSymbologyScale, ml->sizeUnit(), mMapUnits ), QStringLiteral( "0" ), ctx );
ml->writeDxf( *this, mapUnitScaleFactor( mSymbologyScale, ml->sizeUnit(), mMapUnits, ctx.renderContext().mapToPixel().mapUnitsPerPixel() ), QStringLiteral( "0" ), ctx );
writeGroup( 0, QStringLiteral( "ENDBLK" ) );
writeHandle();
@ -966,6 +966,9 @@ void QgsDxfExport::writeEntities()
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
QgsLabelingEngine engine;
engine.setMapSettings( mMapSettings );
@ -3435,7 +3438,7 @@ void QgsDxfExport::writePoint( const QgsPoint &pt, const QString &layer, const Q
const QgsMarkerSymbolLayer *msl = dynamic_cast< const QgsMarkerSymbolLayer * >( symbolLayer );
if ( msl && symbol )
{
if ( symbolLayer->writeDxf( *this, mapUnitScaleFactor( mSymbologyScale, msl->sizeUnit(), mMapUnits ), layer, ctx, QPointF( pt.x(), pt.y() ) ) )
if ( symbolLayer->writeDxf( *this, mapUnitScaleFactor( mSymbologyScale, msl->sizeUnit(), mMapUnits, ctx.renderContext().mapToPixel().mapUnitsPerPixel() ), layer, ctx, QPointF( pt.x(), pt.y() ) ) )
{
return;
}
@ -3982,14 +3985,53 @@ QgsRenderContext QgsDxfExport::renderContext() const
return context;
}
double QgsDxfExport::mapUnitScaleFactor( double scale, QgsUnitTypes::RenderUnit symbolUnits, QgsUnitTypes::DistanceUnit mapUnits )
double QgsDxfExport::mapUnitScaleFactor( double scaleDenominator, QgsUnitTypes::RenderUnit symbolUnits, QgsUnitTypes::DistanceUnit mapUnits, double mapUnitsPerPixel )
{
if ( symbolUnits == QgsUnitTypes::RenderMapUnits )
{
return 1.0;
}
// MM symbol unit
return scale * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::DistanceMeters, mapUnits ) / 1000.0;
else if ( symbolUnits == QgsUnitTypes::RenderMillimeters )
{
return ( scaleDenominator * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::DistanceMeters, mapUnits ) / 1000.0 );
}
else if ( symbolUnits == QgsUnitTypes::RenderPixels )
{
return mapUnitsPerPixel;
}
return 1.0;
}
void QgsDxfExport::clipValueToMapUnitScale( double &value, const QgsMapUnitScale &scale, double pixelToMMFactor ) const
{
if ( !scale.minSizeMMEnabled && !scale.maxSizeMMEnabled )
{
return;
}
double mapUnitsPerPixel = mMapSettings.mapToPixel().mapUnitsPerPixel();
double minSizeMU = -DBL_MAX;
if ( scale.minSizeMMEnabled )
{
minSizeMU = scale.minSizeMM * pixelToMMFactor * mapUnitsPerPixel;
}
if ( !qgsDoubleNear( scale.minScale, 0.0 ) )
{
minSizeMU = qMax( minSizeMU, value );
}
value = qMax( value, minSizeMU );
double maxSizeMU = DBL_MAX;
if ( scale.maxSizeMMEnabled )
{
maxSizeMU = scale.maxSizeMM * pixelToMMFactor * mapUnitsPerPixel;
}
if ( !qgsDoubleNear( scale.maxScale, 0.0 ) )
{
maxSizeMU = qMin( maxSizeMU, value );
}
value = qMin( value, maxSizeMU );
}
QList< QPair< QgsSymbolLayer *, QgsSymbol * > > QgsDxfExport::symbolLayers( QgsRenderContext &context )
@ -4122,7 +4164,7 @@ void QgsDxfExport::writeLinetype( const QString &styleName, const QVector<qreal>
QVector<qreal>::const_iterator dashIt = pattern.constBegin();
for ( ; dashIt != pattern.constEnd(); ++dashIt )
{
length += ( *dashIt * mapUnitScaleFactor( mSymbologyScale, u, mMapUnits ) );
length += ( *dashIt * mapUnitScaleFactor( mSymbologyScale, u, mMapUnits, mMapSettings.mapToPixel().mapUnitsPerPixel() ) );
}
writeGroup( 0, QStringLiteral( "LTYPE" ) );
@ -4143,7 +4185,7 @@ void QgsDxfExport::writeLinetype( const QString &styleName, const QVector<qreal>
{
// map units or mm?
double segmentLength = ( isGap ? -*dashIt : *dashIt );
segmentLength *= mapUnitScaleFactor( mSymbologyScale, u, mMapUnits );
segmentLength *= mapUnitScaleFactor( mSymbologyScale, u, mMapUnits, mMapSettings.mapToPixel().mapUnitsPerPixel() );
writeGroup( 49, segmentLength );
writeGroup( 74, 0 );
isGap = !isGap;

View File

@ -385,10 +385,19 @@ class CORE_EXPORT QgsDxfExport
void writeMText( const QString &layer, const QString &text, const QgsPoint &pt, double width, double angle, const QColor &color );
/**
* Calculates a scaling factor to convert from map units to a specified symbol unit.
* The \a scale parameter indicates the scale denominator, e.g. 1000.0 for a 1:1000 map.
*/
static double mapUnitScaleFactor( double scale, QgsUnitTypes::RenderUnit symbolUnits, QgsUnitTypes::DistanceUnit mapUnits );
* Returns scale factor for conversion to map units
* @param scaleDenominator the map scale denominator
* @param symbolUnits the symbol output units
* @param mapUnits the map units
* @param mapUnitsPerPixel Map units per pixel*/
static double mapUnitScaleFactor( double scaleDenominator, QgsUnitTypes::RenderUnit symbolUnits, QgsUnitTypes::DistanceUnit mapUnits, double mapUnitsPerPixel = 1.0 );
/**
* Clips value to scale minimum/maximum
* @param value the value to clip
* @param scale the scale dependent minimum/maximum values
* @param pixelToMMFactor pixels per mm*/
void clipValueToMapUnitScale( double &value, const QgsMapUnitScale &scale, double pixelToMMFactor ) const;
//! Returns cleaned layer name for use in DXF
static QString dxfLayerName( const QString &name );

View File

@ -24,6 +24,7 @@ QgsDxfPaintEngine::QgsDxfPaintEngine( const QgsDxfPaintDevice *dxfDevice, QgsDxf
: QPaintEngine( QPaintEngine::AllFeatures /*QPaintEngine::PainterPaths | QPaintEngine::PaintOutsidePaintEvent*/ )
, mPaintDevice( dxfDevice )
, mDxf( dxf )
, mOpacity( 1.0 )
{
}
@ -60,6 +61,11 @@ void QgsDxfPaintEngine::updateState( const QPaintEngineState &state )
if ( state.state() & QPaintEngine::DirtyBrush )
mBrush = state.brush();
if ( state.state() & QPaintEngine::DirtyOpacity )
{
mOpacity = state.opacity();
}
}
void QgsDxfPaintEngine::setRing( QgsPointSequence &polyline, const QPointF *points, int pointCount )
@ -82,12 +88,12 @@ void QgsDxfPaintEngine::drawPolygon( const QPointF *points, int pointCount, Poly
if ( mode == QPaintEngine::PolylineMode )
{
if ( mPen.style() != Qt::NoPen && mPen.brush().style() != Qt::NoBrush )
mDxf->writePolyline( polygon.at( 0 ), mLayer, QStringLiteral( "CONTINUOUS" ), mPen.color(), currentWidth() );
mDxf->writePolyline( polygon.at( 0 ), mLayer, QStringLiteral( "CONTINUOUS" ), penColor(), currentWidth() );
}
else
{
if ( mBrush.style() != Qt::NoBrush )
mDxf->writePolygon( polygon, mLayer, QStringLiteral( "SOLID" ), mBrush.color() );
mDxf->writePolygon( polygon, mLayer, QStringLiteral( "SOLID" ), brushColor() );
}
}
@ -118,7 +124,7 @@ void QgsDxfPaintEngine::drawPath( const QPainterPath &path )
endPolygon();
if ( !mPolygon.isEmpty() && mBrush.style() != Qt::NoBrush )
mDxf->writePolygon( mPolygon, mLayer, QStringLiteral( "SOLID" ), mBrush.color() );
mDxf->writePolygon( mPolygon, mLayer, QStringLiteral( "SOLID" ), brushColor() );
mPolygon.clear();
}
@ -194,7 +200,7 @@ void QgsDxfPaintEngine::drawLines( const QLineF *lines, int lineCount )
{
mDxf->writeLine( toDxfCoordinates( lines[i].p1() ),
toDxfCoordinates( lines[i].p2() ),
mLayer, QStringLiteral( "CONTINUOUS" ), mPen.color(), currentWidth() );
mLayer, QStringLiteral( "CONTINUOUS" ), penColor(), currentWidth() );
}
}
@ -287,3 +293,25 @@ int QgsDxfPaintEngine::faculty( int n )
return result;
}
QColor QgsDxfPaintEngine::penColor() const
{
if ( qgsDoubleNear( mOpacity, 1.0 ) )
{
return mPen.color();
}
QColor c = mPen.color();
c.setAlphaF( c.alphaF() * mOpacity );
return c;
}
QColor QgsDxfPaintEngine::brushColor() const
{
if ( qgsDoubleNear( mOpacity, 1.0 ) )
{
return mBrush.color();
}
QColor c = mBrush.color();
c.setAlphaF( c.alphaF() * mOpacity );
return c;
}

View File

@ -64,6 +64,8 @@ class CORE_EXPORT QgsDxfPaintEngine: public QPaintEngine
QTransform mTransform;
QPen mPen;
QBrush mBrush;
//! Opacity
double mOpacity;
QString mLayer;
QPointF mShift;
QgsRingSequence mPolygon;
@ -87,6 +89,11 @@ class CORE_EXPORT QgsDxfPaintEngine: public QPaintEngine
static int lower( int n, int i );
static double power( double a, int b );
static int faculty( int n );
//! Returns current pen color
QColor penColor() const;
//! Returns current brush color
QColor brushColor() const;
};
#endif // QGSDXFPAINTENGINE_H

View File

@ -406,7 +406,7 @@ double QgsSimpleFillSymbolLayer::dxfWidth( const QgsDxfExport &e, QgsSymbolRende
context.setOriginalValueVariable( mStrokeWidth );
width = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyStrokeWidth, context.renderContext().expressionContext(), mStrokeWidth );
}
return width * e.mapUnitScaleFactor( e.symbologyScale(), mStrokeWidthUnit, e.mapUnits() );
return width * e.mapUnitScaleFactor( e.symbologyScale(), mStrokeWidthUnit, e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() );
}
QColor QgsSimpleFillSymbolLayer::dxfColor( QgsSymbolRenderContext &context ) const
@ -1672,7 +1672,7 @@ double QgsImageFillSymbolLayer::dxfWidth( const QgsDxfExport &e, QgsSymbolRender
context.setOriginalValueVariable( mStrokeWidth );
width = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyWidth, context.renderContext().expressionContext(), mStrokeWidth );
}
return width * e.mapUnitScaleFactor( e.symbologyScale(), mStrokeWidthUnit, e.mapUnits() );
return width * e.mapUnitScaleFactor( e.symbologyScale(), mStrokeWidthUnit, e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() );
}
QColor QgsImageFillSymbolLayer::dxfColor( QgsSymbolRenderContext &context ) const

View File

@ -594,15 +594,18 @@ Qt::PenStyle QgsSimpleLineSymbolLayer::dxfPenStyle() const
double QgsSimpleLineSymbolLayer::dxfWidth( const QgsDxfExport &e, QgsSymbolRenderContext &context ) const
{
double width = mWidth;
if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeWidth ) )
{
context.setOriginalValueVariable( mWidth );
width = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyStrokeWidth, context.renderContext().expressionContext(), mWidth )
* e.mapUnitScaleFactor( e.symbologyScale(), widthUnit(), e.mapUnits() );
width = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyStrokeWidth, context.renderContext().expressionContext(), mWidth );
}
return width * e.mapUnitScaleFactor( e.symbologyScale(), widthUnit(), e.mapUnits() );
width *= e.mapUnitScaleFactor( e.symbologyScale(), widthUnit(), e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() );
if ( mWidthUnit == QgsUnitTypes::RenderMapUnits )
{
e.clipValueToMapUnitScale( width, mWidthMapUnitScale, context.renderContext().scaleFactor() );
}
return width;
}
QColor QgsSimpleLineSymbolLayer::dxfColor( QgsSymbolRenderContext &context ) const
@ -625,7 +628,13 @@ double QgsSimpleLineSymbolLayer::dxfOffset( const QgsDxfExport &e, QgsSymbolRend
context.setOriginalValueVariable( mOffset );
offset = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyOffset, context.renderContext().expressionContext(), mOffset );
}
return offset;
offset *= e.mapUnitScaleFactor( e.symbologyScale(), offsetUnit(), e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() );
if ( mOffsetUnit == QgsUnitTypes::RenderMapUnits )
{
e.clipValueToMapUnitScale( offset, mOffsetMapUnitScale, context.renderContext().scaleFactor() );
}
return -offset; //direction seems to be inverse to symbology offset
}
/////////

View File

@ -1221,6 +1221,8 @@ void QgsSimpleMarkerSymbolLayer::drawMarker( QPainter *p, QgsSymbolRenderContext
bool QgsSimpleMarkerSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift ) const
{
Q_UNUSED( mmMapUnitScaleFactor );
//data defined size?
double size = mSize;
@ -1245,11 +1247,11 @@ bool QgsSimpleMarkerSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScal
}
}
size = context.renderContext().convertToPainterUnits( size, mSizeUnit, mSizeMapUnitScale );
size *= e.mapUnitScaleFactor( e.symbologyScale(), mSizeUnit, e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() );
}
if ( mSizeUnit == QgsUnitTypes::RenderMillimeters )
if ( mSizeUnit == QgsUnitTypes::RenderMapUnits )
{
size *= mmMapUnitScaleFactor;
e.clipValueToMapUnitScale( size, mSizeMapUnitScale, context.renderContext().scaleFactor() );
}
double halfSize = size / 2.0;
@ -1261,9 +1263,10 @@ bool QgsSimpleMarkerSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScal
context.setOriginalValueVariable( mStrokeWidth );
strokeWidth = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyStrokeWidth, context.renderContext().expressionContext(), mStrokeWidth );
}
if ( mSizeUnit == QgsUnitTypes::RenderMillimeters )
strokeWidth *= e.mapUnitScaleFactor( e.symbologyScale(), mStrokeWidthUnit, e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() );
if ( mSizeUnit == QgsUnitTypes::RenderMapUnits )
{
strokeWidth *= mmMapUnitScaleFactor;
e.clipValueToMapUnitScale( strokeWidth, mStrokeWidthMapUnitScale, context.renderContext().scaleFactor() );
}
//color
@ -1284,6 +1287,9 @@ bool QgsSimpleMarkerSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScal
double offsetX = 0;
double offsetY = 0;
markerOffset( context, offsetX, offsetY );
offsetX *= context.renderContext().mapToPixel().mapUnitsPerPixel();
offsetY *= context.renderContext().mapToPixel().mapUnitsPerPixel();
QPointF off( offsetX, offsetY );
@ -1308,17 +1314,13 @@ bool QgsSimpleMarkerSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScal
}
}
angle = -angle; //rotation in Qt is counterclockwise
if ( angle )
off = _rotatedOffset( off, angle );
if ( mSizeUnit == QgsUnitTypes::RenderMillimeters )
{
off *= mmMapUnitScaleFactor;
}
off *= e.mapUnitScaleFactor( e.symbologyScale(), mSizeUnit, e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() );
QTransform t;
t.translate( shift.x() + offsetX, shift.y() + offsetY );
t.translate( shift.x() + off.x(), shift.y() - off.y() );
if ( !qgsDoubleNear( angle, 0.0 ) )
t.rotate( angle );
@ -1333,8 +1335,9 @@ bool QgsSimpleMarkerSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScal
QgsPointSequence p;
p.reserve( polygon.size() );
for ( int i = 0; i < polygon.size(); i++ )
{
p << QgsPoint( polygon[i] );
p << p[0];
}
if ( mBrush.style() != Qt::NoBrush )
e.writePolygon( QgsRingSequence() << p, layerName, QStringLiteral( "SOLID" ), bc );
@ -1343,6 +1346,7 @@ bool QgsSimpleMarkerSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScal
}
else if ( shape == Circle )
{
shift += QPointF( off.x(), -off.y() );
if ( mBrush.style() != Qt::NoBrush )
e.writeFilledCircle( layerName, bc, QgsPoint( shift ), halfSize );
if ( mPen.style() != Qt::NoPen )
@ -2387,11 +2391,6 @@ bool QgsSvgMarkerSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFa
}
double offsetX = offset.x();
double offsetY = offset.y();
if ( mSizeUnit == QgsUnitTypes::RenderMillimeters )
{
offsetX *= mmMapUnitScaleFactor;
offsetY *= mmMapUnitScaleFactor;
}
QPointF outputOffset( offsetX, offsetY );
@ -2405,6 +2404,8 @@ bool QgsSvgMarkerSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFa
if ( angle )
outputOffset = _rotatedOffset( outputOffset, angle );
outputOffset *= e.mapUnitScaleFactor( e.symbologyScale(), mOffsetUnit, e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() );
QString path = mPath;
if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyName ) )
{
@ -2419,7 +2420,7 @@ bool QgsSvgMarkerSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFa
context.setOriginalValueVariable( mStrokeWidth );
strokeWidth = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyStrokeWidth, context.renderContext().expressionContext(), mStrokeWidth );
}
strokeWidth = context.renderContext().convertToPainterUnits( strokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale );
strokeWidth *= e.mapUnitScaleFactor( e.symbologyScale(), mStrokeWidthUnit, e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() );
QColor fillColor = mColor;
if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFillColor ) )
@ -2458,7 +2459,7 @@ bool QgsSvgMarkerSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFa
p.rotate( angle );
p.translate( -r.defaultSize().width() / 2.0, -r.defaultSize().height() / 2.0 );
}
pd.setShift( shift );
pd.setShift( shift + QPointF( outputOffset.x(), -outputOffset.y() ) );
pd.setOutputSize( QRectF( -halfSize, -halfSize, size, size ) );
pd.setLayer( layerName );
r.render( &p );

View File

@ -620,7 +620,7 @@ void QgsLineSymbolLayer::renderPolygonStroke( const QPolygonF &points, QList<QPo
double QgsLineSymbolLayer::dxfWidth( const QgsDxfExport &e, QgsSymbolRenderContext &context ) const
{
Q_UNUSED( context );
return width() * e.mapUnitScaleFactor( e.symbologyScale(), widthUnit(), e.mapUnits() );
return width() * e.mapUnitScaleFactor( e.symbologyScale(), widthUnit(), e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() );
}