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