QGIS API Documentation  2.18.3-Las Palmas (77b8c3d)
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( QgsPointSequenceV2 &polyline, const QPointF *points, int pointCount )
70 {
71  polyline.clear();
72  for ( int i = 0; i < pointCount; ++i )
73  polyline.append( 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  QgsRingSequenceV2 polygon;
83  polygon << QgsPointSequenceV2();
84  setRing( polygon.last(), points, pointCount );
85 
86  if ( mode == QPaintEngine::PolylineMode )
87  {
88  if ( mPen.style() != Qt::NoPen && mPen.brush().style() != Qt::NoBrush )
89  mDxf->writePolyline( polygon.at( 0 ), mLayer, "CONTINUOUS", mPen.color(), currentWidth() );
90  }
91  else
92  {
93  if ( mBrush.style() != Qt::NoBrush )
94  mDxf->writePolygon( polygon, mLayer, "SOLID", mBrush.color() );
95  }
96 }
97 
99 {
100  int pathLength = path.elementCount();
101  for ( int i = 0; i < pathLength; ++i )
102  {
103  const QPainterPath::Element& pathElem = path.elementAt( i );
104  if ( pathElem.type == QPainterPath::MoveToElement )
105  {
106  moveTo( pathElem.x, pathElem.y );
107  }
108  else if ( pathElem.type == QPainterPath::LineToElement )
109  {
110  lineTo( pathElem.x, pathElem.y );
111  }
112  else if ( pathElem.type == QPainterPath::CurveToElement )
113  {
114  curveTo( pathElem.x, pathElem.y );
115  }
116  else if ( pathElem.type == QPainterPath::CurveToDataElement )
117  {
118  mCurrentCurve.append( QPointF( pathElem.x, pathElem.y ) );
119  }
120  }
121  endCurve();
122  endPolygon();
123 
124  if ( !mPolygon.isEmpty() && mBrush.style() != Qt::NoBrush )
125  mDxf->writePolygon( mPolygon, mLayer, "SOLID", mBrush.color() );
126 
127  mPolygon.clear();
128 }
129 
130 void QgsDxfPaintEngine::moveTo( double dx, double dy )
131 {
132  endCurve();
133  endPolygon();
134  mCurrentPolygon.append( QPointF( dx, dy ) );
135 }
136 
137 void QgsDxfPaintEngine::lineTo( double dx, double dy )
138 {
139  endCurve();
140  mCurrentPolygon.append( QPointF( dx, dy ) );
141 }
142 
143 void QgsDxfPaintEngine::curveTo( double dx, double dy )
144 {
145  endCurve();
146  if ( !mCurrentPolygon.isEmpty() )
147  mCurrentCurve.append( mCurrentPolygon.last() );
148 
149  mCurrentCurve.append( QPointF( dx, dy ) );
150 }
151 
152 void QgsDxfPaintEngine::endPolygon()
153 {
154  if ( mCurrentPolygon.size() > 1 )
155  {
156  if ( mPen.style() != Qt::NoPen )
157  drawPolygon( mCurrentPolygon.constData(), mCurrentPolygon.size(), QPaintEngine::PolylineMode );
158 
159  mPolygon << QgsPointSequenceV2();
160  setRing( mPolygon.last(), mCurrentPolygon.constData(), mCurrentPolygon.size() );
161  }
162  mCurrentPolygon.clear();
163 }
164 
165 void QgsDxfPaintEngine::endCurve()
166 {
167  if ( mCurrentCurve.size() < 1 )
168  return;
169 
170  if ( mCurrentPolygon.size() < 1 )
171  {
172  mCurrentCurve.clear();
173  return;
174  }
175 
176  if ( mCurrentCurve.size() >= 3 )
177  {
178  double t = 0.05;
179  for ( int i = 1; i <= 20; ++i ) //approximate curve with 20 segments
180  {
181  mCurrentPolygon.append( bezierPoint( mCurrentCurve, t ) );
182  t += 0.05;
183  }
184  }
185  else if ( mCurrentCurve.size() == 2 )
186  {
187  mCurrentPolygon.append( mCurrentCurve.at( 1 ) );
188  }
189  mCurrentCurve.clear();
190 }
191 
192 void QgsDxfPaintEngine::drawLines( const QLineF* lines, int lineCount )
193 {
194  if ( !mDxf || !mPaintDevice || !lines || mPen.style() == Qt::NoPen )
195  return;
196 
197  for ( int i = 0; i < lineCount; ++i )
198  {
199  mDxf->writeLine( toDxfCoordinates( lines[i].p1() ),
200  toDxfCoordinates( lines[i].p2() ),
201  mLayer, "CONTINUOUS", mPen.color(), currentWidth() );
202  }
203 }
204 
205 QgsPointV2 QgsDxfPaintEngine::toDxfCoordinates( QPointF pt ) const
206 {
207  if ( !mPaintDevice || !mDxf )
208  return QgsPointV2( pt.x(), pt.y() );
209 
210  QPointF dxfPt = mPaintDevice->dxfCoordinates( mTransform.map( pt ) ) + mShift;
211  return QgsPointV2( dxfPt.x(), dxfPt.y() );
212 }
213 
214 
215 double QgsDxfPaintEngine::currentWidth() const
216 {
217  if ( !mPaintDevice )
218  return 1;
219 
220  return mPen.widthF() * mPaintDevice->widthScaleFactor();
221 }
222 
223 QPointF QgsDxfPaintEngine::bezierPoint( const QList<QPointF>& controlPolygon, double t )
224 {
225  double x = 0;
226  double y = 0;
227  int cPolySize = controlPolygon.size();
228  double bPoly = 0;
229 
230  QList<QPointF>::const_iterator it = controlPolygon.constBegin();
231  int i = 0;
232  for ( ; it != controlPolygon.constEnd(); ++it )
233  {
234  bPoly = bernsteinPoly( cPolySize - 1, i, t );
235  x += ( it->x() * bPoly );
236  y += ( it->y() * bPoly );
237  ++i;
238  }
239 
240  return QPointF( x, y );
241 }
242 
243 double QgsDxfPaintEngine::bernsteinPoly( int n, int i, double t )
244 {
245  if ( i < 0 )
246  return 0;
247 
248  return lower( n, i )*power( t, i )*power(( 1 - t ), ( n - i ) );
249 }
250 
251 int QgsDxfPaintEngine::lower( int n, int i )
252 {
253  if ( i >= 0 && i <= n )
254  {
255  return faculty( n ) / ( faculty( i )*faculty( n - i ) );
256  }
257  else
258  {
259  return 0;
260  }
261 }
262 
263 double QgsDxfPaintEngine::power( double a, int b )
264 {
265  if ( b == 0 )
266  return 1;
267 
268  double tmp = a;
269  for ( int i = 2; i <= qAbs( static_cast< double >( b ) ); i++ )
270  a *= tmp;
271 
272  if ( b > 0 )
273  return a;
274  else
275  return 1.0 / a;
276 }
277 
278 int QgsDxfPaintEngine::faculty( int n )
279 {
280  if ( n < 0 )//Is faculty also defined for negative integers?
281  return 0;
282 
283  int i;
284  int result = n;
285 
286  if ( n == 0 || n == 1 )
287  return 1; //faculty of 0 is 1!
288 
289  for ( i = n - 1; i >= 2; i-- )
290  result *= i;
291 
292  return result;
293 }
void clear()
Qt::PenStyle style() const
QPointF dxfCoordinates(QPointF pt) const
Converts a point from device coordinates to dxf coordinates.
Q_DECL_DEPRECATED 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
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)
QBrush brush() const
double widthScaleFactor() const
Returns scale factor for line width.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspointv2.h:34
bool isEmpty() const
QgsDxfPaintEngine(const QgsDxfPaintDevice *dxfDevice, QgsDxfExport *dxf)
const T * constData() const
Q_DECL_DEPRECATED 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
bool isEmpty() const
T & last()
void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) override
Q_DECL_DEPRECATED void writePolygon(const QgsPolygon &polygon, const QString &layer, const QString &hatchPattern, const QColor &color)
Draw dxf filled 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
QList< QgsPointV2 > QgsPointSequenceV2