KiCad PCB EDA Suite
dxf_import_plugin.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 // The DXF reader lib (libdxfrw) comes from dxflib project used in QCAD
26 // See http://www.ribbonsoft.com
27 // Each time a dxf entity is read, a "call back" function is called
28 // like void DXF_IMPORT_PLUGIN::addLine( const DL_LineData& data ) when a line is read.
29 // this function just add the BOARD entity from dxf parameters (start and end point ...)
30 
31 
32 #include "dxf_import_plugin.h"
33 #include <wx/arrstr.h>
34 #include <wx/regex.h>
35 
36 #include <trigo.h>
37 #include <macros.h>
38 #include <cmath> // isnan
39 #include <board.h>
40 #include "common.h"
41 
42 
43 /*
44  * Important notes
45  * 1. All output coordinates of this importer are in mm
46  * 2. DXFs have a concept of world (WCS) and object coordinates (OCS)
47  3. The following objects are world coordinates:
48  - Line
49  - Point
50  - Polyline (3D)
51  - Vertex (3D)
52  - Polymesh
53  - Polyface
54  - Viewport
55  4. The following entities are object coordinates
56  - Circle
57  - Arc
58  - Solid
59  - Trace
60  - Attrib
61  - Shape
62  - Insert
63  - Polyline (2D)
64  - Vertex (2D)
65  - LWPolyline
66  - Hatch
67  - Image
68  - Text
69  * 5. Object coordinates must be run through the arbtirary axis
70  * translation even though they are 2D drawings and most of the time
71  * the import is fine. Sometimes, agaisnt all logic, CAD tools like
72  * SolidWorks may randomly insert circles "mirror" that must be unflipped
73  * by following the object to world conversion
74  * 6. Blocks are virtual groups, blocks must be placed by a INSERT entity
75  * 7. Blocks may be repeated multiple times
76  * 8. There is no sane way to make text look perfect like the original CAD.
77  * DXF simply does mpt secifying text/font enough to make it portable.
78  * We however make do try to get it somewhat close/visually appealing.
79  * 9. We silently drop the z coordinate on 3d polylines
80  */
81 
82 
83 // minimum bulge value before resorting to a line segment;
84 // the value 0.0218 is equivalent to about 5 degrees arc,
85 #define MIN_BULGE 0.0218
86 
87 //#define SCALE_FACTOR(x) millimeter2iu(x) /* no longer used */
88 #define SCALE_FACTOR(x) (x)
89 
90 
91 DXF_IMPORT_PLUGIN::DXF_IMPORT_PLUGIN() : DL_CreationAdapter()
92 {
93  m_xOffset = 0.0; // X coord offset for conversion (in mm)
94  m_yOffset = 0.0; // Y coord offset for conversion (in mm)
95  m_version = 0; // the dxf version, not yet used
96  m_defaultThickness = 0.2; // default thickness (in mm)
97  m_brdLayer = Dwgs_User; // The default import layer
98  m_importAsFPShapes = true;
99  m_minX = m_minY = std::numeric_limits<double>::max();
100  m_maxX = m_maxY = std::numeric_limits<double>::min();
102 
103  // placeholder layer so we can fallback to something later
104  std::unique_ptr<DXF_IMPORT_LAYER> layer0 =
105  std::make_unique<DXF_IMPORT_LAYER>( "", DXF_IMPORT_LINEWEIGHT_BY_LW_DEFAULT );
106  m_layers.push_back( std::move( layer0 ) );
107 
108  m_currentBlock = nullptr;
109 }
110 
111 
113 {
114 }
115 
116 
117 bool DXF_IMPORT_PLUGIN::Load( const wxString& aFileName )
118 {
119  return ImportDxfFile( aFileName );
120 }
121 
122 
124 {
125  wxCHECK( m_importer, false );
127 
128  return true;
129 }
130 
131 
133 {
134  return m_maxX - m_minX;
135 }
136 
137 
139 {
140  return m_maxY - m_minY;
141 }
142 
143 
145 {
147 
148  if( m_importer )
150 }
151 
152 
153 double DXF_IMPORT_PLUGIN::mapX( double aDxfCoordX )
154 {
155  return SCALE_FACTOR( m_xOffset + ( aDxfCoordX * getCurrentUnitScale() ) );
156 }
157 
158 
159 double DXF_IMPORT_PLUGIN::mapY( double aDxfCoordY )
160 {
161  return SCALE_FACTOR( m_yOffset - ( aDxfCoordY * getCurrentUnitScale() ) );
162 }
163 
164 
165 double DXF_IMPORT_PLUGIN::mapDim( double aDxfValue )
166 {
167  return SCALE_FACTOR( aDxfValue * getCurrentUnitScale() );
168 }
169 
170 
171 bool DXF_IMPORT_PLUGIN::ImportDxfFile( const wxString& aFile )
172 {
173  DL_Dxf dxf_reader;
174 
175  // wxFopen takes care of unicode filenames across platforms
176  FILE* fp = wxFopen( aFile, "rt" );
177 
178  if( fp == nullptr )
179  return false;
180 
181  // Note the dxf reader takes care of switching to "C" locale before reading the file
182  // and will close the file after reading
183  bool success = dxf_reader.in( fp, this );
184 
185  return success;
186 }
187 
188 
189 void DXF_IMPORT_PLUGIN::reportMsg( const wxString& aMessage )
190 {
191  // Add message to keep trace of not handled dxf entities
192  m_messages += aMessage;
193  m_messages += '\n';
194 }
195 
196 
197 void DXF_IMPORT_PLUGIN::addSpline( const DL_SplineData& aData )
198 {
199  // Called when starting reading a spline
202  m_curr_entity.m_EntityFlag = aData.flags;
203  m_curr_entity.m_EntityType = DL_ENTITY_SPLINE;
204  m_curr_entity.m_SplineDegree = aData.degree;
205  m_curr_entity.m_SplineTangentStartX = aData.tangentStartX;
206  m_curr_entity.m_SplineTangentStartY = aData.tangentStartY;
207  m_curr_entity.m_SplineTangentEndX = aData.tangentEndX;
208  m_curr_entity.m_SplineTangentEndY = aData.tangentEndY;
209  m_curr_entity.m_SplineKnotsCount = aData.nKnots;
210  m_curr_entity.m_SplineControlCount = aData.nControl;
211  m_curr_entity.m_SplineFitCount = aData.nFit;
212 }
213 
214 
215 void DXF_IMPORT_PLUGIN::addControlPoint( const DL_ControlPointData& aData )
216 {
217  // Called for every spline control point, when reading a spline entity
218  m_curr_entity.m_SplineControlPointList.emplace_back( aData.x , aData.y,
219  aData.w );
220 }
221 
222 
223 void DXF_IMPORT_PLUGIN::addFitPoint( const DL_FitPointData& aData )
224 {
225  // Called for every spline fit point, when reading a spline entity
226  // we store only the X,Y coord values in a VECTOR2D
227  m_curr_entity.m_SplineFitPointList.emplace_back( aData.x, aData.y );
228 }
229 
230 
231 void DXF_IMPORT_PLUGIN::addKnot( const DL_KnotData& aData)
232 {
233  // Called for every spline knot value, when reading a spline entity
234  m_curr_entity.m_SplineKnotsList.push_back( aData.k );
235 }
236 
237 
238 void DXF_IMPORT_PLUGIN::addLayer( const DL_LayerData& aData )
239 {
240  wxString name = wxString::FromUTF8( aData.name.c_str() );
241 
242  int lw = attributes.getWidth();
243 
245  {
247  }
248 
249  std::unique_ptr<DXF_IMPORT_LAYER> layer = std::make_unique<DXF_IMPORT_LAYER>( name, lw );
250 
251  m_layers.push_back( std::move( layer ) );
252 }
253 
254 
255 void DXF_IMPORT_PLUGIN::addLinetype( const DL_LinetypeData& data )
256 {
257 #if 0
258  wxString name = FROM_UTF8( data.name.c_str() );
259  wxString description = FROM_UTF8( data.description.c_str() );
260 #endif
261 }
262 
263 
265 {
266  if( lw == DXF_IMPORT_LINEWEIGHT_BY_LAYER && aLayer != nullptr )
267  {
268  lw = aLayer->m_lineWeight;
269  }
270 
271  // All lineweights >= 0 are always in 100ths of mm
272  double mm = m_defaultThickness;
273  if( lw >= 0 )
274  {
275  mm = lw / 100.0;
276  }
277 
278  return SCALE_FACTOR( mm );
279 }
280 
281 
282 DXF_IMPORT_LAYER* DXF_IMPORT_PLUGIN::getImportLayer( const std::string& aLayerName )
283 {
284  DXF_IMPORT_LAYER* layer = m_layers.front().get();
285  wxString layerName = wxString::FromUTF8( aLayerName.c_str() );
286 
287  if( !layerName.IsEmpty() )
288  {
289  auto resultIt = std::find_if( m_layers.begin(), m_layers.end(),
290  [layerName]( const auto& it )
291  {
292  return it->m_layerName == layerName;
293  } );
294 
295  if( resultIt != m_layers.end() )
296  layer = resultIt->get();
297  }
298 
299  return layer;
300 }
301 
302 
303 DXF_IMPORT_BLOCK* DXF_IMPORT_PLUGIN::getImportBlock( const std::string& aBlockName )
304 {
305  DXF_IMPORT_BLOCK* block = nullptr;
306  wxString blockName = wxString::FromUTF8( aBlockName.c_str() );
307 
308  if( !blockName.IsEmpty() )
309  {
310  auto resultIt = std::find_if( m_blocks.begin(), m_blocks.end(),
311  [blockName]( const auto& it )
312  {
313  return it->m_name == blockName;
314  } );
315 
316  if( resultIt != m_blocks.end() )
317  block = resultIt->get();
318  }
319 
320  return block;
321 }
322 
323 
324 DXF_IMPORT_STYLE* DXF_IMPORT_PLUGIN::getImportStyle( const std::string& aStyleName )
325 {
326  DXF_IMPORT_STYLE* style = nullptr;
327  wxString styleName = wxString::FromUTF8( aStyleName.c_str() );
328 
329  if( !styleName.IsEmpty() )
330  {
331  auto resultIt = std::find_if( m_styles.begin(), m_styles.end(),
332  [styleName]( const auto& it ) { return it->m_name == styleName; } );
333 
334  if( resultIt != m_styles.end() )
335  style = resultIt->get();
336  }
337 
338  return style;
339 }
340 
341 
342 void DXF_IMPORT_PLUGIN::addLine( const DL_LineData& aData )
343 {
344  DXF_IMPORT_LAYER* layer = getImportLayer( attributes.getLayer() );
345  double lineWidth = lineWeightToWidth( attributes.getWidth(), layer );
346 
347  VECTOR2D start( mapX( aData.x1 ), mapY( aData.y1 ) );
348  VECTOR2D end( mapX( aData.x2 ), mapY( aData.y2 ) );
349 
350  GRAPHICS_IMPORTER_BUFFER* bufferToUse =
352  bufferToUse->AddLine( start, end, lineWidth );
353 
354  updateImageLimits( start );
355  updateImageLimits( end );
356 }
357 
358 
359 void DXF_IMPORT_PLUGIN::addPolyline(const DL_PolylineData& aData )
360 {
361  // Convert DXF Polylines into a series of KiCad Lines and Arcs.
362  // A Polyline (as opposed to a LWPolyline) may be a 3D line or
363  // even a 3D Mesh. The only type of Polyline which is guaranteed
364  // to import correctly is a 2D Polyline in X and Y, which is what
365  // we assume of all Polylines. The width used is the width of the Polyline.
366  // per-vertex line widths, if present, are ignored.
369  m_curr_entity.m_EntityFlag = aData.flags;
370  m_curr_entity.m_EntityType = DL_ENTITY_POLYLINE;
371 }
372 
373 
374 void DXF_IMPORT_PLUGIN::addVertex( const DL_VertexData& aData )
375 {
377  return; // Error
378 
379  DXF_IMPORT_LAYER* layer = getImportLayer( attributes.getLayer() );
380  double lineWidth = lineWeightToWidth( attributes.getWidth(), layer );
381 
382  const DL_VertexData* vertex = &aData;
383 
384  DXF_ARBITRARY_AXIS arbAxis = getArbitraryAxis( getExtrusion() );
385  VECTOR3D vertexCoords = ocsToWcs( arbAxis, VECTOR3D( vertex->x, vertex->y, vertex->z ) );
386 
387  if( m_curr_entity.m_EntityParseStatus == 1 ) // This is the first vertex of an entity
388  {
389  m_curr_entity.m_LastCoordinate.x = mapX( vertexCoords.x );
390  m_curr_entity.m_LastCoordinate.y = mapY( vertexCoords.y );
392  m_curr_entity.m_BulgeVertex = vertex->bulge;
394  return;
395  }
396 
397  VECTOR2D seg_end( mapX( vertexCoords.x ), mapY( vertexCoords.y ) );
398 
399  if( std::abs( m_curr_entity.m_BulgeVertex ) < MIN_BULGE )
400  insertLine( m_curr_entity.m_LastCoordinate, seg_end, lineWidth );
401  else
403  lineWidth );
404 
406  m_curr_entity.m_BulgeVertex = vertex->bulge;
407 }
408 
409 
411 {
412  DXF_IMPORT_LAYER* layer = getImportLayer( attributes.getLayer() );
413  double lineWidth = lineWeightToWidth( attributes.getWidth(), layer );
414 
415  if( m_curr_entity.m_EntityType == DL_ENTITY_POLYLINE ||
416  m_curr_entity.m_EntityType == DL_ENTITY_LWPOLYLINE )
417  {
418  // Polyline flags bit 0 indicates closed (1) or open (0) polyline
419  if( m_curr_entity.m_EntityFlag & 1 )
420  {
421  if( std::abs( m_curr_entity.m_BulgeVertex ) < MIN_BULGE )
423  lineWidth );
424  else
426  m_curr_entity.m_BulgeVertex, lineWidth );
427  }
428  }
429 
430  if( m_curr_entity.m_EntityType == DL_ENTITY_SPLINE )
431  {
432  insertSpline( lineWidth );
433  }
434 
436 }
437 
438 
439 void DXF_IMPORT_PLUGIN::addBlock( const DL_BlockData& aData )
440 {
441  wxString name = wxString::FromUTF8( aData.name.c_str() );
442 
443  std::unique_ptr<DXF_IMPORT_BLOCK> block =
444  std::make_unique<DXF_IMPORT_BLOCK>( name, aData.bpx, aData.bpy );
445 
446  m_blocks.push_back( std::move( block ) );
447 
448  m_currentBlock = m_blocks.back().get();
449 }
450 
451 
453 {
454  m_currentBlock = nullptr;
455 }
456 
457 void DXF_IMPORT_PLUGIN::addInsert( const DL_InsertData& aData )
458 {
459  DXF_IMPORT_BLOCK* block = getImportBlock( aData.name );
460 
461  if( block == nullptr )
462  return;
463 
464  DXF_ARBITRARY_AXIS arbAxis = getArbitraryAxis( getExtrusion() );
465  VECTOR3D insertCoords = ocsToWcs( arbAxis, VECTOR3D( aData.ipx, aData.ipy, aData.ipz ) );
466 
467  VECTOR2D translation( mapX( insertCoords.x ), mapY( insertCoords.y ) );
468  translation -= VECTOR2D( mapX( block->m_baseX ), mapY( block->m_baseY ) );
469 
470 
471  for( auto& shape : block->m_buffer.GetShapes() )
472  {
473  std::unique_ptr<IMPORTED_SHAPE> newShape = shape->clone();
474 
475  newShape->Translate( translation );
476  newShape->Scale( aData.sx, aData.sy );
477 
478  m_internalImporter.AddShape( newShape );
479  }
480 }
481 
482 
483 void DXF_IMPORT_PLUGIN::addCircle( const DL_CircleData& aData )
484 {
485  DXF_ARBITRARY_AXIS arbAxis = getArbitraryAxis( getExtrusion() );
486  VECTOR3D centerCoords = ocsToWcs( arbAxis, VECTOR3D( aData.cx, aData.cy, aData.cz ) );
487 
488  VECTOR2D center( mapX( centerCoords.x ), mapY( centerCoords.y ) );
489  DXF_IMPORT_LAYER* layer = getImportLayer( attributes.getLayer() );
490  double lineWidth = lineWeightToWidth( attributes.getWidth(), layer );
491 
492  GRAPHICS_IMPORTER_BUFFER* bufferToUse =
494  bufferToUse->AddCircle( center, mapDim( aData.radius ), lineWidth, false );
495 
496  VECTOR2D radiusDelta( mapDim( aData.radius ), mapDim( aData.radius ) );
497 
498  updateImageLimits( center + radiusDelta );
499  updateImageLimits( center - radiusDelta );
500 }
501 
502 
503 void DXF_IMPORT_PLUGIN::addArc( const DL_ArcData& aData )
504 {
505  DXF_ARBITRARY_AXIS arbAxis = getArbitraryAxis( getExtrusion() );
506  VECTOR3D centerCoords = ocsToWcs( arbAxis, VECTOR3D( aData.cx, aData.cy, aData.cz ) );
507 
508  // Init arc centre:
509  VECTOR2D center( mapX( centerCoords.x ), mapY( centerCoords.y ) );
510 
511  // aData.anglex is in degrees.
512  double startangle = aData.angle1;
513  double endangle = aData.angle2;
514 
515  // Init arc start point
516  VECTOR2D startPoint( aData.radius, 0.0 );
517  startPoint = startPoint.Rotate( startangle * M_PI / 180.0 );
518  VECTOR2D arcStart(
519  mapX( startPoint.x + centerCoords.x ), mapY( startPoint.y + centerCoords.y ) );
520 
521  // calculate arc angle (arcs are CCW, and should be < 0 in Pcbnew)
522  double angle = -( endangle - startangle );
523 
524  if( angle > 0.0 )
525  angle -= 360.0;
526 
527  DXF_IMPORT_LAYER* layer = getImportLayer( attributes.getLayer() );
528  double lineWidth = lineWeightToWidth( attributes.getWidth(), layer );
529 
530  GRAPHICS_IMPORTER_BUFFER* bufferToUse =
532  bufferToUse->AddArc( center, arcStart, angle, lineWidth );
533 
534  VECTOR2D radiusDelta( mapDim( aData.radius ), mapDim( aData.radius ) );
535 
536  updateImageLimits( center + radiusDelta );
537  updateImageLimits( center - radiusDelta );
538 }
539 
540 
541 void DXF_IMPORT_PLUGIN::addText( const DL_TextData& aData )
542 {
543  DXF_ARBITRARY_AXIS arbAxis = getArbitraryAxis( getExtrusion() );
544  VECTOR3D refPointCoords = ocsToWcs( arbAxis, VECTOR3D( aData.ipx, aData.ipy, aData.ipz ) );
545  VECTOR3D secPointCoords = ocsToWcs( arbAxis, VECTOR3D( std::isnan( aData.apx ) ? 0 : aData.apx,
546  std::isnan( aData.apy ) ? 0 : aData.apy,
547  std::isnan( aData.apz ) ? 0 : aData.apz ) );
548 
549  VECTOR2D refPoint( mapX( refPointCoords.x ), mapY( refPointCoords.y ) );
550  VECTOR2D secPoint( mapX( secPointCoords.x ), mapY( secPointCoords.y ) );
551 
552  if( aData.vJustification != 0 || aData.hJustification != 0 || aData.hJustification == 4 )
553  {
554  if( aData.hJustification != 3 && aData.hJustification != 5 )
555  {
556  VECTOR2D tmp = secPoint;
557  secPoint = refPoint;
558  refPoint = tmp;
559  }
560  }
561 
562  wxString text = toNativeString( wxString::FromUTF8( aData.text.c_str() ) );
563 
564  DXF_IMPORT_STYLE* style = getImportStyle( aData.style.c_str() );
565 
566  double textHeight = mapDim( aData.height );
567  // The 0.9 factor gives a better height/width base ratio with our font
568  double charWidth = textHeight * 0.9;
569 
570  if( style != nullptr )
571  charWidth *= style->m_widthFactor;
572 
573  double textWidth = charWidth * text.length(); // Rough approximation
574  double textThickness = textHeight/8.0; // Use a reasonable line thickness for this text
575 
576  VECTOR2D bottomLeft(0.0, 0.0);
577  VECTOR2D bottomRight(0.0, 0.0);
578  VECTOR2D topLeft(0.0, 0.0);
579  VECTOR2D topRight(0.0, 0.0);
580 
583 
584  switch( aData.vJustification )
585  {
586  case 0: //DRW_Text::VBaseLine:
587  case 1: //DRW_Text::VBottom:
588  vJustify = GR_TEXT_VJUSTIFY_BOTTOM;
589 
590  topLeft.y = textHeight;
591  topRight.y = textHeight;
592  break;
593 
594  case 2: //DRW_Text::VMiddle:
595  vJustify = GR_TEXT_VJUSTIFY_CENTER;
596 
597  bottomRight.y = -textHeight / 2.0;
598  bottomLeft.y = -textHeight / 2.0;
599  topLeft.y = textHeight / 2.0;
600  topRight.y = textHeight / 2.0;
601  break;
602 
603  case 3: //DRW_Text::VTop:
604  vJustify = GR_TEXT_VJUSTIFY_TOP;
605 
606  bottomLeft.y = -textHeight;
607  bottomRight.y = -textHeight;
608  break;
609  }
610 
611  switch( aData.hJustification )
612  {
613  case 0: //DRW_Text::HLeft:
614  case 3: //DRW_Text::HAligned: // no equivalent options in text pcb.
615  case 5: //DRW_Text::HFit: // no equivalent options in text pcb.
616  hJustify = GR_TEXT_HJUSTIFY_LEFT;
617 
618  bottomRight.x = textWidth;
619  topRight.x = textWidth;
620  break;
621 
622  case 1: //DRW_Text::HCenter:
623  case 4: //DRW_Text::HMiddle: // no equivalent options in text pcb.
624  hJustify = GR_TEXT_HJUSTIFY_CENTER;
625 
626  bottomLeft.x = -textWidth / 2.0;
627  topLeft.x = -textWidth / 2.0;
628  bottomRight.x = textWidth / 2.0;
629  topRight.x = textWidth / 2.0;
630  break;
631 
632  case 2: //DRW_Text::HRight:
633  hJustify = GR_TEXT_HJUSTIFY_RIGHT;
634 
635  bottomLeft.x = -textWidth;
636  topLeft.x = -textWidth;
637  break;
638  }
639 
640 #if 0
641  wxString sty = wxString::FromUTF8( aData.style.c_str() );
642  sty = sty.ToLower();
643 
644  if( aData.textgen == 2 )
645  {
646  // Text dir = left to right;
647  } else if( aData.textgen == 4 )
648  {
649  // Text dir = top to bottom;
650  } else
651  {
652  }
653 #endif
654 
655  // dxf_lib imports text angle in radians (although there are no comment about that.
656  // So, for the moment, convert this angle to degrees
657  double angle_degree = aData.angle * 180 / M_PI;
658  // We also need the angle in radians. so convert angle_degree to radians
659  // regardless the aData.angle unit
660  double angleInRads = angle_degree * M_PI / 180.0;
661  double cosine = cos(angleInRads);
662  double sine = sin(angleInRads);
663 
664  GRAPHICS_IMPORTER_BUFFER* bufferToUse =
666  bufferToUse->AddText( refPoint, text, textHeight, charWidth, textThickness, angle_degree,
667  hJustify, vJustify );
668 
669  // Calculate the boundary box and update the image limits:
670  bottomLeft.x = bottomLeft.x * cosine - bottomLeft.y * sine;
671  bottomLeft.y = bottomLeft.x * sine + bottomLeft.y * cosine;
672 
673  bottomRight.x = bottomRight.x * cosine - bottomRight.y * sine;
674  bottomRight.y = bottomRight.x * sine + bottomRight.y * cosine;
675 
676  topLeft.x = topLeft.x * cosine - topLeft.y * sine;
677  topLeft.y = topLeft.x * sine + topLeft.y * cosine;
678 
679  topRight.x = topRight.x * cosine - topRight.y * sine;
680  topRight.y = topRight.x * sine + topRight.y * cosine;
681 
682  bottomLeft += refPoint;
683  bottomRight += refPoint;
684  topLeft += refPoint;
685  topRight += refPoint;
686 
687  updateImageLimits( bottomLeft );
688  updateImageLimits( bottomRight );
689  updateImageLimits( topLeft );
690  updateImageLimits( topRight );
691 
692 }
693 
694 
695 void DXF_IMPORT_PLUGIN::addMText( const DL_MTextData& aData )
696 {
697  wxString text = toNativeString( wxString::FromUTF8( aData.text.c_str() ) );
698  wxString attrib, tmp;
699 
700  DXF_IMPORT_STYLE* style = getImportStyle( aData.style.c_str() );
701 
702  double textHeight = mapDim( aData.height );
703 
704  // The 0.9 factor gives a better height/width base ratio with our font
705  double charWidth = textHeight * 0.9;
706  if( style != nullptr )
707  charWidth *= style->m_widthFactor;
708 
709  double textWidth = charWidth * text.length(); // Rough approximation
710  double textThickness = textHeight/8.0; // Use a reasonable line thickness for this text
711 
712  VECTOR2D bottomLeft(0.0, 0.0);
713  VECTOR2D bottomRight(0.0, 0.0);
714  VECTOR2D topLeft(0.0, 0.0);
715  VECTOR2D topRight(0.0, 0.0);
716 
717  /* Some texts start by '\' and have formatting chars (font name, font option...)
718  * ending with ';'
719  * Here are some mtext formatting codes:
720  * Format code Purpose
721  * \0...\o Turns overline on and off
722  * \L...\l Turns underline on and off
723  * \~ Inserts a nonbreaking space
724  \\ Inserts a backslash
725  \\\{...\} Inserts an opening and closing brace
726  \\ \File name; Changes to the specified font file
727  \\ \Hvalue; Changes to the text height specified in drawing units
728  \\ \Hvaluex; Changes the text height to a multiple of the current text height
729  \\ \S...^...; Stacks the subsequent text at the \, #, or ^ symbol
730  \\ \Tvalue; Adjusts the space between characters, from.75 to 4 times
731  \\ \Qangle; Changes oblique angle
732  \\ \Wvalue; Changes width factor to produce wide text
733  \\ \A Sets the alignment value; valid values: 0, 1, 2 (bottom, center, top) while( text.StartsWith( wxT("\\") ) )
734  */
735  while( text.StartsWith( wxT( "\\" ) ) )
736  {
737  attrib << text.BeforeFirst( ';' );
738  tmp = text.AfterFirst( ';' );
739  text = tmp;
740  }
741 
742  DXF_ARBITRARY_AXIS arbAxis = getArbitraryAxis( getExtrusion() );
743  VECTOR3D textposCoords = ocsToWcs( arbAxis, VECTOR3D( aData.ipx, aData.ipy, aData.ipz ) );
744 
745  VECTOR2D textpos( mapX( textposCoords.x ), mapY( textposCoords.y ) );
746 
747  // Initialize text justifications:
750 
751  if( aData.attachmentPoint <= 3 )
752  {
753  vJustify = GR_TEXT_VJUSTIFY_TOP;
754 
755  bottomLeft.y = -textHeight;
756  bottomRight.y = -textHeight;
757  }
758  else if( aData.attachmentPoint <= 6 )
759  {
760  vJustify = GR_TEXT_VJUSTIFY_CENTER;
761 
762  bottomRight.y = -textHeight / 2.0;
763  bottomLeft.y = -textHeight / 2.0;
764  topLeft.y = textHeight / 2.0;
765  topRight.y = textHeight / 2.0;
766  }
767  else
768  {
769  vJustify = GR_TEXT_VJUSTIFY_BOTTOM;
770 
771  topLeft.y = textHeight;
772  topRight.y = textHeight;
773  }
774 
775  if( aData.attachmentPoint % 3 == 1 )
776  {
777  hJustify = GR_TEXT_HJUSTIFY_LEFT;
778 
779  bottomRight.x = textWidth;
780  topRight.x = textWidth;
781  }
782  else if( aData.attachmentPoint % 3 == 2 )
783  {
784  hJustify = GR_TEXT_HJUSTIFY_CENTER;
785 
786  bottomLeft.x = -textWidth / 2.0;
787  topLeft.x = -textWidth / 2.0;
788  bottomRight.x = textWidth / 2.0;
789  topRight.x = textWidth / 2.0;
790  }
791  else
792  {
793  hJustify = GR_TEXT_HJUSTIFY_RIGHT;
794 
795  bottomLeft.x = -textWidth;
796  topLeft.x = -textWidth;
797  }
798 
799 #if 0 // These setting have no meaning in Pcbnew
800  if( data.alignH == 1 )
801  {
802  // Text is left to right;
803  }
804  else if( data.alignH == 3 )
805  {
806  // Text is top to bottom;
807  }
808  else
809  {
810  // use ByStyle;
811  }
812 
813  if( aData.alignV == 1 )
814  {
815  // use AtLeast;
816  }
817  else
818  {
819  // useExact;
820  }
821 #endif
822 
823  // dxf_lib imports text angle in radians (although there are no comment about that.
824  // So, for the moment, convert this angle to degrees
825  double angle_degree = aData.angle * 180/M_PI;
826  // We also need the angle in radians. so convert angle_degree to radians
827  // regardless the aData.angle unit
828  double angleInRads = angle_degree * M_PI / 180.0;
829  double cosine = cos(angleInRads);
830  double sine = sin(angleInRads);
831 
832 
833  GRAPHICS_IMPORTER_BUFFER* bufferToUse =
835  bufferToUse->AddText( textpos, text, textHeight, charWidth,
836  textThickness, angle_degree, hJustify, vJustify );
837 
838  bottomLeft.x = bottomLeft.x * cosine - bottomLeft.y * sine;
839  bottomLeft.y = bottomLeft.x * sine + bottomLeft.y * cosine;
840 
841  bottomRight.x = bottomRight.x * cosine - bottomRight.y * sine;
842  bottomRight.y = bottomRight.x * sine + bottomRight.y * cosine;
843 
844  topLeft.x = topLeft.x * cosine - topLeft.y * sine;
845  topLeft.y = topLeft.x * sine + topLeft.y * cosine;
846 
847  topRight.x = topRight.x * cosine - topRight.y * sine;
848  topRight.y = topRight.x * sine + topRight.y * cosine;
849 
850  bottomLeft += textpos;
851  bottomRight += textpos;
852  topLeft += textpos;
853  topRight += textpos;
854 
855  updateImageLimits( bottomLeft );
856  updateImageLimits( bottomRight );
857  updateImageLimits( topLeft );
858  updateImageLimits( topRight );
859 
860 }
861 
862 
864 {
865  double scale = 1.0;
866  switch( m_currentUnit )
867  {
869  scale = 25.4;
870  break;
871 
873  scale = 304.8;
874  break;
875 
877  scale = 1.0;
878  break;
879 
881  scale = 10.0;
882  break;
883 
885  scale = 1000.0;
886  break;
887 
889  scale = 2.54e-5;
890  break;
891 
893  scale = 0.0254;
894  break;
895 
897  scale = 914.4;
898  break;
899 
901  scale = 1.0e-7;
902  break;
903 
905  scale = 1.0e-6;
906  break;
907 
909  scale = 1.0e-3;
910  break;
911 
913  scale = 100.0;
914  break;
915 
916  default:
917  // use the default of 1.0 for:
918  // 0: Unspecified Units
919  // 3: miles
920  // 7: kilometers
921  // 15: decameters
922  // 16: hectometers
923  // 17: gigameters
924  // 18: AU
925  // 19: lightyears
926  // 20: parsecs
927  scale = 1.0;
928  break;
929  }
930 
931  return scale;
932 }
933 
934 
935 
936 void DXF_IMPORT_PLUGIN::setVariableInt( const std::string& key, int value, int code )
937 {
938  // Called for every int variable in the DXF file (e.g. "$INSUNITS").
939 
940  if( key == "$DWGCODEPAGE" )
941  {
942  m_codePage = value;
943  return;
944  }
945 
946  if( key == "$INSUNITS" ) // Drawing units
947  {
948  switch( value )
949  {
950  case 1: // inches
952  break;
953 
954  case 2: // feet
956  break;
957 
958  case 4: // mm
960  break;
961 
962  case 5: // centimeters
964  break;
965 
966  case 6: // meters
968  break;
969 
970  case 8: // microinches
972  break;
973 
974  case 9: // mils
976  break;
977 
978  case 10: // yards
980  break;
981 
982  case 11: // Angstroms
984  break;
985 
986  case 12: // nanometers
988  break;
989 
990  case 13: // micrometers
992  break;
993 
994  case 14: // decimeters
996  break;
997 
998  default:
999  // use the default of 1.0 for:
1000  // 0: Unspecified Units
1001  // 3: miles
1002  // 7: kilometers
1003  // 15: decameters
1004  // 16: hectometers
1005  // 17: gigameters
1006  // 18: AU
1007  // 19: lightyears
1008  // 20: parsecs
1010  break;
1011  }
1012 
1013  return;
1014  }
1015 }
1016 
1017 
1018 void DXF_IMPORT_PLUGIN::setVariableString( const std::string& key, const std::string& value,
1019  int code )
1020 {
1021  // Called for every string variable in the DXF file (e.g. "$ACADVER").
1022 }
1023 
1024 
1025 wxString DXF_IMPORT_PLUGIN::toDxfString( const wxString& aStr )
1026 {
1027  wxString res;
1028  int j = 0;
1029 
1030  for( unsigned i = 0; i<aStr.length(); ++i )
1031  {
1032  int c = aStr[i];
1033 
1034  if( c > 175 || c < 11 )
1035  {
1036  res.append( aStr.Mid( j, i - j ) );
1037  j = i;
1038 
1039  switch( c )
1040  {
1041  case 0x0A:
1042  res += wxT( "\\P" );
1043  break;
1044 
1045  // diameter:
1046 #ifdef _WIN32
1047  // windows, as always, is special.
1048  case 0x00D8:
1049 #else
1050  case 0x2205:
1051 #endif
1052  res += wxT( "%%C" );
1053  break;
1054 
1055  // degree:
1056  case 0x00B0:
1057  res += wxT( "%%D" );
1058  break;
1059 
1060  // plus/minus
1061  case 0x00B1:
1062  res += wxT( "%%P" );
1063  break;
1064 
1065  default:
1066  j--;
1067  break;
1068  }
1069 
1070  j++;
1071  }
1072  }
1073 
1074  res.append( aStr.Mid( j ) );
1075  return res;
1076 }
1077 
1078 
1079 wxString DXF_IMPORT_PLUGIN::toNativeString( const wxString& aData )
1080 {
1081  wxString res;
1082 
1083  // Ignore font tags:
1084  int j = 0;
1085 
1086  for( unsigned i = 0; i < aData.length(); ++i )
1087  {
1088  if( aData[ i ] == 0x7B ) // is '{' ?
1089  {
1090  if( aData[ i + 1 ] == 0x5c && aData[ i + 2 ] == 0x66 ) // is "\f" ?
1091  {
1092  // found font tag, append parsed part
1093  res.append( aData.Mid( j, i - j ) );
1094 
1095  // skip to ';'
1096  for( unsigned k = i + 3; k < aData.length(); ++k )
1097  {
1098  if( aData[ k ] == 0x3B )
1099  {
1100  i = j = ++k;
1101  break;
1102  }
1103  }
1104 
1105  // add to '}'
1106  for( unsigned k = i; k < aData.length(); ++k )
1107  {
1108  if( aData[ k ] == 0x7D )
1109  {
1110  res.append( aData.Mid( i, k - i ) );
1111  i = j = ++k;
1112  break;
1113  }
1114  }
1115  }
1116  }
1117  }
1118 
1119  res.append( aData.Mid( j ) );
1120 
1121 #if 1
1122  wxRegEx regexp;
1123  // Line feed:
1124  regexp.Compile( wxT( "\\\\P" ) );
1125  regexp.Replace( &res, wxT( "\n" ) );
1126 
1127  // Space:
1128  regexp.Compile( wxT( "\\\\~" ) );
1129  regexp.Replace( &res, wxT( " " ) );
1130 
1131  // diameter:
1132  regexp.Compile( wxT( "%%[cC]" ) );
1133 #ifdef __WINDOWS__
1134  // windows, as always, is special.
1135  regexp.Replace( &res, wxChar( 0xD8 ) );
1136 #else
1137  // Empty_set, diameter is 0x2300
1138  regexp.Replace( &res, wxChar( 0x2205 ) );
1139 #endif
1140 
1141  // degree:
1142  regexp.Compile( wxT( "%%[dD]" ) );
1143  regexp.Replace( &res, wxChar( 0x00B0 ) );
1144  // plus/minus
1145  regexp.Compile( wxT( "%%[pP]" ) );
1146  regexp.Replace( &res, wxChar( 0x00B1 ) );
1147 #endif
1148 
1149  return res;
1150 }
1151 
1152 
1153 void DXF_IMPORT_PLUGIN::addTextStyle( const DL_StyleData& aData )
1154 {
1155  wxString name = wxString::FromUTF8( aData.name.c_str() );
1156 
1157  std::unique_ptr<DXF_IMPORT_STYLE> style =
1158  std::make_unique<DXF_IMPORT_STYLE>( name, aData.fixedTextHeight, aData.widthFactor, aData.bold, aData.italic );
1159 
1160  m_styles.push_back( std::move( style ) );
1161 }
1162 
1163 
1165  const VECTOR2D& aSegEnd, int aWidth )
1166 {
1167  VECTOR2D origin( SCALE_FACTOR( aSegStart.x ), SCALE_FACTOR( aSegStart.y ) );
1168  VECTOR2D end( SCALE_FACTOR( aSegEnd.x ), SCALE_FACTOR( aSegEnd.y ) );
1169 
1170  GRAPHICS_IMPORTER_BUFFER* bufferToUse =
1172  bufferToUse->AddLine( origin, end, aWidth );
1173 
1174  updateImageLimits( origin );
1175  updateImageLimits( end );
1176 }
1177 
1178 
1179 void DXF_IMPORT_PLUGIN::insertArc( const VECTOR2D& aSegStart, const VECTOR2D& aSegEnd,
1180  double aBulge, int aWidth )
1181 {
1182  VECTOR2D segment_startpoint( SCALE_FACTOR( aSegStart.x ), SCALE_FACTOR( aSegStart.y ) );
1183  VECTOR2D segment_endpoint( SCALE_FACTOR( aSegEnd.x ), SCALE_FACTOR( aSegEnd.y ) );
1184 
1185  // ensure aBulge represents an angle from +/- ( 0 .. approx 359.8 deg )
1186  if( aBulge < -2000.0 )
1187  aBulge = -2000.0;
1188  else if( aBulge > 2000.0 )
1189  aBulge = 2000.0;
1190 
1191  double ang = 4.0 * atan( aBulge );
1192 
1193  // reflect the Y values to put everything in a RHCS
1194  VECTOR2D sp( aSegStart.x, -aSegStart.y );
1195  VECTOR2D ep( aSegEnd.x, -aSegEnd.y );
1196  // angle from end->start
1197  double offAng = atan2( ep.y - sp.y, ep.x - sp.x );
1198  // length of subtended segment = 1/2 distance between the 2 points
1199  double d = 0.5 * sqrt( (sp.x - ep.x) * (sp.x - ep.x) + (sp.y - ep.y) * (sp.y - ep.y) );
1200  // midpoint of the subtended segment
1201  double xm = ( sp.x + ep.x ) * 0.5;
1202  double ym = ( sp.y + ep.y ) * 0.5;
1203  double radius = d / sin( ang * 0.5 );
1204 
1205  if( radius < 0.0 )
1206  radius = -radius;
1207 
1208  // calculate the height of the triangle with base d and hypotenuse r
1209  double dh2 = radius * radius - d * d;
1210 
1211  // this should only ever happen due to rounding errors when r == d
1212  if( dh2 < 0.0 )
1213  dh2 = 0.0;
1214 
1215  double h = sqrt( dh2 );
1216 
1217  if( ang < 0.0 )
1218  offAng -= M_PI_2;
1219  else
1220  offAng += M_PI_2;
1221 
1222  // for angles greater than 180 deg we need to flip the
1223  // direction in which the arc center is found relative
1224  // to the midpoint of the subtended segment.
1225  if( ang < -M_PI )
1226  offAng += M_PI;
1227  else if( ang > M_PI )
1228  offAng -= M_PI;
1229 
1230  // center point
1231  double cx = h * cos( offAng ) + xm;
1232  double cy = h * sin( offAng ) + ym;
1233  VECTOR2D center( SCALE_FACTOR( cx ), SCALE_FACTOR( -cy ) );
1234  VECTOR2D arc_start;
1235  double angle = RAD2DEG( ang );
1236 
1237  if( ang < 0.0 )
1238  {
1239  arc_start = VECTOR2D( SCALE_FACTOR( ep.x ), SCALE_FACTOR( -ep.y ) );
1240  }
1241  else
1242  {
1243  arc_start = VECTOR2D( SCALE_FACTOR( sp.x ), SCALE_FACTOR( -sp.y ) );
1244  angle = -angle;
1245  }
1246 
1247  GRAPHICS_IMPORTER_BUFFER* bufferToUse =
1249  bufferToUse->AddArc( center, arc_start, angle, aWidth );
1250 
1251  VECTOR2D radiusDelta( SCALE_FACTOR( radius ), SCALE_FACTOR( radius ) );
1252 
1253  updateImageLimits( center + radiusDelta );
1254  updateImageLimits( center - radiusDelta );
1255  return;
1256 }
1257 
1258 
1259 #include "tinysplinecpp.h"
1260 
1262 {
1263  #if 0 // Debug only
1264  wxLogMessage("spl deg %d kn %d ctr %d fit %d",
1269  #endif
1270 
1271  unsigned imax = m_curr_entity.m_SplineControlPointList.size();
1272 
1273  if( imax < 2 ) // malformed spline
1274  return;
1275 
1276 #if 0 // set to 1 to approximate the spline by segments between 2 control points
1277  VECTOR2D startpoint( mapX( m_curr_entity.m_SplineControlPointList[0].m_x ),
1279 
1280  for( unsigned int ii = 1; ii < imax; ++ii )
1281  {
1282  VECTOR2D endpoint( mapX( m_curr_entity.m_SplineControlPointList[ii].m_x ),
1284 
1285  if( startpoint != endpoint )
1286  {
1287  m_internalImporter.AddLine( startpoint, endpoint, aWidth );
1288 
1289  updateImageLimits( startpoint );
1290  updateImageLimits( endpoint );
1291 
1292  startpoint = endpoint;
1293  }
1294  }
1295 #else // Use bezier curves, supported by pcbnew, to approximate the spline
1296  std::vector<double> ctrlp;
1297 
1298  for( unsigned ii = 0; ii < imax; ++ii )
1299  {
1300  ctrlp.push_back( m_curr_entity.m_SplineControlPointList[ii].m_x );
1301  ctrlp.push_back( m_curr_entity.m_SplineControlPointList[ii].m_y );
1302  }
1303 
1304  std::vector<double> coords;
1305  try
1306  {
1307  tinyspline::BSpline dxfspline( m_curr_entity.m_SplineControlPointList.size(),
1308  /* coord dim */ 2, m_curr_entity.m_SplineDegree );
1309 
1310  dxfspline.setCtrlp( ctrlp );
1311  dxfspline.setKnots( m_curr_entity.m_SplineKnotsList );
1312  tinyspline::BSpline beziers( dxfspline.toBeziers() );
1313 
1314  coords = beziers.ctrlp();
1315  }
1316  catch( const std::runtime_error& ) //tinyspline throws everything including data validation as runtime errors
1317  {
1318  // invalid spline definition, drop this block
1319  reportMsg( _( "Invalid spline definition encountered" ) );
1320  return;
1321  }
1322 
1323  if( coords.size() % 8 != 0 )
1324  {
1325  // somehow we generated a bad Bezier curve
1326  reportMsg( _( "Invalid Bezier curve created" ) );
1327  return;
1328  }
1329 
1330  // Each Bezier curve uses 4 vertices (a start point, 2 control points and a end point).
1331  // So we can have more than one Bezier curve ( there are one curve each four vertices)
1332  // However, one can have one Bezier curve with end point = ctrl point 2, having only 3
1333  // defined points in list.
1334  for( unsigned ii = 0; ii < coords.size(); ii += 8 )
1335  {
1336  VECTOR2D start( mapX( coords[ii] ), mapY( coords[ii+1] ) );
1337  VECTOR2D bezierControl1( mapX( coords[ii+2] ), mapY( coords[ii+3] ) );
1338  VECTOR2D bezierControl2( mapX( coords[ii+4] ), mapY( coords[ii+5] ) );
1339  VECTOR2D end;
1340 
1341  if( ii+7 < coords.size() )
1342  end = VECTOR2D( mapX( coords[ii+6] ), mapY( coords[ii+7] ) );
1343  else
1344  end = bezierControl2;
1345 
1346  GRAPHICS_IMPORTER_BUFFER* bufferToUse =
1348  bufferToUse->AddSpline( start, bezierControl1, bezierControl2, end, aWidth );
1349  }
1350 #endif
1351 }
1352 
1353 
1355 {
1356  m_minX = std::min( aPoint.x, m_minX );
1357  m_maxX = std::max( aPoint.x, m_maxX );
1358 
1359  m_minY = std::min( aPoint.y, m_minY );
1360  m_maxY = std::max( aPoint.y, m_maxY );
1361 }
1362 
1363 
1365 {
1366  VECTOR3D arbZ, arbX, arbY;
1367 
1368  double direction[3];
1369  aData->getDirection( direction );
1370 
1371  arbZ = VECTOR3D( direction[0], direction[1], direction[2] ).Normalize();
1372 
1373  if( ( abs( arbZ.x ) < ( 1.0 / 64.0 ) ) && ( abs( arbZ.y ) < ( 1.0 / 64.0 ) ) )
1374  {
1375  arbX = VECTOR3D( 0, 1, 0 ).Cross( arbZ ).Normalize();
1376  }
1377  else
1378  {
1379  arbX = VECTOR3D( 0, 0, 1 ).Cross( arbZ ).Normalize();
1380  }
1381 
1382  arbY = arbZ.Cross( arbX ).Normalize();
1383 
1384  return DXF_ARBITRARY_AXIS{ arbX, arbY, arbZ };
1385 }
1386 
1387 
1389 {
1390  double x, y, z;
1391  x = point.x * arbitraryAxis.vecX.x + point.y * arbitraryAxis.vecX.y
1392  + point.z * arbitraryAxis.vecX.z;
1393  y = point.x * arbitraryAxis.vecY.x + point.y * arbitraryAxis.vecY.y
1394  + point.z * arbitraryAxis.vecY.z;
1395  z = point.x * arbitraryAxis.vecZ.x + point.y * arbitraryAxis.vecZ.y
1396  + point.z * arbitraryAxis.vecZ.z;
1397 
1398  return VECTOR3D( x, y, z );
1399 }
1400 
1401 
1403 {
1404  VECTOR3D worldX = wcsToOcs( arbitraryAxis, VECTOR3D( 1, 0, 0 ) );
1405  VECTOR3D worldY = wcsToOcs( arbitraryAxis, VECTOR3D( 0, 1, 0 ) );
1406  VECTOR3D worldZ = wcsToOcs( arbitraryAxis, VECTOR3D( 0, 0, 1 ) );
1407 
1408  double x, y, z;
1409  x = point.x * worldX.x + point.y * worldX.y + point.z * worldX.z;
1410  y = point.x * worldY.x + point.y * worldY.y + point.z * worldY.z;
1411  z = point.x * worldZ.x + point.y * worldZ.y + point.z * worldZ.z;
1412 
1413  return VECTOR3D( x, y, z );
1414 }
Interface that creates objects representing shapes for a given data model.
DXF2BRD_ENTITY_DATA m_curr_entity
void insertArc(const VECTOR2D &aSegStart, const VECTOR2D &aSegEnd, double aBulge, int aWidth)
std::vector< std::unique_ptr< DXF_IMPORT_STYLE > > m_styles
#define DXF_IMPORT_LINEWEIGHT_BY_LW_DEFAULT
virtual void addInsert(const DL_InsertData &aData) override
T z
Definition: vector3.h:58
EDA_TEXT_HJUSTIFY_T
Definition: eda_text.h:61
void AddLine(const VECTOR2D &aStart, const VECTOR2D &aEnd, double aWidth) override
Create an object representing a line segment.
VECTOR3< T > Normalize()
Compute the normalized vector.
Definition: vector3.h:159
static wxString FROM_UTF8(const char *cstring)
Convert a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:110
double GetImageHeight() const override
Return image height from original imported file.
virtual void addTextStyle(const DL_StyleData &aData) override
virtual void addLine(const DL_LineData &aData) override
virtual void addPolyline(const DL_PolylineData &aData) override
virtual void endBlock() override
A helper class to hold layer settings temporarily during import.
DXF_IMPORT_LAYER * getImportLayer(const std::string &aLayerName)
Returns the import layer data.
virtual void addBlock(const DL_BlockData &) override
Called for each BLOCK in the DXF file These are re-usable elements that may be placed into the model ...
static wxString toDxfString(const wxString &aStr)
Convert a native unicode string into a DXF encoded string.
VECTOR3D ocsToWcs(const DXF_ARBITRARY_AXIS &arbitraryAxis, VECTOR3D point)
#define MIN_BULGE
unsigned int m_SplineFitCount
double GetImageWidth() const override
Return image width from original imported file.
void AddArc(const VECTOR2D &aCenter, const VECTOR2D &aStart, double aAngle, double aWidth) override
Create an object representing an arc.
#define M_PI_2
Definition: transline.cpp:37
bool Load(const wxString &aFileName) override
Load file for import.
unsigned int m_SplineControlCount
double RAD2DEG(double rad)
Definition: trigo.h:232
double mapX(double aDxfCoordX)
virtual void addFitPoint(const DL_FitPointData &aData) override
Called for every spline fit point.
virtual void addLinetype(const DL_LinetypeData &data) override
DXF_IMPORT_UNITS m_currentUnit
virtual void addSpline(const DL_SplineData &aData) override
Called for every spline.
std::vector< VECTOR2D > m_SplineFitPointList
DXF_IMPORT_BLOCK * getImportBlock(const std::string &aBlockName)
Returns the import layer block.
void reportMsg(const wxString &aMessage)
#define DXF_IMPORT_LINEWEIGHT_BY_LAYER
void updateImageLimits(const VECTOR2D &aPoint)
void SetDefaultLineWidthMM(double aWidth)
Set the default line width when importing dxf items like lines to Pcbnew.
A helper class to hold style settings temporarily during import.
#define SCALE_FACTOR(x)
DXF_IMPORT_BLOCK * m_currentBlock
DXF_IMPORT_STYLE * getImportStyle(const std::string &aStyleName)
Returns the import style.
This file contains miscellaneous commonly used macros and functions.
void AddShape(std::unique_ptr< IMPORTED_SHAPE > &aShape)
DXF_ARBITRARY_AXIS getArbitraryAxis(DL_Extrusion *aData)
virtual void endEntity() override
virtual void setVariableInt(const std::string &key, int value, int code) override
Called for every int variable in the DXF file (e.g.
bool Import() override
Actually imports the file.
VECTOR3< T > Cross(const VECTOR3< T > &aVector) const
Compute cross product of self with aVector.
Definition: vector3.h:133
void AddSpline(const VECTOR2D &aStart, const VECTOR2D &BezierControl1, const VECTOR2D &BezierControl2, const VECTOR2D &aEnd, double aWidth) override
Create an object representing an arc.
VECTOR2< double > VECTOR2D
Definition: vector2d.h:622
virtual void addVertex(const DL_VertexData &aData) override
Called for every polyline vertex.
unsigned int m_SplineKnotsCount
unsigned int m_SplineDegree
virtual void addKnot(const DL_KnotData &aData) override
Called for every spline knot value.
double lineWeightToWidth(int lw, DXF_IMPORT_LAYER *aLayer)
static wxString toNativeString(const wxString &aData)
Converts a DXF encoded string into a native Unicode string.
std::vector< std::unique_ptr< DXF_IMPORT_LAYER > > m_layers
VECTOR3D wcsToOcs(const DXF_ARBITRARY_AXIS &arbitraryAxis, VECTOR3D point)
double mapDim(double aDxfValue)
void AddCircle(const VECTOR2D &aCenter, double aRadius, double aWidth, bool aFilled) override
Create an object representing a circle.
GRAPHICS_IMPORTER_BUFFER m_buffer
void AddText(const VECTOR2D &aOrigin, const wxString &aText, double aHeight, double aWidth, double aThickness, double aOrientation, EDA_TEXT_HJUSTIFY_T aHJustify, EDA_TEXT_VJUSTIFY_T aVJustify) override
Create an object representing a text.
EDA_TEXT_VJUSTIFY_T
Definition: eda_text.h:68
virtual void addControlPoint(const DL_ControlPointData &aData) override
Called for every spline control point.
std::vector< std::unique_ptr< DXF_IMPORT_BLOCK > > m_blocks
virtual void SetImporter(GRAPHICS_IMPORTER *aImporter) override
Set the receiver of the imported shapes.
VECTOR2< T > Rotate(double aAngle) const
Rotate the vector by a given angle.
Definition: vector2d.h:371
const int scale
T x
Definition: vector3.h:58
virtual void addMText(const DL_MTextData &aData) override
const char * name
Definition: DXF_plotter.cpp:59
double GetLineWidthMM() const
Return the line width used for importing the outlines (in mm).
#define _(s)
Definition: 3d_actions.cpp:33
void insertSpline(int aWidth)
bool ImportDxfFile(const wxString &aFile)
Implementation of the method used for communicate with this filter.
virtual void SetImporter(GRAPHICS_IMPORTER *aImporter)
Set the receiver of the imported shapes.
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
void insertLine(const VECTOR2D &aSegStart, const VECTOR2D &aSegEnd, int aWidth)
The common library.
GRAPHICS_IMPORTER * m_importer
< Importer used to create objects representing the imported shapes.
Helper class representing the DXF specification's "arbitrary axis".
std::list< std::unique_ptr< IMPORTED_SHAPE > > & GetShapes()
virtual void addLayer(const DL_LayerData &aData) override
virtual void addArc(const DL_ArcData &aData) override
double mapY(double aDxfCoordY)
virtual void addText(const DL_TextData &aData) override
GRAPHICS_IMPORTER_BUFFER m_internalImporter
std::vector< double > m_SplineKnotsList
void ImportTo(GRAPHICS_IMPORTER &aImporter)
virtual void setVariableString(const std::string &key, const std::string &value, int code) override
Called for every string variable in the DXF file (e.g.
std::vector< SPLINE_CTRL_POINT > m_SplineControlPointList
T y
Definition: vector3.h:58
A helper class to hold layer settings temporarily during import.
VECTOR3< double > VECTOR3D
Definition: vector3.h:185
virtual void addCircle(const DL_CircleData &aData) override