QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
qgsdxfpaintengine.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsdxpaintengine.cpp
3 --------------------
4 begin : November 2013
5 copyright : (C) 2013 by Marco Hugentobler
6 email : marco at sourcepole dot ch
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include "qgsdxfpaintengine.h"
19
20#include "qgsdxfexport.h"
21#include "qgsdxfpaintdevice.h"
22#include "qgslogger.h"
23
25 : QPaintEngine( QPaintEngine::AllFeatures /*QPaintEngine::PainterPaths | QPaintEngine::PaintOutsidePaintEvent*/ )
26 , mPaintDevice( dxfDevice )
27 , mDxf( dxf )
28{
29}
30
31bool QgsDxfPaintEngine::begin( QPaintDevice *pdev )
32{
33 Q_UNUSED( pdev )
34 return true;
35}
36
38{
39 return true;
40}
41
42QPaintEngine::Type QgsDxfPaintEngine::type() const
43{
44 return QPaintEngine::User;
45}
46
47void QgsDxfPaintEngine::drawPixmap( const QRectF &r, const QPixmap &pm, const QRectF &sr )
48{
49 Q_UNUSED( r )
50 Q_UNUSED( pm )
51 Q_UNUSED( sr )
52}
53
54void QgsDxfPaintEngine::updateState( const QPaintEngineState &state )
55{
56 if ( state.state() & QPaintEngine::DirtyTransform )
57 mTransform = state.transform();
58
59 if ( state.state() & QPaintEngine::DirtyPen )
60 mPen = state.pen();
61
62 if ( state.state() & QPaintEngine::DirtyBrush )
63 mBrush = state.brush();
64
65 if ( state.state() & QPaintEngine::DirtyOpacity )
66 {
67 mOpacity = state.opacity();
68 }
69}
70
71void QgsDxfPaintEngine::setRing( QgsPointSequence &polyline, const QPointF *points, int pointCount )
72{
73 polyline.clear();
74 for ( int i = 0; i < pointCount; ++i )
75 polyline.append( toDxfCoordinates( points[i] ) );
76}
77
78void QgsDxfPaintEngine::drawPolygon( const QPointF *points, int pointCount, PolygonDrawMode mode )
79{
80 Q_UNUSED( mode )
81 if ( !mDxf || !mPaintDevice )
82 return;
83
84 QgsRingSequence polygon;
85 polygon << QgsPointSequence();
86 setRing( polygon.last(), points, pointCount );
87
88 if ( mode == QPaintEngine::PolylineMode )
89 {
90 if ( mPen.style() != Qt::NoPen && mPen.brush().style() != Qt::NoBrush )
91 mDxf->writePolyline( polygon.at( 0 ), mLayer, QStringLiteral( "CONTINUOUS" ), penColor(), currentWidth() );
92 }
93 else
94 {
95 if ( mBrush.style() != Qt::NoBrush )
96 mDxf->writePolygon( polygon, mLayer, QStringLiteral( "SOLID" ), brushColor() );
97 }
98}
99
100void QgsDxfPaintEngine::drawPath( const QPainterPath &path )
101{
102 const int pathLength = path.elementCount();
103 for ( int i = 0; i < pathLength; ++i )
104 {
105 const QPainterPath::Element &pathElem = path.elementAt( i );
106 if ( pathElem.type == QPainterPath::MoveToElement )
107 {
108 moveTo( pathElem.x, pathElem.y );
109 }
110 else if ( pathElem.type == QPainterPath::LineToElement )
111 {
112 lineTo( pathElem.x, pathElem.y );
113 }
114 else if ( pathElem.type == QPainterPath::CurveToElement )
115 {
116 curveTo( pathElem.x, pathElem.y );
117 }
118 else if ( pathElem.type == QPainterPath::CurveToDataElement )
119 {
120 mCurrentCurve.append( QPointF( pathElem.x, pathElem.y ) );
121 }
122 }
123 endCurve();
124 endPolygon();
125
126 if ( !mPolygon.isEmpty() && mBrush.style() != Qt::NoBrush )
127 mDxf->writePolygon( mPolygon, mLayer, QStringLiteral( "SOLID" ), brushColor() );
128
129 mPolygon.clear();
130}
131
132void QgsDxfPaintEngine::moveTo( double dx, double dy )
133{
134 endCurve();
135 endPolygon();
136 mCurrentPolygon.append( QPointF( dx, dy ) );
137}
138
139void QgsDxfPaintEngine::lineTo( double dx, double dy )
140{
141 endCurve();
142 mCurrentPolygon.append( QPointF( dx, dy ) );
143}
144
145void QgsDxfPaintEngine::curveTo( double dx, double dy )
146{
147 endCurve();
148 if ( !mCurrentPolygon.isEmpty() )
149 mCurrentCurve.append( mCurrentPolygon.last() );
150
151 mCurrentCurve.append( QPointF( dx, dy ) );
152}
153
154void QgsDxfPaintEngine::endPolygon()
155{
156 if ( mCurrentPolygon.size() > 1 )
157 {
158 if ( mPen.style() != Qt::NoPen )
159 drawPolygon( mCurrentPolygon.constData(), mCurrentPolygon.size(), QPaintEngine::PolylineMode );
160
161 mPolygon << QgsPointSequence();
162 setRing( mPolygon.last(), mCurrentPolygon.constData(), mCurrentPolygon.size() );
163 }
164 mCurrentPolygon.clear();
165}
166
167void QgsDxfPaintEngine::endCurve()
168{
169 if ( mCurrentCurve.empty() )
170 return;
171
172 if ( mCurrentPolygon.empty() )
173 {
174 mCurrentCurve.clear();
175 return;
176 }
177
178 if ( mCurrentCurve.size() >= 3 )
179 {
180 double t = 0.05;
181 for ( int i = 1; i <= 20; ++i ) //approximate curve with 20 segments
182 {
183 mCurrentPolygon.append( bezierPoint( mCurrentCurve, t ) );
184 t += 0.05;
185 }
186 }
187 else if ( mCurrentCurve.size() == 2 )
188 {
189 mCurrentPolygon.append( mCurrentCurve.at( 1 ) );
190 }
191 mCurrentCurve.clear();
192}
193
194void QgsDxfPaintEngine::drawLines( const QLineF *lines, int lineCount )
195{
196 if ( !mDxf || !mPaintDevice || !lines || mPen.style() == Qt::NoPen )
197 return;
198
199 for ( int i = 0; i < lineCount; ++i )
200 {
201 mDxf->writeLine( toDxfCoordinates( lines[i].p1() ),
202 toDxfCoordinates( lines[i].p2() ),
203 mLayer, QStringLiteral( "CONTINUOUS" ), penColor(), currentWidth() );
204 }
205}
206
207QgsPoint QgsDxfPaintEngine::toDxfCoordinates( QPointF pt ) const
208{
209 if ( !mPaintDevice || !mDxf )
210 return QgsPoint( pt.x(), pt.y() );
211
212 const QPointF dxfPt = mPaintDevice->dxfCoordinates( mTransform.map( pt ) ) + mShift;
213 return QgsPoint( dxfPt.x(), dxfPt.y() );
214}
215
216
217double QgsDxfPaintEngine::currentWidth() const
218{
219 if ( !mPaintDevice )
220 return 1;
221
222 return mPen.widthF() * mPaintDevice->widthScaleFactor();
223}
224
225QPointF QgsDxfPaintEngine::bezierPoint( const QList<QPointF> &controlPolygon, double t )
226{
227 double x = 0;
228 double y = 0;
229 const int cPolySize = controlPolygon.size();
230 double bPoly = 0;
231
232 QList<QPointF>::const_iterator it = controlPolygon.constBegin();
233 int i = 0;
234 for ( ; it != controlPolygon.constEnd(); ++it )
235 {
236 bPoly = bernsteinPoly( cPolySize - 1, i, t );
237 x += ( it->x() * bPoly );
238 y += ( it->y() * bPoly );
239 ++i;
240 }
241
242 return QPointF( x, y );
243}
244
245double QgsDxfPaintEngine::bernsteinPoly( int n, int i, double t )
246{
247 if ( i < 0 )
248 return 0;
249
250 return lower( n, i ) * power( t, i ) * power( ( 1 - t ), ( n - i ) );
251}
252
253int QgsDxfPaintEngine::lower( int n, int i )
254{
255 if ( i >= 0 && i <= n )
256 {
257 return faculty( n ) / ( faculty( i ) * faculty( n - i ) );
258 }
259 else
260 {
261 return 0;
262 }
263}
264
265double QgsDxfPaintEngine::power( double a, int b )
266{
267 if ( b == 0 )
268 return 1;
269
270 const double tmp = a;
271 for ( int i = 2; i <= std::abs( b ); i++ )
272 a *= tmp;
273
274 if ( b > 0 )
275 return a;
276 else
277 return 1.0 / a;
278}
279
280int QgsDxfPaintEngine::faculty( int n )
281{
282 if ( n < 0 )//Is faculty also defined for negative integers?
283 return 0;
284
285 int i;
286 int result = n;
287
288 if ( n == 0 || n == 1 )
289 return 1; //faculty of 0 is 1!
290
291 for ( i = n - 1; i >= 2; i-- )
292 result *= i;
293
294 return result;
295}
296
297QColor QgsDxfPaintEngine::penColor() const
298{
299 if ( qgsDoubleNear( mOpacity, 1.0 ) )
300 {
301 return mPen.color();
302 }
303 QColor c = mPen.color();
304 c.setAlphaF( c.alphaF() * mOpacity );
305 return c;
306}
307
308QColor QgsDxfPaintEngine::brushColor() const
309{
310 if ( qgsDoubleNear( mOpacity, 1.0 ) )
311 {
312 return mBrush.color();
313 }
314 QColor c = mBrush.color();
315 c.setAlphaF( c.alphaF() * mOpacity );
316 return c;
317}
Exports QGIS layers to the DXF format.
A paint device for drawing into dxf files.
QPointF dxfCoordinates(QPointF pt) const
Converts a point from device coordinates to dxf coordinates.
void drawPath(const QPainterPath &path) override
bool begin(QPaintDevice *pdev) override
QgsDxfPaintEngine(const QgsDxfPaintDevice *dxfDevice, QgsDxfExport *dxf)
void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) override
void updateState(const QPaintEngineState &state) override
void drawLines(const QLineF *lines, int lineCount) override
QPaintEngine::Type type() const override
void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) override
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:49
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6607
QVector< QgsPointSequence > QgsRingSequence
QVector< QgsPoint > QgsPointSequence