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 arbitrary axis
70  * translation even though they are 2D drawings and most of the time
71  * the import is fine. Sometimes, against 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  m_importCoordinatePrecision = 4; // initial value per dxf spec
103  m_importAnglePrecision = 0; // initial value per dxf spec
104 
105  // placeholder layer so we can fallback to something later
106  std::unique_ptr<DXF_IMPORT_LAYER> layer0 =
107  std::make_unique<DXF_IMPORT_LAYER>( "", DXF_IMPORT_LINEWEIGHT_BY_LW_DEFAULT );
108  m_layers.push_back( std::move( layer0 ) );
109 
110  m_currentBlock = nullptr;
111 }
112 
113 
115 {
116 }
117 
118 
119 bool DXF_IMPORT_PLUGIN::Load( const wxString& aFileName )
120 {
121  return ImportDxfFile( aFileName );
122 }
123 
124 
126 {
127  wxCHECK( m_importer, false );
129 
130  return true;
131 }
132 
133 
135 {
136  return m_maxX - m_minX;
137 }
138 
139 
141 {
142  return m_maxY - m_minY;
143 }
144 
145 
147 {
149 
150  if( m_importer )
152 }
153 
154 
155 double DXF_IMPORT_PLUGIN::mapX( double aDxfCoordX )
156 {
157  return SCALE_FACTOR( m_xOffset + ( aDxfCoordX * getCurrentUnitScale() ) );
158 }
159 
160 
161 double DXF_IMPORT_PLUGIN::mapY( double aDxfCoordY )
162 {
163  return SCALE_FACTOR( m_yOffset - ( aDxfCoordY * getCurrentUnitScale() ) );
164 }
165 
166 
167 double DXF_IMPORT_PLUGIN::mapDim( double aDxfValue )
168 {
169  return SCALE_FACTOR( aDxfValue * getCurrentUnitScale() );
170 }
171 
172 
173 bool DXF_IMPORT_PLUGIN::ImportDxfFile( const wxString& aFile )
174 {
175  DL_Dxf dxf_reader;
176 
177  // wxFopen takes care of unicode filenames across platforms
178  FILE* fp = wxFopen( aFile, "rt" );
179 
180  if( fp == nullptr )
181  return false;
182 
183  // Note the dxf reader takes care of switching to "C" locale before reading the file
184  // and will close the file after reading
185  bool success = dxf_reader.in( fp, this );
186 
187  return success;
188 }
189 
190 
191 void DXF_IMPORT_PLUGIN::reportMsg( const wxString& aMessage )
192 {
193  // Add message to keep trace of not handled dxf entities
194  m_messages += aMessage;
195  m_messages += '\n';
196 }
197 
198 
199 void DXF_IMPORT_PLUGIN::addSpline( const DL_SplineData& aData )
200 {
201  // Called when starting reading a spline
204  m_curr_entity.m_EntityFlag = aData.flags;
205  m_curr_entity.m_EntityType = DL_ENTITY_SPLINE;
206  m_curr_entity.m_SplineDegree = aData.degree;
207  m_curr_entity.m_SplineTangentStartX = aData.tangentStartX;
208  m_curr_entity.m_SplineTangentStartY = aData.tangentStartY;
209  m_curr_entity.m_SplineTangentEndX = aData.tangentEndX;
210  m_curr_entity.m_SplineTangentEndY = aData.tangentEndY;
211  m_curr_entity.m_SplineKnotsCount = aData.nKnots;
212  m_curr_entity.m_SplineControlCount = aData.nControl;
213  m_curr_entity.m_SplineFitCount = aData.nFit;
214 }
215 
216 
217 void DXF_IMPORT_PLUGIN::addControlPoint( const DL_ControlPointData& aData )
218 {
219  // Called for every spline control point, when reading a spline entity
220  m_curr_entity.m_SplineControlPointList.emplace_back( aData.x , aData.y,
221  aData.w );
222 }
223 
224 
225 void DXF_IMPORT_PLUGIN::addFitPoint( const DL_FitPointData& aData )
226 {
227  // Called for every spline fit point, when reading a spline entity
228  // we store only the X,Y coord values in a VECTOR2D
229  m_curr_entity.m_SplineFitPointList.emplace_back( aData.x, aData.y );
230 }
231 
232 
233 void DXF_IMPORT_PLUGIN::addKnot( const DL_KnotData& aData)
234 {
235  // Called for every spline knot value, when reading a spline entity
236  m_curr_entity.m_SplineKnotsList.push_back( aData.k );
237 }
238 
239 
240 void DXF_IMPORT_PLUGIN::addLayer( const DL_LayerData& aData )
241 {
242  wxString name = wxString::FromUTF8( aData.name.c_str() );
243 
244  int lw = attributes.getWidth();
245 
247  {
249  }
250 
251  std::unique_ptr<DXF_IMPORT_LAYER> layer = std::make_unique<DXF_IMPORT_LAYER>( name, lw );
252 
253  m_layers.push_back( std::move( layer ) );
254 }
255 
256 
257 void DXF_IMPORT_PLUGIN::addLinetype( const DL_LinetypeData& data )
258 {
259 #if 0
260  wxString name = FROM_UTF8( data.name.c_str() );
261  wxString description = FROM_UTF8( data.description.c_str() );
262 #endif
263 }
264 
265 
267 {
268  if( lw == DXF_IMPORT_LINEWEIGHT_BY_LAYER && aLayer != nullptr )
269  {
270  lw = aLayer->m_lineWeight;
271  }
272 
273  // All lineweights >= 0 are always in 100ths of mm
274  double mm = m_defaultThickness;
275  if( lw >= 0 )
276  {
277  mm = lw / 100.0;
278  }
279 
280  return SCALE_FACTOR( mm );
281 }
282 
283 
284 DXF_IMPORT_LAYER* DXF_IMPORT_PLUGIN::getImportLayer( const std::string& aLayerName )
285 {
286  DXF_IMPORT_LAYER* layer = m_layers.front().get();
287  wxString layerName = wxString::FromUTF8( aLayerName.c_str() );
288 
289  if( !layerName.IsEmpty() )
290  {
291  auto resultIt = std::find_if( m_layers.begin(), m_layers.end(),
292  [layerName]( const auto& it )
293  {
294  return it->m_layerName == layerName;
295  } );
296 
297  if( resultIt != m_layers.end() )
298  layer = resultIt->get();
299  }
300 
301  return layer;
302 }
303 
304 
305 DXF_IMPORT_BLOCK* DXF_IMPORT_PLUGIN::getImportBlock( const std::string& aBlockName )
306 {
307  DXF_IMPORT_BLOCK* block = nullptr;
308  wxString blockName = wxString::FromUTF8( aBlockName.c_str() );
309 
310  if( !blockName.IsEmpty() )
311  {
312  auto resultIt = std::find_if( m_blocks.begin(), m_blocks.end(),
313  [blockName]( const auto& it )
314  {
315  return it->m_name == blockName;
316  } );
317 
318  if( resultIt != m_blocks.end() )
319  block = resultIt->get();
320  }
321 
322  return block;
323 }
324 
325 
326 DXF_IMPORT_STYLE* DXF_IMPORT_PLUGIN::getImportStyle( const std::string& aStyleName )
327 {
328  DXF_IMPORT_STYLE* style = nullptr;
329  wxString styleName = wxString::FromUTF8( aStyleName.c_str() );
330 
331  if( !styleName.IsEmpty() )
332  {
333  auto resultIt = std::find_if( m_styles.begin(), m_styles.end(),
334  [styleName]( const auto& it ) { return it->m_name == styleName; } );
335 
336  if( resultIt != m_styles.end() )
337  style = resultIt->get();
338  }
339 
340  return style;
341 }
342 
343 
344 void DXF_IMPORT_PLUGIN::addLine( const DL_LineData& aData )
345 {
346  DXF_IMPORT_LAYER* layer = getImportLayer( attributes.getLayer() );
347  double lineWidth = lineWeightToWidth( attributes.getWidth(), layer );
348 
349  VECTOR2D start( mapX( aData.x1 ), mapY( aData.y1 ) );
350  VECTOR2D end( mapX( aData.x2 ), mapY( aData.y2 ) );
351 
352  GRAPHICS_IMPORTER_BUFFER* bufferToUse =
354  bufferToUse->AddLine( start, end, lineWidth );
355 
356  updateImageLimits( start );
357  updateImageLimits( end );
358 }
359 
360 
361 void DXF_IMPORT_PLUGIN::addPolyline(const DL_PolylineData& aData )
362 {
363  // Convert DXF Polylines into a series of KiCad Lines and Arcs.
364  // A Polyline (as opposed to a LWPolyline) may be a 3D line or
365  // even a 3D Mesh. The only type of Polyline which is guaranteed
366  // to import correctly is a 2D Polyline in X and Y, which is what
367  // we assume of all Polylines. The width used is the width of the Polyline.
368  // per-vertex line widths, if present, are ignored.
371  m_curr_entity.m_EntityFlag = aData.flags;
372  m_curr_entity.m_EntityType = DL_ENTITY_POLYLINE;
373 }
374 
375 
376 void DXF_IMPORT_PLUGIN::addVertex( const DL_VertexData& aData )
377 {
379  return; // Error
380 
381  DXF_IMPORT_LAYER* layer = getImportLayer( attributes.getLayer() );
382  double lineWidth = lineWeightToWidth( attributes.getWidth(), layer );
383 
384  const DL_VertexData* vertex = &aData;
385 
386  DXF_ARBITRARY_AXIS arbAxis = getArbitraryAxis( getExtrusion() );
387  VECTOR3D vertexCoords = ocsToWcs( arbAxis, VECTOR3D( vertex->x, vertex->y, vertex->z ) );
388 
389  if( m_curr_entity.m_EntityParseStatus == 1 ) // This is the first vertex of an entity
390  {
391  m_curr_entity.m_LastCoordinate.x = mapX( vertexCoords.x );
392  m_curr_entity.m_LastCoordinate.y = mapY( vertexCoords.y );
394  m_curr_entity.m_BulgeVertex = vertex->bulge;
396  return;
397  }
398 
399  VECTOR2D seg_end( mapX( vertexCoords.x ), mapY( vertexCoords.y ) );
400 
401  if( std::abs( m_curr_entity.m_BulgeVertex ) < MIN_BULGE )
402  insertLine( m_curr_entity.m_LastCoordinate, seg_end, lineWidth );
403  else
405  lineWidth );
406 
408  m_curr_entity.m_BulgeVertex = vertex->bulge;
409 }
410 
411 
413 {
414  DXF_IMPORT_LAYER* layer = getImportLayer( attributes.getLayer() );
415  double lineWidth = lineWeightToWidth( attributes.getWidth(), layer );
416 
417  if( m_curr_entity.m_EntityType == DL_ENTITY_POLYLINE ||
418  m_curr_entity.m_EntityType == DL_ENTITY_LWPOLYLINE )
419  {
420  // Polyline flags bit 0 indicates closed (1) or open (0) polyline
421  if( m_curr_entity.m_EntityFlag & 1 )
422  {
423  if( std::abs( m_curr_entity.m_BulgeVertex ) < MIN_BULGE )
425  lineWidth );
426  else
428  m_curr_entity.m_BulgeVertex, lineWidth );
429  }
430  }
431 
432  if( m_curr_entity.m_EntityType == DL_ENTITY_SPLINE )
433  {
434  insertSpline( lineWidth );
435  }
436 
438 }
439 
440 
441 void DXF_IMPORT_PLUGIN::addBlock( const DL_BlockData& aData )
442 {
443  wxString name = wxString::FromUTF8( aData.name.c_str() );
444 
445  std::unique_ptr<DXF_IMPORT_BLOCK> block =
446  std::make_unique<DXF_IMPORT_BLOCK>( name, aData.bpx, aData.bpy );
447 
448  m_blocks.push_back( std::move( block ) );
449 
450  m_currentBlock = m_blocks.back().get();
451 }
452 
453 
455 {
456  m_currentBlock = nullptr;
457 }
458 
459 void DXF_IMPORT_PLUGIN::addInsert( const DL_InsertData& aData )
460 {
461  DXF_IMPORT_BLOCK* block = getImportBlock( aData.name );
462 
463  if( block == nullptr )
464  return;
465 
466  DXF_ARBITRARY_AXIS arbAxis = getArbitraryAxis( getExtrusion() );
467  VECTOR3D insertCoords = ocsToWcs( arbAxis, VECTOR3D( aData.ipx, aData.ipy, aData.ipz ) );
468 
469  VECTOR2D translation( mapX( insertCoords.x ), mapY( insertCoords.y ) );
470  translation -= VECTOR2D( mapX( block->m_baseX ), mapY( block->m_baseY ) );
471 
472 
473  for( auto& shape : block->m_buffer.GetShapes() )
474  {
475  std::unique_ptr<IMPORTED_SHAPE> newShape = shape->clone();
476 
477  newShape->Translate( translation );
478  newShape->Scale( aData.sx, aData.sy );
479 
480  m_internalImporter.AddShape( newShape );
481  }
482 }
483 
484 
485 void DXF_IMPORT_PLUGIN::addCircle( const DL_CircleData& aData )
486 {
487  DXF_ARBITRARY_AXIS arbAxis = getArbitraryAxis( getExtrusion() );
488  VECTOR3D centerCoords = ocsToWcs( arbAxis, VECTOR3D( aData.cx, aData.cy, aData.cz ) );
489 
490  VECTOR2D center( mapX( centerCoords.x ), mapY( centerCoords.y ) );
491  DXF_IMPORT_LAYER* layer = getImportLayer( attributes.getLayer() );
492  double lineWidth = lineWeightToWidth( attributes.getWidth(), layer );
493 
494  GRAPHICS_IMPORTER_BUFFER* bufferToUse =
496  bufferToUse->AddCircle( center, mapDim( aData.radius ), lineWidth, false );
497 
498  VECTOR2D radiusDelta( mapDim( aData.radius ), mapDim( aData.radius ) );
499 
500  updateImageLimits( center + radiusDelta );
501  updateImageLimits( center - radiusDelta );
502 }
503 
504 
505 void DXF_IMPORT_PLUGIN::addArc( const DL_ArcData& aData )
506 {
507  DXF_ARBITRARY_AXIS arbAxis = getArbitraryAxis( getExtrusion() );
508  VECTOR3D centerCoords = ocsToWcs( arbAxis, VECTOR3D( aData.cx, aData.cy, aData.cz ) );
509 
510  // Init arc centre:
511  VECTOR2D center( mapX( centerCoords.x ), mapY( centerCoords.y ) );
512 
513  // aData.anglex is in degrees.
514  double startangle = aData.angle1;
515  double endangle = aData.angle2;
516 
517  // Init arc start point
518  VECTOR2D startPoint( aData.radius, 0.0 );
519  startPoint = startPoint.Rotate( startangle * M_PI / 180.0 );
520  VECTOR2D arcStart(
521  mapX( startPoint.x + centerCoords.x ), mapY( startPoint.y + centerCoords.y ) );
522 
523  // calculate arc angle (arcs are CCW, and should be < 0 in Pcbnew)
524  double angle = -( endangle - startangle );
525 
526  if( angle > 0.0 )
527  angle -= 360.0;
528 
529  DXF_IMPORT_LAYER* layer = getImportLayer( attributes.getLayer() );
530  double lineWidth = lineWeightToWidth( attributes.getWidth(), layer );
531 
532  GRAPHICS_IMPORTER_BUFFER* bufferToUse =
534  bufferToUse->AddArc( center, arcStart, angle, lineWidth );
535 
536  VECTOR2D radiusDelta( mapDim( aData.radius ), mapDim( aData.radius ) );
537 
538  updateImageLimits( center + radiusDelta );
539  updateImageLimits( center - radiusDelta );
540 }
541 
542 
543 void DXF_IMPORT_PLUGIN::addText( const DL_TextData& aData )
544 {
545  DXF_ARBITRARY_AXIS arbAxis = getArbitraryAxis( getExtrusion() );
546  VECTOR3D refPointCoords = ocsToWcs( arbAxis, VECTOR3D( aData.ipx, aData.ipy, aData.ipz ) );
547  VECTOR3D secPointCoords = ocsToWcs( arbAxis, VECTOR3D( std::isnan( aData.apx ) ? 0 : aData.apx,
548  std::isnan( aData.apy ) ? 0 : aData.apy,
549  std::isnan( aData.apz ) ? 0 : aData.apz ) );
550 
551  VECTOR2D refPoint( mapX( refPointCoords.x ), mapY( refPointCoords.y ) );
552  VECTOR2D secPoint( mapX( secPointCoords.x ), mapY( secPointCoords.y ) );
553 
554  if( aData.vJustification != 0 || aData.hJustification != 0 || aData.hJustification == 4 )
555  {
556  if( aData.hJustification != 3 && aData.hJustification != 5 )
557  {
558  VECTOR2D tmp = secPoint;
559  secPoint = refPoint;
560  refPoint = tmp;
561  }
562  }
563 
564  wxString text = toNativeString( wxString::FromUTF8( aData.text.c_str() ) );
565 
566  DXF_IMPORT_STYLE* style = getImportStyle( aData.style.c_str() );
567 
568  double textHeight = mapDim( aData.height );
569  // The 0.9 factor gives a better height/width base ratio with our font
570  double charWidth = textHeight * 0.9;
571 
572  if( style != nullptr )
573  charWidth *= style->m_widthFactor;
574 
575  double textWidth = charWidth * text.length(); // Rough approximation
576  double textThickness = textHeight/8.0; // Use a reasonable line thickness for this text
577 
578  VECTOR2D bottomLeft(0.0, 0.0);
579  VECTOR2D bottomRight(0.0, 0.0);
580  VECTOR2D topLeft(0.0, 0.0);
581  VECTOR2D topRight(0.0, 0.0);
582 
585 
586  switch( aData.vJustification )
587  {
588  case 0: //DRW_Text::VBaseLine:
589  case 1: //DRW_Text::VBottom:
590  vJustify = GR_TEXT_VJUSTIFY_BOTTOM;
591 
592  topLeft.y = textHeight;
593  topRight.y = textHeight;
594  break;
595 
596  case 2: //DRW_Text::VMiddle:
597  vJustify = GR_TEXT_VJUSTIFY_CENTER;
598 
599  bottomRight.y = -textHeight / 2.0;
600  bottomLeft.y = -textHeight / 2.0;
601  topLeft.y = textHeight / 2.0;
602  topRight.y = textHeight / 2.0;
603  break;
604 
605  case 3: //DRW_Text::VTop:
606  vJustify = GR_TEXT_VJUSTIFY_TOP;
607 
608  bottomLeft.y = -textHeight;
609  bottomRight.y = -textHeight;
610  break;
611  }
612 
613  switch( aData.hJustification )
614  {
615  case 0: //DRW_Text::HLeft:
616  case 3: //DRW_Text::HAligned: // no equivalent options in text pcb.
617  case 5: //DRW_Text::HFit: // no equivalent options in text pcb.
618  hJustify = GR_TEXT_HJUSTIFY_LEFT;
619 
620  bottomRight.x = textWidth;
621  topRight.x = textWidth;
622  break;
623 
624  case 1: //DRW_Text::HCenter:
625  case 4: //DRW_Text::HMiddle: // no equivalent options in text pcb.
626  hJustify = GR_TEXT_HJUSTIFY_CENTER;
627 
628  bottomLeft.x = -textWidth / 2.0;
629  topLeft.x = -textWidth / 2.0;
630  bottomRight.x = textWidth / 2.0;
631  topRight.x = textWidth / 2.0;
632  break;
633 
634  case 2: //DRW_Text::HRight:
635  hJustify = GR_TEXT_HJUSTIFY_RIGHT;
636 
637  bottomLeft.x = -textWidth;
638  topLeft.x = -textWidth;
639  break;
640  }
641 
642 #if 0
643  wxString sty = wxString::FromUTF8( aData.style.c_str() );
644  sty = sty.ToLower();
645 
646  if( aData.textgen == 2 )
647  {
648  // Text dir = left to right;
649  } else if( aData.textgen == 4 )
650  {
651  // Text dir = top to bottom;
652  } else
653  {
654  }
655 #endif
656 
657  // dxf_lib imports text angle in radians (although there are no comment about that.
658  // So, for the moment, convert this angle to degrees
659  double angle_degree = aData.angle * 180 / M_PI;
660  // We also need the angle in radians. so convert angle_degree to radians
661  // regardless the aData.angle unit
662  double angleInRads = angle_degree * M_PI / 180.0;
663  double cosine = cos(angleInRads);
664  double sine = sin(angleInRads);
665 
666  GRAPHICS_IMPORTER_BUFFER* bufferToUse =
668  bufferToUse->AddText( refPoint, text, textHeight, charWidth, textThickness, angle_degree,
669  hJustify, vJustify );
670 
671  // Calculate the boundary box and update the image limits:
672  bottomLeft.x = bottomLeft.x * cosine - bottomLeft.y * sine;
673  bottomLeft.y = bottomLeft.x * sine + bottomLeft.y * cosine;
674 
675  bottomRight.x = bottomRight.x * cosine - bottomRight.y * sine;
676  bottomRight.y = bottomRight.x * sine + bottomRight.y * cosine;
677 
678  topLeft.x = topLeft.x * cosine - topLeft.y * sine;
679  topLeft.y = topLeft.x * sine + topLeft.y * cosine;
680 
681  topRight.x = topRight.x * cosine - topRight.y * sine;
682  topRight.y = topRight.x * sine + topRight.y * cosine;
683 
684  bottomLeft += refPoint;
685  bottomRight += refPoint;
686  topLeft += refPoint;
687  topRight += refPoint;
688 
689  updateImageLimits( bottomLeft );
690  updateImageLimits( bottomRight );
691  updateImageLimits( topLeft );
692  updateImageLimits( topRight );
693 
694 }
695 
696 
697 void DXF_IMPORT_PLUGIN::addMText( const DL_MTextData& aData )
698 {
699  wxString text = toNativeString( wxString::FromUTF8( aData.text.c_str() ) );
700  wxString attrib, tmp;
701 
702  DXF_IMPORT_STYLE* style = getImportStyle( aData.style.c_str() );
703 
704  double textHeight = mapDim( aData.height );
705 
706  // The 0.9 factor gives a better height/width base ratio with our font
707  double charWidth = textHeight * 0.9;
708  if( style != nullptr )
709  charWidth *= style->m_widthFactor;
710 
711  double textWidth = charWidth * text.length(); // Rough approximation
712  double textThickness = textHeight/8.0; // Use a reasonable line thickness for this text
713 
714  VECTOR2D bottomLeft(0.0, 0.0);
715  VECTOR2D bottomRight(0.0, 0.0);
716  VECTOR2D topLeft(0.0, 0.0);
717  VECTOR2D topRight(0.0, 0.0);
718 
719  /* Some texts start by '\' and have formatting chars (font name, font option...)
720  * ending with ';'
721  * Here are some mtext formatting codes:
722  * Format code Purpose
723  * \0...\o Turns overline on and off
724  * \L...\l Turns underline on and off
725  * \~ Inserts a nonbreaking space
726  \\ Inserts a backslash
727  \\\{...\} Inserts an opening and closing brace
728  \\ \File name; Changes to the specified font file
729  \\ \Hvalue; Changes to the text height specified in drawing units
730  \\ \Hvaluex; Changes the text height to a multiple of the current text height
731  \\ \S...^...; Stacks the subsequent text at the \, #, or ^ symbol
732  \\ \Tvalue; Adjusts the space between characters, from.75 to 4 times
733  \\ \Qangle; Changes oblique angle
734  \\ \Wvalue; Changes width factor to produce wide text
735  \\ \A Sets the alignment value; valid values: 0, 1, 2 (bottom, center, top) while( text.StartsWith( wxT("\\") ) )
736  */
737  while( text.StartsWith( wxT( "\\" ) ) )
738  {
739  attrib << text.BeforeFirst( ';' );
740  tmp = text.AfterFirst( ';' );
741  text = tmp;
742  }
743 
744  DXF_ARBITRARY_AXIS arbAxis = getArbitraryAxis( getExtrusion() );
745  VECTOR3D textposCoords = ocsToWcs( arbAxis, VECTOR3D( aData.ipx, aData.ipy, aData.ipz ) );
746 
747  VECTOR2D textpos( mapX( textposCoords.x ), mapY( textposCoords.y ) );
748 
749  // Initialize text justifications:
752 
753  if( aData.attachmentPoint <= 3 )
754  {
755  vJustify = GR_TEXT_VJUSTIFY_TOP;
756 
757  bottomLeft.y = -textHeight;
758  bottomRight.y = -textHeight;
759  }
760  else if( aData.attachmentPoint <= 6 )
761  {
762  vJustify = GR_TEXT_VJUSTIFY_CENTER;
763 
764  bottomRight.y = -textHeight / 2.0;
765  bottomLeft.y = -textHeight / 2.0;
766  topLeft.y = textHeight / 2.0;
767  topRight.y = textHeight / 2.0;
768  }
769  else
770  {
771  vJustify = GR_TEXT_VJUSTIFY_BOTTOM;
772 
773  topLeft.y = textHeight;
774  topRight.y = textHeight;
775  }
776 
777  if( aData.attachmentPoint % 3 == 1 )
778  {
779  hJustify = GR_TEXT_HJUSTIFY_LEFT;
780 
781  bottomRight.x = textWidth;
782  topRight.x = textWidth;
783  }
784  else if( aData.attachmentPoint % 3 == 2 )
785  {
786  hJustify = GR_TEXT_HJUSTIFY_CENTER;
787 
788  bottomLeft.x = -textWidth / 2.0;
789  topLeft.x = -textWidth / 2.0;
790  bottomRight.x = textWidth / 2.0;
791  topRight.x = textWidth / 2.0;
792  }
793  else
794  {
795  hJustify = GR_TEXT_HJUSTIFY_RIGHT;
796 
797  bottomLeft.x = -textWidth;
798  topLeft.x = -textWidth;
799  }
800 
801 #if 0 // These setting have no meaning in Pcbnew
802  if( data.alignH == 1 )
803  {
804  // Text is left to right;
805  }
806  else if( data.alignH == 3 )
807  {
808  // Text is top to bottom;
809  }
810  else
811  {
812  // use ByStyle;
813  }
814 
815  if( aData.alignV == 1 )
816  {
817  // use AtLeast;
818  }
819  else
820  {
821  // useExact;
822  }
823 #endif
824 
825  // dxf_lib imports text angle in radians (although there are no comment about that.
826  // So, for the moment, convert this angle to degrees
827  double angle_degree = aData.angle * 180/M_PI;
828  // We also need the angle in radians. so convert angle_degree to radians
829  // regardless the aData.angle unit
830  double angleInRads = angle_degree * M_PI / 180.0;
831  double cosine = cos(angleInRads);
832  double sine = sin(angleInRads);
833 
834 
835  GRAPHICS_IMPORTER_BUFFER* bufferToUse =
837  bufferToUse->AddText( textpos, text, textHeight, charWidth,
838  textThickness, angle_degree, hJustify, vJustify );
839 
840  bottomLeft.x = bottomLeft.x * cosine - bottomLeft.y * sine;
841  bottomLeft.y = bottomLeft.x * sine + bottomLeft.y * cosine;
842 
843  bottomRight.x = bottomRight.x * cosine - bottomRight.y * sine;
844  bottomRight.y = bottomRight.x * sine + bottomRight.y * cosine;
845 
846  topLeft.x = topLeft.x * cosine - topLeft.y * sine;
847  topLeft.y = topLeft.x * sine + topLeft.y * cosine;
848 
849  topRight.x = topRight.x * cosine - topRight.y * sine;
850  topRight.y = topRight.x * sine + topRight.y * cosine;
851 
852  bottomLeft += textpos;
853  bottomRight += textpos;
854  topLeft += textpos;
855  topRight += textpos;
856 
857  updateImageLimits( bottomLeft );
858  updateImageLimits( bottomRight );
859  updateImageLimits( topLeft );
860  updateImageLimits( topRight );
861 
862 }
863 
864 
866 {
867  double scale = 1.0;
868  switch( m_currentUnit )
869  {
871  scale = 25.4;
872  break;
873 
875  scale = 304.8;
876  break;
877 
879  scale = 1.0;
880  break;
881 
883  scale = 10.0;
884  break;
885 
887  scale = 1000.0;
888  break;
889 
891  scale = 2.54e-5;
892  break;
893 
895  scale = 0.0254;
896  break;
897 
899  scale = 914.4;
900  break;
901 
903  scale = 1.0e-7;
904  break;
905 
907  scale = 1.0e-6;
908  break;
909 
911  scale = 1.0e-3;
912  break;
913 
915  scale = 100.0;
916  break;
917 
918  default:
919  // use the default of 1.0 for:
920  // 0: Unspecified Units
921  // 3: miles
922  // 7: kilometers
923  // 15: decameters
924  // 16: hectometers
925  // 17: gigameters
926  // 18: AU
927  // 19: lightyears
928  // 20: parsecs
929  scale = 1.0;
930  break;
931  }
932 
933  return scale;
934 }
935 
936 
937 
938 void DXF_IMPORT_PLUGIN::setVariableInt( const std::string& key, int value, int code )
939 {
940  // Called for every int variable in the DXF file (e.g. "$INSUNITS").
941 
942  if( key == "$DWGCODEPAGE" )
943  {
944  m_codePage = value;
945  return;
946  }
947 
948  if( key == "$AUPREC" )
949  {
950  m_importAnglePrecision = value;
951  return;
952  }
953 
954  if( key == "$LUPREC" )
955  {
957  return;
958  }
959 
960  if( key == "$INSUNITS" ) // Drawing units
961  {
962  switch( value )
963  {
964  case 1: // inches
966  break;
967 
968  case 2: // feet
970  break;
971 
972  case 4: // mm
974  break;
975 
976  case 5: // centimeters
978  break;
979 
980  case 6: // meters
982  break;
983 
984  case 8: // microinches
986  break;
987 
988  case 9: // mils
990  break;
991 
992  case 10: // yards
994  break;
995 
996  case 11: // Angstroms
998  break;
999 
1000  case 12: // nanometers
1002  break;
1003 
1004  case 13: // micrometers
1006  break;
1007 
1008  case 14: // decimeters
1010  break;
1011 
1012  default:
1013  // use the default of 1.0 for:
1014  // 0: Unspecified Units
1015  // 3: miles
1016  // 7: kilometers
1017  // 15: decameters
1018  // 16: hectometers
1019  // 17: gigameters
1020  // 18: AU
1021  // 19: lightyears
1022  // 20: parsecs
1024  break;
1025  }
1026 
1027  return;
1028  }
1029 }
1030 
1031 
1032 void DXF_IMPORT_PLUGIN::setVariableString( const std::string& key, const std::string& value,
1033  int code )
1034 {
1035  // Called for every string variable in the DXF file (e.g. "$ACADVER").
1036 }
1037 
1038 
1039 wxString DXF_IMPORT_PLUGIN::toDxfString( const wxString& aStr )
1040 {
1041  wxString res;
1042  int j = 0;
1043 
1044  for( unsigned i = 0; i<aStr.length(); ++i )
1045  {
1046  int c = aStr[i];
1047 
1048  if( c > 175 || c < 11 )
1049  {
1050  res.append( aStr.Mid( j, i - j ) );
1051  j = i;
1052 
1053  switch( c )
1054  {
1055  case 0x0A:
1056  res += wxT( "\\P" );
1057  break;
1058 
1059  // diameter:
1060 #ifdef _WIN32
1061  // windows, as always, is special.
1062  case 0x00D8:
1063 #else
1064  case 0x2205:
1065 #endif
1066  res += wxT( "%%C" );
1067  break;
1068 
1069  // degree:
1070  case 0x00B0:
1071  res += wxT( "%%D" );
1072  break;
1073 
1074  // plus/minus
1075  case 0x00B1:
1076  res += wxT( "%%P" );
1077  break;
1078 
1079  default:
1080  j--;
1081  break;
1082  }
1083 
1084  j++;
1085  }
1086  }
1087 
1088  res.append( aStr.Mid( j ) );
1089  return res;
1090 }
1091 
1092 
1093 wxString DXF_IMPORT_PLUGIN::toNativeString( const wxString& aData )
1094 {
1095  wxString res;
1096 
1097  // Ignore font tags:
1098  int j = 0;
1099 
1100  for( unsigned i = 0; i < aData.length(); ++i )
1101  {
1102  if( aData[ i ] == 0x7B ) // is '{' ?
1103  {
1104  if( aData[ i + 1 ] == 0x5c && aData[ i + 2 ] == 0x66 ) // is "\f" ?
1105  {
1106  // found font tag, append parsed part
1107  res.append( aData.Mid( j, i - j ) );
1108 
1109  // skip to ';'
1110  for( unsigned k = i + 3; k < aData.length(); ++k )
1111  {
1112  if( aData[ k ] == 0x3B )
1113  {
1114  i = j = ++k;
1115  break;
1116  }
1117  }
1118 
1119  // add to '}'
1120  for( unsigned k = i; k < aData.length(); ++k )
1121  {
1122  if( aData[ k ] == 0x7D )
1123  {
1124  res.append( aData.Mid( i, k - i ) );
1125  i = j = ++k;
1126  break;
1127  }
1128  }
1129  }
1130  }
1131  }
1132 
1133  res.append( aData.Mid( j ) );
1134 
1135 #if 1
1136  wxRegEx regexp;
1137  // Line feed:
1138  regexp.Compile( wxT( "\\\\P" ) );
1139  regexp.Replace( &res, wxT( "\n" ) );
1140 
1141  // Space:
1142  regexp.Compile( wxT( "\\\\~" ) );
1143  regexp.Replace( &res, wxT( " " ) );
1144 
1145  // diameter:
1146  regexp.Compile( wxT( "%%[cC]" ) );
1147 #ifdef __WINDOWS__
1148  // windows, as always, is special.
1149  regexp.Replace( &res, wxChar( 0xD8 ) );
1150 #else
1151  // Empty_set, diameter is 0x2300
1152  regexp.Replace( &res, wxChar( 0x2205 ) );
1153 #endif
1154 
1155  // degree:
1156  regexp.Compile( wxT( "%%[dD]" ) );
1157  regexp.Replace( &res, wxChar( 0x00B0 ) );
1158  // plus/minus
1159  regexp.Compile( wxT( "%%[pP]" ) );
1160  regexp.Replace( &res, wxChar( 0x00B1 ) );
1161 #endif
1162 
1163  return res;
1164 }
1165 
1166 
1167 void DXF_IMPORT_PLUGIN::addTextStyle( const DL_StyleData& aData )
1168 {
1169  wxString name = wxString::FromUTF8( aData.name.c_str() );
1170 
1171  std::unique_ptr<DXF_IMPORT_STYLE> style =
1172  std::make_unique<DXF_IMPORT_STYLE>( name, aData.fixedTextHeight, aData.widthFactor, aData.bold, aData.italic );
1173 
1174  m_styles.push_back( std::move( style ) );
1175 }
1176 
1177 
1178 void DXF_IMPORT_PLUGIN::addPoint( const DL_PointData& aData )
1179 {
1180  DXF_ARBITRARY_AXIS arbAxis = getArbitraryAxis( getExtrusion() );
1181  VECTOR3D centerCoords = ocsToWcs( arbAxis, VECTOR3D( aData.x, aData.y, aData.z ) );
1182 
1183  VECTOR2D center( mapX( centerCoords.x ), mapY( centerCoords.y ) );
1184 
1185  // we emulate points with filled circles
1186  // set the linewidth to something that even small circles look good with
1187  // thickness is optional for dxf points
1188  // note: we had to modify the dxf library to grab the attribute for thickness
1189  double lineWidth = 0.0001;
1190  double thickness = mapDim( std::max( aData.thickness, 0.01 ) );
1191 
1192  GRAPHICS_IMPORTER_BUFFER* bufferToUse =
1194  bufferToUse->AddCircle( center, thickness, lineWidth, true );
1195 
1196  VECTOR2D radiusDelta( SCALE_FACTOR( thickness ), SCALE_FACTOR( thickness ) );
1197 
1198  updateImageLimits( center + radiusDelta );
1199  updateImageLimits( center - radiusDelta );
1200 }
1201 
1202 
1204  const VECTOR2D& aSegEnd, int aWidth )
1205 {
1206  VECTOR2D origin( SCALE_FACTOR( aSegStart.x ), SCALE_FACTOR( aSegStart.y ) );
1207  VECTOR2D end( SCALE_FACTOR( aSegEnd.x ), SCALE_FACTOR( aSegEnd.y ) );
1208 
1209  GRAPHICS_IMPORTER_BUFFER* bufferToUse =
1211  bufferToUse->AddLine( origin, end, aWidth );
1212 
1213  updateImageLimits( origin );
1214  updateImageLimits( end );
1215 }
1216 
1217 
1218 void DXF_IMPORT_PLUGIN::insertArc( const VECTOR2D& aSegStart, const VECTOR2D& aSegEnd,
1219  double aBulge, int aWidth )
1220 {
1221  VECTOR2D segment_startpoint( SCALE_FACTOR( aSegStart.x ), SCALE_FACTOR( aSegStart.y ) );
1222  VECTOR2D segment_endpoint( SCALE_FACTOR( aSegEnd.x ), SCALE_FACTOR( aSegEnd.y ) );
1223 
1224  // ensure aBulge represents an angle from +/- ( 0 .. approx 359.8 deg )
1225  if( aBulge < -2000.0 )
1226  aBulge = -2000.0;
1227  else if( aBulge > 2000.0 )
1228  aBulge = 2000.0;
1229 
1230  double ang = 4.0 * atan( aBulge );
1231 
1232  // reflect the Y values to put everything in a RHCS
1233  VECTOR2D sp( aSegStart.x, -aSegStart.y );
1234  VECTOR2D ep( aSegEnd.x, -aSegEnd.y );
1235  // angle from end->start
1236  double offAng = atan2( ep.y - sp.y, ep.x - sp.x );
1237  // length of subtended segment = 1/2 distance between the 2 points
1238  double d = 0.5 * sqrt( (sp.x - ep.x) * (sp.x - ep.x) + (sp.y - ep.y) * (sp.y - ep.y) );
1239  // midpoint of the subtended segment
1240  double xm = ( sp.x + ep.x ) * 0.5;
1241  double ym = ( sp.y + ep.y ) * 0.5;
1242  double radius = d / sin( ang * 0.5 );
1243 
1244  if( radius < 0.0 )
1245  radius = -radius;
1246 
1247  // calculate the height of the triangle with base d and hypotenuse r
1248  double dh2 = radius * radius - d * d;
1249 
1250  // this should only ever happen due to rounding errors when r == d
1251  if( dh2 < 0.0 )
1252  dh2 = 0.0;
1253 
1254  double h = sqrt( dh2 );
1255 
1256  if( ang < 0.0 )
1257  offAng -= M_PI_2;
1258  else
1259  offAng += M_PI_2;
1260 
1261  // for angles greater than 180 deg we need to flip the
1262  // direction in which the arc center is found relative
1263  // to the midpoint of the subtended segment.
1264  if( ang < -M_PI )
1265  offAng += M_PI;
1266  else if( ang > M_PI )
1267  offAng -= M_PI;
1268 
1269  // center point
1270  double cx = h * cos( offAng ) + xm;
1271  double cy = h * sin( offAng ) + ym;
1272  VECTOR2D center( SCALE_FACTOR( cx ), SCALE_FACTOR( -cy ) );
1273  VECTOR2D arc_start;
1274  double angle = RAD2DEG( ang );
1275 
1276  if( ang < 0.0 )
1277  {
1278  arc_start = VECTOR2D( SCALE_FACTOR( ep.x ), SCALE_FACTOR( -ep.y ) );
1279  }
1280  else
1281  {
1282  arc_start = VECTOR2D( SCALE_FACTOR( sp.x ), SCALE_FACTOR( -sp.y ) );
1283  angle = -angle;
1284  }
1285 
1286  GRAPHICS_IMPORTER_BUFFER* bufferToUse =
1288  bufferToUse->AddArc( center, arc_start, angle, aWidth );
1289 
1290  VECTOR2D radiusDelta( SCALE_FACTOR( radius ), SCALE_FACTOR( radius ) );
1291 
1292  updateImageLimits( center + radiusDelta );
1293  updateImageLimits( center - radiusDelta );
1294  return;
1295 }
1296 
1297 
1298 #include "tinysplinecpp.h"
1299 
1301 {
1302  #if 0 // Debug only
1303  wxLogMessage("spl deg %d kn %d ctr %d fit %d",
1308  #endif
1309 
1310  unsigned imax = m_curr_entity.m_SplineControlPointList.size();
1311 
1312  if( imax < 2 ) // malformed spline
1313  return;
1314 
1315 #if 0 // set to 1 to approximate the spline by segments between 2 control points
1316  VECTOR2D startpoint( mapX( m_curr_entity.m_SplineControlPointList[0].m_x ),
1318 
1319  for( unsigned int ii = 1; ii < imax; ++ii )
1320  {
1321  VECTOR2D endpoint( mapX( m_curr_entity.m_SplineControlPointList[ii].m_x ),
1323 
1324  if( startpoint != endpoint )
1325  {
1326  m_internalImporter.AddLine( startpoint, endpoint, aWidth );
1327 
1328  updateImageLimits( startpoint );
1329  updateImageLimits( endpoint );
1330 
1331  startpoint = endpoint;
1332  }
1333  }
1334 #else // Use bezier curves, supported by pcbnew, to approximate the spline
1335  std::vector<double> ctrlp;
1336 
1337  for( unsigned ii = 0; ii < imax; ++ii )
1338  {
1339  ctrlp.push_back( m_curr_entity.m_SplineControlPointList[ii].m_x );
1340  ctrlp.push_back( m_curr_entity.m_SplineControlPointList[ii].m_y );
1341  }
1342 
1343  std::vector<double> coords;
1344  try
1345  {
1346  tinyspline::BSpline dxfspline( m_curr_entity.m_SplineControlPointList.size(),
1347  /* coord dim */ 2, m_curr_entity.m_SplineDegree );
1348 
1349  dxfspline.setCtrlp( ctrlp );
1350  dxfspline.setKnots( m_curr_entity.m_SplineKnotsList );
1351  tinyspline::BSpline beziers( dxfspline.toBeziers() );
1352 
1353  coords = beziers.ctrlp();
1354  }
1355  catch( const std::runtime_error& ) //tinyspline throws everything including data validation as runtime errors
1356  {
1357  // invalid spline definition, drop this block
1358  reportMsg( _( "Invalid spline definition encountered" ) );
1359  return;
1360  }
1361 
1362  if( coords.size() % 8 != 0 )
1363  {
1364  // somehow we generated a bad Bezier curve
1365  reportMsg( _( "Invalid Bezier curve created" ) );
1366  return;
1367  }
1368 
1369  // Each Bezier curve uses 4 vertices (a start point, 2 control points and a end point).
1370  // So we can have more than one Bezier curve ( there are one curve each four vertices)
1371  // However, one can have one Bezier curve with end point = ctrl point 2, having only 3
1372  // defined points in list.
1373  for( unsigned ii = 0; ii < coords.size(); ii += 8 )
1374  {
1375  VECTOR2D start( mapX( coords[ii] ), mapY( coords[ii+1] ) );
1376  VECTOR2D bezierControl1( mapX( coords[ii+2] ), mapY( coords[ii+3] ) );
1377  VECTOR2D bezierControl2( mapX( coords[ii+4] ), mapY( coords[ii+5] ) );
1378  VECTOR2D end;
1379 
1380  if( ii+7 < coords.size() )
1381  end = VECTOR2D( mapX( coords[ii+6] ), mapY( coords[ii+7] ) );
1382  else
1383  end = bezierControl2;
1384 
1385  GRAPHICS_IMPORTER_BUFFER* bufferToUse =
1387  bufferToUse->AddSpline( start, bezierControl1, bezierControl2, end, aWidth );
1388  }
1389 #endif
1390 }
1391 
1392 
1394 {
1395  m_minX = std::min( aPoint.x, m_minX );
1396  m_maxX = std::max( aPoint.x, m_maxX );
1397 
1398  m_minY = std::min( aPoint.y, m_minY );
1399  m_maxY = std::max( aPoint.y, m_maxY );
1400 }
1401 
1402 
1404 {
1405  VECTOR3D arbZ, arbX, arbY;
1406 
1407  double direction[3];
1408  aData->getDirection( direction );
1409 
1410  arbZ = VECTOR3D( direction[0], direction[1], direction[2] ).Normalize();
1411 
1412  if( ( abs( arbZ.x ) < ( 1.0 / 64.0 ) ) && ( abs( arbZ.y ) < ( 1.0 / 64.0 ) ) )
1413  {
1414  arbX = VECTOR3D( 0, 1, 0 ).Cross( arbZ ).Normalize();
1415  }
1416  else
1417  {
1418  arbX = VECTOR3D( 0, 0, 1 ).Cross( arbZ ).Normalize();
1419  }
1420 
1421  arbY = arbZ.Cross( arbX ).Normalize();
1422 
1423  return DXF_ARBITRARY_AXIS{ arbX, arbY, arbZ };
1424 }
1425 
1426 
1428 {
1429  double x, y, z;
1430  x = point.x * arbitraryAxis.vecX.x + point.y * arbitraryAxis.vecX.y
1431  + point.z * arbitraryAxis.vecX.z;
1432  y = point.x * arbitraryAxis.vecY.x + point.y * arbitraryAxis.vecY.y
1433  + point.z * arbitraryAxis.vecY.z;
1434  z = point.x * arbitraryAxis.vecZ.x + point.y * arbitraryAxis.vecZ.y
1435  + point.z * arbitraryAxis.vecZ.z;
1436 
1437  return VECTOR3D( x, y, z );
1438 }
1439 
1440 
1442 {
1443  VECTOR3D worldX = wcsToOcs( arbitraryAxis, VECTOR3D( 1, 0, 0 ) );
1444  VECTOR3D worldY = wcsToOcs( arbitraryAxis, VECTOR3D( 0, 1, 0 ) );
1445  VECTOR3D worldZ = wcsToOcs( arbitraryAxis, VECTOR3D( 0, 0, 1 ) );
1446 
1447  double x, y, z;
1448  x = point.x * worldX.x + point.y * worldX.y + point.z * worldX.z;
1449  y = point.x * worldY.x + point.y * worldY.y + point.z * worldY.z;
1450  z = point.x * worldZ.x + point.y * worldZ.y + point.z * worldZ.z;
1451 
1452  return VECTOR3D( x, y, z );
1453 }
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)
Return the import layer data.
virtual void addBlock(const DL_BlockData &) override
Called for each BLOCK in the DXF file.
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)
Converts a given object coordinate point to world coordinate using the given arbitrary axis vectors.
#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:40
bool Load(const wxString &aFileName) override
Load file for import.
unsigned int m_SplineControlCount
double RAD2DEG(double rad)
Definition: trigo.h:230
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)
Return 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)
Return 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)
#define _(s)
static wxString toNativeString(const wxString &aData)
Convert 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)
Converts a given world coordinate point to object coordinate using the given arbitrary axis vectors.
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:56
double GetLineWidthMM() const
Return the line width used for importing the outlines (in mm).
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
virtual void addPoint(const DL_PointData &aData) override
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