QGIS API Documentation  2.12.0-Lyon
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 
31 {
32 }
33 
35 {
36  Q_UNUSED( pdev );
37  return true;
38 }
39 
41 {
42  return true;
43 }
44 
45 QPaintEngine::Type QgsDxfPaintEngine::type() const
46 {
47  return QPaintEngine::User;
48 }
49 
50 void 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 
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 
69 void QgsDxfPaintEngine::setRing( QgsPolyline &polyline, const QPointF *points, int pointCount )
70 {
71  polyline.resize( pointCount );
72  for ( int i = 0; i < pointCount; ++i )
73  polyline[i] = toDxfCoordinates( points[i] );
74 }
75 
76 void QgsDxfPaintEngine::drawPolygon( const QPointF *points, int pointCount, PolygonDrawMode mode )
77 {
78  Q_UNUSED( mode );
79  if ( !mDxf || !mPaintDevice )
80  return;
81 
82  QgsPolygon polygon( 1 );
83  setRing( polygon[0], points, pointCount );
84 
85  if ( mode == QPaintEngine::PolylineMode )
86  {
87  if ( mPen.style() != Qt::NoPen && mPen.brush().style() != Qt::NoBrush )
88  mDxf->writePolyline( polygon[0], mLayer, "CONTINUOUS", mPen.color(), currentWidth() );
89  }
90  else
91  {
92  if ( mBrush.style() != Qt::NoBrush )
93  mDxf->writePolygon( polygon, mLayer, "SOLID", mBrush.color() );
94  }
95 }
96 
98 {
99  int pathLength = path.elementCount();
100  for ( int i = 0; i < pathLength; ++i )
101  {
102  const QPainterPath::Element& pathElem = path.elementAt( i );
103  if ( pathElem.type == QPainterPath::MoveToElement )
104  {
105  moveTo( pathElem.x, pathElem.y );
106  }
107  else if ( pathElem.type == QPainterPath::LineToElement )
108  {
109  lineTo( pathElem.x, pathElem.y );
110  }
111  else if ( pathElem.type == QPainterPath::CurveToElement )
112  {
113  curveTo( pathElem.x, pathElem.y );
114  }
115  else if ( pathElem.type == QPainterPath::CurveToDataElement )
116  {
117  mCurrentCurve.append( QPointF( pathElem.x, pathElem.y ) );
118  }
119  }
120  endCurve();
121  endPolygon();
122 
123  if ( mPolygon.size() > 0 && mBrush.style() != Qt::NoBrush )
124  mDxf->writePolygon( mPolygon, mLayer, "SOLID", mBrush.color() );
125 
126  mPolygon.clear();
127 }
128 
129 void QgsDxfPaintEngine::moveTo( double dx, double dy )
130 {
131  endCurve();
132  endPolygon();
133  mCurrentPolygon.append( QPointF( dx, dy ) );
134 }
135 
136 void QgsDxfPaintEngine::lineTo( double dx, double dy )
137 {
138  endCurve();
139  mCurrentPolygon.append( QPointF( dx, dy ) );
140 }
141 
142 void QgsDxfPaintEngine::curveTo( double dx, double dy )
143 {
144  endCurve();
145  if ( mCurrentPolygon.size() > 0 )
146  mCurrentCurve.append( mCurrentPolygon.last() );
147 
148  mCurrentCurve.append( QPointF( dx, dy ) );
149 }
150 
151 void QgsDxfPaintEngine::endPolygon()
152 {
153  if ( mCurrentPolygon.size() > 1 )
154  {
155  if ( mPen.style() != Qt::NoPen )
156  drawPolygon( mCurrentPolygon.constData(), mCurrentPolygon.size(), QPaintEngine::PolylineMode );
157 
158  mPolygon.resize( mPolygon.size() + 1 );
159  setRing( mPolygon[ mPolygon.size() - 1 ], mCurrentPolygon.constData(), mCurrentPolygon.size() );
160  }
161  mCurrentPolygon.clear();
162 }
163 
164 void QgsDxfPaintEngine::endCurve()
165 {
166  if ( mCurrentCurve.size() < 1 )
167  return;
168 
169  if ( mCurrentPolygon.size() < 1 )
170  {
171  mCurrentCurve.clear();
172  return;
173  }
174 
175  if ( mCurrentCurve.size() >= 3 )
176  {
177  double t = 0.05;
178  for ( int i = 1; i <= 20; ++i ) //approximate curve with 20 segments
179  {
180  mCurrentPolygon.append( bezierPoint( mCurrentCurve, t ) );
181  t += 0.05;
182  }
183  }
184  else if ( mCurrentCurve.size() == 2 )
185  {
186  mCurrentPolygon.append( mCurrentCurve.at( 1 ) );
187  }
188  mCurrentCurve.clear();
189 }
190 
191 void QgsDxfPaintEngine::drawLines( const QLineF* lines, int lineCount )
192 {
193  if ( !mDxf || !mPaintDevice || !lines || mPen.style() == Qt::NoPen )
194  return;
195 
196  for ( int i = 0; i < lineCount; ++i )
197  {
198  QgsPoint pt1 = toDxfCoordinates( lines[i].p1() );
199  QgsPoint pt2 = toDxfCoordinates( lines[i].p2() );
200  mDxf->writeLine( pt1, pt2, mLayer, "CONTINUOUS", mPen.color(), currentWidth() );
201  }
202 }
203 
204 QgsPoint QgsDxfPaintEngine::toDxfCoordinates( const QPointF& pt ) const
205 {
206  if ( !mPaintDevice || !mDxf )
207  return QgsPoint( pt.x(), pt.y() );
208 
209  QPointF dxfPt = mPaintDevice->dxfCoordinates( mTransform.map( pt ) ) + mShift;
210  return QgsPoint( dxfPt.x(), dxfPt.y() );
211 }
212 
213 
214 double QgsDxfPaintEngine::currentWidth() const
215 {
216  if ( !mPaintDevice )
217  return 1;
218 
219  return mPen.widthF() * mPaintDevice->widthScaleFactor();
220 }
221 
222 QPointF QgsDxfPaintEngine::bezierPoint( const QList<QPointF>& controlPolygon, double t )
223 {
224  double x = 0;
225  double y = 0;
226  int cPolySize = controlPolygon.size();
227  double bPoly = 0;
228 
229  QList<QPointF>::const_iterator it = controlPolygon.constBegin();
230  int i = 0;
231  for ( ; it != controlPolygon.constEnd(); ++it )
232  {
233  bPoly = bernsteinPoly( cPolySize - 1, i, t );
234  x += ( it->x() * bPoly );
235  y += ( it->y() * bPoly );
236  ++i;
237  }
238 
239  return QPointF( x, y );
240 }
241 
242 double QgsDxfPaintEngine::bernsteinPoly( int n, int i, double t )
243 {
244  if ( i < 0 )
245  return 0;
246 
247  return lower( n, i )*power( t, i )*power(( 1 - t ), ( n - i ) );
248 }
249 
250 int QgsDxfPaintEngine::lower( int n, int i )
251 {
252  if ( i >= 0 && i <= n )
253  {
254  return faculty( n ) / ( faculty( i )*faculty( n - i ) );
255  }
256  else
257  {
258  return 0;
259  }
260 }
261 
262 double QgsDxfPaintEngine::power( double a, int b )
263 {
264  if ( b == 0 )
265  return 1;
266 
267  double tmp = a;
268  for ( int i = 2; i <= qAbs(( double )b ); i++ )
269  a *= tmp;
270 
271  if ( b > 0 )
272  return a;
273  else
274  return 1.0 / a;
275 }
276 
277 int QgsDxfPaintEngine::faculty( int n )
278 {
279  if ( n < 0 )//Is faculty also defined for negative integers?
280  return 0;
281 
282  int i;
283  int result = n;
284 
285  if ( n == 0 || n == 1 )
286  return 1; //faculty of 0 is 1!
287 
288  for ( i = n - 1; i >= 2; i-- )
289  result *= i;
290 
291  return result;
292 }
void clear()
Qt::PenStyle style() const
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)
A paint device for drawing into dxf files.
void append(const T &value)
Qt::BrushStyle style() const
QPoint map(const QPoint &point) const
QPointF dxfCoordinates(const QPointF &pt) const
Converts a point from device coordinates to dxf coordinates.
const T & at(int i) const
T & last()
QTransform transform() const
void drawPath(const QPainterPath &path) override
const QPainterPath::Element & elementAt(int index) const
int elementCount() const
void updateState(const QPaintEngineState &state) override
void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) override
int size() const
const QColor & color() const
QPen pen() const
QColor color() const
void clear()
qreal x() const
qreal y() const
void append(const T &value)
void resize(int size)
QBrush brush() const
double widthScaleFactor() const
Returns scale factor for line width.
QgsDxfPaintEngine(const QgsDxfPaintDevice *dxfDevice, QgsDxfExport *dxf)
const T * constData() const
A class to represent a point.
Definition: qgspoint.h:63
void writePolyline(const QgsPolyline &line, const QString &layer, const QString &lineStyleName, const QColor &color, double width=-1)
Draw dxf primitives (LWPOLYLINE)
void drawLines(const QLineF *lines, int lineCount) override
void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) override
void writePolygon(const QgsPolygon &polygon, const QString &layer, const QString &hatchPattern, const QColor &color)
Draw dxf polygon (HATCH)
qreal widthF() const
QPaintEngine::Type type() const override
bool begin(QPaintDevice *pdev) override
bool end() override
QBrush brush() const
const_iterator constEnd() const
const_iterator constBegin() const
QPaintEngine::DirtyFlags state() const
int size() const