1,724 changes: 1,724 additions & 0 deletions src/core/dxf/qgsdxfexport.cpp

Large diffs are not rendered by default.

160 changes: 160 additions & 0 deletions src/core/dxf/qgsdxfexport.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/***************************************************************************
qgsdxfexport.h
--------------
begin : September 2013
copyright : (C) 2013 by Marco Hugentobler
email : marco at sourcepole dot ch
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSDXFEXPORT_H
#define QGSDXFEXPORT_H

#include "qgsgeometry.h"
#include "qgssymbolv2.h"
#include <QColor>
#include <QList>
#include <QTextStream>

class QgsMapLayer;
class QgsPoint;
class QgsSymbolLayerV2;
class QIODevice;

class CORE_EXPORT QgsDxfExport
{
public:
enum SymbologyExport
{
NoSymbology = 0, //export only data
FeatureSymbology, //Keeps the number of features and export symbology per feature (using the first symbol level)
SymbolLayerSymbology //Exports one feature per symbol layer (considering symbol levels)
};

QgsDxfExport();
QgsDxfExport( const QgsDxfExport& dxfExport );
~QgsDxfExport();
QgsDxfExport& operator=( const QgsDxfExport& dxfExport );

void addLayers( QList< QgsMapLayer* >& layers ) { mLayers = layers; }
int writeToFile( QIODevice* d ); //maybe add progress dialog? //other parameters (e.g. scale, dpi)?

void setSymbologyScaleDenominator( double d ) { mSymbologyScaleDenominator = d; }
double symbologyScaleDenominator() const { return mSymbologyScaleDenominator; }

void setMapUnits( QGis::UnitType u ) { mMapUnits = u; }
QGis::UnitType mapUnits() const { return mMapUnits; }

void setSymbologyExport( SymbologyExport e ) { mSymbologyExport = e; }
SymbologyExport symbologyExport() const { return mSymbologyExport; }

//get closest entry in dxf palette
static int closestColorMatch( QRgb pixel );

void writeGroup( int code, int i );
void writeGroup( int code, double d );
void writeGroup( int code, const QString& s );
void writeGroupCode( int code );
void writeInt( int i );
void writeDouble( double d );
void writeString( const QString& s );

//draw dxf primitives
void writePolyline( const QgsPolyline& line, const QString& layer, const QString& lineStyleName, int color,
double width = -1, bool polygon = false );

void writeSolid( const QString& layer, int color, const QgsPoint& pt1, const QgsPoint& pt2, const QgsPoint& pt3, const QgsPoint& pt4 );

//write line (as a polyline)
void writeLine( const QgsPoint& pt1, const QgsPoint& pt2, const QString& layer, const QString& lineStyleName, int color, double width = -1 );

void writePoint( const QString& layer, int color, const QgsPoint& pt );

void writeCircle( const QString& layer, int color, const QgsPoint& pt, double radius );

private:

QList< QgsMapLayer* > mLayers;
/**Scale for symbology export (used if symbols units are mm)*/
double mSymbologyScaleDenominator;
SymbologyExport mSymbologyExport;
QGis::UnitType mMapUnits;

QTextStream mTextStream;

static double mDxfColors[][3];

int mSymbolLayerCounter; //internal counter
int mNextHandleId;
int mBlockCounter;

QHash< const QgsSymbolLayerV2*, QString > mLineStyles; //symbol layer name types
QHash< const QgsSymbolLayerV2*, QString > mPointSymbolBlocks; //reference to point symbol blocks

//AC1009
void writeHeader();
void writeTables();
void writeBlocks();
void writeEntities();
void writeEntitiesSymbolLevels( QgsVectorLayer* layer );
void writeEndFile();

void startSection();
void endSection();

void writePoint( const QgsPoint& pt, const QString& layer, int color, const QgsFeature* f, const QgsSymbolLayerV2* symbolLayer, const QgsSymbolV2* symbol );
void writeVertex( const QgsPoint& pt, const QString& layer );
void writeDefaultLinestyles();
void writeSymbolLayerLinestyle( const QgsSymbolLayerV2* symbolLayer );
void writeLinestyle( const QString& styleName, const QVector<qreal>& pattern, QgsSymbolV2::OutputUnit u );

//AC1018
void writeHeaderAC1018( QTextStream& stream );
void writeTablesAC1018( QTextStream& stream );
void writeEntitiesAC1018( QTextStream& stream );
void writeEntitiesSymbolLevelsAC1018( QTextStream& stream, QgsVectorLayer* layer );
void writeSymbolLayerLinestyleAC1018( QTextStream& stream, const QgsSymbolLayerV2* symbolLayer );
void writeLinestyleAC1018( QTextStream& stream, const QString& styleName, const QVector<qreal>& pattern, QgsSymbolV2::OutputUnit u );
void writeVertexAC1018( QTextStream& stream, const QgsPoint& pt );
void writePolylineAC1018( QTextStream& stream, const QgsPolyline& line, const QString& layer, const QString& lineStyleName, int color,
double width = -1, bool polygon = false );


QgsRectangle dxfExtent() const;

void addFeature( const QgsFeature& fet, const QString& layer, const QgsSymbolLayerV2* symbolLayer, const QgsSymbolV2* symbol );
double scaleToMapUnits( double value, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits ) const;

//returns dxf palette index from symbol layer color
static int colorFromSymbolLayer( const QgsSymbolLayerV2* symbolLayer );
double widthFromSymbolLayer( const QgsSymbolLayerV2* symbolLayer ) const;
QString lineStyleFromSymbolLayer( const QgsSymbolLayerV2* symbolLayer );

//functions for dxf palette
static int color_distance( QRgb p1, int index );
static QRgb createRgbEntry( qreal r, qreal g, qreal b );

//helper functions for symbology export
QgsRenderContext renderContext() const;
void startRender( QgsVectorLayer* vl ) const;
void stopRender( QgsVectorLayer* vl ) const;
static double mapUnitScaleFactor( double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits );
QList< QPair< QgsSymbolLayerV2*, QgsSymbolV2* > > symbolLayers();
static int nLineTypes( const QList< QPair< QgsSymbolLayerV2*, QgsSymbolV2*> >& symbolLayers );
static bool hasDataDefinedProperties( const QgsSymbolLayerV2* sl, const QgsSymbolV2* symbol );
double dashSize() const;
double dotSize() const;
double dashSeparatorSize() const;
double sizeToMapUnits( double s ) const;
static QString lineNameFromPenStyle( Qt::PenStyle style );
};

#endif // QGSDXFEXPORT_H
100 changes: 100 additions & 0 deletions src/core/dxf/qgsdxfpaintdevice.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/***************************************************************************
qgsdxpaintdevice.cpp
--------------------
begin : November 2013
copyright : (C) 2013 by Marco Hugentobler
email : marco at sourcepole dot ch
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsdxfpaintdevice.h"

QgsDxfPaintDevice::QgsDxfPaintDevice( QgsDxfExport* dxf ): QPaintDevice(), mPaintEngine( 0 )
{
mPaintEngine = new QgsDxfPaintEngine( this, dxf );
}

QgsDxfPaintDevice::~QgsDxfPaintDevice()
{
delete mPaintEngine;
}

QPaintEngine* QgsDxfPaintDevice::paintEngine() const
{
return mPaintEngine;
}

int QgsDxfPaintDevice::metric( PaintDeviceMetric metric ) const
{
switch ( metric )
{
case QPaintDevice::PdmWidth:
return mDrawingSize.width();
case QPaintDevice::PdmHeight:
return mDrawingSize.height();
case QPaintDevice::PdmWidthMM:
return mDrawingSize.width();
case QPaintDevice::PdmHeightMM:
return mDrawingSize.height();
case QPaintDevice::PdmNumColors:
return INT_MAX;
case QPaintDevice::PdmDepth:
return 32;
case QPaintDevice::PdmDpiX:
case QPaintDevice::PdmDpiY:
case QPaintDevice::PdmPhysicalDpiX:
case QPaintDevice::PdmPhysicalDpiY:
return 96;
}
return 0;
}

double QgsDxfPaintDevice::widthScaleFactor() const
{
if ( !mDrawingSize.isValid() || mRectangle.isEmpty() )
{
return 1.0;
}

double widthFactor = mRectangle.width() / mDrawingSize.width();
double heightFactor = mRectangle.height() / mDrawingSize.height();
return ( widthFactor + heightFactor ) / 2.0;
}

QPointF QgsDxfPaintDevice::dxfCoordinates( const QPointF& pt ) const
{
if ( !mDrawingSize.isValid() || mRectangle.isEmpty() )
{
return QPointF( pt.x(), pt.y() );
}

double x = mRectangle.left() + pt.x() * ( mRectangle.width() / mDrawingSize.width() );
double y = mRectangle.bottom() - pt.y() * ( mRectangle.height() / mDrawingSize.height() );
return QPointF( x, y );
}

void QgsDxfPaintDevice::setLayer( const QString& layer )
{
if ( mPaintEngine )
{
mPaintEngine->setLayer( layer );
}
}

void QgsDxfPaintDevice::setShift( const QPointF& shift )
{
if ( mPaintEngine )
{
mPaintEngine->setShift( shift );
}
}


63 changes: 63 additions & 0 deletions src/core/dxf/qgsdxfpaintdevice.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/***************************************************************************
qgsdxpaintdevice.h
------------------
begin : November 2013
copyright : (C) 2013 by Marco Hugentobler
email : marco at sourcepole dot ch
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSDXFPAINTDEVICE_H
#define QGSDXFPAINTDEVICE_H

#include <QPaintDevice>
#include "qgsdxfpaintengine.h"

class QgsDxfExport;
class QPaintEngine;

/**A paint device for drawing into dxf files*/

class CORE_EXPORT QgsDxfPaintDevice: public QPaintDevice
{
public:
QgsDxfPaintDevice( QgsDxfExport* dxf );
~QgsDxfPaintDevice();

QPaintEngine* paintEngine() const;

void setDrawingSize( const QSizeF& size ) { mDrawingSize = size; }
void setOutputSize( const QRectF& r ) { mRectangle = r; }

/**Returns scale factor for line width*/
double widthScaleFactor() const;

/**Converts a point from device coordinates to dxf coordinates*/
QPointF dxfCoordinates( const QPointF& pt ) const;

/*int height() const { return mDrawingSize.height(); }
int width() const { return mDrawingSize.width(); }*/

int metric( PaintDeviceMetric metric ) const;

void setLayer( const QString& layer );

void setShift( const QPointF& shift );


private:
QgsDxfPaintEngine* mPaintEngine;

QSizeF mDrawingSize; //size (in source coordinates)
QRectF mRectangle; //size (in dxf coordinates)
};

#endif // QGSDXFPAINTDEVICE_H
171 changes: 171 additions & 0 deletions src/core/dxf/qgsdxfpaintengine.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/***************************************************************************
qgsdxpaintengine.cpp
--------------------
begin : November 2013
copyright : (C) 2013 by Marco Hugentobler
email : marco at sourcepole dot ch
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsdxfpaintengine.h"
#include "qgsdxfexport.h"
#include "qgsdxfpaintdevice.h"
#include "qgslogger.h"

QgsDxfPaintEngine::QgsDxfPaintEngine( const QgsDxfPaintDevice* dxfDevice, QgsDxfExport* dxf ): QPaintEngine( QPaintEngine::AllFeatures /*QPaintEngine::PainterPaths | QPaintEngine::PaintOutsidePaintEvent*/ )
, mPaintDevice( dxfDevice ), mDxf( dxf )
{

}

QgsDxfPaintEngine::~QgsDxfPaintEngine()
{

}

bool QgsDxfPaintEngine::begin( QPaintDevice* pdev )
{
Q_UNUSED( pdev );
return true;
}

bool QgsDxfPaintEngine::end()
{
return true;
}

QPaintEngine::Type QgsDxfPaintEngine::type() const
{
return QPaintEngine::User;
}

void QgsDxfPaintEngine::drawPixmap( const QRectF& r, const QPixmap& pm, const QRectF& sr )
{
Q_UNUSED( r ); Q_UNUSED( pm ); Q_UNUSED( sr );
}

void QgsDxfPaintEngine::updateState( const QPaintEngineState& state )
{
if ( state.state() & QPaintEngine::DirtyTransform )
{
mTransform = state.transform();
}
if ( state.state() & QPaintEngine::DirtyPen )
{
mPen = state.pen();
}
}

void QgsDxfPaintEngine::drawPolygon( const QPointF* points, int pointCount, PolygonDrawMode mode )
{
if ( !mDxf || !mPaintDevice )
{
return;
}

QgsPolyline polyline( pointCount );
for ( int i = 0; i < pointCount; ++i )
{
polyline[i] = toDxfCoordinates( points[i] );
}

mDxf->writePolyline( polyline, mLayer, "CONTINUOUS", currentPenColor(), currentWidth(), mode != QPaintEngine::PolylineMode );
}

void QgsDxfPaintEngine::drawRects( const QRectF* rects, int rectCount )
{
if ( !mDxf || !mPaintDevice || !rects )
{
return;
}

for ( int i = 0; i < rectCount; ++i )
{
double left = rects[i].left();
double right = rects[i].right();
double top = rects[i].top();
double bottom = rects[i].bottom();
QgsPoint pt1 = toDxfCoordinates( QPointF( left, bottom ) );
QgsPoint pt2 = toDxfCoordinates( QPointF( right, bottom ) );
QgsPoint pt3 = toDxfCoordinates( QPointF( left, top ) );
QgsPoint pt4 = toDxfCoordinates( QPointF( right, top ) );
mDxf->writeSolid( mLayer, currentPenColor(), pt1, pt2, pt3, pt4 );
}
}

void QgsDxfPaintEngine::drawEllipse( const QRectF& rect )
{
QPoint midPoint(( rect.left() + rect.right() ) / 2.0, ( rect.top() + rect.bottom() ) / 2.0 );

//a circle
if ( qgsDoubleNear( rect.width(), rect.height() ) )
{
mDxf->writeCircle( mLayer, currentPenColor(), toDxfCoordinates( midPoint ), rect.width() / 2.0 );
}

//todo: create polyline for real ellises
}

void QgsDxfPaintEngine::drawPath( const QPainterPath& path )
{
QList<QPolygonF> polygonList = path.toFillPolygons();
QList<QPolygonF>::const_iterator pIt = polygonList.constBegin();
for ( ; pIt != polygonList.constEnd(); ++pIt )
{
drawPolygon( pIt->constData(), pIt->size(), pIt->isClosed() ? QPaintEngine::OddEvenMode : QPaintEngine::PolylineMode );
}
}

void QgsDxfPaintEngine::drawLines( const QLineF* lines, int lineCount )
{
if ( !mDxf || !mPaintDevice || !lines )
{
return;
}

for ( int i = 0; i < lineCount; ++i )
{
QgsPoint pt1 = toDxfCoordinates( lines[i].p1() );
QgsPoint pt2 = toDxfCoordinates( lines[i].p2() );
mDxf->writeLine( pt1, pt2, mLayer, "CONTINUOUS", currentPenColor(), currentWidth() );
}
}

QgsPoint QgsDxfPaintEngine::toDxfCoordinates( const QPointF& pt ) const
{
if ( !mPaintDevice || !mDxf )
{
return QgsPoint( pt.x(), pt.y() );
}

QPointF dxfPt = mPaintDevice->dxfCoordinates( mTransform.map( pt ) ) + mShift;
return QgsPoint( dxfPt.x(), dxfPt.y() );
}

int QgsDxfPaintEngine::currentPenColor() const
{
if ( !mDxf )
{
return 0;
}

return mDxf->closestColorMatch( mPen.color().rgb() );
}

double QgsDxfPaintEngine::currentWidth() const
{
if ( !mPaintDevice )
{
return 1;
}

return mPen.widthF() * mPaintDevice->widthScaleFactor();
}
66 changes: 66 additions & 0 deletions src/core/dxf/qgsdxfpaintengine.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/***************************************************************************
qgsdxpaintengine.h
------------------
begin : November 2013
copyright : (C) 2013 by Marco Hugentobler
email : marco at sourcepole dot ch
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSDXFPAINTENGINE_H
#define QGSDXFPAINTENGINE_H

#include <QPaintEngine>

class QgsDxfExport;
class QgsDxfPaintDevice;
class QgsPoint;

class CORE_EXPORT QgsDxfPaintEngine: public QPaintEngine
{
public:
QgsDxfPaintEngine( const QgsDxfPaintDevice* dxfDevice, QgsDxfExport* dxf );
~QgsDxfPaintEngine();

bool begin( QPaintDevice* pdev );
bool end();
QPaintEngine::Type type() const;
void updateState( const QPaintEngineState& state );

void drawPixmap( const QRectF& r, const QPixmap& pm, const QRectF& sr );

void drawPolygon( const QPointF * points, int pointCount, PolygonDrawMode mode );
void drawRects( const QRectF * rects, int rectCount );
void drawEllipse( const QRectF& rect );
void drawPath( const QPainterPath& path );
void drawLines( const QLineF* lines, int lineCount );

void setLayer( const QString& layer ) { mLayer = layer; }
QString layer() const { return mLayer; }

void setShift( const QPointF& shift ) { mShift = shift; }

private:
const QgsDxfPaintDevice* mPaintDevice;
QgsDxfExport* mDxf;

//painter state information
QTransform mTransform;
QPen mPen;
QString mLayer;
QPointF mShift;

QgsPoint toDxfCoordinates( const QPointF& pt ) const;
int currentPenColor() const;
double currentWidth() const;
};

#endif // QGSDXFPAINTENGINE_H
137 changes: 137 additions & 0 deletions src/core/symbology-ng/qgsellipsesymbollayerv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* *
***************************************************************************/
#include "qgsellipsesymbollayerv2.h"
#include "qgsdxfexport.h"
#include "qgsexpression.h"
#include "qgsfeature.h"
#include "qgsrendercontext.h"
Expand Down Expand Up @@ -492,3 +493,139 @@ QgsSymbolV2::OutputUnit QgsEllipseSymbolLayerV2::outputUnit() const
}
return unit;
}

bool QgsEllipseSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, const QgsSymbolV2RenderContext* context, const QgsFeature* f, const QPointF& shift ) const
{
//width
double symbolWidth = mSymbolWidth;
QgsExpression* widthExpression = expression( "width" );
if ( widthExpression ) //1. priority: data defined setting on symbol layer level
{
symbolWidth = widthExpression->evaluate( const_cast<QgsFeature*>( f ) ).toDouble();
}
else if ( context->renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
{
symbolWidth = mSize;
}
if ( mSymbolWidthUnit == QgsSymbolV2::MM )
{
symbolWidth *= mmMapUnitScaleFactor;
}

//height
double symbolHeight = mSymbolHeight;
QgsExpression* heightExpression = expression( "height" );
if ( heightExpression ) //1. priority: data defined setting on symbol layer level
{
symbolHeight = heightExpression->evaluate( const_cast<QgsFeature*>( f ) ).toDouble();
}
else if ( context->renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
{
symbolHeight = mSize;
}
if ( mSymbolHeightUnit == QgsSymbolV2::MM )
{
symbolHeight *= mmMapUnitScaleFactor;
}

//outline width
double outlineWidth = mOutlineWidth;
QgsExpression* outlineWidthExpression = expression( "outline_width" );
if ( outlineWidthExpression )
{
outlineWidth = outlineWidthExpression->evaluate( const_cast<QgsFeature*>( context->feature() ) ).toDouble();
}
if ( mOutlineWidthUnit == QgsSymbolV2::MM )
{
outlineWidth *= outlineWidth;
}

//color
QColor c = mFillColor;
QgsExpression* fillColorExpression = expression( "fill_color" );
if ( fillColorExpression )
{
c = QColor( fillColorExpression->evaluate( const_cast<QgsFeature*>( context->feature() ) ).toString() );
}
int colorIndex = e.closestColorMatch( c.rgb() );

//symbol name
QString symbolName = mSymbolName;
QgsExpression* symbolNameExpression = expression( "symbol_name" );
if ( symbolNameExpression )
{
QgsExpression* symbolNameExpression = expression( "symbol_name" );
symbolName = symbolNameExpression->evaluate( const_cast<QgsFeature*>( context->feature() ) ).toString();
}

//offset
double offsetX = 0;
double offsetY = 0;
markerOffset( *context, offsetX, offsetY );
QPointF off( offsetX, offsetY );

//priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
double rotation = 0.0;
QgsExpression* rotationExpression = expression( "rotation" );
if ( rotationExpression )
{
rotation = rotationExpression->evaluate( const_cast<QgsFeature*>( context->feature() ) ).toDouble();
}
else if ( !qgsDoubleNear( mAngle, 0.0 ) )
{
rotation = mAngle;
}
rotation = -rotation; //rotation in Qt is counterclockwise
if ( rotation )
off = _rotatedOffset( off, rotation );

QTransform t;
t.translate( shift.x() + offsetX, shift.y() + offsetY );

if ( rotation != 0 )
t.rotate( rotation );

double halfWidth = symbolWidth / 2.0;
double halfHeight = symbolHeight / 2.0;

if ( symbolName == "circle" )
{
//soon...
}
else if ( symbolName == "rectangle" )
{
QPointF pt1( t.map( QPointF( -halfWidth, -halfHeight ) ) );
QPointF pt2( t.map( QPointF( halfWidth, -halfHeight ) ) );
QPointF pt3( t.map( QPointF( -halfWidth, halfHeight ) ) );
QPointF pt4( t.map( QPointF( halfWidth, halfHeight ) ) );
e.writeSolid( layerName, colorIndex, QgsPoint( pt1.x(), pt1.y() ), QgsPoint( pt2.x(), pt2.y() ), QgsPoint( pt3.x(), pt3.y() ), QgsPoint( pt4.x(), pt4.y() ) );
return true;
}
else if ( symbolName == "cross" )
{
QgsPolyline line1( 2 );
QPointF pt1( t.map( QPointF( -halfWidth, 0 ) ) );
QPointF pt2( t.map( QPointF( halfWidth, 0 ) ) );
line1[0] = QgsPoint( pt1.x(), pt1.y() );
line1[1] = QgsPoint( pt2.x(), pt2.y() );
e.writePolyline( line1, layerName, "CONTINUOUS", colorIndex, outlineWidth, false );
QgsPolyline line2( 2 );
QPointF pt3( t.map( QPointF( 0, halfHeight ) ) );
QPointF pt4( t.map( QPointF( 0, -halfHeight ) ) );
line2[0] = QgsPoint( pt3.x(), pt3.y() );
line2[1] = QgsPoint( pt3.x(), pt3.y() );
e.writePolyline( line2, layerName, "CONTINUOUS", colorIndex, outlineWidth, false );
return true;
}
else if ( symbolName == "triangle" )
{
QPointF pt1( t.map( QPointF( -halfWidth, -halfHeight ) ) );
QPointF pt2( t.map( QPointF( halfWidth, -halfHeight ) ) );
QPointF pt3( t.map( QPointF( 0, halfHeight ) ) );
QPointF pt4( t.map( QPointF( 0, halfHeight ) ) );
e.writeSolid( layerName, colorIndex, QgsPoint( pt1.x(), pt1.y() ), QgsPoint( pt2.x(), pt2.y() ), QgsPoint( pt3.x(), pt3.y() ), QgsPoint( pt4.x(), pt4.y() ) );
return true;
}

return false; //soon...
}
2 changes: 2 additions & 0 deletions src/core/symbology-ng/qgsellipsesymbollayerv2.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ class CORE_EXPORT QgsEllipseSymbolLayerV2: public QgsMarkerSymbolLayerV2
void toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props ) const;
void writeSldMarker( QDomDocument& doc, QDomElement &element, QgsStringMap props ) const;

bool writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, const QgsSymbolV2RenderContext* context, const QgsFeature* f, const QPointF& shift = QPointF( 0.0, 0.0 ) ) const;

void setSymbolName( const QString& name ) { mSymbolName = name; }
QString symbolName() const { return mSymbolName; }

Expand Down
199 changes: 199 additions & 0 deletions src/core/symbology-ng/qgsmarkersymbollayerv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include "qgsmarkersymbollayerv2.h"
#include "qgssymbollayerv2utils.h"

#include "qgsdxfexport.h"
#include "qgsdxfpaintdevice.h"
#include "qgsexpression.h"
#include "qgsrendercontext.h"
#include "qgslogger.h"
Expand Down Expand Up @@ -721,6 +723,116 @@ void QgsSimpleMarkerSymbolLayerV2::drawMarker( QPainter* p, QgsSymbolV2RenderCon
}
}

bool QgsSimpleMarkerSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, const QgsSymbolV2RenderContext* context, const QgsFeature* f, const QPointF& shift ) const
{
//data defined size?
double size = mSize;

QgsExpression *sizeExpression = expression( "size" );
bool hasDataDefinedSize = false;
if ( context )
{
hasDataDefinedSize = context->renderHints() & QgsSymbolV2::DataDefinedSizeScale || sizeExpression;
}

//data defined size
if ( hasDataDefinedSize )
{
if ( sizeExpression )
{
size = sizeExpression->evaluate( const_cast<QgsFeature*>( context->feature() ) ).toDouble();
}
size *= QgsSymbolLayerV2Utils::lineWidthScaleFactor( context->renderContext(), mSizeUnit );

switch ( mScaleMethod )
{
case QgsSymbolV2::ScaleArea:
size = sqrt( size );
break;
case QgsSymbolV2::ScaleDiameter:
break;
}
}

if ( mSizeUnit == QgsSymbolV2::MM )
{
size *= mmMapUnitScaleFactor;
}
double halfSize = size / 2.0;


QColor c = mBrush.color();
QgsExpression* colorExpression = expression( "color" );
if ( colorExpression )
{
c = QgsSymbolLayerV2Utils::decodeColor( colorExpression->evaluate( *f ).toString() );
}
int colorIndex = QgsDxfExport::closestColorMatch( c.rgb() );

//offset
double offsetX = 0;
double offsetY = 0;
markerOffset( *context, offsetX, offsetY );
QPointF off( offsetX, offsetY );

//angle
double angle = mAngle;
QgsExpression* angleExpression = expression( "angle" );
if ( angleExpression )
{
angle = angleExpression->evaluate( const_cast<QgsFeature*>( context->feature() ) ).toDouble();
}
angle = -angle; //rotation in Qt is counterclockwise
if ( angle )
off = _rotatedOffset( off, angle );

if ( mSizeUnit == QgsSymbolV2::MM )
{
off *= mmMapUnitScaleFactor;
}

QTransform t;
t.translate( shift.x() + offsetX, shift.y() + offsetY );

if ( angle != 0 )
t.rotate( angle );

//data defined symbol name

if ( mName == "circle" )
{
e.writeGroup( 0, "CIRCLE" );
e.writeGroup( 8, layerName );

e.writeGroup( 62, colorIndex );
e.writeGroup( 10, halfSize + shift.x() );
e.writeGroup( 20, halfSize + shift.y() );
e.writeGroup( 30, 0.0 );
e.writeGroup( 40, halfSize );
}
else if ( mName == "square" || mName == "rectangle" )
{
QPointF pt1 = t.map( QPointF( -halfSize, -halfSize ) );
QPointF pt2 = t.map( QPointF( halfSize, -halfSize ) );
QPointF pt3 = t.map( QPointF( -halfSize, halfSize ) );
QPointF pt4 = t.map( QPointF( halfSize, halfSize ) );
e.writeSolid( layerName, colorIndex, QgsPoint( pt1.x(), pt1.y() ), QgsPoint( pt2.x(), pt2.y() ), QgsPoint( pt3.x(), pt3.y() ), QgsPoint( pt4.x(), pt4.y() ) );
}
else if ( mName == "diamond" )
{
QPointF pt1 = t.map( QPointF( -halfSize, 0 ) );
QPointF pt2 = t.map( QPointF( 0, -halfSize ) );
QPointF pt3 = t.map( QPointF( 0, halfSize ) );
QPointF pt4 = t.map( QPointF( halfSize, 0 ) );
e.writeSolid( layerName, colorIndex, QgsPoint( pt1.x(), pt1.y() ), QgsPoint( pt2.x(), pt2.y() ), QgsPoint( pt3.x(), pt3.y() ), QgsPoint( pt4.x(), pt4.y() ) );
}
else
{
return false;
}
return true;
}

//////////


Expand Down Expand Up @@ -1143,6 +1255,93 @@ QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::createFromSld( QDomElement &element
return m;
}

bool QgsSvgMarkerSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, const QgsSymbolV2RenderContext* context, const QgsFeature* f,
const QPointF& shift ) const
{
Q_UNUSED( layerName );
Q_UNUSED( shift ); //todo...

QSvgRenderer r( mPath );
if ( !r.isValid() )
{
return false;
}

QgsDxfPaintDevice pd( &e );
pd.setDrawingSize( QSizeF( r.defaultSize() ) );

//size
double size = mSize;
QgsExpression* sizeExpression = expression( "size" );
bool hasDataDefinedSize = context->renderHints() & QgsSymbolV2::DataDefinedSizeScale || sizeExpression;

if ( sizeExpression )
{
size = sizeExpression->evaluate( *f ).toDouble();
}
if ( mSizeUnit == QgsSymbolV2::MM )
{
size *= mmMapUnitScaleFactor;
}

if ( hasDataDefinedSize )
{
switch ( mScaleMethod )
{
case QgsSymbolV2::ScaleArea:
size = sqrt( size );
break;
case QgsSymbolV2::ScaleDiameter:
break;
}
}

double halfSize = size / 2.0;

//offset, angle
QPointF offset = mOffset;
QgsExpression* offsetExpression = expression( "offset" );
if ( offsetExpression )
{
QString offsetString = offsetExpression->evaluate( *f ).toString();
offset = QgsSymbolLayerV2Utils::decodePoint( offsetString );
}
double offsetX = offset.x();
double offsetY = offset.y();
if ( mSizeUnit == QgsSymbolV2::MM )
{
offsetX *= mmMapUnitScaleFactor;
offsetY *= mmMapUnitScaleFactor;
}

QPointF outputOffset( offsetX, offsetY );

double angle = mAngle;
QgsExpression* angleExpression = expression( "angle" );
if ( angleExpression )
{
angle = angleExpression->evaluate( *f ).toDouble();
}
//angle = -angle; //rotation in Qt is counterclockwise
if ( angle )
outputOffset = _rotatedOffset( outputOffset, angle );

QPainter p;
p.begin( &pd );
if ( !qgsDoubleNear( angle, 0.0 ) )
{
p.translate( r.defaultSize().width() / 2.0, r.defaultSize().height() / 2.0 );
p.rotate( angle );
p.translate( -r.defaultSize().width() / 2.0, -r.defaultSize().height() / 2.0 );
}
pd.setShift( shift );
pd.setOutputSize( QRectF( -halfSize, -halfSize, size, size ) );
pd.setLayer( layerName );
r.render( &p );
p.end();
return true;
}

//////////

QgsFontMarkerSymbolLayerV2::QgsFontMarkerSymbolLayerV2( QString fontFamily, QChar chr, double pointSize, QColor color, double angle )
Expand Down
4 changes: 4 additions & 0 deletions src/core/symbology-ng/qgsmarkersymbollayerv2.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ class CORE_EXPORT QgsSimpleMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2
QgsSymbolV2::OutputUnit outlineWidthUnit() const { return mOutlineWidthUnit; }
void setOutlineWidthUnit( QgsSymbolV2::OutputUnit u ) { mOutlineWidthUnit = u; }

bool writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, const QgsSymbolV2RenderContext* context, const QgsFeature* f, const QPointF& shift = QPointF( 0.0, 0.0 ) ) const;

protected:

void drawMarker( QPainter* p, QgsSymbolV2RenderContext& context );
Expand Down Expand Up @@ -157,6 +159,8 @@ class CORE_EXPORT QgsSvgMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2
void setOutputUnit( QgsSymbolV2::OutputUnit unit );
QgsSymbolV2::OutputUnit outputUnit() const;

bool writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, const QgsSymbolV2RenderContext* context, const QgsFeature* f, const QPointF& shift = QPointF( 0.0, 0.0 ) ) const;

protected:
QString mPath;

Expand Down
12 changes: 6 additions & 6 deletions src/core/symbology-ng/qgssymbollayerv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ const QgsExpression* QgsSymbolLayerV2::dataDefinedProperty( const QString& prope
return 0;
}

QgsExpression* QgsSymbolLayerV2::expression( const QString& property )
QgsExpression* QgsSymbolLayerV2::expression( const QString& property ) const
{
QMap< QString, QgsExpression* >::iterator it = mDataDefinedProperties.find( property );
if ( it != mDataDefinedProperties.end() )
QMap< QString, QgsExpression* >::const_iterator it = mDataDefinedProperties.find( property );
if ( it != mDataDefinedProperties.constEnd() )
{
return it.value();
}
Expand Down Expand Up @@ -180,14 +180,14 @@ void QgsMarkerSymbolLayerV2::setOutputUnit( QgsSymbolV2::OutputUnit unit )
mOffsetUnit = unit;
}

void QgsMarkerSymbolLayerV2::markerOffset( QgsSymbolV2RenderContext& context, double& offsetX, double& offsetY )
void QgsMarkerSymbolLayerV2::markerOffset( const QgsSymbolV2RenderContext& context, double& offsetX, double& offsetY ) const
{
markerOffset( context, mSize, mSize, mSizeUnit, mSizeUnit, offsetX, offsetY );
}

void QgsMarkerSymbolLayerV2::markerOffset( QgsSymbolV2RenderContext& context, double width, double height,
void QgsMarkerSymbolLayerV2::markerOffset( const QgsSymbolV2RenderContext& context, double width, double height,
QgsSymbolV2::OutputUnit widthUnit, QgsSymbolV2::OutputUnit heightUnit,
double& offsetX, double& offsetY )
double& offsetX, double& offsetY ) const
{
offsetX = mOffset.x();
offsetY = mOffset.y();
Expand Down
16 changes: 12 additions & 4 deletions src/core/symbology-ng/qgssymbollayerv2.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class QPainter;
class QSize;
class QPolygonF;

class QgsDxfExport;
class QgsExpression;
class QgsRenderContext;

Expand Down Expand Up @@ -91,6 +92,10 @@ class CORE_EXPORT QgsSymbolLayerV2
virtual void setDataDefinedProperty( const QString& property, const QString& expressionString );
virtual void removeDataDefinedProperty( const QString& property );
virtual void removeDataDefinedProperties();
bool hasDataDefinedProperties() const { return mDataDefinedProperties.size() > 0; }

virtual bool writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, const QgsSymbolV2RenderContext* context, const QgsFeature* f, const QPointF& shift = QPointF( 0.0, 0.0 ) ) const
{ Q_UNUSED( e ); Q_UNUSED( mmMapUnitScaleFactor ); Q_UNUSED( layerName ); Q_UNUSED( context ); Q_UNUSED( f ); Q_UNUSED( shift ); return false; }

protected:
QgsSymbolLayerV2( QgsSymbolV2::SymbolType type, bool locked = false )
Expand All @@ -109,7 +114,8 @@ class CORE_EXPORT QgsSymbolLayerV2
static const bool selectFillStyle = false; // Fill symbol uses symbol layer style..

virtual void prepareExpressions( const QgsVectorLayer* vl, double scale = -1 );
virtual QgsExpression* expression( const QString& property );
virtual QgsExpression* expression( const QString& property ) const;

/**Saves data defined properties to string map*/
void saveDataDefinedProperties( QgsStringMap& stringMap ) const;
/**Copies data defined properties of this layer to another symbol layer*/
Expand Down Expand Up @@ -174,11 +180,13 @@ class CORE_EXPORT QgsMarkerSymbolLayerV2 : public QgsSymbolLayerV2

protected:
QgsMarkerSymbolLayerV2( bool locked = false );

//handles marker offset and anchor point shift together
void markerOffset( QgsSymbolV2RenderContext& context, double& offsetX, double& offsetY );
void markerOffset( QgsSymbolV2RenderContext& context, double width, double height,
void markerOffset( const QgsSymbolV2RenderContext& context, double& offsetX, double& offsetY ) const;
void markerOffset( const QgsSymbolV2RenderContext& context, double width, double height,
QgsSymbolV2::OutputUnit widthUnit, QgsSymbolV2::OutputUnit heightUnit,
double& offsetX, double& offsetY );
double& offsetX, double& offsetY ) const;

static QPointF _rotatedOffset( const QPointF& offset, double angle );

double mAngle;
Expand Down
8 changes: 7 additions & 1 deletion src/ui/qgisapp.ui
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<x>0</x>
<y>0</y>
<width>1050</width>
<height>31</height>
<height>20</height>
</rect>
</property>
<widget class="QMenu" name="mProjectMenu">
Expand Down Expand Up @@ -47,6 +47,7 @@
<addaction name="mActionSaveProject"/>
<addaction name="mActionSaveProjectAs"/>
<addaction name="mActionSaveMapAsImage"/>
<addaction name="mActionDxfExport"/>
<addaction name="separator"/>
<addaction name="mActionNewPrintComposer"/>
<addaction name="mActionShowComposerManager"/>
Expand Down Expand Up @@ -2136,6 +2137,11 @@ Acts on currently active editable layer</string>
<string>Paste features in clipboard into a new memory vector layer.</string>
</property>
</action>
<action name="mActionDxfExport">
<property name="text">
<string>DXF Export...</string>
</property>
</action>
</widget>
<resources>
<include location="../../images/images.qrc"/>
Expand Down
124 changes: 124 additions & 0 deletions src/ui/qgsdxfexportdialogbase.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QgsDxfExportDialogBase</class>
<widget class="QDialog" name="QgsDxfExportDialogBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>377</width>
<height>292</height>
</rect>
</property>
<property name="windowTitle">
<string>DXF export</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QLineEdit" name="mFileLineEdit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="mSymbologyModeLabel">
<property name="text">
<string>Symbology mode</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="mSymbologyScaleLabel">
<property name="text">
<string>Symbology scale</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="mSaveAsLabel">
<property name="text">
<string>Save as</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QToolButton" name="mFileSelectionButton">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QComboBox" name="mSymbologyModeComboBox">
<item>
<property name="text">
<string>No symbology</string>
</property>
</item>
<item>
<property name="text">
<string>Feature symbology</string>
</property>
</item>
<item>
<property name="text">
<string>Symbol layer symbology</string>
</property>
</item>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QLineEdit" name="mSymbologyScaleLineEdit"/>
</item>
<item row="3" column="0" colspan="3">
<widget class="QListWidget" name="mLayersListWidget"/>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>QgsDxfExportDialogBase</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>QgsDxfExportDialogBase</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>