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