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