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