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