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