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