QGIS API Documentation  3.14.0-Pi (9f7028fd23)
qgsdxfexport.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsdxfexport.cpp
3  ----------------
4  begin : September 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 // Specs:
19 // AutoCAD 2000: http://www.autodesk.com/techpubs/autocad/acad2000/dxf/
20 // AutoCAD 2002: http://www.autodesk.com/techpubs/autocad/dxf/dxf2002.pdf
21 // AutoCAD 2004: http://atrey.karlin.mff.cuni.cz/projekty/vrr/doc/dxf14.pdf
22 // AutoCAD 2006: http://images.autodesk.com/adsk/files/dxf_format.pdf
23 // AutoCAD 2008: http://images.autodesk.com/adsk/files/acad_dxf0.pdf
24 // AutoCAD 2009: http://images.autodesk.com/adsk/files/acad_dxf.pdf
25 // AutoCAD 2011: http://images.autodesk.com/adsk/files/acad_dxf2.pdf
26 // AutoCAD 2012: http://images.autodesk.com/adsk/files/autocad_2012_pdf_dxf-reference_enu.pdf
27 // AutoCAD 2014: http://images.autodesk.com/adsk/files/autocad_2014_pdf_dxf_reference_enu.pdf
28 
29 #include "qgsdxfexport.h"
31 #include "qgsgeometrycollection.h"
32 #include "qgscurvepolygon.h"
33 #include "qgscompoundcurve.h"
34 #include "qgscircularstring.h"
35 #include "qgslinestring.h"
36 #include "qgsvectordataprovider.h"
37 #include "qgspointxy.h"
38 #include "qgsproject.h"
39 #include "qgsrenderer.h"
40 #include "qgssymbollayer.h"
41 #include "qgsfillsymbollayer.h"
42 #include "qgsfeatureiterator.h"
43 #include "qgslinesymbollayer.h"
44 #include "qgsvectorlayer.h"
45 #include "qgsunittypes.h"
46 #include "qgstextlabelfeature.h"
47 #include "qgslogger.h"
48 #include "qgsmaplayerstyle.h"
51 #include "qgsdxfexport_p.h"
52 
53 #include "qgswkbtypes.h"
54 #include "qgspoint.h"
55 #include "qgsgeos.h"
56 
57 #include "pal/feature.h"
58 #include "pal/pointset.h"
59 #include "pal/labelposition.h"
60 
61 #include <QIODevice>
62 
63 QgsDxfExport::QgsDxfExport() = default;
64 
66 {
67  qDeleteAll( mJobs );
68 }
69 
71 {
72  mMapSettings = settings;
73 }
74 
75 void QgsDxfExport::setFlags( QgsDxfExport::Flags flags )
76 {
77  mFlags = flags;
78 }
79 
80 QgsDxfExport::Flags QgsDxfExport::flags() const
81 {
82  return mFlags;
83 }
84 
85 void QgsDxfExport::addLayers( const QList<DxfLayer> &layers )
86 {
87  QList<QgsMapLayer *> layerList;
88 
89  mLayerNameAttribute.clear();
90 
91  for ( const DxfLayer &dxfLayer : layers )
92  {
93  layerList << dxfLayer.layer();
94  if ( dxfLayer.layerOutputAttributeIndex() >= 0 )
95  mLayerNameAttribute.insert( dxfLayer.layer()->id(), dxfLayer.layerOutputAttributeIndex() );
96  }
97 
98  mMapSettings.setLayers( layerList );
99 }
100 
101 void QgsDxfExport::writeGroup( int code, int i )
102 {
103  writeGroupCode( code );
104  writeInt( i );
105 }
106 
107 void QgsDxfExport::writeGroup( int code, double d )
108 {
109  writeGroupCode( code );
110  writeDouble( d );
111 }
112 
113 void QgsDxfExport::writeGroup( int code, const QString &s )
114 {
115  writeGroupCode( code );
116  writeString( s );
117 }
118 
119 void QgsDxfExport::writeGroup( int code, const QgsPoint &p )
120 {
121  writeGroup( code + 10, p.x() );
122  writeGroup( code + 20, p.y() );
123  if ( !mForce2d && p.is3D() && std::isfinite( p.z() ) )
124  writeGroup( code + 30, p.z() );
125 }
126 
127 void QgsDxfExport::writeGroup( const QColor &color, int exactMatchCode, int rgbCode, int transparencyCode )
128 {
129  int minDistAt = -1;
130  int minDist = std::numeric_limits<int>::max();
131 
132  for ( int i = 1; i < static_cast< int >( sizeof( sDxfColors ) / sizeof( *sDxfColors ) ) && minDist > 0; ++i )
133  {
134  int dist = color_distance( color.rgba(), i );
135  if ( dist >= minDist )
136  continue;
137 
138  minDistAt = i;
139  minDist = dist;
140  }
141 
142  if ( minDist == 0 && minDistAt != 7 )
143  {
144  // exact full opaque match, not black/white
145  writeGroup( exactMatchCode, minDistAt );
146  if ( color.alpha() == 255 )
147  return;
148  }
149 
150  int c = ( color.red() & 0xff ) * 0x10000 + ( color.green() & 0xff ) * 0x100 + ( color.blue() & 0xff );
151  writeGroup( rgbCode, c );
152  if ( transparencyCode != -1 && color.alpha() < 255 )
153  writeGroup( transparencyCode, 0x2000000 | color.alpha() );
154 }
155 
157 {
158  mTextStream << QStringLiteral( "%1\n" ).arg( code, 3, 10, QChar( ' ' ) );
159 }
160 
162 {
163  mTextStream << QStringLiteral( "%1\n" ).arg( i, 6, 10, QChar( ' ' ) );
164 }
165 
167 {
168  QString s( qgsDoubleToString( d ) );
169  if ( !s.contains( '.' ) )
170  s += QLatin1String( ".0" );
171  mTextStream << s << '\n';
172 }
173 
174 void QgsDxfExport::writeString( const QString &s )
175 {
176  mTextStream << s << '\n';
177 }
178 
179 QgsDxfExport::ExportResult QgsDxfExport::writeToFile( QIODevice *d, const QString &encoding )
180 {
181  if ( !d )
182  {
184  }
185 
186  if ( !d->isOpen() && !d->open( QIODevice::WriteOnly | QIODevice::Truncate ) )
187  {
189  }
190 
191  mTextStream.setDevice( d );
192  mTextStream.setCodec( encoding.toLocal8Bit() );
193 
194  if ( mCrs.isValid() )
195  mMapSettings.setDestinationCrs( mCrs );
196 
197  if ( mExtent.isEmpty() )
198  {
199  const QList< QgsMapLayer * > layers = mMapSettings.layers();
200  for ( QgsMapLayer *ml : layers )
201  {
202  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml );
203  if ( !vl )
204  continue;
205 
206  QgsRectangle layerExtent = vl->extent();
207  if ( layerExtent.isEmpty() )
208  continue;
209 
210  layerExtent = mMapSettings.layerToMapCoordinates( vl, layerExtent );
211 
212  if ( mExtent.isEmpty() )
213  {
214  mExtent = layerExtent;
215  }
216  else
217  {
218  mExtent.combineExtentWith( layerExtent );
219  }
220  }
221  }
222 
223  if ( mExtent.isEmpty() )
225 
227  mMapSettings.setExtent( mExtent );
228 
229  int dpi = 96;
230  mFactor = 1000 * dpi / mSymbologyScale / 25.4 * QgsUnitTypes::fromUnitToUnitFactor( mapUnits, QgsUnitTypes::DistanceMeters );
231  mMapSettings.setOutputSize( QSize( mExtent.width() * mFactor, mExtent.height() * mFactor ) );
232  mMapSettings.setOutputDpi( dpi );
233 
234  writeHeader( dxfEncoding( encoding ) );
235  prepareRenderers();
236  writeTables();
237  writeBlocks();
238  writeEntities();
239  writeEndFile();
240  stopRenderers();
241 
242  return ExportResult::Success;
243 }
244 
246 {
247  return mMapUnits;
248 }
249 
250 void QgsDxfExport::writeHeader( const QString &codepage )
251 {
252  writeGroup( 999, QStringLiteral( "DXF created from QGIS" ) );
253 
254  startSection();
255  writeGroup( 2, QStringLiteral( "HEADER" ) );
256 
257  // ACADVER
258  writeGroup( 9, QStringLiteral( "$ACADVER" ) );
259  writeGroup( 1, QStringLiteral( "AC1015" ) );
260 
261  // EXTMIN
262  writeGroup( 9, QStringLiteral( "$EXTMIN" ) );
263  writeGroup( 0, QgsPoint( QgsWkbTypes::PointZ, mExtent.xMinimum(), mExtent.yMinimum(), 0.0 ) );
264 
265  // EXTMAX
266  writeGroup( 9, QStringLiteral( "$EXTMAX" ) );
267  writeGroup( 0, QgsPoint( QgsWkbTypes::PointZ, mExtent.xMaximum(), mExtent.yMaximum(), 0.0 ) );
268 
269  // Global linetype scale
270  writeGroup( 9, QStringLiteral( "$LTSCALE" ) );
271  writeGroup( 40, 1.0 );
272 
273  // Point display mode (33 = circle)
274  writeGroup( 9, QStringLiteral( "$PDMODE" ) );
275  writeGroup( 70, 33 );
276 
277  // Point display size
278  writeGroup( 9, QStringLiteral( "$PDSIZE" ) );
279  writeGroup( 40, 1 );
280 
281  // Controls paper space linetype scaling (1 = No special linetype scaling, 0 = Viewport scaling governs linetype scaling)
282  writeGroup( 9, QStringLiteral( "$PSLTSCALE" ) );
283  writeGroup( 70, 0 );
284 
285  writeGroup( 9, QStringLiteral( "$HANDSEED" ) );
286  writeGroup( 5, DXF_HANDMAX );
287 
288  writeGroup( 9, QStringLiteral( "$DWGCODEPAGE" ) );
289  writeGroup( 3, codepage );
290 
291  endSection();
292 }
293 
294 int QgsDxfExport::writeHandle( int code, int handle )
295 {
296  if ( handle == 0 )
297  handle = mNextHandleId++;
298 
299  Q_ASSERT_X( handle < DXF_HANDMAX, "QgsDxfExport::writeHandle(int, int)", "DXF handle too large" );
300 
301  writeGroup( code, QStringLiteral( "%1" ).arg( handle, 0, 16 ) );
302  return handle;
303 }
304 
305 void QgsDxfExport::writeTables()
306 {
307  startSection();
308  writeGroup( 2, QStringLiteral( "TABLES" ) );
309 
310  // Iterate through all layers and get symbol layer pointers
311  QgsRenderContext context = renderContext();
312  QList< QPair< QgsSymbolLayer *, QgsSymbol * > > slList;
313  if ( mSymbologyExport != NoSymbology )
314  {
315  slList = symbolLayers( context );
316  }
317 
318  // Line types
319  mLineStyles.clear();
320  writeGroup( 0, QStringLiteral( "TABLE" ) );
321  writeGroup( 2, QStringLiteral( "LTYPE" ) );
322  writeHandle();
323  writeGroup( 100, QStringLiteral( "AcDbSymbolTable" ) );
324  writeGroup( 70, nLineTypes( slList ) + 5 );
325 
326  writeDefaultLinetypes();
327 
328  // Add custom linestyles
329  for ( const auto &symbolLayer : qgis::as_const( slList ) )
330  {
331  writeSymbolLayerLinetype( symbolLayer.first );
332  }
333 
334  writeGroup( 0, QStringLiteral( "ENDTAB" ) );
335 
336  // BLOCK_RECORD
337  writeGroup( 0, QStringLiteral( "TABLE" ) );
338  writeGroup( 2, QStringLiteral( "BLOCK_RECORD" ) );
339  writeHandle();
340 
341  writeGroup( 100, QStringLiteral( "AcDbSymbolTable" ) );
342  writeGroup( 70, 0 );
343 
344  const QStringList blockStrings = QStringList() << QStringLiteral( "*Model_Space" ) << QStringLiteral( "*Paper_Space" ) << QStringLiteral( "*Paper_Space0" );
345  for ( const QString &block : blockStrings )
346  {
347  writeGroup( 0, QStringLiteral( "BLOCK_RECORD" ) );
348  mBlockHandles.insert( block, writeHandle() );
349  writeGroup( 100, QStringLiteral( "AcDbSymbolTableRecord" ) );
350  writeGroup( 100, QStringLiteral( "AcDbBlockTableRecord" ) );
351  writeGroup( 2, block );
352  }
353 
354  int i = 0;
355  for ( const auto &symbolLayer : qgis::as_const( slList ) )
356  {
357  QgsMarkerSymbolLayer *ml = dynamic_cast< QgsMarkerSymbolLayer *>( symbolLayer.first );
358  if ( !ml )
359  continue;
360 
361  if ( hasDataDefinedProperties( ml, symbolLayer.second ) )
362  continue;
363 
364  QString name = QStringLiteral( "symbolLayer%1" ).arg( i++ );
365  writeGroup( 0, QStringLiteral( "BLOCK_RECORD" ) );
366  mBlockHandles.insert( name, writeHandle() );
367  writeGroup( 100, QStringLiteral( "AcDbSymbolTableRecord" ) );
368  writeGroup( 100, QStringLiteral( "AcDbBlockTableRecord" ) );
369  writeGroup( 2, name );
370  }
371 
372  writeGroup( 0, QStringLiteral( "ENDTAB" ) );
373 
374  // APPID
375  writeGroup( 0, QStringLiteral( "TABLE" ) );
376  writeGroup( 2, QStringLiteral( "APPID" ) );
377  writeHandle();
378  writeGroup( 100, QStringLiteral( "AcDbSymbolTable" ) );
379  writeGroup( 70, 1 );
380  writeGroup( 0, QStringLiteral( "APPID" ) );
381  writeHandle();
382  writeGroup( 100, QStringLiteral( "AcDbSymbolTableRecord" ) );
383  writeGroup( 100, QStringLiteral( "AcDbRegAppTableRecord" ) );
384  writeGroup( 2, QStringLiteral( "ACAD" ) );
385  writeGroup( 70, 0 );
386  writeGroup( 0, QStringLiteral( "ENDTAB" ) );
387 
388  // VIEW
389  writeGroup( 0, QStringLiteral( "TABLE" ) );
390  writeGroup( 2, QStringLiteral( "VIEW" ) );
391  writeHandle();
392  writeGroup( 100, QStringLiteral( "AcDbSymbolTable" ) );
393  writeGroup( 70, 0 );
394  writeGroup( 0, QStringLiteral( "ENDTAB" ) );
395 
396  // UCS
397  writeGroup( 0, QStringLiteral( "TABLE" ) );
398  writeGroup( 2, QStringLiteral( "UCS" ) );
399  writeHandle();
400  writeGroup( 100, QStringLiteral( "AcDbSymbolTable" ) );
401  writeGroup( 70, 0 );
402  writeGroup( 0, QStringLiteral( "ENDTAB" ) );
403 
404  // VPORT
405  writeGroup( 0, QStringLiteral( "TABLE" ) );
406  writeGroup( 2, QStringLiteral( "VPORT" ) );
407  writeHandle();
408  writeGroup( 100, QStringLiteral( "AcDbSymbolTable" ) );
409 
410  writeGroup( 0, QStringLiteral( "VPORT" ) );
411  writeHandle();
412  writeGroup( 100, QStringLiteral( "AcDbSymbolTableRecord" ) );
413  writeGroup( 100, QStringLiteral( "AcDbViewportTableRecord" ) );
414  writeGroup( 2, QStringLiteral( "*ACTIVE" ) );
415  writeGroup( 70, 0 ); // flags
416  writeGroup( 0, QgsPoint( 0.0, 0.0 ) ); // lower left
417  writeGroup( 1, QgsPoint( 1.0, 1.0 ) ); // upper right
418  writeGroup( 2, QgsPoint( 0.0, 0.0 ) ); // view center point
419  writeGroup( 3, QgsPoint( 0.0, 0.0 ) ); // snap base point
420  writeGroup( 4, QgsPoint( 1.0, 1.0 ) ); // snap spacing
421  writeGroup( 5, QgsPoint( 1.0, 1.0 ) ); // grid spacing
422  writeGroup( 6, QgsPoint( QgsWkbTypes::PointZ, 0.0, 0.0, 1.0 ) ); // view direction from target point
423  writeGroup( 7, QgsPoint( mExtent.center() ) ); // view target point
424  writeGroup( 40, mExtent.height() ); // view height
425  writeGroup( 41, mExtent.width() / mExtent.height() ); // view aspect ratio
426  writeGroup( 42, 50.0 ); // lens length
427  writeGroup( 43, 0.0 ); // front clipping plane
428  writeGroup( 44, 0.0 ); // back clipping plane
429  writeGroup( 50, 0.0 ); // snap rotation
430  writeGroup( 51, 0.0 ); // view twist angle
431  writeGroup( 71, 0 ); // view mode (0 = deactivates)
432  writeGroup( 72, 100 ); // circle zoom percent
433  writeGroup( 73, 1 ); // fast zoom setting
434  writeGroup( 74, 1 ); // UCSICON setting
435  writeGroup( 75, 0 ); // snapping off
436  writeGroup( 76, 0 ); // grid off
437  writeGroup( 77, 0 ); // snap style
438  writeGroup( 78, 0 ); // snap isopair
439  writeGroup( 281, 0 ); // render mode (0 = 2D optimized)
440  writeGroup( 65, 1 ); // value of UCSVP for this viewport
441  writeGroup( 100, QgsPoint( QgsWkbTypes::PointZ, 0.0, 0.0, 0.0 ) );// UCS origin
442  writeGroup( 101, QgsPoint( QgsWkbTypes::PointZ, 1.0, 0.0, 0.0 ) );// UCS x axis
443  writeGroup( 102, QgsPoint( QgsWkbTypes::PointZ, 0.0, 1.0, 0.0 ) );// UCS y axis
444  writeGroup( 79, 0 ); // Orthographic type of UCS (0 = UCS is not orthographic)
445  writeGroup( 146, 0.0 ); // Elevation
446 
447  writeGroup( 70, 0 );
448  writeGroup( 0, QStringLiteral( "ENDTAB" ) );
449 
450  // DIMSTYLE
451  writeGroup( 0, QStringLiteral( "TABLE" ) );
452  writeGroup( 2, QStringLiteral( "DIMSTYLE" ) );
453  writeHandle();
454  writeGroup( 100, QStringLiteral( "AcDbSymbolTable" ) );
455  writeGroup( 100, QStringLiteral( "AcDbDimStyleTable" ) );
456  writeGroup( 70, 0 );
457  writeGroup( 0, QStringLiteral( "ENDTAB" ) );
458 
459  QSet<QString> layerNames;
460  const QList< QgsMapLayer * > layers = mMapSettings.layers();
461  for ( QgsMapLayer *ml : layers )
462  {
463  if ( !layerIsScaleBasedVisible( ml ) )
464  continue;
465 
466  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml );
467  if ( !vl )
468  continue;
469 
470  int attrIdx = mLayerNameAttribute.value( vl->id(), -1 );
471  if ( attrIdx < 0 )
472  {
473  layerNames << dxfLayerName( layerName( vl ) );
474  }
475  else
476  {
477  const QSet<QVariant> values = vl->uniqueValues( attrIdx );
478  for ( const QVariant &v : values )
479  {
480  layerNames << dxfLayerName( v.toString() );
481  }
482  }
483  }
484 
485  // Layers
486  // TODO: iterate features of all layer to produce a data-defined layer list
487  writeGroup( 0, QStringLiteral( "TABLE" ) );
488  writeGroup( 2, QStringLiteral( "LAYER" ) );
489  writeHandle();
490  writeGroup( 100, QStringLiteral( "AcDbSymbolTable" ) );
491  writeGroup( 70, layerNames.size() + 1 );
492 
493  writeGroup( 0, QStringLiteral( "LAYER" ) );
494  writeHandle();
495  writeGroup( 100, QStringLiteral( "AcDbSymbolTableRecord" ) );
496  writeGroup( 100, QStringLiteral( "AcDbLayerTableRecord" ) );
497  writeGroup( 2, QStringLiteral( "0" ) );
498  writeGroup( 70, 64 );
499  writeGroup( 62, 1 );
500  writeGroup( 6, QStringLiteral( "CONTINUOUS" ) );
502 
503  for ( const QString &layerName : qgis::as_const( layerNames ) )
504  {
505  writeGroup( 0, QStringLiteral( "LAYER" ) );
506  writeHandle();
507  writeGroup( 100, QStringLiteral( "AcDbSymbolTableRecord" ) );
508  writeGroup( 100, QStringLiteral( "AcDbLayerTableRecord" ) );
509  writeGroup( 2, layerName );
510  writeGroup( 70, 64 );
511  writeGroup( 62, 1 );
512  writeGroup( 6, QStringLiteral( "CONTINUOUS" ) );
514  }
515  writeGroup( 0, QStringLiteral( "ENDTAB" ) );
516 
517  // Text styles
518  writeGroup( 0, QStringLiteral( "TABLE" ) );
519  writeGroup( 2, QStringLiteral( "STYLE" ) );
520  writeHandle();
521  writeGroup( 100, QStringLiteral( "AcDbSymbolTable" ) );
522  writeGroup( 70, 1 );
523 
524  // Provide only standard font for the moment
525  writeGroup( 0, QStringLiteral( "STYLE" ) );
526  writeHandle();
527  writeGroup( 100, QStringLiteral( "AcDbSymbolTableRecord" ) );
528  writeGroup( 100, QStringLiteral( "AcDbTextStyleTableRecord" ) );
529  writeGroup( 2, QStringLiteral( "STANDARD" ) );
530  writeGroup( 70, 64 );
531  writeGroup( 40, 0.0 );
532  writeGroup( 41, 1.0 );
533  writeGroup( 50, 0.0 );
534  writeGroup( 71, 0 );
535  writeGroup( 42, 5.0 );
536  writeGroup( 3, QStringLiteral( "romans.shx" ) );
537  writeGroup( 4, QString() );
538 
539  writeGroup( 0, QStringLiteral( "ENDTAB" ) );
540 
541  endSection();
542 }
543 
544 void QgsDxfExport::writeBlocks()
545 {
546  startSection();
547  writeGroup( 2, QStringLiteral( "BLOCKS" ) );
548 
549  static const QStringList blockStrings = QStringList() << QStringLiteral( "*Model_Space" ) << QStringLiteral( "*Paper_Space" ) << QStringLiteral( "*Paper_Space0" );
550  for ( const QString &block : blockStrings )
551  {
552  writeGroup( 0, QStringLiteral( "BLOCK" ) );
553  writeHandle();
554  writeGroup( 330, QStringLiteral( "%1" ).arg( mBlockHandles[ block ], 0, 16 ) );
555  writeGroup( 100, QStringLiteral( "AcDbEntity" ) );
556  writeGroup( 8, QStringLiteral( "0" ) );
557  writeGroup( 100, QStringLiteral( "AcDbBlockBegin" ) );
558  writeGroup( 2, block );
559  writeGroup( 70, 0 );
560  writeGroup( 0, QgsPoint( QgsWkbTypes::PointZ, 0.0, 0.0, 0.0 ) );
561  writeGroup( 3, block );
562  writeGroup( 1, QString() );
563  writeGroup( 0, QStringLiteral( "ENDBLK" ) );
564  writeHandle();
565  writeGroup( 100, QStringLiteral( "AcDbEntity" ) );
566  writeGroup( 8, QStringLiteral( "0" ) );
567  writeGroup( 100, QStringLiteral( "AcDbBlockEnd" ) );
568  }
569 
570  QgsRenderContext ct = renderContext();
571 
572  // Iterate through all layers and get symbol layer pointers
573  QList< QPair< QgsSymbolLayer *, QgsSymbol * > > slList;
574  if ( mSymbologyExport != NoSymbology )
575  {
576  slList = symbolLayers( ct );
577  }
578 
579  for ( const auto &symbolLayer : qgis::as_const( slList ) )
580  {
581  QgsMarkerSymbolLayer *ml = dynamic_cast< QgsMarkerSymbolLayer *>( symbolLayer.first );
582  if ( !ml )
583  continue;
584 
585  // if point symbol layer and no data defined properties: write block
586  QgsSymbolRenderContext ctx( ct, QgsUnitTypes::RenderMapUnits, symbolLayer.second->opacity(), false, symbolLayer.second->renderHints(), nullptr );
587 
588  // markers with data defined properties are inserted inline
589  if ( hasDataDefinedProperties( ml, symbolLayer.second ) )
590  {
591  continue;
592  }
593 
594  QString block( QStringLiteral( "symbolLayer%1" ).arg( mBlockCounter++ ) );
595  mBlockHandle = QStringLiteral( "%1" ).arg( mBlockHandles[ block ], 0, 16 );
596 
597  writeGroup( 0, QStringLiteral( "BLOCK" ) );
598  writeHandle();
599  writeGroup( 330, mBlockHandle );
600  writeGroup( 100, QStringLiteral( "AcDbEntity" ) );
601  writeGroup( 8, QStringLiteral( "0" ) );
602  writeGroup( 100, QStringLiteral( "AcDbBlockBegin" ) );
603  writeGroup( 2, block );
604  writeGroup( 70, 0 );
605 
606  // x/y/z coordinates of reference point
607  // todo: consider anchor point
608  // double size = ml->size();
609  // size *= mapUnitScaleFactor( mSymbologyScale, ml->sizeUnit(), mMapUnits );
610  writeGroup( 0, QgsPoint( QgsWkbTypes::PointZ, 0.0, 0.0, 0.0 ) );
611  writeGroup( 3, block );
612  writeGroup( 1, QString() );
613 
614  // maplayer 0 -> block receives layer from INSERT statement
615  ml->writeDxf( *this, mapUnitScaleFactor( mSymbologyScale, ml->sizeUnit(), mMapUnits, ctx.renderContext().mapToPixel().mapUnitsPerPixel() ), QStringLiteral( "0" ), ctx );
616 
617  writeGroup( 0, QStringLiteral( "ENDBLK" ) );
618  writeHandle();
619  writeGroup( 100, QStringLiteral( "AcDbEntity" ) );
620  writeGroup( 8, QStringLiteral( "0" ) );
621  writeGroup( 100, QStringLiteral( "AcDbBlockEnd" ) );
622 
623  mPointSymbolBlocks.insert( ml, block );
624  }
625  endSection();
626 }
627 
628 
629 void QgsDxfExport::writeEntities()
630 {
631  startSection();
632  writeGroup( 2, QStringLiteral( "ENTITIES" ) );
633 
634  mBlockHandle = QStringLiteral( "%1" ).arg( mBlockHandles[ QStringLiteral( "*Model_Space" )], 0, 16 );
635 
636  // iterate through the maplayers
637  for ( DxfLayerJob *job : qgis::as_const( mJobs ) )
638  {
639  QgsSymbolRenderContext sctx( mRenderContext, QgsUnitTypes::RenderMillimeters, 1.0, false, nullptr, nullptr );
640 
641  if ( mSymbologyExport == QgsDxfExport::SymbolLayerSymbology &&
642  ( job->renderer->capabilities() & QgsFeatureRenderer::SymbolLevels ) &&
643  job->renderer->usingSymbolLevels() )
644  {
645  writeEntitiesSymbolLevels( job );
646 
647  continue;
648  }
649 
650  QgsCoordinateTransform ct( mMapSettings.destinationCrs(), job->crs, mMapSettings.transformContext() );
651 
652  QgsFeatureRequest request = QgsFeatureRequest().setSubsetOfAttributes( job->attributes, job->fields ).setExpressionContext( job->renderContext.expressionContext() );
653  request.setFilterRect( ct.transform( mExtent ) );
654 
655  QgsFeatureIterator featureIt = job->featureSource.getFeatures( request );
656 
657  QgsFeature fet;
658  while ( featureIt.nextFeature( fet ) )
659  {
660  mRenderContext.expressionContext().setFeature( fet );
661  QString lName( dxfLayerName( job->splitLayerAttribute.isNull() ? job->layerTitle : fet.attribute( job->splitLayerAttribute ).toString() ) );
662 
663  sctx.setFeature( &fet );
664 
665  if ( !job->renderer->willRenderFeature( fet, mRenderContext ) )
666  continue;
667 
668  if ( mSymbologyExport == NoSymbology )
669  {
670  addFeature( sctx, ct, lName, nullptr, nullptr ); // no symbology at all
671  }
672  else
673  {
674  const QgsSymbolList symbolList = job->renderer->symbolsForFeature( fet, mRenderContext );
675  bool hasSymbology = symbolList.size() > 0;
676 
677  if ( hasSymbology && mSymbologyExport == QgsDxfExport::SymbolLayerSymbology ) // symbol layer symbology, but layer does not use symbol levels
678  {
679  for ( QgsSymbol *symbol : symbolList )
680  {
681  const QgsSymbolLayerList symbolLayers = symbol->symbolLayers();
682  for ( QgsSymbolLayer *symbolLayer : symbolLayers )
683  {
684  if ( !symbolLayer )
685  continue;
686 
687  bool isGeometryGenerator = ( symbolLayer->layerType() == QLatin1String( "GeometryGenerator" ) );
688  if ( isGeometryGenerator )
689  {
690  addGeometryGeneratorSymbolLayer( sctx, ct, lName, symbolLayer, true );
691  }
692  else
693  {
694  addFeature( sctx, ct, lName, symbolLayer, symbol );
695  }
696  }
697  }
698  }
699  else if ( hasSymbology )
700  {
701  // take first symbollayer from first symbol
702  QgsSymbol *s = symbolList.first();
703  if ( !s || s->symbolLayerCount() < 1 )
704  {
705  continue;
706  }
707 
708  if ( s->symbolLayer( 0 )->layerType() == QLatin1String( "GeometryGenerator" ) )
709  {
710  addGeometryGeneratorSymbolLayer( sctx, ct, lName, s->symbolLayer( 0 ), false );
711  }
712  else
713  {
714  addFeature( sctx, ct, lName, s->symbolLayer( 0 ), s );
715  }
716  }
717 
718  if ( job->labelProvider )
719  {
720  job->labelProvider->registerFeature( fet, mRenderContext );
722  registerDxfLayer( job->featureSource.id(), fet.id(), lName );
724  }
725  else if ( job->ruleBasedLabelProvider )
726  {
727  job->ruleBasedLabelProvider->registerFeature( fet, mRenderContext );
729  registerDxfLayer( job->featureSource.id(), fet.id(), lName );
731  }
732  }
733  }
734  }
735 
736  QImage image( 10, 10, QImage::Format_ARGB32_Premultiplied );
737  image.setDotsPerMeterX( 96 / 25.4 * 1000 );
738  image.setDotsPerMeterY( 96 / 25.4 * 1000 );
739  QPainter painter( &image );
740  mRenderContext.setPainter( &painter );
741 
742  mRenderContext.labelingEngine()->run( mRenderContext );
743 
744  endSection();
745 }
746 
747 void QgsDxfExport::prepareRenderers()
748 {
749  Q_ASSERT( mJobs.empty() ); // If this fails, stopRenderers() was not called after the last job
750 
751  mRenderContext = QgsRenderContext();
752  mRenderContext.setRendererScale( mSymbologyScale );
753  mRenderContext.setExtent( mExtent );
754 
755  mRenderContext.setScaleFactor( 96.0 / 25.4 );
756  mRenderContext.setMapToPixel( QgsMapToPixel( 1.0 / mFactor, mExtent.center().x(), mExtent.center().y(), mExtent.width() * mFactor,
757  mExtent.height() * mFactor, 0 ) );
758 
761 
762  mLabelingEngine = qgis::make_unique<QgsDefaultLabelingEngine>();
763  mLabelingEngine->setMapSettings( mMapSettings );
764  mRenderContext.setLabelingEngine( mLabelingEngine.get() );
765 
766  const QList< QgsMapLayer * > layers = mMapSettings.layers();
767  for ( QgsMapLayer *ml : layers )
768  {
769  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml );
770  if ( !vl )
771  continue;
772 
773  if ( !vl->renderer() )
774  continue;
775 
776  if ( !layerIsScaleBasedVisible( vl ) )
777  continue;
778 
779  QString splitLayerAttribute;
780  int splitLayerAttributeIndex = mLayerNameAttribute.value( vl->id(), -1 );
781  const QgsFields fields = vl->fields();
782  if ( splitLayerAttributeIndex >= 0 && splitLayerAttributeIndex < fields.size() )
783  splitLayerAttribute = fields.at( splitLayerAttributeIndex ).name();
784  DxfLayerJob *job = new DxfLayerJob( vl, mMapSettings.layerStyleOverrides().value( vl->id() ), mRenderContext, this, splitLayerAttribute );
785  mJobs.append( job );
786  }
787 }
788 
789 void QgsDxfExport::writeEntitiesSymbolLevels( DxfLayerJob *job )
790 {
791  QHash< QgsSymbol *, QList<QgsFeature> > features;
792 
793  QgsRenderContext ctx = renderContext();
794  const QList<QgsExpressionContextScope *> scopes = job->renderContext.expressionContext().scopes();
795  for ( QgsExpressionContextScope *scope : scopes )
797  QgsSymbolRenderContext sctx( ctx, QgsUnitTypes::RenderMillimeters, 1.0, false, nullptr, nullptr );
798 
799  // get iterator
800  QgsFeatureRequest req;
801  req.setSubsetOfAttributes( job->renderer->usedAttributes( ctx ), job->featureSource.fields() );
802  QgsCoordinateTransform ct( mMapSettings.destinationCrs(), job->crs, mMapSettings.transformContext() );
803  req.setFilterRect( ct.transform( mExtent ) );
804 
805  QgsFeatureIterator fit = job->featureSource.getFeatures( req );
806 
807  // fetch features
808  QgsFeature fet;
809  QgsSymbol *featureSymbol = nullptr;
810  while ( fit.nextFeature( fet ) )
811  {
812  ctx.expressionContext().setFeature( fet );
813  featureSymbol = job->renderer->symbolForFeature( fet, ctx );
814  if ( !featureSymbol )
815  {
816  continue;
817  }
818 
819  QHash< QgsSymbol *, QList<QgsFeature> >::iterator it = features.find( featureSymbol );
820  if ( it == features.end() )
821  {
822  it = features.insert( featureSymbol, QList<QgsFeature>() );
823  }
824  it.value().append( fet );
825  }
826 
827  // find out order
828  QgsSymbolLevelOrder levels;
829  const QgsSymbolList symbols = job->renderer->symbols( ctx );
830  for ( QgsSymbol *symbol : symbols )
831  {
832  for ( int j = 0; j < symbol->symbolLayerCount(); j++ )
833  {
834  int level = symbol->symbolLayer( j )->renderingPass();
835  if ( level < 0 || level >= 1000 ) // ignore invalid levels
836  continue;
837  QgsSymbolLevelItem item( symbol, j );
838  while ( level >= levels.count() ) // append new empty levels
839  levels.append( QgsSymbolLevel() );
840  levels[level].append( item );
841  }
842  }
843 
844  // export symbol layers and symbology
845  for ( const QgsSymbolLevel &level : qgis::as_const( levels ) )
846  {
847  for ( const QgsSymbolLevelItem &item : level )
848  {
849  QHash< QgsSymbol *, QList<QgsFeature> >::iterator levelIt = features.find( item.symbol() );
850  if ( levelIt == features.end() )
851  {
852  continue;
853  }
854 
855  int llayer = item.layer();
856  const QList<QgsFeature> &featureList = levelIt.value();
857  for ( const QgsFeature &feature : featureList )
858  {
859  sctx.setFeature( &feature );
860  addFeature( sctx, ct, job->layerName, levelIt.key()->symbolLayer( llayer ), levelIt.key() );
861  }
862  }
863  }
864 }
865 
866 void QgsDxfExport::stopRenderers()
867 {
868  qDeleteAll( mJobs );
869  mJobs.clear();
870 }
871 
872 void QgsDxfExport::writeEndFile()
873 {
874  mTextStream << DXF_TRAILER;
875 
876  writeGroup( 0, QStringLiteral( "EOF" ) );
877 }
878 
879 void QgsDxfExport::startSection()
880 {
881  writeGroup( 0, QStringLiteral( "SECTION" ) );
882 }
883 
884 void QgsDxfExport::endSection()
885 {
886  writeGroup( 0, QStringLiteral( "ENDSEC" ) );
887 }
888 
889 void QgsDxfExport::writePoint( const QgsPoint &pt, const QString &layer, const QColor &color, QgsSymbolRenderContext &ctx, const QgsSymbolLayer *symbolLayer, const QgsSymbol *symbol, double angle )
890 {
891 #if 0
892  // debug: draw rectangle for debugging
893  const QgsMarkerSymbolLayer *msl = dynamic_cast< const QgsMarkerSymbolLayer * >( symbolLayer );
894  if ( msl )
895  {
896  double halfSize = msl->size() * mapUnitScaleFactor( mSymbologyScale,
897  msl->sizeUnit(), mMapUnits ) / 2.0;
898  writeGroup( 0, "SOLID" );
899  writeGroup( 8, layer );
900  writeGroup( 62, 1 );
901  writeGroup( 0, QgsPoint( QgsWkbTypes::PointZ, pt.x() - halfSize, pt.y() - halfSize ) );
902  writeGroup( 1, QgsPoint( QgsWkbTypes::PointZ, pt.x() + halfSize, pt.y() - halfSize ) );
903  writeGroup( 2, QgsPoint( QgsWkbTypes::PointZ, pt.x() - halfSize, pt.y() + halfSize ) );
904  writeGroup( 3, QgsPoint( QgsWkbTypes::PointZ, pt.x() + halfSize, pt.y() + halfSize ) );
905  }
906 #endif // 0
907 
908  // insert block or write point directly?
909  QHash< const QgsSymbolLayer *, QString >::const_iterator blockIt = mPointSymbolBlocks.constFind( symbolLayer );
910  if ( !symbolLayer || blockIt == mPointSymbolBlocks.constEnd() )
911  {
912  // write symbol directly here
913  const QgsMarkerSymbolLayer *msl = dynamic_cast< const QgsMarkerSymbolLayer * >( symbolLayer );
914  if ( msl && symbol )
915  {
916  if ( msl->writeDxf( *this, mapUnitScaleFactor( mSymbologyScale, msl->sizeUnit(), mMapUnits, ctx.renderContext().mapToPixel().mapUnitsPerPixel() ), layer, ctx, QPointF( pt.x(), pt.y() ) ) )
917  {
918  return;
919  }
920  }
921  writePoint( layer, color, pt ); // write default point symbol
922  }
923  else
924  {
925  // insert block reference
926  writeGroup( 0, QStringLiteral( "INSERT" ) );
927  writeHandle();
928  writeGroup( 100, QStringLiteral( "AcDbEntity" ) );
929  writeGroup( 100, QStringLiteral( "AcDbBlockReference" ) );
930  writeGroup( 8, layer );
931  writeGroup( 2, blockIt.value() ); // Block name
932  writeGroup( 50, angle ); // angle
933  writeGroup( 0, pt ); // Insertion point (in OCS)
934  }
935 }
936 
937 void QgsDxfExport::writePolyline( const QgsPointSequence &line, const QString &layer, const QString &lineStyleName, const QColor &color, double width )
938 {
939  int n = line.size();
940  if ( n == 0 )
941  {
942  QgsDebugMsg( QStringLiteral( "writePolyline: empty line layer=%1 lineStyleName=%2" ).arg( layer, lineStyleName ) );
943  return;
944  }
945 
946  if ( n < 2 )
947  {
948  QgsDebugMsg( QStringLiteral( "writePolyline: line too short layer=%1 lineStyleName=%2" ).arg( layer, lineStyleName ) );
949  return;
950  }
951 
952  if ( mForce2d || !line.at( 0 ).is3D() )
953  {
954  bool polygon = line[0] == line[ line.size() - 1 ];
955  if ( polygon )
956  --n;
957 
958  writeGroup( 0, QStringLiteral( "LWPOLYLINE" ) );
959  writeHandle();
960  writeGroup( 8, layer );
961  writeGroup( 100, QStringLiteral( "AcDbEntity" ) );
962  writeGroup( 100, QStringLiteral( "AcDbPolyline" ) );
963  writeGroup( 6, lineStyleName );
964  writeGroup( color );
965 
966  writeGroup( 90, n );
967  writeGroup( 70, polygon ? 1 : 0 );
968  writeGroup( 43, width );
969 
970  for ( int i = 0; i < n; i++ )
971  writeGroup( 0, line[i] );
972  }
973  else
974  {
975  writeGroup( 0, QStringLiteral( "POLYLINE" ) );
976  int plHandle = writeHandle();
977  writeGroup( 330, mBlockHandle );
978  writeGroup( 100, QStringLiteral( "AcDbEntity" ) );
979  writeGroup( 8, layer );
980  writeGroup( 6, lineStyleName );
981  writeGroup( color );
982  writeGroup( 100, QStringLiteral( "AcDb3dPolyline" ) );
983  writeGroup( 0, QgsPoint( QgsWkbTypes::PointZ, 0.0, 0.0, 0.0 ) );
984  writeGroup( 70, 8 );
985 
986  for ( int i = 0; i < n; i++ )
987  {
988  writeGroup( 0, QStringLiteral( "VERTEX" ) );
989  writeHandle();
990  writeGroup( 330, plHandle );
991  writeGroup( 100, QStringLiteral( "AcDbEntity" ) );
992  writeGroup( 8, layer );
993  writeGroup( color );
994  writeGroup( 100, QStringLiteral( "AcDbVertex" ) );
995  writeGroup( 100, QStringLiteral( "AcDb3dPolylineVertex" ) );
996  writeGroup( 0, line[i] );
997  writeGroup( 70, 32 );
998  }
999 
1000  writeGroup( 0, QStringLiteral( "SEQEND" ) );
1001  writeHandle();
1002  writeGroup( 330, plHandle );
1003  writeGroup( 100, QStringLiteral( "AcDbEntity" ) );
1004  writeGroup( 8, layer );
1005  writeGroup( color );
1006  }
1007 }
1008 
1009 void QgsDxfExport::appendCurve( const QgsCurve &c, QVector<QgsPoint> &points, QVector<double> &bulges )
1010 {
1011  switch ( QgsWkbTypes::flatType( c.wkbType() ) )
1012  {
1014  appendLineString( *dynamic_cast<const QgsLineString *>( &c ), points, bulges );
1015  break;
1016 
1018  appendCircularString( *dynamic_cast<const QgsCircularString *>( &c ), points, bulges );
1019  break;
1020 
1022  appendCompoundCurve( *dynamic_cast<const QgsCompoundCurve *>( &c ), points, bulges );
1023  break;
1024 
1025  default:
1026  QgsDebugMsg( QStringLiteral( "Unexpected curve type %1" ).arg( c.wktTypeStr() ) );
1027  break;
1028  }
1029 }
1030 
1031 void QgsDxfExport::appendLineString( const QgsLineString &ls, QVector<QgsPoint> &points, QVector<double> &bulges )
1032 {
1033  for ( int i = 0; i < ls.numPoints(); i++ )
1034  {
1035  const QgsPoint &p = ls.pointN( i );
1036  if ( !points.isEmpty() && points.last() == p )
1037  continue;
1038 
1039  points << p;
1040  bulges << 0.0;
1041  }
1042 }
1043 
1044 void QgsDxfExport::appendCircularString( const QgsCircularString &cs, QVector<QgsPoint> &points, QVector<double> &bulges )
1045 {
1046  for ( int i = 0; i < cs.numPoints() - 2; i += 2 )
1047  {
1048  const QgsPoint &p1 = cs.pointN( i );
1049  const QgsPoint &p2 = cs.pointN( i + 1 );
1050  const QgsPoint &p3 = cs.pointN( i + 2 );
1051 
1052  if ( points.isEmpty() || points.last() != p1 )
1053  points << p1;
1054  else if ( !bulges.isEmpty() )
1055  bulges.removeLast();
1056 
1057  double a = ( M_PI - ( p1 - p2 ).angle() + ( p3 - p2 ).angle() ) / 2.0;
1058  bulges << sin( a ) / cos( a );
1059 
1060  points << p3;
1061  bulges << 0.0;
1062  }
1063 }
1064 
1065 void QgsDxfExport::appendCompoundCurve( const QgsCompoundCurve &cc, QVector<QgsPoint> &points, QVector<double> &bulges )
1066 {
1067  for ( int i = 0; i < cc.nCurves(); i++ )
1068  {
1069  const QgsCurve *c = cc.curveAt( i );
1070  Q_ASSERT( c );
1071  appendCurve( *c, points, bulges );
1072  }
1073 }
1074 
1075 void QgsDxfExport::writePolyline( const QgsCurve &curve, const QString &layer, const QString &lineStyleName, const QColor &color, double width )
1076 {
1077  int n = curve.numPoints();
1078  if ( n == 0 )
1079  {
1080  QgsDebugMsg( QStringLiteral( "writePolyline: empty line layer=%1 lineStyleName=%2" ).arg( layer, lineStyleName ) );
1081  return;
1082  }
1083 
1084  if ( n < 2 )
1085  {
1086  QgsDebugMsg( QStringLiteral( "writePolyline: line too short layer=%1 lineStyleName=%2" ).arg( layer, lineStyleName ) );
1087  return;
1088  }
1089 
1090  QVector<QgsPoint> points;
1091  QVector<double> bulges;
1092  appendCurve( curve, points, bulges );
1093 
1094  if ( mForce2d || !curve.is3D() )
1095  {
1096  writeGroup( 0, QStringLiteral( "LWPOLYLINE" ) );
1097  writeHandle();
1098  writeGroup( 8, layer );
1099  writeGroup( 100, QStringLiteral( "AcDbEntity" ) );
1100  writeGroup( 100, QStringLiteral( "AcDbPolyline" ) );
1101  writeGroup( 6, lineStyleName );
1102  writeGroup( color );
1103 
1104  writeGroup( 90, points.size() );
1105  QgsDxfExport::DxfPolylineFlags polylineFlags;
1106  if ( curve.isClosed() )
1107  polylineFlags.setFlag( QgsDxfExport::DxfPolylineFlag::Closed );
1108  if ( curve.hasCurvedSegments() )
1109  polylineFlags.setFlag( QgsDxfExport::DxfPolylineFlag::Curve );
1110 
1111  // Might need to conditional once this feature is implemented
1112  // https://github.com/qgis/QGIS/issues/32468
1113  polylineFlags.setFlag( QgsDxfExport::DxfPolylineFlag::ContinuousPattern );
1114 
1115  writeGroup( 70, static_cast<int>( polylineFlags ) );
1116  writeGroup( 43, width );
1117 
1118  for ( int i = 0; i < points.size(); i++ )
1119  {
1120  writeGroup( 0, points[i] );
1121  if ( bulges[i] != 0.0 )
1122  writeGroup( 42, bulges[i] );
1123  }
1124  }
1125  else
1126  {
1127  writeGroup( 0, QStringLiteral( "POLYLINE" ) );
1128  int plHandle = writeHandle();
1129  writeGroup( 330, mBlockHandle );
1130  writeGroup( 100, QStringLiteral( "AcDbEntity" ) );
1131  writeGroup( 8, layer );
1132  writeGroup( 6, lineStyleName );
1133  writeGroup( color );
1134  writeGroup( 100, QStringLiteral( "AcDb3dPolyline" ) );
1135  writeGroup( 0, QgsPoint( QgsWkbTypes::PointZ, 0.0, 0.0, 0.0 ) );
1136  writeGroup( 70, 8 );
1137 
1138  for ( int i = 0; i < points.size(); i++ )
1139  {
1140  writeGroup( 0, QStringLiteral( "VERTEX" ) );
1141  writeHandle();
1142  writeGroup( 330, plHandle );
1143  writeGroup( 100, QStringLiteral( "AcDbEntity" ) );
1144  writeGroup( 8, layer );
1145  writeGroup( color );
1146  writeGroup( 100, QStringLiteral( "AcDbVertex" ) );
1147  writeGroup( 100, QStringLiteral( "AcDb3dPolylineVertex" ) );
1148  writeGroup( 0, points[i] );
1149  if ( bulges[i] != 0.0 )
1150  writeGroup( 42, bulges[i] );
1151  writeGroup( 70, 32 );
1152  }
1153 
1154  writeGroup( 0, QStringLiteral( "SEQEND" ) );
1155  writeHandle();
1156  writeGroup( 330, plHandle );
1157  writeGroup( 100, QStringLiteral( "AcDbEntity" ) );
1158  writeGroup( 8, layer );
1159  writeGroup( color );
1160  }
1161 }
1162 
1163 void QgsDxfExport::writePolygon( const QgsRingSequence &polygon, const QString &layer, const QString &hatchPattern, const QColor &color )
1164 {
1165  writeGroup( 0, QStringLiteral( "HATCH" ) ); // Entity type
1166  writeHandle();
1167  writeGroup( 330, mBlockHandle );
1168  writeGroup( 100, QStringLiteral( "AcDbEntity" ) );
1169  writeGroup( 8, layer ); // Layer name
1170  writeGroup( color ); // Color
1171  writeGroup( 100, QStringLiteral( "AcDbHatch" ) );
1172 
1173  writeGroup( 0, QgsPoint( QgsWkbTypes::PointZ, 0.0, 0.0, 0.0 ) ); // Elevation point (in OCS)
1174  writeGroup( 200, QgsPoint( QgsWkbTypes::PointZ, 0.0, 0.0, 1.0 ) );
1175 
1176  writeGroup( 2, hatchPattern ); // Hatch pattern name
1177  writeGroup( 70, hatchPattern == QLatin1String( "SOLID" ) ); // Solid fill flag (solid fill = 1; pattern fill = 0)
1178  writeGroup( 71, 0 ); // Associativity flag (associative = 1; non-associative = 0)
1179 
1180  writeGroup( 91, polygon.size() ); // Number of boundary paths (loops)
1181  for ( int i = 0; i < polygon.size(); ++i )
1182  {
1183  writeGroup( 92, 2 ); // Boundary path type flag (bit coded): 0 = Default; 1 = External; 2 = Polyline 4 = Derived; 8 = Textbox; 16 = Outermost
1184  writeGroup( 72, 0 ); // Has bulge flag
1185  writeGroup( 73, 1 ); // Is closed flag
1186  writeGroup( 93, polygon[i].size() ); // Number of edges in this boundary path (only if boundary is not a polyline)
1187 
1188  for ( int j = 0; j < polygon[i].size(); ++j )
1189  {
1190  writeGroup( 0, polygon[i][j] ); // Vertex location (in OCS)
1191  }
1192 
1193  writeGroup( 97, 0 ); // Number of source boundary objects
1194  }
1195 
1196  writeGroup( 75, 0 ); // Hatch style: 0 = Hatch "odd parity" area (Normal style), 1 = Hatch outermost area only (Outer style), 2 = Hatch through entire area (Ignore style)
1197  writeGroup( 76, 1 ); // Hatch pattern type: 0 = User-defined; 1 = Predefined; 2 = Custom
1198 
1199  writeGroup( 98, 0 ); // Number of seed points
1200 }
1201 
1202 void QgsDxfExport::writePolygon( const QgsCurvePolygon &polygon, const QString &layer, const QString &hatchPattern, const QColor &color )
1203 {
1204  writeGroup( 0, QStringLiteral( "HATCH" ) ); // Entity type
1205  writeHandle();
1206  writeGroup( 330, mBlockHandle );
1207  writeGroup( 100, QStringLiteral( "AcDbEntity" ) );
1208  writeGroup( 8, layer ); // Layer name
1209  writeGroup( color ); // Color
1210  writeGroup( 100, QStringLiteral( "AcDbHatch" ) );
1211 
1212  writeGroup( 0, QgsPoint( QgsWkbTypes::PointZ, 0.0, 0.0, 0.0 ) ); // Elevation point (in OCS)
1213  writeGroup( 200, QgsPoint( QgsWkbTypes::PointZ, 0.0, 0.0, 1.0 ) );
1214 
1215  writeGroup( 2, hatchPattern ); // Hatch pattern name
1216  writeGroup( 70, hatchPattern == QLatin1String( "SOLID" ) ); // Solid fill flag (solid fill = 1; pattern fill = 0)
1217  writeGroup( 71, 0 ); // Associativity flag (associative = 1; non-associative = 0)
1218 
1219  QVector<QVector<QgsPoint>> points;
1220  QVector<QVector<double>> bulges;
1221 
1222  points << QVector<QgsPoint>();
1223  bulges << QVector<double>();
1224  appendCurve( *polygon.exteriorRing(), points.last(), bulges.last() );
1225 
1226  for ( int i = 0; i < polygon.numInteriorRings(); i++ )
1227  {
1228  points << QVector<QgsPoint>();
1229  bulges << QVector<double>();
1230  appendCurve( *polygon.interiorRing( i ), points.last(), bulges.last() );
1231  }
1232 
1233  bool hasBulges = false;
1234  for ( int i = 0; i < points.size() && !hasBulges; ++i )
1235  for ( int j = 0; j < points[i].size() && !hasBulges; ++j )
1236  hasBulges = bulges[i][j] != 0.0;
1237 
1238  writeGroup( 91, points.size() ); // Number of boundary paths (loops)
1239 
1240  for ( int i = 0; i < points.size(); ++i )
1241  {
1242  writeGroup( 92, 2 ); // Boundary path type flag (bit coded): 0 = Default; 1 = External; 2 = Polyline 4 = Derived; 8 = Textbox; 16 = Outermost
1243  writeGroup( 72, hasBulges ? 1 : 0 ); // Has bulge flag
1244  writeGroup( 73, 1 ); // Is closed flag
1245  writeGroup( 93, points[i].size() ); // Number of edges in this boundary path (only if boundary is not a polyline)
1246 
1247  for ( int j = 0; j < points[i].size(); ++j )
1248  {
1249  writeGroup( 0, points[i][j] ); // Vertex location (in OCS)
1250  if ( hasBulges )
1251  writeGroup( 42, bulges[i][j] );
1252  }
1253 
1254  writeGroup( 97, 0 ); // Number of source boundary objects
1255  }
1256 
1257  writeGroup( 75, 0 ); // Hatch style: 0 = Hatch "odd parity" area (Normal style), 1 = Hatch outermost area only (Outer style), 2 = Hatch through entire area (Ignore style)
1258  writeGroup( 76, 1 ); // Hatch pattern type: 0 = User-defined; 1 = Predefined; 2 = Custom
1259 
1260  writeGroup( 98, 0 ); // Number of seed points
1261 }
1262 
1263 void QgsDxfExport::writeLine( const QgsPoint &pt1, const QgsPoint &pt2, const QString &layer, const QString &lineStyleName, const QColor &color, double width )
1264 {
1265  writePolyline( QgsPointSequence() << pt1 << pt2, layer, lineStyleName, color, width );
1266 }
1267 
1268 void QgsDxfExport::writeText( const QString &layer, const QString &text, pal::LabelPosition *label, const QgsPalLayerSettings &layerSettings, const QgsExpressionContext &expressionContext )
1269 {
1270 
1271  double lblX = label->getX();
1272  double lblY = label->getY();
1273 
1274  QgsLabelFeature *labelFeature = label->getFeaturePart()->feature();
1275 
1276  HAlign hali = HAlign::Undefined;
1277  VAlign vali = VAlign::Undefined;
1278 
1279  const QgsPropertyCollection &props = layerSettings.dataDefinedProperties();
1280 
1281  if ( layerSettings.placement == QgsPalLayerSettings::Placement::OverPoint )
1282  {
1283  lblX = labelFeature->anchorPosition().x();
1284  lblY = labelFeature->anchorPosition().y();
1285 
1286  QgsPalLayerSettings::QuadrantPosition offsetQuad = layerSettings.quadOffset;
1287 
1289  {
1290  const QVariant exprVal = props.value( QgsPalLayerSettings::OffsetQuad, expressionContext );
1291  if ( exprVal.isValid() )
1292  {
1293  offsetQuad = static_cast<QgsPalLayerSettings::QuadrantPosition>( exprVal.toInt() );
1294  }
1295  }
1296 
1297  switch ( offsetQuad )
1298  {
1299  case QgsPalLayerSettings::QuadrantPosition::QuadrantAboveLeft:
1300  hali = HAlign::HRight;
1301  vali = VAlign::VBottom;
1302  break;
1303  case QgsPalLayerSettings::QuadrantPosition::QuadrantAbove:
1304  hali = HAlign::HCenter;
1305  vali = VAlign::VBottom;
1306  break;
1307  case QgsPalLayerSettings::QuadrantPosition::QuadrantAboveRight:
1308  hali = HAlign::HLeft;
1309  vali = VAlign::VBottom;
1310  break;
1311  case QgsPalLayerSettings::QuadrantPosition::QuadrantLeft:
1312  hali = HAlign::HRight;
1313  vali = VAlign::VMiddle;
1314  break;
1315  case QgsPalLayerSettings::QuadrantPosition::QuadrantOver:
1316  hali = HAlign::HCenter;
1317  vali = VAlign::VMiddle;
1318  break;
1319  case QgsPalLayerSettings::QuadrantPosition::QuadrantRight:
1320  hali = HAlign::HLeft;
1321  vali = VAlign::VMiddle;
1322  break;
1323  case QgsPalLayerSettings::QuadrantPosition::QuadrantBelowLeft:
1324  hali = HAlign::HRight;
1325  vali = VAlign::VTop;
1326  break;
1327  case QgsPalLayerSettings::QuadrantPosition::QuadrantBelow:
1328  hali = HAlign::HCenter;
1329  vali = VAlign::VTop;
1330  break;
1331  case QgsPalLayerSettings::QuadrantPosition::QuadrantBelowRight:
1332  hali = HAlign::HLeft;
1333  vali = VAlign::VTop;
1334  break;
1335  default: // OverHali
1336  hali = HAlign::HCenter;
1337  vali = VAlign::VTop;
1338  break;
1339  }
1340  }
1341 
1342  if ( props.isActive( QgsPalLayerSettings::Hali ) )
1343  {
1344  lblX = labelFeature->anchorPosition().x();
1345  lblY = labelFeature->anchorPosition().y();
1346 
1347  hali = HAlign::HLeft;
1348  QVariant exprVal = props.value( QgsPalLayerSettings::Hali, expressionContext );
1349  if ( exprVal.isValid() )
1350  {
1351  const QString haliString = exprVal.toString();
1352  if ( haliString.compare( QLatin1String( "Center" ), Qt::CaseInsensitive ) == 0 )
1353  {
1354  hali = HAlign::HCenter;
1355  }
1356  else if ( haliString.compare( QLatin1String( "Right" ), Qt::CaseInsensitive ) == 0 )
1357  {
1358  hali = HAlign::HRight;
1359  }
1360  }
1361  }
1362 
1363  //vertical alignment
1364  if ( props.isActive( QgsPalLayerSettings::Vali ) )
1365  {
1366  vali = VAlign::VBottom;
1367  QVariant exprVal = props.value( QgsPalLayerSettings::Vali, expressionContext );
1368  if ( exprVal.isValid() )
1369  {
1370  const QString valiString = exprVal.toString();
1371  if ( valiString.compare( QLatin1String( "Bottom" ), Qt::CaseInsensitive ) != 0 )
1372  {
1373  if ( valiString.compare( QLatin1String( "Base" ), Qt::CaseInsensitive ) == 0 )
1374  {
1375  vali = VAlign::VBaseLine;
1376  }
1377  else if ( valiString.compare( QLatin1String( "Half" ), Qt::CaseInsensitive ) == 0 )
1378  {
1379  vali = VAlign::VMiddle;
1380  }
1381  else //'Cap' or 'Top'
1382  {
1383  vali = VAlign::VTop;
1384  }
1385  }
1386  }
1387  }
1388 
1389  writeText( layer, text, QgsPoint( lblX, lblY ), label->getHeight(), label->getAlpha() * 180.0 / M_PI, layerSettings.format().color(), hali, vali );
1390 }
1391 
1392 void QgsDxfExport::writePoint( const QString &layer, const QColor &color, const QgsPoint &pt )
1393 {
1394  writeGroup( 0, QStringLiteral( "POINT" ) );
1395  writeHandle();
1396  writeGroup( 100, QStringLiteral( "AcDbEntity" ) );
1397  writeGroup( 100, QStringLiteral( "AcDbPoint" ) );
1398  writeGroup( 8, layer );
1399  writeGroup( color );
1400  writeGroup( 0, pt );
1401 }
1402 
1403 void QgsDxfExport::writeFilledCircle( const QString &layer, const QColor &color, const QgsPoint &pt, double radius )
1404 {
1405  writeGroup( 0, QStringLiteral( "HATCH" ) ); // Entity type
1406  writeHandle();
1407  writeGroup( 330, mBlockHandle );
1408  writeGroup( 100, QStringLiteral( "AcDbEntity" ) );
1409  writeGroup( 8, layer ); // Layer name
1410  writeGroup( color ); // Color (0 by block, 256 by layer)
1411  writeGroup( 100, QStringLiteral( "AcDbHatch" ) );
1412 
1413  writeGroup( 0, QgsPoint( QgsWkbTypes::PointZ, 0.0, 0.0, 0.0 ) ); // Elevation point (in OCS)
1414  writeGroup( 200, QgsPoint( QgsWkbTypes::PointZ, 0.0, 0.0, 1.0 ) );
1415 
1416  writeGroup( 2, QStringLiteral( "SOLID" ) ); // Hatch pattern name
1417  writeGroup( 70, 1 ); // Solid fill flag (solid fill = 1; pattern fill = 0)
1418  writeGroup( 71, 0 ); // Associativity flag (associative = 1; non-associative = 0)
1419 
1420  writeGroup( 91, 1 ); // Number of boundary paths (loops)
1421 
1422  writeGroup( 92, 3 ); // Boundary path type flag (bit coded): 0 = Default; 1 = External; 2 = Polyline 4 = Derived; 8 = Textbox; 16 = Outermost
1423  writeGroup( 72, 1 );
1424  writeGroup( 73, 1 ); // Is closed flag
1425  writeGroup( 93, 2 ); // Number of polyline vertices
1426 
1427  writeGroup( 0, QgsPoint( QgsWkbTypes::Point, pt.x() - radius, pt.y() ) );
1428  writeGroup( 42, 1.0 );
1429 
1430  writeGroup( 0, QgsPoint( QgsWkbTypes::Point, pt.x() + radius, pt.y() ) );
1431  writeGroup( 42, 1.0 );
1432 
1433  writeGroup( 97, 0 ); // Number of source boundary objects
1434 
1435  writeGroup( 75, 0 ); // Hatch style: 0 = Hatch "odd parity" area (Normal style), 1 = Hatch outermost area only (Outer style), 2 = Hatch through entire area (Ignore style)
1436  writeGroup( 76, 1 ); // Hatch pattern type: 0 = User-defined; 1 = Predefined; 2 = Custom
1437  writeGroup( 98, 0 ); // Number of seed points
1438 }
1439 
1440 void QgsDxfExport::writeCircle( const QString &layer, const QColor &color, const QgsPoint &pt, double radius, const QString &lineStyleName, double width )
1441 {
1442  writeGroup( 0, QStringLiteral( "LWPOLYLINE" ) );
1443  writeHandle();
1444  writeGroup( 330, mBlockHandle );
1445  writeGroup( 8, layer );
1446  writeGroup( 100, QStringLiteral( "AcDbEntity" ) );
1447  writeGroup( 100, QStringLiteral( "AcDbPolyline" ) );
1448  writeGroup( 6, lineStyleName );
1449  writeGroup( color );
1450 
1451  writeGroup( 90, 2 );
1452 
1453  writeGroup( 70, 1 );
1454  writeGroup( 43, width );
1455 
1456  writeGroup( 0, QgsPoint( pt.x() - radius, pt.y() ) );
1457  writeGroup( 42, 1.0 );
1458  writeGroup( 0, QgsPoint( pt.x() + radius, pt.y() ) );
1459  writeGroup( 42, 1.0 );
1460 }
1461 
1462 void QgsDxfExport::writeText( const QString &layer, const QString &text, const QgsPoint &pt, double size, double angle, const QColor &color, HAlign hali, VAlign vali )
1463 {
1464  writeGroup( 0, QStringLiteral( "TEXT" ) );
1465  writeHandle();
1466  writeGroup( 100, QStringLiteral( "AcDbEntity" ) );
1467  // writeGroup( 6, "Continuous" ); // Line style
1468  // writeGroup( 370, 18 ); // Line weight
1469  writeGroup( 100, QStringLiteral( "AcDbText" ) );
1470  writeGroup( 8, layer );
1471  writeGroup( color );
1472  writeGroup( 0, pt );
1473  if ( hali != HAlign::Undefined || vali != VAlign::Undefined )
1474  writeGroup( 1, pt ); // Second alignment point
1475  writeGroup( 40, size );
1476  writeGroup( 1, text );
1477  writeGroup( 50, fmod( angle, 360 ) );
1478  if ( hali != HAlign::Undefined )
1479  writeGroup( 72, static_cast<int>( hali ) );
1480  writeGroup( 7, QStringLiteral( "STANDARD" ) ); // so far only support for standard font
1481  writeGroup( 100, QStringLiteral( "AcDbText" ) );
1482  if ( vali != VAlign::Undefined )
1483  {
1484  writeGroup( 73, static_cast<int>( vali ) );
1485  }
1486 }
1487 
1488 void QgsDxfExport::writeMText( const QString &layer, const QString &text, const QgsPoint &pt, double width, double angle, const QColor &color )
1489 {
1490  if ( !mTextStream.codec()->canEncode( text ) )
1491  {
1492  // TODO return error
1493  QgsDebugMsg( QStringLiteral( "could not encode:%1" ).arg( text ) );
1494  return;
1495  }
1496 
1497  writeGroup( 0, QStringLiteral( "MTEXT" ) );
1498  writeHandle();
1499  writeGroup( 100, QStringLiteral( "AcDbEntity" ) );
1500  writeGroup( 100, QStringLiteral( "AcDbMText" ) );
1501  writeGroup( 8, layer );
1502  writeGroup( color );
1503 
1504  writeGroup( 0, pt );
1505 
1506  QString t( text );
1507  while ( t.length() > 250 )
1508  {
1509  writeGroup( 3, t.left( 250 ) );
1510  t = t.mid( 250 );
1511  }
1512  writeGroup( 1, t );
1513 
1514  writeGroup( 50, angle ); // Rotation angle in radians
1515  writeGroup( 41, width * 1.1 ); // Reference rectangle width
1516 
1517  // Attachment point:
1518  // 1 2 3
1519  // 4 5 6
1520  // 7 8 9
1521  writeGroup( 71, 7 );
1522 
1523  writeGroup( 7, QStringLiteral( "STANDARD" ) ); // so far only support for standard font
1524 }
1525 
1526 void QgsDxfExport::addFeature( QgsSymbolRenderContext &ctx, const QgsCoordinateTransform &ct, const QString &layer, const QgsSymbolLayer *symbolLayer, const QgsSymbol *symbol )
1527 {
1528  const QgsFeature *fet = ctx.feature();
1529  if ( !fet )
1530  return;
1531 
1532  if ( !fet->hasGeometry() )
1533  return;
1534 
1535  QgsGeometry geom( fet->geometry() );
1536  if ( ct.isValid() )
1537  {
1538  geom.transform( ct );
1539  }
1540 
1541  QgsWkbTypes::Type geometryType = geom.wkbType();
1542 
1543  QColor penColor;
1544  QColor brushColor;
1545  if ( mSymbologyExport != NoSymbology && symbolLayer )
1546  {
1547  penColor = colorFromSymbolLayer( symbolLayer, ctx );
1548  brushColor = symbolLayer->dxfBrushColor( ctx );
1549  }
1550 
1551  Qt::PenStyle penStyle( Qt::SolidLine );
1552  Qt::BrushStyle brushStyle( Qt::NoBrush );
1553  double width = -1;
1554  double offset = 0.0;
1555  double angle = 0.0;
1556  if ( mSymbologyExport != NoSymbology && symbolLayer )
1557  {
1558  width = symbolLayer->dxfWidth( *this, ctx );
1559  offset = symbolLayer->dxfOffset( *this, ctx );
1560  angle = symbolLayer->dxfAngle( ctx );
1561  penStyle = symbolLayer->dxfPenStyle();
1562  brushStyle = symbolLayer->dxfBrushStyle();
1563 
1564  if ( qgsDoubleNear( offset, 0.0 ) )
1565  offset = 0.0;
1566  }
1567 
1568  QString lineStyleName = QStringLiteral( "CONTINUOUS" );
1569  if ( mSymbologyExport != NoSymbology )
1570  {
1571  lineStyleName = lineStyleFromSymbolLayer( symbolLayer );
1572  }
1573 
1574  // single point
1575  if ( QgsWkbTypes::flatType( geometryType ) == QgsWkbTypes::Point )
1576  {
1577  writePoint( geom.constGet()->coordinateSequence().at( 0 ).at( 0 ).at( 0 ), layer, penColor, ctx, symbolLayer, symbol, angle );
1578  return;
1579  }
1580 
1581  if ( QgsWkbTypes::flatType( geometryType ) == QgsWkbTypes::MultiPoint )
1582  {
1583  const QgsCoordinateSequence &cs = geom.constGet()->coordinateSequence();
1584  for ( int i = 0; i < cs.size(); i++ )
1585  {
1586  writePoint( cs.at( i ).at( 0 ).at( 0 ), layer, penColor, ctx, symbolLayer, symbol, angle );
1587  }
1588  return;
1589  }
1590 
1591  if ( penStyle != Qt::NoPen )
1592  {
1593  const QgsAbstractGeometry *sourceGeom = geom.constGet();
1594  std::unique_ptr< QgsAbstractGeometry > tempGeom;
1595 
1596  switch ( QgsWkbTypes::flatType( geometryType ) )
1597  {
1601  {
1602  if ( !qgsDoubleNear( offset, 0.0 ) )
1603  {
1604  QgsGeos geos( sourceGeom );
1605  tempGeom.reset( geos.offsetCurve( offset, 0, GEOSBUF_JOIN_MITRE, 2.0 ) ); //#spellok
1606  if ( tempGeom )
1607  sourceGeom = tempGeom.get();
1608  else
1609  sourceGeom = geom.constGet();
1610  }
1611 
1612  const QgsCurve *curve = dynamic_cast<const QgsCurve *>( sourceGeom );
1613  Q_ASSERT( curve );
1614  writePolyline( *curve, layer, lineStyleName, penColor, width );
1615 
1616  break;
1617  }
1618 
1621  {
1622  if ( !qgsDoubleNear( offset, 0.0 ) )
1623  {
1624  QgsGeos geos( sourceGeom );
1625  tempGeom.reset( geos.offsetCurve( offset, 0, GEOSBUF_JOIN_MITRE, 2.0 ) ); //#spellok
1626  if ( tempGeom )
1627  sourceGeom = tempGeom.get();
1628  else
1629  sourceGeom = geom.constGet();
1630  }
1631 
1632  const QgsGeometryCollection *gc = dynamic_cast<const QgsGeometryCollection *>( sourceGeom );
1633  Q_ASSERT( gc );
1634 
1635  for ( int i = 0; i < gc->numGeometries(); i++ )
1636  {
1637  const QgsCurve *curve = dynamic_cast<const QgsCurve *>( gc->geometryN( i ) );
1638  Q_ASSERT( curve );
1639  writePolyline( *curve, layer, lineStyleName, penColor, width );
1640  }
1641 
1642  break;
1643  }
1644 
1646  case QgsWkbTypes::Polygon:
1647  {
1648  if ( !qgsDoubleNear( offset, 0.0 ) )
1649  {
1650  QgsGeos geos( sourceGeom );
1651  tempGeom.reset( geos.buffer( offset, 0, GEOSBUF_CAP_FLAT, GEOSBUF_JOIN_MITRE, 2.0 ) ); //#spellok
1652  if ( tempGeom )
1653  sourceGeom = tempGeom.get();
1654  else
1655  sourceGeom = geom.constGet();
1656  }
1657 
1658  const QgsCurvePolygon *polygon = dynamic_cast<const QgsCurvePolygon *>( sourceGeom );
1659  Q_ASSERT( polygon );
1660 
1661  writePolyline( *polygon->exteriorRing(), layer, lineStyleName, penColor, width );
1662  for ( int i = 0; i < polygon->numInteriorRings(); i++ )
1663  writePolyline( *polygon->interiorRing( i ), layer, lineStyleName, penColor, width );
1664 
1665  break;
1666  }
1667 
1670  {
1671  if ( !qgsDoubleNear( offset, 0.0 ) )
1672  {
1673  QgsGeos geos( sourceGeom );
1674  tempGeom.reset( geos.buffer( offset, 0, GEOSBUF_CAP_FLAT, GEOSBUF_JOIN_MITRE, 2.0 ) ); //#spellok
1675  if ( tempGeom )
1676  sourceGeom = tempGeom.get();
1677  else
1678  sourceGeom = geom.constGet();
1679  }
1680 
1681  const QgsGeometryCollection *gc = dynamic_cast<const QgsGeometryCollection *>( sourceGeom );
1682  Q_ASSERT( gc );
1683 
1684  for ( int i = 0; i < gc->numGeometries(); i++ )
1685  {
1686  const QgsCurvePolygon *polygon = dynamic_cast<const QgsCurvePolygon *>( gc->geometryN( i ) );
1687  Q_ASSERT( polygon );
1688 
1689  writePolyline( *polygon->exteriorRing(), layer, lineStyleName, penColor, width );
1690  for ( int j = 0; j < polygon->numInteriorRings(); j++ )
1691  writePolyline( *polygon->interiorRing( j ), layer, lineStyleName, penColor, width );
1692  }
1693 
1694  break;
1695  }
1696 
1697  default:
1698  break;
1699  }
1700 
1701  }
1702 
1703  if ( brushStyle != Qt::NoBrush )
1704  {
1705  const QgsAbstractGeometry *sourceGeom = geom.constGet();
1706  std::unique_ptr< QgsAbstractGeometry > tempGeom;
1707 
1708  switch ( QgsWkbTypes::flatType( geometryType ) )
1709  {
1711  case QgsWkbTypes::Polygon:
1712  {
1713  const QgsCurvePolygon *polygon = dynamic_cast<const QgsCurvePolygon *>( sourceGeom );
1714  Q_ASSERT( polygon );
1715  writePolygon( *polygon, layer, QStringLiteral( "SOLID" ), brushColor );
1716  break;
1717  }
1718 
1721  {
1722  const QgsGeometryCollection *gc = dynamic_cast<const QgsGeometryCollection *>( sourceGeom );
1723  Q_ASSERT( gc );
1724 
1725  for ( int i = 0; i < gc->numGeometries(); i++ )
1726  {
1727  const QgsCurvePolygon *polygon = dynamic_cast<const QgsCurvePolygon *>( gc->geometryN( i ) );
1728  Q_ASSERT( polygon );
1729  writePolygon( *polygon, layer, QStringLiteral( "SOLID" ), brushColor );
1730  }
1731  break;
1732  }
1733 
1734  default:
1735  break;
1736 
1737  }
1738  }
1739 }
1740 
1741 QColor QgsDxfExport::colorFromSymbolLayer( const QgsSymbolLayer *symbolLayer, QgsSymbolRenderContext &ctx )
1742 {
1743  if ( !symbolLayer )
1744  return QColor();
1745 
1746  return symbolLayer->dxfColor( ctx );
1747 }
1748 
1749 QString QgsDxfExport::lineStyleFromSymbolLayer( const QgsSymbolLayer *symbolLayer )
1750 {
1751  QString lineStyleName = QStringLiteral( "CONTINUOUS" );
1752  if ( !symbolLayer )
1753  {
1754  return lineStyleName;
1755  }
1756 
1757  QHash< const QgsSymbolLayer *, QString >::const_iterator lineTypeIt = mLineStyles.constFind( symbolLayer );
1758  if ( lineTypeIt != mLineStyles.constEnd() )
1759  {
1760  lineStyleName = lineTypeIt.value();
1761  return lineStyleName;
1762  }
1763  else
1764  {
1765  return lineNameFromPenStyle( symbolLayer->dxfPenStyle() );
1766  }
1767 }
1768 
1770 {
1771  int idx = 0;
1772  int current_distance = std::numeric_limits<int>::max();
1773  for ( int i = 1; i < static_cast< int >( sizeof( sDxfColors ) / sizeof( *sDxfColors ) ); ++i )
1774  {
1775  int dist = color_distance( pixel, i );
1776  if ( dist < current_distance )
1777  {
1778  current_distance = dist;
1779  idx = i;
1780  if ( dist == 0 )
1781  break;
1782  }
1783  }
1784  return idx;
1785 }
1786 
1787 int QgsDxfExport::color_distance( QRgb p1, int index )
1788 {
1789  if ( index > 255 || index < 0 )
1790  {
1791  return 0;
1792  }
1793 
1794  double redDiff = qRed( p1 ) - sDxfColors[index][0];
1795  double greenDiff = qGreen( p1 ) - sDxfColors[index][1];
1796  double blueDiff = qBlue( p1 ) - sDxfColors[index][2];
1797 #if 0
1798  QgsDebugMsg( QStringLiteral( "color_distance( r:%1 g:%2 b:%3 <=> i:%4 r:%5 g:%6 b:%7 ) => %8" )
1799  .arg( qRed( p1 ) ).arg( qGreen( p1 ) ).arg( qBlue( p1 ) )
1800  .arg( index )
1801  .arg( mDxfColors[index][0] )
1802  .arg( mDxfColors[index][1] )
1803  .arg( mDxfColors[index][2] )
1804  .arg( redDiff * redDiff + greenDiff * greenDiff + blueDiff * blueDiff ) );
1805 #endif
1806  return redDiff * redDiff + greenDiff * greenDiff + blueDiff * blueDiff;
1807 }
1808 
1809 QRgb QgsDxfExport::createRgbEntry( qreal r, qreal g, qreal b )
1810 {
1811  return QColor::fromRgbF( r, g, b ).rgb();
1812 }
1813 
1814 QgsRenderContext QgsDxfExport::renderContext() const
1815 {
1816  return mRenderContext;
1817 }
1818 
1819 double QgsDxfExport::mapUnitScaleFactor( double scale, QgsUnitTypes::RenderUnit symbolUnits, QgsUnitTypes::DistanceUnit mapUnits, double mapUnitsPerPixel )
1820 {
1821  if ( symbolUnits == QgsUnitTypes::RenderMapUnits )
1822  {
1823  return 1.0;
1824  }
1825  else if ( symbolUnits == QgsUnitTypes::RenderMillimeters )
1826  {
1828  }
1829  else if ( symbolUnits == QgsUnitTypes::RenderPixels )
1830  {
1831  return mapUnitsPerPixel;
1832  }
1833  return 1.0;
1834 }
1835 
1836 void QgsDxfExport::clipValueToMapUnitScale( double &value, const QgsMapUnitScale &scale, double pixelToMMFactor ) const
1837 {
1838  if ( !scale.minSizeMMEnabled && !scale.maxSizeMMEnabled )
1839  {
1840  return;
1841  }
1842 
1843  double mapUnitsPerPixel = mMapSettings.mapToPixel().mapUnitsPerPixel();
1844 
1845  double minSizeMU = std::numeric_limits<double>::lowest();
1846  if ( scale.minSizeMMEnabled )
1847  {
1848  minSizeMU = scale.minSizeMM * pixelToMMFactor * mapUnitsPerPixel;
1849  }
1850  if ( !qgsDoubleNear( scale.minScale, 0.0 ) )
1851  {
1852  minSizeMU = std::max( minSizeMU, value );
1853  }
1854  value = std::max( value, minSizeMU );
1855 
1856  double maxSizeMU = std::numeric_limits<double>::max();
1857  if ( scale.maxSizeMMEnabled )
1858  {
1859  maxSizeMU = scale.maxSizeMM * pixelToMMFactor * mapUnitsPerPixel;
1860  }
1861  if ( !qgsDoubleNear( scale.maxScale, 0.0 ) )
1862  {
1863  maxSizeMU = std::min( maxSizeMU, value );
1864  }
1865  value = std::min( value, maxSizeMU );
1866 }
1867 
1868 QList< QPair< QgsSymbolLayer *, QgsSymbol * > > QgsDxfExport::symbolLayers( QgsRenderContext &context )
1869 {
1870  QList< QPair< QgsSymbolLayer *, QgsSymbol * > > symbolLayers;
1871 
1872  for ( DxfLayerJob *job : mJobs )
1873  {
1874  const QgsSymbolList symbols = job->renderer->symbols( context );
1875 
1876  for ( QgsSymbol *symbol : symbols )
1877  {
1878  int maxSymbolLayers = symbol->symbolLayerCount();
1879  if ( mSymbologyExport != SymbolLayerSymbology )
1880  {
1881  maxSymbolLayers = 1;
1882  }
1883  for ( int i = 0; i < maxSymbolLayers; ++i )
1884  {
1885  symbolLayers.append( qMakePair( symbol->symbolLayer( i ), symbol ) );
1886  }
1887  }
1888  }
1889 
1890  return symbolLayers;
1891 }
1892 
1893 void QgsDxfExport::writeDefaultLinetypes()
1894 {
1895  // continuous (Qt solid line)
1896  for ( const QString &ltype : { QStringLiteral( "ByLayer" ), QStringLiteral( "ByBlock" ), QStringLiteral( "CONTINUOUS" ) } )
1897  {
1898  writeGroup( 0, QStringLiteral( "LTYPE" ) );
1899  writeHandle();
1900  writeGroup( 100, QStringLiteral( "AcDbSymbolTableRecord" ) );
1901  writeGroup( 100, QStringLiteral( "AcDbLinetypeTableRecord" ) );
1902  writeGroup( 2, ltype );
1903  writeGroup( 70, 64 );
1904  writeGroup( 3, QStringLiteral( "Defaultstyle" ) );
1905  writeGroup( 72, 65 );
1906  writeGroup( 73, 0 );
1907  writeGroup( 40, 0.0 );
1908  }
1909 
1910  double das = dashSize();
1911  double dss = dashSeparatorSize();
1912  double dos = dotSize();
1913 
1914  QVector<qreal> dashVector( 2 );
1915  dashVector[0] = das;
1916  dashVector[1] = dss;
1917  writeLinetype( QStringLiteral( "DASH" ), dashVector, QgsUnitTypes::RenderMapUnits );
1918 
1919  QVector<qreal> dotVector( 2 );
1920  dotVector[0] = dos;
1921  dotVector[1] = dss;
1922  writeLinetype( QStringLiteral( "DOT" ), dotVector, QgsUnitTypes::RenderMapUnits );
1923 
1924  QVector<qreal> dashDotVector( 4 );
1925  dashDotVector[0] = das;
1926  dashDotVector[1] = dss;
1927  dashDotVector[2] = dos;
1928  dashDotVector[3] = dss;
1929  writeLinetype( QStringLiteral( "DASHDOT" ), dashDotVector, QgsUnitTypes::RenderMapUnits );
1930 
1931  QVector<qreal> dashDotDotVector( 6 );
1932  dashDotDotVector[0] = das;
1933  dashDotDotVector[1] = dss;
1934  dashDotDotVector[2] = dos;
1935  dashDotDotVector[3] = dss;
1936  dashDotDotVector[4] = dos;
1937  dashDotDotVector[5] = dss;
1938  writeLinetype( QStringLiteral( "DASHDOTDOT" ), dashDotDotVector, QgsUnitTypes::RenderMapUnits );
1939 }
1940 
1941 void QgsDxfExport::writeSymbolLayerLinetype( const QgsSymbolLayer *symbolLayer )
1942 {
1943  if ( !symbolLayer )
1944  {
1945  return;
1946  }
1947 
1949  QVector<qreal> customLinestyle = symbolLayer->dxfCustomDashPattern( unit );
1950  if ( !customLinestyle.isEmpty() )
1951  {
1952  QString name = QStringLiteral( "symbolLayer%1" ).arg( mSymbolLayerCounter++ );
1953  writeLinetype( name, customLinestyle, unit );
1954  mLineStyles.insert( symbolLayer, name );
1955  }
1956 }
1957 
1958 int QgsDxfExport::nLineTypes( const QList< QPair< QgsSymbolLayer *, QgsSymbol * > > &symbolLayers )
1959 {
1960  int nLineTypes = 0;
1961  for ( const auto &symbolLayer : symbolLayers )
1962  {
1963  const QgsSimpleLineSymbolLayer *simpleLine = dynamic_cast< const QgsSimpleLineSymbolLayer * >( symbolLayer.first );
1964  if ( simpleLine )
1965  {
1966  if ( simpleLine->useCustomDashPattern() )
1967  {
1968  ++nLineTypes;
1969  }
1970  }
1971  }
1972  return nLineTypes;
1973 }
1974 
1975 void QgsDxfExport::writeLinetype( const QString &styleName, const QVector<qreal> &pattern, QgsUnitTypes::RenderUnit u )
1976 {
1977  double length = 0;
1978  for ( qreal size : pattern )
1979  {
1980  length += ( size * mapUnitScaleFactor( mSymbologyScale, u, mMapUnits, mMapSettings.mapToPixel().mapUnitsPerPixel() ) );
1981  }
1982 
1983  writeGroup( 0, QStringLiteral( "LTYPE" ) );
1984  writeHandle();
1985  // 330 5
1986  writeGroup( 100, QStringLiteral( "AcDbSymbolTableRecord" ) );
1987  writeGroup( 100, QStringLiteral( "AcDbLinetypeTableRecord" ) );
1988  writeGroup( 2, styleName );
1989  writeGroup( 70, 64 ); // 0?
1990  writeGroup( 3, QString() );
1991  writeGroup( 72, 65 );
1992  writeGroup( 73, pattern.size() );
1993  writeGroup( 40, length );
1994 
1995  bool isGap = false;
1996  for ( qreal size : pattern )
1997  {
1998  // map units or mm?
1999  double segmentLength = ( isGap ? -size : size );
2000  segmentLength *= mapUnitScaleFactor( mSymbologyScale, u, mMapUnits, mMapSettings.mapToPixel().mapUnitsPerPixel() );
2001  writeGroup( 49, segmentLength );
2002  writeGroup( 74, 0 );
2003  isGap = !isGap;
2004  }
2005 }
2006 
2007 void QgsDxfExport::addGeometryGeneratorSymbolLayer( QgsSymbolRenderContext &ctx, const QgsCoordinateTransform &ct, const QString &layer, QgsSymbolLayer *symbolLayer, bool allSymbolLayers )
2008 {
2009  QgsGeometryGeneratorSymbolLayer *gg = dynamic_cast<QgsGeometryGeneratorSymbolLayer *>( symbolLayer );
2010  if ( !gg )
2011  {
2012  return;
2013  }
2014 
2015  const QgsFeature *fet = ctx.feature();
2016  if ( !fet )
2017  {
2018  return;
2019  }
2020 
2021  QgsFeature f = *fet;
2022 
2023  QgsExpressionContext &expressionContext = ctx.renderContext().expressionContext();
2024  QgsExpression geomExpr( gg->geometryExpression() );
2025  geomExpr.prepare( &expressionContext );
2026  QgsGeometry geom = geomExpr.evaluate( &expressionContext ).value<QgsGeometry>();
2027  f.setGeometry( geom );
2028 
2029  QgsSymbol *symbol = gg->subSymbol();
2030  if ( symbol && symbol->symbolLayerCount() > 0 )
2031  {
2032  QgsExpressionContextScope *symbolExpressionContextScope = symbol->symbolRenderContext()->expressionContextScope();
2033  symbolExpressionContextScope->setFeature( f );
2034 
2035  ctx.setFeature( &f );
2036 
2037  int nSymbolLayers = allSymbolLayers ? symbol->symbolLayerCount() : 1;
2038  for ( int i = 0; i < nSymbolLayers; ++i )
2039  {
2040  addFeature( ctx, ct, layer, symbol->symbolLayer( i ), symbol );
2041  }
2042 
2043  ctx.setFeature( fet );
2044  }
2045 }
2046 
2047 bool QgsDxfExport::hasDataDefinedProperties( const QgsSymbolLayer *sl, const QgsSymbol *symbol )
2048 {
2049  if ( !sl || !symbol )
2050  {
2051  return false;
2052  }
2053 
2054  if ( symbol->renderHints() & QgsSymbol::DynamicRotation )
2055  {
2056  return true;
2057  }
2058 
2059  return sl->hasDataDefinedProperties();
2060 }
2061 
2062 double QgsDxfExport::dashSize() const
2063 {
2064  double size = mSymbologyScale * 0.002;
2065  return sizeToMapUnits( size );
2066 }
2067 
2068 double QgsDxfExport::dotSize() const
2069 {
2070  double size = mSymbologyScale * 0.0006;
2071  return sizeToMapUnits( size );
2072 }
2073 
2074 double QgsDxfExport::dashSeparatorSize() const
2075 {
2076  double size = mSymbologyScale * 0.0006;
2077  return sizeToMapUnits( size );
2078 }
2079 
2080 double QgsDxfExport::sizeToMapUnits( double s ) const
2081 {
2082  double size = s * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::DistanceMeters, mMapUnits );
2083  return size;
2084 }
2085 
2086 QString QgsDxfExport::lineNameFromPenStyle( Qt::PenStyle style )
2087 {
2088  switch ( style )
2089  {
2090  case Qt::DashLine:
2091  return QStringLiteral( "DASH" );
2092  case Qt::DotLine:
2093  return QStringLiteral( "DOT" );
2094  case Qt::DashDotLine:
2095  return QStringLiteral( "DASHDOT" );
2096  case Qt::DashDotDotLine:
2097  return QStringLiteral( "DASHDOTDOT" );
2098  case Qt::SolidLine:
2099  default:
2100  return QStringLiteral( "CONTINUOUS" );
2101  }
2102 }
2103 
2104 QString QgsDxfExport::dxfLayerName( const QString &name )
2105 {
2106  if ( name.isEmpty() )
2107  return QStringLiteral( "0" );
2108 
2109  // dxf layers can be max 255 characters long
2110  QString layerName = name.left( 255 );
2111 
2112  // replaced restricted characters with underscore
2113  // < > / \ " : ; ? * | = '
2114  // See http://docs.autodesk.com/ACD/2010/ENU/AutoCAD%202010%20User%20Documentation/index.html?url=WS1a9193826455f5ffa23ce210c4a30acaf-7345.htm,topicNumber=d0e41665
2115  layerName.replace( '<', '_' );
2116  layerName.replace( '>', '_' );
2117  layerName.replace( '/', '_' );
2118  layerName.replace( '\\', '_' );
2119  layerName.replace( '\"', '_' );
2120  layerName.replace( ':', '_' );
2121  layerName.replace( ';', '_' );
2122  layerName.replace( '?', '_' );
2123  layerName.replace( '*', '_' );
2124  layerName.replace( '|', '_' );
2125  layerName.replace( '=', '_' );
2126  layerName.replace( '\'', '_' );
2127 
2128  // also remove newline characters (#15067)
2129  layerName.replace( QLatin1String( "\r\n" ), QLatin1String( "_" ) );
2130  layerName.replace( '\r', '_' );
2131  layerName.replace( '\n', '_' );
2132 
2133  return layerName.trimmed();
2134 }
2135 
2136 bool QgsDxfExport::layerIsScaleBasedVisible( const QgsMapLayer *layer ) const
2137 {
2138  if ( !layer )
2139  return false;
2140 
2141  if ( mSymbologyExport == QgsDxfExport::NoSymbology )
2142  return true;
2143 
2144  return layer->isInScaleRange( mSymbologyScale );
2145 }
2146 
2147 QString QgsDxfExport::layerName( const QString &id, const QgsFeature &f ) const
2148 {
2149  // TODO: make this thread safe
2150  const QList< QgsMapLayer * > layers = mMapSettings.layers();
2151  for ( QgsMapLayer *ml : layers )
2152  {
2153  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml );
2154  if ( vl && vl->id() == id )
2155  {
2156  int attrIdx = mLayerNameAttribute.value( vl->id(), -1 );
2157  return dxfLayerName( attrIdx < 0 ? layerName( vl ) : f.attribute( attrIdx ).toString() );
2158  }
2159  }
2160 
2161  return QStringLiteral( "0" );
2162 }
2163 
2164 QString QgsDxfExport::dxfEncoding( const QString &name )
2165 {
2166  const QList< QByteArray > codecs = QTextCodec::availableCodecs();
2167  for ( const QByteArray &codec : codecs )
2168  {
2169  if ( name != codec )
2170  continue;
2171 
2172  int i;
2173  for ( i = 0; i < static_cast< int >( sizeof( DXF_ENCODINGS ) / sizeof( *DXF_ENCODINGS ) ) && name != DXF_ENCODINGS[i][1]; ++i )
2174  ;
2175 
2176  if ( i == static_cast< int >( sizeof( DXF_ENCODINGS ) / sizeof( *DXF_ENCODINGS ) ) )
2177  continue;
2178 
2179  return DXF_ENCODINGS[i][0];
2180  }
2181 
2182  return QString();
2183 }
2184 
2186 {
2187  QStringList encodings;
2188  const QList< QByteArray > codecs = QTextCodec::availableCodecs();
2189  for ( const QByteArray &codec : codecs )
2190  {
2191  int i;
2192  for ( i = 0; i < static_cast< int >( sizeof( DXF_ENCODINGS ) / sizeof( *DXF_ENCODINGS ) ) && strcmp( codec.data(), DXF_ENCODINGS[i][1] ) != 0; ++i )
2193  ;
2194 
2195  if ( i < static_cast< int >( sizeof( DXF_ENCODINGS ) / sizeof( *DXF_ENCODINGS ) ) )
2196  encodings << codec.data();
2197  }
2198  return encodings;
2199 }
2200 
2202 {
2203  Q_ASSERT( vl );
2204  return mLayerTitleAsName && !vl->title().isEmpty() ? vl->title() : vl->name();
2205 }
2206 
2207 void QgsDxfExport::drawLabel( const QString &layerId, QgsRenderContext &context, pal::LabelPosition *label, const QgsPalLayerSettings &settings )
2208 {
2209  Q_UNUSED( context )
2210 
2211  if ( !settings.drawLabels )
2212  return;
2213 
2214  QgsTextLabelFeature *lf = dynamic_cast<QgsTextLabelFeature *>( label->getFeaturePart()->feature() );
2215 
2216  // Copy to temp, editable layer settings
2217  // these settings will be changed by any data defined values, then used for rendering label components
2218  // settings may be adjusted during rendering of components
2219  QgsPalLayerSettings tmpLyr( settings );
2220 
2221  // apply any previously applied data defined settings for the label
2222  const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues = lf->dataDefinedValues();
2223 
2224  //font
2225  QFont dFont = lf->definedFont();
2226  QgsDebugMsgLevel( QStringLiteral( "PAL font tmpLyr: %1, Style: %2" ).arg( tmpLyr.format().font().toString(), tmpLyr.format().font().styleName() ), 4 );
2227  QgsDebugMsgLevel( QStringLiteral( "PAL font definedFont: %1, Style: %2" ).arg( dFont.toString(), dFont.styleName() ), 4 );
2228 
2229  QgsTextFormat format = tmpLyr.format();
2230  format.setFont( dFont );
2231  tmpLyr.setFormat( format );
2232 
2234  {
2235  //calculate font alignment based on label quadrant
2236  switch ( label->getQuadrant() )
2237  {
2242  break;
2247  break;
2252  break;
2253  }
2254  }
2255 
2256  // update tmpLyr with any data defined text style values
2257  QgsPalLabeling::dataDefinedTextStyle( tmpLyr, ddValues );
2258 
2259  // update tmpLyr with any data defined text buffer values
2260  QgsPalLabeling::dataDefinedTextBuffer( tmpLyr, ddValues );
2261 
2262  // update tmpLyr with any data defined text formatting values
2263  QgsPalLabeling::dataDefinedTextFormatting( tmpLyr, ddValues );
2264 
2265  // add to the results
2266  QString txt = label->getFeaturePart()->feature()->labelText();
2267 
2268  QgsFeatureId fid = label->getFeaturePart()->featureId();
2269  QString dxfLayer = mDxfLayerNames[layerId][fid];
2270 
2271  QString wrapchr = tmpLyr.wrapChar.isEmpty() ? QStringLiteral( "\n" ) : tmpLyr.wrapChar;
2272 
2273  //add the direction symbol if needed
2274  if ( !txt.isEmpty() && tmpLyr.placement == QgsPalLayerSettings::Line && tmpLyr.addDirectionSymbol )
2275  {
2276  bool prependSymb = false;
2277  QString symb = tmpLyr.rightDirectionSymbol;
2278 
2279  if ( label->getReversed() )
2280  {
2281  prependSymb = true;
2282  symb = tmpLyr.leftDirectionSymbol;
2283  }
2284 
2285  if ( tmpLyr.reverseDirectionSymbol )
2286  {
2287  if ( symb == tmpLyr.rightDirectionSymbol )
2288  {
2289  prependSymb = true;
2290  symb = tmpLyr.leftDirectionSymbol;
2291  }
2292  else
2293  {
2294  prependSymb = false;
2295  symb = tmpLyr.rightDirectionSymbol;
2296  }
2297  }
2298 
2300  {
2301  prependSymb = true;
2302  symb = symb + wrapchr;
2303  }
2305  {
2306  prependSymb = false;
2307  symb = wrapchr + symb;
2308  }
2309 
2310  if ( prependSymb )
2311  {
2312  txt.prepend( symb );
2313  }
2314  else
2315  {
2316  txt.append( symb );
2317  }
2318  }
2319 
2320  if ( mFlags & FlagNoMText )
2321  {
2322  txt.replace( QChar( QChar::LineFeed ), ' ' );
2323  txt.replace( QChar( QChar::CarriageReturn ), ' ' );
2324  writeText( dxfLayer, txt, label, tmpLyr, context.expressionContext() );
2325  }
2326  else
2327  {
2328  txt.replace( QString( QChar( QChar::CarriageReturn ) ) + QString( QChar( QChar::LineFeed ) ), QStringLiteral( "\\P" ) );
2329  txt.replace( QChar( QChar::CarriageReturn ), QStringLiteral( "\\P" ) );
2330  txt = txt.replace( wrapchr, QLatin1String( "\\P" ) );
2331  txt.replace( " ", "\\~" );
2332 
2333  if ( tmpLyr.format().font().underline() )
2334  {
2335  txt.prepend( "\\L" ).append( "\\l" );
2336  }
2337 
2338  if ( tmpLyr.format().font().overline() )
2339  {
2340  txt.prepend( "\\O" ).append( "\\o" );
2341  }
2342 
2343  if ( tmpLyr.format().font().strikeOut() )
2344  {
2345  txt.prepend( "\\K" ).append( "\\k" );
2346  }
2347 
2348  txt.prepend( QStringLiteral( "\\f%1|i%2|b%3;\\H%4;" )
2349  .arg( tmpLyr.format().font().family() )
2350  .arg( tmpLyr.format().font().italic() ? 1 : 0 )
2351  .arg( tmpLyr.format().font().bold() ? 1 : 0 )
2352  .arg( label->getHeight() / ( 1 + txt.count( QStringLiteral( "\\P" ) ) ) * 0.75 ) );
2353  writeMText( dxfLayer, txt, QgsPoint( label->getX(), label->getY() ), label->getWidth(), label->getAlpha() * 180.0 / M_PI, tmpLyr.format().color() );
2354  }
2355 }
2356 
2357 
2358 void QgsDxfExport::registerDxfLayer( const QString &layerId, QgsFeatureId fid, const QString &layerName )
2359 {
2360  if ( !mDxfLayerNames.contains( layerId ) )
2361  mDxfLayerNames[ layerId ] = QMap<QgsFeatureId, QString>();
2362 
2363  mDxfLayerNames[layerId][fid] = layerName;
2364 }
2365 
2367 {
2368  mCrs = crs;
2369  mMapUnits = crs.mapUnits();
2370 }
2371 
2373 {
2374  return mCrs;
2375 }
2376 
2378 {
2379  QString splitLayerFieldName;
2380  const QgsFields fields = mLayer->fields();
2381  if ( mLayerOutputAttributeIndex >= 0 && mLayerOutputAttributeIndex < fields.size() )
2382  {
2383  splitLayerFieldName = fields.at( mLayerOutputAttributeIndex ).name();
2384  }
2385 
2386  return splitLayerFieldName;
2387 }
QgsCurve
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
QgsDxfExport::encodings
static QStringList encodings()
Returns list of available DXF encodings.
Definition: qgsdxfexport.cpp:2185
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:369
QgsCoordinateSequence
QVector< QgsRingSequence > QgsCoordinateSequence
Definition: qgsabstractgeometry.h:49
qgsmaplayerstyle.h
QgsExpressionContext::scopes
QList< QgsExpressionContextScope * > scopes()
Returns a list of scopes contained within the stack.
Definition: qgsexpressioncontext.h:507
QgsMapSettings::setDestinationCrs
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
sets destination coordinate reference system
Definition: qgsmapsettings.cpp:309
QgsExpressionContextScope::setFeature
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the scope.
Definition: qgsexpressioncontext.h:317
QgsVectorLayerFeatureSource::getFeatures
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) override
Gets an iterator for features matching the specified request.
Definition: qgsvectorlayerfeatureiterator.cpp:96
qgsexpressioncontextutils.h
QgsLineString::pointN
QgsPoint pointN(int i) const
Returns the specified point from inside the line string.
Definition: qgslinestring.cpp:660
QgsTextLabelFeature::dataDefinedValues
const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant > & dataDefinedValues() const
Gets data-defined values.
Definition: qgspalgeometry.h:140
pal::LabelPosition::getY
double getY(int i=0) const
Returns the down-left y coordinate.
Definition: labelposition.cpp:353
QgsDxfExport::closestColorMatch
static int closestColorMatch(QRgb color)
Gets DXF palette index of nearest entry for given color.
Definition: qgsdxfexport.cpp:1769
QgsPalLayerSettings::Hali
@ Hali
Horizontal alignment for data defined label position (Left, Center, Right)
Definition: qgspallabeling.h:437
QgsDxfExport::writeHandle
int writeHandle(int code=5, int handle=0)
Write a tuple of group code and a handle.
Definition: qgsdxfexport.cpp:294
QgsPointXY::y
double y
Definition: qgspointxy.h:48
QgsPalLayerSettings::leftDirectionSymbol
QString leftDirectionSymbol
String to use for left direction arrows.
Definition: qgspallabeling.h:603
qgsmaplayerstylemanager.h
QgsRenderContext::mapToPixel
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
Definition: qgsrendercontext.h:309
QgsSymbolLayer::dxfAngle
virtual double dxfAngle(QgsSymbolRenderContext &context) const
Gets angle.
Definition: qgssymbollayer.cpp:157
QgsMarkerSymbolLayer::size
double size() const
Returns the symbol size.
Definition: qgssymbollayer.h:655
QgsTextFormat::setFont
void setFont(const QFont &font)
Sets the font used for rendering text.
Definition: qgstextformat.cpp:76
QgsUnitTypes::RenderUnit
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:166
QgsWkbTypes::Point
@ Point
Definition: qgswkbtypes.h:71
QgsSymbolLevel
QList< QgsSymbolLevelItem > QgsSymbolLevel
Definition: qgsrenderer.h:85
QgsPalLayerSettings::reverseDirectionSymbol
bool reverseDirectionSymbol
True if direction symbols should be reversed.
Definition: qgspallabeling.h:619
QgsRenderContext::expressionContext
QgsExpressionContext & expressionContext()
Gets the expression context.
Definition: qgsrendercontext.h:580
QgsMapToPixel::mapUnitsPerPixel
double mapUnitsPerPixel() const
Returns current map units per pixel.
Definition: qgsmaptopixel.cpp:128
QgsRectangle::combineExtentWith
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
Definition: qgsrectangle.h:359
QgsSymbolLayer::dxfPenStyle
virtual Qt::PenStyle dxfPenStyle() const
Gets pen style.
Definition: qgssymbollayer.cpp:169
QgsExpressionContextUtils::globalScope
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Definition: qgsexpressioncontextutils.cpp:33
qgslinestring.h
QgsDxfExport::addLayers
void addLayers(const QList< QgsDxfExport::DxfLayer > &layers)
Add layers to export.
Definition: qgsdxfexport.cpp:85
QgsWkbTypes::MultiPolygon
@ MultiPolygon
Definition: qgswkbtypes.h:77
QgsPoint
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
QgsDxfExport::~QgsDxfExport
~QgsDxfExport() override
Definition: qgsdxfexport.cpp:65
QgsSymbolLayer::dxfCustomDashPattern
virtual QVector< qreal > dxfCustomDashPattern(QgsUnitTypes::RenderUnit &unit) const
Gets dash pattern.
Definition: qgssymbollayer.cpp:163
QgsDxfExport::writePolygon
void writePolygon(const QgsRingSequence &polygon, const QString &layer, const QString &hatchPattern, const QColor &color)
Draw dxf filled polygon (HATCH)
Definition: qgsdxfexport.cpp:1163
QgsGeometryCollection::numGeometries
int numGeometries() const
Returns the number of geometries within the collection.
Definition: qgsgeometrycollection.h:51
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsSymbolRenderContext::feature
const QgsFeature * feature() const
Returns the current feature being rendered.
Definition: qgssymbol.h:789
QgsGeometryGeneratorSymbolLayer::subSymbol
QgsSymbol * subSymbol() override
Returns the symbol's sub symbol, if present.
Definition: qgsgeometrygeneratorsymbollayer.h:72
labelposition.h
QgsPalLayerSettings
Definition: qgspallabeling.h:205
QgsLineString::numPoints
int numPoints() const override
Returns the number of points in the curve.
Definition: qgslinestring.cpp:650
QgsDxfExport::writeString
void writeString(const QString &s)
Write a string value.
Definition: qgsdxfexport.cpp:174
crs
const QgsCoordinateReferenceSystem & crs
Definition: qgswfsgetfeature.cpp:105
qgscompoundcurve.h
pal::LabelPosition
LabelPosition is a candidate feature label position.
Definition: labelposition.h:55
QgsDxfExport::HAlign::Undefined
@ Undefined
Undefined.
QgsCurvePolygon
Curve polygon geometry type.
Definition: qgscurvepolygon.h:34
QgsRenderContext::setPainter
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
Definition: qgsrendercontext.h:475
QgsRectangle::xMaximum
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
QgsDxfExport::writePoint
void writePoint(const QString &layer, const QColor &color, const QgsPoint &pt)
Write point.
Definition: qgsdxfexport.cpp:1392
qgsdxfexport_p.h
QgsWkbTypes::LineString
@ LineString
Definition: qgswkbtypes.h:72
qgsfeatureiterator.h
QgsFields
Definition: qgsfields.h:44
geos
Contains geos related utilities and functions.
Definition: qgsgeos.h:41
QgsSymbolLayer::hasDataDefinedProperties
virtual bool hasDataDefinedProperties() const
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
Definition: qgssymbollayer.cpp:215
pal::LabelPosition::QuadrantOver
@ QuadrantOver
Definition: labelposition.h:71
pal::LabelPosition::QuadrantAboveLeft
@ QuadrantAboveLeft
Definition: labelposition.h:67
QgsFeature::geometry
QgsGeometry geometry
Definition: qgsfeature.h:71
QgsCurvePolygon::exteriorRing
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
Definition: qgscurvepolygon.h:86
QgsPoint::z
double z
Definition: qgspoint.h:60
QgsPalLayerSettings::addDirectionSymbol
bool addDirectionSymbol
If true, '<' or '>' (or custom strings set via leftDirectionSymbol and rightDirectionSymbol) will be ...
Definition: qgspallabeling.h:596
QgsVectorLayerFeatureSource::fields
QgsFields fields() const
Returns the fields that will be available for features that are retrieved from this source.
Definition: qgsvectorlayerfeatureiterator.cpp:102
QgsPalLayerSettings::QuadrantPosition
QuadrantPosition
Definition: qgspallabeling.h:282
QgsRenderContext
Definition: qgsrendercontext.h:57
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:458
QgsRenderContext::setLabelingEngine
void setLabelingEngine(QgsLabelingEngine *engine)
Assign new labeling engine.
Definition: qgsrendercontext.h:509
QgsGeometryGeneratorSymbolLayer::geometryExpression
QString geometryExpression() const
Gets the expression to generate this geometry.
Definition: qgsgeometrygeneratorsymbollayer.h:70
qgsunittypes.h
QgsCircularString::numPoints
int numPoints() const override
Returns the number of points in the curve.
Definition: qgscircularstring.cpp:503
QgsSimpleLineSymbolLayer::useCustomDashPattern
bool useCustomDashPattern() const
Returns true if the line uses a custom dash pattern.
Definition: qgslinesymbollayer.h:135
QgsMapSettings::layerStyleOverrides
QMap< QString, QString > layerStyleOverrides() const
Gets map of map layer style overrides (key: layer ID, value: style name) where a different style shou...
Definition: qgsmapsettings.cpp:299
QgsUnitTypes::RenderMillimeters
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:168
QgsMapUnitScale::minSizeMM
double minSizeMM
The minimum size in millimeters, or 0.0 if unset.
Definition: qgsmapunitscale.h:67
QgsMarkerSymbolLayer
Abstract base class for marker symbol layers.
Definition: qgssymbollayer.h:575
QgsWkbTypes::Type
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:68
QgsPalLayerSettings::Vali
@ Vali
Vertical alignment for data defined label position (Bottom, Base, Half, Cap, Top)
Definition: qgspallabeling.h:438
QgsWkbTypes::MultiCurve
@ MultiCurve
Definition: qgswkbtypes.h:82
QgsCircularString::pointN
QgsPoint pointN(int i) const
Returns the point at index i within the circular string.
Definition: qgscircularstring.cpp:508
qgspoint.h
QgsDxfExport::VAlign::Undefined
@ Undefined
Undefined.
pal::LabelPosition::getQuadrant
Quadrant getQuadrant() const
Definition: labelposition.h:269
QgsFeatureRequest::setSubsetOfAttributes
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Definition: qgsfeaturerequest.cpp:190
QgsDxfExport::writeGroupCode
void writeGroupCode(int code)
Write a group code.
Definition: qgsdxfexport.cpp:156
QgsMapSettings::setOutputDpi
void setOutputDpi(double dpi)
Sets DPI used for conversion between real world units (e.g. mm) and pixels.
Definition: qgsmapsettings.cpp:267
QgsSymbol
Definition: qgssymbol.h:63
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsLineString
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:43
QgsUnitTypes::DistanceUnit
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:67
QgsDxfExport::writeLine
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)
Definition: qgsdxfexport.cpp:1263
QgsPalLayerSettings::Line
@ Line
Arranges candidates parallel to a generalised line representing the feature or parallel to a polygon'...
Definition: qgspallabeling.h:224
QgsSymbol::symbolLayer
QgsSymbolLayer * symbolLayer(int layer)
Returns the symbol layer at the specified index.
Definition: qgssymbol.cpp:366
QgsDxfExport::setDestinationCrs
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
Set destination CRS.
Definition: qgsdxfexport.cpp:2366
QgsCoordinateTransform::isValid
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
Definition: qgscoordinatetransform.cpp:876
QgsDxfExport::FlagNoMText
@ FlagNoMText
Export text as TEXT elements. If not set, text will be exported as MTEXT elements.
Definition: qgsdxfexport.h:111
QgsTextLabelFeature
Class that adds extra information to QgsLabelFeature for text labels.
Definition: qgspalgeometry.h:30
QgsDxfExport::mapUnitScaleFactor
static double mapUnitScaleFactor(double scale, QgsUnitTypes::RenderUnit symbolUnits, QgsUnitTypes::DistanceUnit mapUnits, double mapUnitsPerPixel=1.0)
Returns scale factor for conversion to map units.
Definition: qgsdxfexport.cpp:1819
QgsField::name
QString name
Definition: qgsfield.h:59
QgsDxfExport::HAlign::HLeft
@ HLeft
Left (0)
QgsDxfExport::writeGroup
void writeGroup(int code, int i)
Write a tuple of group code and integer value.
Definition: qgsdxfexport.cpp:101
QgsRectangle
Definition: qgsrectangle.h:41
QgsCurvePolygon::interiorRing
const QgsCurve * interiorRing(int i) const
Retrieves an interior ring from the curve polygon.
Definition: qgscurvepolygon.h:99
pal::LabelPosition::getFeaturePart
FeaturePart * getFeaturePart() const
Returns the feature corresponding to this labelposition.
Definition: labelposition.cpp:371
QgsSymbolRenderContext::setFeature
void setFeature(const QgsFeature *f)
Definition: qgssymbol.h:784
qgsDoubleToString
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:275
QgsFeatureRequest::setExpressionContext
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
Definition: qgsfeaturerequest.cpp:149
QgsDxfExport::ExportResult::EmptyExtentError
@ EmptyExtentError
Empty extent, no extent given and no extent could be derived from layers.
QgsFeatureRenderer::SymbolLevels
@ SymbolLevels
Rendering with symbol levels (i.e. implements symbols(), symbolForFeature())
Definition: qgsrenderer.h:254
QgsTextFormat::color
QColor color() const
Returns the color that text will be rendered in.
Definition: qgstextformat.cpp:126
QgsMarkerSymbolLayer::sizeUnit
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units for the symbol's size.
Definition: qgssymbollayer.h:672
QgsSymbolRenderContext
Definition: qgssymbol.h:681
QgsSymbolRenderContext::expressionContextScope
QgsExpressionContextScope * expressionContextScope()
This scope is always available when a symbol of this type is being rendered.
Definition: qgssymbol.cpp:1396
QgsFeatureRequest::setFilterRect
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
Definition: qgsfeaturerequest.cpp:97
QgsDxfExport::VAlign::VBaseLine
@ VBaseLine
Top (0)
pal::LabelPosition::QuadrantBelowRight
@ QuadrantBelowRight
Definition: labelposition.h:75
QgsCompoundCurve::nCurves
int nCurves() const
Returns the number of curves in the geometry.
Definition: qgscompoundcurve.h:76
QgsVectorLayer::fields
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Definition: qgsvectorlayer.cpp:3280
QgsSymbolLayer::writeDxf
virtual bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift=QPointF(0.0, 0.0)) const
write as DXF
Definition: qgssymbollayer.cpp:127
Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:752
QgsUnitTypes::fromUnitToUnitFactor
static Q_INVOKABLE double fromUnitToUnitFactor(QgsUnitTypes::DistanceUnit fromUnit, QgsUnitTypes::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
Definition: qgsunittypes.cpp:352
QgsFeature::id
QgsFeatureId id
Definition: qgsfeature.h:68
QgsPoint::y
double y
Definition: qgspoint.h:59
pal::LabelPosition::QuadrantBelowLeft
@ QuadrantBelowLeft
Definition: labelposition.h:73
QgsTextFormat
Definition: qgstextformat.h:38
QgsMapLayer::isInScaleRange
bool isInScaleRange(double scale) const
Tests whether the layer should be visible at the specified scale.
Definition: qgsmaplayer.cpp:669
QgsFeatureRequest
Definition: qgsfeaturerequest.h:75
QgsWkbTypes::MultiLineString
@ MultiLineString
Definition: qgswkbtypes.h:76
QgsGeometryCollection
Geometry collection.
Definition: qgsgeometrycollection.h:35
feature.h
QgsExpressionContextUtils::projectScope
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
Definition: qgsexpressioncontextutils.cpp:221
QgsDxfExport::writeToFile
ExportResult writeToFile(QIODevice *d, const QString &codec)
Export to a dxf file in the given encoding.
Definition: qgsdxfexport.cpp:179
QgsSymbolLayer
Definition: qgssymbollayer.h:52
QgsDxfExport::mapUnits
QgsUnitTypes::DistanceUnit mapUnits() const
Retrieve map units.
Definition: qgsdxfexport.cpp:245
QgsCircularString
Circular string geometry type.
Definition: qgscircularstring.h:34
QgsSymbolLayer::dxfOffset
virtual double dxfOffset(const QgsDxfExport &e, QgsSymbolRenderContext &context) const
Gets offset.
Definition: qgssymbollayer.cpp:144
DxfLayerJob
Holds information about each layer in a DXF job.
Definition: qgsdxfexport_p.h:31
QgsMapSettings::transformContext
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
Definition: qgsmapsettings.cpp:400
DXF_TRAILER
#define DXF_TRAILER
Definition: qgsdxfexport_p.h:422
QgsDxfExport::dxfEncoding
static QString dxfEncoding(const QString &name)
Returns DXF encoding for Qt encoding.
Definition: qgsdxfexport.cpp:2164
QgsFeature::setGeometry
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:137
QgsDxfExport::flags
QgsDxfExport::Flags flags() const
Returns the export flags.
Definition: qgsdxfexport.cpp:80
QgsPalLayerSettings::SymbolAbove
@ SymbolAbove
Place direction symbols on above label.
Definition: qgspallabeling.h:305
QgsDxfExport::layerName
QString layerName(const QString &id, const QgsFeature &f) const
Gets layer name for feature.
Definition: qgsdxfexport.cpp:2147
QgsPalLayerSettings::wrapChar
QString wrapChar
Wrapping character string.
Definition: qgspallabeling.h:560
QgsSymbolList
QList< QgsSymbol * > QgsSymbolList
Definition: qgsrenderer.h:45
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:315
QgsDxfExport::writeInt
void writeInt(int i)
Write an integer value.
Definition: qgsdxfexport.cpp:161
QgsRenderContext::setExtent
void setExtent(const QgsRectangle &extent)
When rendering a map layer, calling this method sets the "clipping" extent for the layer (in the laye...
Definition: qgsrendercontext.h:418
QgsPalLayerSettings::multilineAlign
MultiLineAlign multilineAlign
Horizontal alignment of multi-line labels.
Definition: qgspallabeling.h:584
DxfLayerJob::crs
QgsCoordinateReferenceSystem crs
Definition: qgsdxfexport_p.h:112
QgsPalLayerSettings::format
const QgsTextFormat & format() const
Returns the label text formatting settings, e.g., font settings, buffer settings, etc.
Definition: qgspallabeling.h:1015
QgsSimpleLineSymbolLayer
Definition: qgslinesymbollayer.h:39
QgsGeos
Definition: qgsgeos.h:103
QgsPalLayerSettings::drawLabels
bool drawLabels
Whether to draw labels for this layer.
Definition: qgspallabeling.h:522
QgsSymbolLevelItem
Definition: qgsrenderer.h:60
QgsWkbTypes::CurvePolygon
@ CurvePolygon
Definition: qgswkbtypes.h:81
QgsVectorLayer::uniqueValues
QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const FINAL
Calculates a list of unique values contained within an attribute in the layer.
Definition: qgsvectorlayer.cpp:3949
QgsPalLayerSettings::setFormat
void setFormat(const QgsTextFormat &format)
Sets the label text formatting settings, e.g., font settings, buffer settings, etc.
Definition: qgspallabeling.h:1023
QgsPalLayerSettings::placement
Placement placement
Definition: qgspallabeling.h:645
QgsGeometryGeneratorSymbolLayer
Definition: qgsgeometrygeneratorsymbollayer.h:26
QgsDxfExport::drawLabel
void drawLabel(const QString &layerId, QgsRenderContext &context, pal::LabelPosition *label, const QgsPalLayerSettings &settings) override
Add a label to the dxf output.
Definition: qgsdxfexport.cpp:2207
QgsFields::size
int size() const
Returns number of items.
Definition: qgsfields.cpp:138
pointset.h
QgsDxfExport::setFlags
void setFlags(QgsDxfExport::Flags flags)
Sets the export flags.
Definition: qgsdxfexport.cpp:75
qgsvectordataprovider.h
QgsLabelingEngine::run
virtual void run(QgsRenderContext &context)=0
Runs the labeling job.
QgsRenderContext::setMapToPixel
void setMapToPixel(const QgsMapToPixel &mtp)
Sets the context's map to pixel transform, which transforms between map coordinates and device coordi...
Definition: qgsrendercontext.h:404
QgsWkbTypes::PointZ
@ PointZ
Definition: qgswkbtypes.h:85
QgsDxfExport::VAlign::VBottom
@ VBottom
Bottom (1)
QgsCoordinateReferenceSystem::isValid
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Definition: qgscoordinatereferencesystem.cpp:902
QgsDxfExport::writeCircle
void writeCircle(const QString &layer, const QColor &color, const QgsPoint &pt, double radius, const QString &lineStyleName, double width)
Write circle (as polyline)
Definition: qgsdxfexport.cpp:1440
DxfLayerJob::featureSource
QgsVectorLayerFeatureSource featureSource
Definition: qgsdxfexport_p.h:108
QgsUnitTypes::DistanceMeters
@ DistanceMeters
Meters.
Definition: qgsunittypes.h:69
QgsTextLabelFeature::definedFont
QFont definedFont()
Font to be used for rendering.
Definition: qgspalgeometry.h:147
QgsDxfExport::HAlign
HAlign
Horizontal alignments.
Definition: qgsdxfexport.h:141
qgssymbollayer.h
QgsFeature::attribute
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:262
QgsMapLayer::id
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
Definition: qgsmaplayer.cpp:148
QgsDxfExport::setMapSettings
void setMapSettings(const QgsMapSettings &settings)
Set map settings and assign layer name attributes.
Definition: qgsdxfexport.cpp:70
QgsAbstractGeometry::is3D
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
Definition: qgsabstractgeometry.h:202
QgsMapLayer::title
QString title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:286
QgsDxfExport::writeDouble
void writeDouble(double d)
Write a floating point value.
Definition: qgsdxfexport.cpp:166
QgsMapUnitScale
Struct for storing maximum and minimum scales for measurements in map units.
Definition: qgsmapunitscale.h:37
QgsAbstractGeometry::hasCurvedSegments
virtual bool hasCurvedSegments() const
Returns true if the geometry contains curved segments.
Definition: qgsabstractgeometry.cpp:305
qgsrenderer.h
qgsfillsymbollayer.h
QgsSymbol::symbolRenderContext
QgsSymbolRenderContext * symbolRenderContext()
Returns the symbol render context.
Definition: qgssymbol.cpp:1292
QgsRingSequence
QVector< QgsPointSequence > QgsRingSequence
Definition: qgsabstractgeometry.h:48
qgscurvepolygon.h
DxfLayerJob::layerName
QString layerName
Definition: qgsdxfexport_p.h:113
qgscircularstring.h
QgsCurve::coordinateSequence
QgsCoordinateSequence coordinateSequence() const override
Retrieves the sequence of geometries, rings and nodes.
Definition: qgscurve.cpp:61
pal::LabelPosition::QuadrantAboveRight
@ QuadrantAboveRight
Definition: labelposition.h:69
QgsCoordinateReferenceSystem
Definition: qgscoordinatereferencesystem.h:206
QgsAbstractGeometry
Abstract base class for all geometries.
Definition: qgsabstractgeometry.h:71
QgsRectangle::yMaximum
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext....
Definition: qgsexpressioncontext.h:111
QgsMapSettings::setLayers
void setLayers(const QList< QgsMapLayer * > &layers)
Set list of layers for map rendering.
Definition: qgsmapsettings.cpp:286
QgsUnitTypes::RenderPixels
@ RenderPixels
Pixels.
Definition: qgsunittypes.h:170
QgsRenderContext::setRendererScale
void setRendererScale(double scale)
Sets the renderer map scale.
Definition: qgsrendercontext.h:467
QgsPalLayerSettings::MultiLeft
@ MultiLeft
Definition: qgspallabeling.h:311
QgsVectorLayer::extent
QgsRectangle extent() const FINAL
Returns the extent of the layer.
Definition: qgsvectorlayer.cpp:833
QgsExpressionContext::appendScope
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
Definition: qgsexpressioncontext.cpp:490
QgsPalLayerSettings::placeDirectionSymbol
DirectionSymbols placeDirectionSymbol
Placement option for direction symbols.
Definition: qgspallabeling.h:616
qgsvectorlayer.h
QgsDxfExport::VAlign::VMiddle
@ VMiddle
Middle (2)
QgsCompoundCurve::curveAt
const QgsCurve * curveAt(int i) const
Returns the curve at the specified index.
Definition: qgscompoundcurve.cpp:448
QgsMapSettings::destinationCrs
QgsCoordinateReferenceSystem destinationCrs() const
returns CRS of destination coordinate reference system
Definition: qgsmapsettings.cpp:317
QgsDxfExport::DxfLayer::splitLayerAttribute
QString splitLayerAttribute() const
If the split layer attribute is set, the vector layer will be split into several dxf layers,...
Definition: qgsdxfexport.cpp:2377
QgsPropertyCollection
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
Definition: qgspropertycollection.h:318
QgsRenderContext::labelingEngine
QgsLabelingEngine * labelingEngine() const
Gets access to new labeling engine (may be nullptr)
Definition: qgsrendercontext.h:367
QgsSymbolLayer::dxfBrushStyle
virtual Qt::BrushStyle dxfBrushStyle() const
Gets brush/fill style.
Definition: qgssymbollayer.cpp:180
QgsDxfExport::ExportResult::DeviceNotWritableError
@ DeviceNotWritableError
Device not writable error.
QgsCurvePolygon::numInteriorRings
int numInteriorRings() const
Returns the number of interior rings contained with the curve polygon.
Definition: qgscurvepolygon.h:76
QgsSymbol::renderHints
RenderHints renderHints() const
Returns the rendering hint flags for the symbol.
Definition: qgssymbol.h:464
QgsWkbTypes::CircularString
@ CircularString
Definition: qgswkbtypes.h:79
pal::LabelPosition::QuadrantLeft
@ QuadrantLeft
Definition: labelposition.h:70
QgsDxfExport::VAlign::VTop
@ VTop
Top (3)
QgsMapUnitScale::maxSizeMMEnabled
bool maxSizeMMEnabled
Whether the maximum size in mm should be respected.
Definition: qgsmapunitscale.h:69
QgsCoordinateReferenceSystem::mapUnits
QgsUnitTypes::DistanceUnit mapUnits
Definition: qgscoordinatereferencesystem.h:210
QgsDxfExport::VAlign
VAlign
Vertical alignments.
Definition: qgsdxfexport.h:131
QgsGeometryCollection::geometryN
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
Definition: qgsgeometrycollection.h:79
QgsCurve::isClosed
virtual bool isClosed() const
Returns true if the curve is closed.
Definition: qgscurve.cpp:40
QgsWkbTypes::MultiSurface
@ MultiSurface
Definition: qgswkbtypes.h:83
qgslinesymbollayer.h
QgsRectangle::center
QgsPointXY center() const
Returns the center point of the rectangle.
Definition: qgsrectangle.h:230
QgsPalLayerSettings::rightDirectionSymbol
QString rightDirectionSymbol
String to use for right direction arrows.
Definition: qgspallabeling.h:610
pal::LabelPosition::getHeight
double getHeight() const
Definition: labelposition.h:260
QgsDxfExport::DxfLayer
Layers and optional attribute index to split into multiple layers using attribute value as layer name...
Definition: qgsdxfexport.h:71
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:373
QgsPointSequence
QVector< QgsPoint > QgsPointSequence
Definition: qgsabstractgeometry.h:44
QgsPropertyCollection::value
QVariant value(int key, const QgsExpressionContext &context, const QVariant &defaultValue=QVariant()) const override
Returns the calculated value of the property with the specified key from within the collection.
Definition: qgspropertycollection.cpp:218
c
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
Definition: porting_processing.dox:1
QgsGeometry
Definition: qgsgeometry.h:122
QgsMapToPixel
Definition: qgsmaptopixel.h:37
QgsDxfExport::writeFilledCircle
void writeFilledCircle(const QString &layer, const QColor &color, const QgsPoint &pt, double radius)
Write filled circle (as hatch)
Definition: qgsdxfexport.cpp:1403
QgsDxfExport::writeMText
void writeMText(const QString &layer, const QString &text, const QgsPoint &pt, double width, double angle, const QColor &color)
Write mtext (MTEXT)
Definition: qgsdxfexport.cpp:1488
QgsMapUnitScale::maxSizeMM
double maxSizeMM
The maximum size in millimeters, or 0.0 if unset.
Definition: qgsmapunitscale.h:71
QgsVectorLayer
Definition: qgsvectorlayer.h:385
QgsFeature::hasGeometry
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:197
QgsSymbol::DynamicRotation
@ DynamicRotation
Rotation of symbol may be changed during rendering and symbol should not be cached.
Definition: qgssymbol.h:106
QgsSymbolLayerList
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition: qgssymbol.h:53
QgsMapLayer
Definition: qgsmaplayer.h:81
QgsDxfExport::ExportResult::InvalidDeviceError
@ InvalidDeviceError
Invalid device error.
QgsWkbTypes::Polygon
@ Polygon
Definition: qgswkbtypes.h:73
pal::LabelPosition::getReversed
bool getReversed() const
Definition: labelposition.h:266
QgsPalLayerSettings::quadOffset
QuadrantPosition quadOffset
Sets the quadrant in which to offset labels from feature.
Definition: qgspallabeling.h:767
QgsWkbTypes::MultiPoint
@ MultiPoint
Definition: qgswkbtypes.h:75
QgsPointXY::x
double x
Definition: qgspointxy.h:47
pal::LabelPosition::getX
double getX(int i=0) const
Returns the down-left x coordinate.
Definition: labelposition.cpp:348
QgsLabelFeature::anchorPosition
QgsPointXY anchorPosition() const
In case of quadrand or aligned positioning, this is set to the anchor point.
Definition: qgslabelfeature.cpp:73
QgsPalLayerSettings::MultiFollowPlacement
@ MultiFollowPlacement
Definition: qgspallabeling.h:314
QgsRectangle::height
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:209
QgsMapLayer::name
QString name
Definition: qgsmaplayer.h:85
QgsDxfExport::destinationCrs
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination CRS, or an invalid CRS if no reprojection will be done.
Definition: qgsdxfexport.cpp:2372
QgsSymbolLevelOrder
QList< QgsSymbolLevel > QgsSymbolLevelOrder
Definition: qgsrenderer.h:89
QgsRectangle::yMinimum
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
DxfLayerJob::renderer
std::unique_ptr< QgsFeatureRenderer > renderer
Definition: qgsdxfexport_p.h:109
QgsPalLayerSettings::OffsetQuad
@ OffsetQuad
Definition: qgspallabeling.h:427
QgsTextFormat::font
QFont font() const
Returns the font used for rendering text.
Definition: qgstextformat.cpp:62
QgsSymbolLayer::dxfColor
virtual QColor dxfColor(QgsSymbolRenderContext &context) const
Gets color.
Definition: qgssymbollayer.cpp:151
QgsMapSettings::layers
QList< QgsMapLayer * > layers() const
Gets list of layers for map rendering The layers are stored in the reverse order of how they are rend...
Definition: qgsmapsettings.cpp:281
pal::LabelPosition::QuadrantRight
@ QuadrantRight
Definition: labelposition.h:72
DXF_HANDMAX
#define DXF_HANDMAX
Definition: qgsdxfexport.h:45
qgsdxfexport.h
QgsPalLayerSettings::MultiRight
@ MultiRight
Definition: qgspallabeling.h:313
qgsgeometrycollection.h
QgsSymbolLayer::layerType
virtual QString layerType() const =0
Returns a string that represents this layer type.
QgsFeature
Definition: qgsfeature.h:55
QgsSymbolRenderContext::renderContext
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
Definition: qgssymbol.h:708
QgsDxfExport::HAlign::HCenter
@ HCenter
Centered (1)
QgsCurve::numPoints
virtual int numPoints() const =0
Returns the number of points in the curve.
QgsDxfExport::clipValueToMapUnitScale
void clipValueToMapUnitScale(double &value, const QgsMapUnitScale &scale, double pixelToMMFactor) const
Clips value to scale minimum/maximum.
Definition: qgsdxfexport.cpp:1836
QgsLabelFeature
The QgsLabelFeature class describes a feature that should be used within the labeling engine....
Definition: qgslabelfeature.h:56
qgsgeometrygeneratorsymbollayer.h
QgsMapUnitScale::minScale
double minScale
The minimum scale, or 0.0 if unset.
Definition: qgsmapunitscale.h:56
QgsDxfExport::ExportResult
ExportResult
The result of an export as dxf operation.
Definition: qgsdxfexport.h:120
QgsMapSettings::setOutputSize
void setOutputSize(QSize size)
Sets the size of the resulting map image.
Definition: qgsmapsettings.cpp:239
qgslogger.h
pal::LabelPosition::getAlpha
double getAlpha() const
Returns the angle to rotate text (in rad).
Definition: labelposition.cpp:358
QgsDxfExport::SymbolLayerSymbology
@ SymbolLayerSymbology
Exports one feature per symbol layer (considering symbol levels)
Definition: qgsdxfexport.h:105
QgsDxfExport::dxfLayerName
static QString dxfLayerName(const QString &name)
Returns cleaned layer name for use in DXF.
Definition: qgsdxfexport.cpp:2104
QgsMapUnitScale::maxScale
double maxScale
The maximum scale, or 0.0 if unset.
Definition: qgsmapunitscale.h:62
pal::FeaturePart::featureId
QgsFeatureId featureId() const
Returns the unique ID of the feature.
Definition: feature.cpp:157
QgsDxfExport::NoSymbology
@ NoSymbology
Export only data.
Definition: qgsdxfexport.h:103
DxfLayerJob::renderContext
QgsRenderContext renderContext
Definition: qgsdxfexport_p.h:103
QgsDxfExport::HAlign::HRight
@ HRight
Right (2)
QgsFields::at
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
QgsExpression
Definition: qgsexpression.h:113
QgsMapSettings
Definition: qgsmapsettings.h:86
QgsPalLayerSettings::dataDefinedProperties
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the label's property collection, used for data defined overrides.
Definition: qgspallabeling.h:990
QgsPalLayerSettings::SymbolBelow
@ SymbolBelow
Place direction symbols on below label.
Definition: qgspallabeling.h:306
QgsPropertyCollection::isActive
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
Definition: qgspropertycollection.cpp:258
QgsCoordinateTransform
Definition: qgscoordinatetransform.h:52
pal::FeaturePart::feature
QgsLabelFeature * feature()
Returns the parent feature.
Definition: feature.h:117
QgsDxfExport::writeText
void writeText(const QString &layer, const QString &text, const QgsPoint &pt, double size, double angle, const QColor &color, QgsDxfExport::HAlign hali=QgsDxfExport::HAlign::Undefined, QgsDxfExport::VAlign vali=QgsDxfExport::VAlign::Undefined)
Write text (TEXT)
Definition: qgsdxfexport.cpp:1462
pal::LabelPosition::QuadrantBelow
@ QuadrantBelow
Definition: labelposition.h:74
QgsFeatureIterator
Definition: qgsfeatureiterator.h:263
pal::LabelPosition::QuadrantAbove
@ QuadrantAbove
Definition: labelposition.h:68
QgsMapSettings::layerToMapCoordinates
QgsPointXY layerToMapCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from layer's CRS to output CRS
Definition: qgsmapsettings.cpp:482
Q_NOWARN_DEPRECATED_PUSH
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:751
QgsSymbolLayer::dxfWidth
virtual double dxfWidth(const QgsDxfExport &e, QgsSymbolRenderContext &context) const
Gets line width.
Definition: qgssymbollayer.cpp:137
QgsMapSettings::setExtent
void setExtent(const QgsRectangle &rect, bool magnified=true)
Set coordinates of the rectangle which should be rendered.
Definition: qgsmapsettings.cpp:79
QgsMapUnitScale::minSizeMMEnabled
bool minSizeMMEnabled
Whether the minimum size in mm should be respected.
Definition: qgsmapunitscale.h:65
QgsRectangle::isEmpty
bool isEmpty() const
Returns true if the rectangle is empty.
Definition: qgsrectangle.h:437
MathUtils::angle
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:786
qgswkbtypes.h
qgstextlabelfeature.h
QgsMapSettings::mapToPixel
const QgsMapToPixel & mapToPixel() const
Definition: qgsmapsettings.h:433
QgsUnitTypes::RenderMapUnits
@ RenderMapUnits
Map units.
Definition: qgsunittypes.h:169
QgsPoint::x
double x
Definition: qgspoint.h:58
qgsproject.h
QgsRenderContext::setScaleFactor
void setScaleFactor(double factor)
Sets the scaling factor for the render to convert painter units to physical sizes.
Definition: qgsrendercontext.h:460
QgsRectangle::width
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:202
QgsSymbolLayer::dxfBrushColor
virtual QColor dxfBrushColor(QgsSymbolRenderContext &context) const
Gets brush/fill color.
Definition: qgssymbollayer.cpp:174
QgsLabelFeature::labelText
QString labelText() const
Text of the label.
Definition: qgslabelfeature.h:343
QgsDxfExport::QgsDxfExport
QgsDxfExport()
Constructor for QgsDxfExport.
qgspointxy.h
QgsPalLayerSettings::MultiCenter
@ MultiCenter
Definition: qgspallabeling.h:312
QgsRectangle::xMinimum
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
QgsWkbTypes::flatType
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:701
QgsCompoundCurve
Compound curve geometry type.
Definition: qgscompoundcurve.h:31
qgsgeos.h
QgsDxfExport::writePolyline
void writePolyline(const QgsPointSequence &line, const QString &layer, const QString &lineStyleName, const QColor &color, double width=-1)
Draw dxf primitives (LWPOLYLINE)
Definition: qgsdxfexport.cpp:937
QgsSymbol::symbolLayerCount
int symbolLayerCount() const
Returns the total number of symbol layers contained in the symbol.
Definition: qgssymbol.h:183
QgsFeatureId
qint64 QgsFeatureId
Definition: qgsfeatureid.h:25
QgsWkbTypes::CompoundCurve
@ CompoundCurve
Definition: qgswkbtypes.h:80
QgsExpressionContext::setFeature
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Definition: qgsexpressioncontext.cpp:521
QgsVectorLayer::renderer
QgsFeatureRenderer * renderer()
Returns renderer.
Definition: qgsvectorlayer.h:881
pal::LabelPosition::getWidth
double getWidth() const
Definition: labelposition.h:259
DXF_HANDPLOTSTYLE
#define DXF_HANDPLOTSTYLE
Definition: qgsdxfexport.h:46
QgsDxfExport::registerDxfLayer
Q_DECL_DEPRECATED void registerDxfLayer(const QString &layerId, QgsFeatureId fid, const QString &layer)
Register name of layer for feature.
Definition: qgsdxfexport.cpp:2358
QgsDxfExport::ExportResult::Success
@ Success
Successful export.