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