QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
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
24#include <QString>
25
26using namespace Qt::StringLiterals;
27
29 : QPaintEngine( QPaintEngine::AllFeatures /*QPaintEngine::PainterPaths | QPaintEngine::PaintOutsidePaintEvent*/ )
30 , mPaintDevice( dxfDevice )
31 , mDxf( dxf )
32{}
33
34bool QgsDxfPaintEngine::begin( QPaintDevice *pdev )
35{
36 Q_UNUSED( pdev )
37 return true;
38}
39
41{
42 return true;
43}
44
45QPaintEngine::Type QgsDxfPaintEngine::type() const
46{
47 return QPaintEngine::User;
48}
49
50void QgsDxfPaintEngine::drawPixmap( const QRectF &r, const QPixmap &pm, const QRectF &sr )
51{
52 Q_UNUSED( r )
53 Q_UNUSED( pm )
54 Q_UNUSED( sr )
55}
56
57void QgsDxfPaintEngine::updateState( const QPaintEngineState &state )
58{
59 if ( state.state() & QPaintEngine::DirtyTransform )
60 mTransform = state.transform();
61
62 if ( state.state() & QPaintEngine::DirtyPen )
63 mPen = state.pen();
64
65 if ( state.state() & QPaintEngine::DirtyBrush )
66 mBrush = state.brush();
67
68 if ( state.state() & QPaintEngine::DirtyOpacity )
69 {
70 mOpacity = state.opacity();
71 }
72}
73
74void QgsDxfPaintEngine::setRing( QgsPointSequence &polyline, const QPointF *points, int pointCount )
75{
76 polyline.clear();
77 for ( int i = 0; i < pointCount; ++i )
78 polyline.append( toDxfCoordinates( points[i] ) );
79}
80
81void QgsDxfPaintEngine::drawPolygon( const QPointF *points, int pointCount, PolygonDrawMode mode )
82{
83 Q_UNUSED( mode )
84 if ( !mDxf || !mPaintDevice )
85 return;
86
87 QgsRingSequence polygon;
88 polygon << QgsPointSequence();
89 setRing( polygon.last(), points, pointCount );
90
91 if ( mode == QPaintEngine::PolylineMode )
92 {
93 if ( mPen.style() != Qt::NoPen && mPen.brush().style() != Qt::NoBrush )
94 mDxf->writePolyline( polygon.at( 0 ), mLayer, u"CONTINUOUS"_s, penColor(), currentWidth() );
95 }
96 else
97 {
98 if ( mBrush.style() != Qt::NoBrush )
99 mDxf->writePolygon( polygon, mLayer, u"SOLID"_s, brushColor() );
100 }
101}
102
103void QgsDxfPaintEngine::drawPath( const QPainterPath &path )
104{
105 const int pathLength = path.elementCount();
106 for ( int i = 0; i < pathLength; ++i )
107 {
108 const QPainterPath::Element &pathElem = path.elementAt( i );
109 if ( pathElem.type == QPainterPath::MoveToElement )
110 {
111 moveTo( pathElem.x, pathElem.y );
112 }
113 else if ( pathElem.type == QPainterPath::LineToElement )
114 {
115 lineTo( pathElem.x, pathElem.y );
116 }
117 else if ( pathElem.type == QPainterPath::CurveToElement )
118 {
119 curveTo( pathElem.x, pathElem.y );
120 }
121 else if ( pathElem.type == QPainterPath::CurveToDataElement )
122 {
123 mCurrentCurve.append( QPointF( pathElem.x, pathElem.y ) );
124 }
125 }
126 endCurve();
127 endPolygon();
128
129 if ( !mPolygon.isEmpty() && mBrush.style() != Qt::NoBrush )
130 mDxf->writePolygon( mPolygon, mLayer, u"SOLID"_s, brushColor() );
131
132 mPolygon.clear();
133}
134
135void QgsDxfPaintEngine::moveTo( double dx, double dy )
136{
137 endCurve();
138 endPolygon();
139 mCurrentPolygon.append( QPointF( dx, dy ) );
140}
141
142void QgsDxfPaintEngine::lineTo( double dx, double dy )
143{
144 endCurve();
145 mCurrentPolygon.append( QPointF( dx, dy ) );
146}
147
148void QgsDxfPaintEngine::curveTo( double dx, double dy )
149{
150 endCurve();
151 if ( !mCurrentPolygon.isEmpty() )
152 mCurrentCurve.append( mCurrentPolygon.last() );
153
154 mCurrentCurve.append( QPointF( dx, dy ) );
155}
156
157void QgsDxfPaintEngine::endPolygon()
158{
159 if ( mCurrentPolygon.size() > 1 )
160 {
161 if ( mPen.style() != Qt::NoPen )
162 drawPolygon( mCurrentPolygon.constData(), mCurrentPolygon.size(), QPaintEngine::PolylineMode );
163
164 mPolygon << QgsPointSequence();
165 setRing( mPolygon.last(), mCurrentPolygon.constData(), mCurrentPolygon.size() );
166 }
167 mCurrentPolygon.clear();
168}
169
170void QgsDxfPaintEngine::endCurve()
171{
172 if ( mCurrentCurve.empty() )
173 return;
174
175 if ( mCurrentPolygon.empty() )
176 {
177 mCurrentCurve.clear();
178 return;
179 }
180
181 if ( mCurrentCurve.size() >= 3 )
182 {
183 double t = 0.05;
184 for ( int i = 1; i <= 20; ++i ) //approximate curve with 20 segments
185 {
186 mCurrentPolygon.append( bezierPoint( mCurrentCurve, t ) );
187 t += 0.05;
188 }
189 }
190 else if ( mCurrentCurve.size() == 2 )
191 {
192 mCurrentPolygon.append( mCurrentCurve.at( 1 ) );
193 }
194 mCurrentCurve.clear();
195}
196
197void QgsDxfPaintEngine::drawLines( const QLineF *lines, int lineCount )
198{
199 if ( !mDxf || !mPaintDevice || !lines || mPen.style() == Qt::NoPen )
200 return;
201
202 for ( int i = 0; i < lineCount; ++i )
203 {
204 mDxf->writeLine( toDxfCoordinates( lines[i].p1() ), toDxfCoordinates( lines[i].p2() ), mLayer, u"CONTINUOUS"_s, penColor(), currentWidth() );
205 }
206}
207
208QgsPoint QgsDxfPaintEngine::toDxfCoordinates( QPointF pt ) const
209{
210 if ( !mPaintDevice || !mDxf )
211 return QgsPoint( pt.x(), pt.y() );
212
213 const QPointF dxfPt = mPaintDevice->dxfCoordinates( mTransform.map( pt ) ) + mShift;
214 return QgsPoint( dxfPt.x(), dxfPt.y() );
215}
216
217
218double QgsDxfPaintEngine::currentWidth() const
219{
220 if ( !mPaintDevice )
221 return 1;
222
223 return mPen.widthF() * mPaintDevice->widthScaleFactor();
224}
225
226QPointF QgsDxfPaintEngine::bezierPoint( const QList<QPointF> &controlPolygon, double t )
227{
228 double x = 0;
229 double y = 0;
230 const int cPolySize = controlPolygon.size();
231 double bPoly = 0;
232
233 QList<QPointF>::const_iterator it = controlPolygon.constBegin();
234 int i = 0;
235 for ( ; it != controlPolygon.constEnd(); ++it )
236 {
237 bPoly = bernsteinPoly( cPolySize - 1, i, t );
238 x += ( it->x() * bPoly );
239 y += ( it->y() * bPoly );
240 ++i;
241 }
242
243 return QPointF( x, y );
244}
245
246double QgsDxfPaintEngine::bernsteinPoly( int n, int i, double t )
247{
248 if ( i < 0 )
249 return 0;
250
251 return lower( n, i ) * power( t, i ) * power( ( 1 - t ), ( n - i ) );
252}
253
254int QgsDxfPaintEngine::lower( int n, int i )
255{
256 if ( i >= 0 && i <= n )
257 {
258 return faculty( n ) / ( faculty( i ) * faculty( n - i ) );
259 }
260 else
261 {
262 return 0;
263 }
264}
265
266double QgsDxfPaintEngine::power( double a, int b )
267{
268 if ( b == 0 )
269 return 1;
270
271 const double tmp = a;
272 for ( int i = 2; i <= std::abs( b ); i++ )
273 a *= tmp;
274
275 if ( b > 0 )
276 return a;
277 else
278 return 1.0 / a;
279}
280
281int QgsDxfPaintEngine::faculty( int n )
282{
283 if ( n < 0 ) //Is faculty also defined for negative integers?
284 return 0;
285
286 int i;
287 int result = n;
288
289 if ( n == 0 || n == 1 )
290 return 1; //faculty of 0 is 1!
291
292 for ( i = n - 1; i >= 2; i-- )
293 result *= i;
294
295 return result;
296}
297
298QColor QgsDxfPaintEngine::penColor() const
299{
300 if ( qgsDoubleNear( mOpacity, 1.0 ) )
301 {
302 return mPen.color();
303 }
304 QColor c = mPen.color();
305 c.setAlphaF( c.alphaF() * mOpacity );
306 return c;
307}
308
309QColor QgsDxfPaintEngine::brushColor() const
310{
311 if ( qgsDoubleNear( mOpacity, 1.0 ) )
312 {
313 return mBrush.color();
314 }
315 QColor c = mBrush.color();
316 c.setAlphaF( c.alphaF() * mOpacity );
317 return c;
318}
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:53
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:6975
QVector< QgsPointSequence > QgsRingSequence
QVector< QgsPoint > QgsPointSequence