KiCad PCB EDA Suite
dxf2brd_items.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) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 1992-2018 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 LibreCAD project, a 2D CAD program
26 // libdxfrw can be found on http://sourceforge.net/projects/libdxfrw/
27 // or (latest sources) on
28 // https://github.com/LibreCAD/LibreCAD/tree/master/libraries/libdxfrw/src
29 //
30 // There is no doc to use it, but have a look to
31 // https://github.com/LibreCAD/LibreCAD/blob/master/librecad/src/lib/filters/rs_filterdxf.cpp
32 // and https://github.com/LibreCAD/LibreCAD/blob/master/librecad/src/lib/filters/rs_filterdxf.h
33 // Each time a dxf entity is read, a "call back" fuction is called
34 // like void DXF2BRD_CONVERTER::addLine( const DRW_Line& data ) when a line is read.
35 // this function just add the BOARD entity from dxf parameters (start and end point ...)
36 
37 
38 #include "dxf2brd_items.h"
39 #include <wx/arrstr.h>
40 #include <wx/regex.h>
41 
42 #include <trigo.h>
43 #include <macros.h>
44 #include <class_board.h>
45 #include <class_drawsegment.h>
46 #include <class_edge_mod.h>
47 #include <class_pcb_text.h>
48 #include <class_text_mod.h>
49 #include "common.h"
50 
51 // minimum bulge value before resorting to a line segment;
52 // the value 0.0218 is equivalent to about 5 degrees arc,
53 #define MIN_BULGE 0.0218
54 
55 DXF2BRD_CONVERTER::DXF2BRD_CONVERTER() : DL_CreationAdapter()
56 {
57  m_xOffset = 0.0; // X coord offset for conversion (in mm)
58  m_yOffset = 0.0; // Y coord offset for conversion (in mm)
59  m_DXF2mm = 1.0; // The scale factor to convert DXF units to mm
60  m_version = 0; // the dxf version, not yet used
61  m_defaultThickness = 0.2; // default thickness (in mm)
62  m_brdLayer = Dwgs_User; // The default import layer
64 }
65 
66 
68 {
69 }
70 
71 
72 // coordinate conversions from dxf to internal units
73 int DXF2BRD_CONVERTER::mapX( double aDxfCoordX )
74 {
75  return Millimeter2iu( m_xOffset + ( aDxfCoordX * m_DXF2mm ) );
76 }
77 
78 
79 int DXF2BRD_CONVERTER::mapY( double aDxfCoordY )
80 {
81  return Millimeter2iu( m_yOffset - ( aDxfCoordY * m_DXF2mm ) );
82 }
83 
84 
85 int DXF2BRD_CONVERTER::mapDim( double aDxfValue )
86 {
87  return Millimeter2iu( aDxfValue * m_DXF2mm );
88 }
89 
90 
91 int DXF2BRD_CONVERTER::mapWidth( double aDxfWidth )
92 {
93  // Always return the default line width
94 #if 0
95  // mapWidth returns the aDxfValue if aDxfWidth > 0 m_defaultThickness
96  if( aDxfWidth > 0.0 )
97  return Millimeter2iu( aDxfWidth * m_DXF2mm );
98 #endif
99  return Millimeter2iu( m_defaultThickness );
100 }
101 
102 bool DXF2BRD_CONVERTER::ImportDxfFile( const wxString& aFile )
103 {
104  LOCALE_IO locale;
105 
106  DL_Dxf dxf_reader;
107  std::string filename = TO_UTF8( aFile );
108  bool success = true;
109 
110  if( !dxf_reader.in( filename, this ) ) // if file open failed
111  success = false;
112 
113  return success;
114 }
115 
116 
117 void DXF2BRD_CONVERTER::reportMsg( const char* aMessage )
118 {
119  // Add message to keep trace of not handled dxf entities
120  m_messages += aMessage;
121  m_messages += '\n';
122 }
123 
124 
125 void DXF2BRD_CONVERTER::addSpline( const DL_SplineData& aData )
126 {
127  // Called when starting reading a spline
130  m_curr_entity.m_EntityFlag = aData.flags;
131  m_curr_entity.m_EntityType = DL_ENTITY_SPLINE;
132  m_curr_entity.m_SplineDegree = aData.degree;
133  m_curr_entity.m_SplineTangentStartX = aData.tangentStartX;
134  m_curr_entity.m_SplineTangentStartY = aData.tangentStartY;
135  m_curr_entity.m_SplineTangentEndX = aData.tangentEndX;
136  m_curr_entity.m_SplineTangentEndY = aData.tangentEndY;
137  m_curr_entity.m_SplineKnotsCount = aData.nKnots;
138  m_curr_entity.m_SplineControlCount = aData.nControl;
139  m_curr_entity.m_SplineFitCount = aData.nFit;
140 }
141 
142 
143 void DXF2BRD_CONVERTER::addControlPoint( const DL_ControlPointData& aData )
144 {
145  // Called for every spline control point, when reading a spline entity
146  m_curr_entity.m_SplineControlPointList.push_back( SPLINE_CTRL_POINT( aData.x , aData.y, aData.w ) );
147 }
148 
149 void DXF2BRD_CONVERTER::addFitPoint( const DL_FitPointData& aData )
150 {
151  // Called for every spline fit point, when reading a spline entity
152  // we store only the X,Y coord values in a wxRealPoint
153  m_curr_entity.m_SplineFitPointList.push_back( wxRealPoint( aData.x, aData.y ) );
154 }
155 
156 
157 void DXF2BRD_CONVERTER::addKnot( const DL_KnotData& aData)
158 {
159  // Called for every spline knot value, when reading a spline entity
160  m_curr_entity.m_SplineKnotsList.push_back( aData.k );
161 }
162 
163 
164 void DXF2BRD_CONVERTER::addLayer( const DL_LayerData& aData )
165 {
166  // Not yet useful in Pcbnew.
167 #if 0
168  wxString name = wxString::FromUTF8( aData.name.c_str() );
169  wxLogMessage( name );
170 #endif
171 }
172 
173 
174 void DXF2BRD_CONVERTER::addLine( const DL_LineData& aData )
175 {
177  static_cast< DRAWSEGMENT* >( new EDGE_MODULE( NULL ) ) : new DRAWSEGMENT;
178 
179  segm->SetLayer( ToLAYER_ID( m_brdLayer ) );
180  wxPoint start( mapX( aData.x1 ), mapY( aData.y1 ) );
181  segm->SetStart( start );
182  wxPoint end( mapX( aData.x2 ), mapY( aData.y2 ) );
183  segm->SetEnd( end );
184  segm->SetWidth( mapWidth( attributes.getWidth() ) );
185  m_newItemsList.push_back( segm );
186 }
187 
188 
189 void DXF2BRD_CONVERTER::addPolyline(const DL_PolylineData& aData )
190 {
191  // Convert DXF Polylines into a series of KiCad Lines and Arcs.
192  // A Polyline (as opposed to a LWPolyline) may be a 3D line or
193  // even a 3D Mesh. The only type of Polyline which is guaranteed
194  // to import correctly is a 2D Polyline in X and Y, which is what
195  // we assume of all Polylines. The width used is the width of the Polyline.
196  // per-vertex line widths, if present, are ignored.
197 
200  m_curr_entity.m_EntityFlag = aData.flags;
201  m_curr_entity.m_EntityType = DL_ENTITY_POLYLINE;
202 }
203 
204 
205 void DXF2BRD_CONVERTER::addVertex( const DL_VertexData& aData )
206 {
208  return; // Error
209 
210  int lineWidth = mapWidth( attributes.getWidth() );
211 
212  const DL_VertexData* vertex = &aData;
213 
214  if( m_curr_entity.m_EntityParseStatus == 1 ) // This is the first vertex of an entity
215  {
219  m_curr_entity.m_BulgeVertex = vertex->bulge;
221  return;
222  }
223 
224 
225  wxRealPoint seg_end( m_xOffset + vertex->x * m_DXF2mm,
226  m_yOffset - vertex->y * m_DXF2mm );
227 
229  insertLine( m_curr_entity.m_LastCoordinate, seg_end, lineWidth );
230  else
232 
234  m_curr_entity.m_BulgeVertex = vertex->bulge;
235 }
236 
237 
239 {
240  if( m_curr_entity.m_EntityType == DL_ENTITY_POLYLINE ||
241  m_curr_entity.m_EntityType == DL_ENTITY_LWPOLYLINE )
242  {
243  // Polyline flags bit 0 indicates closed (1) or open (0) polyline
244  if( m_curr_entity.m_EntityFlag & 1 )
245  {
246  int lineWidth = mapWidth( attributes.getWidth() );
247 
250  else
252  m_curr_entity.m_BulgeVertex, lineWidth );
253  }
254  }
255 
256  if( m_curr_entity.m_EntityType == DL_ENTITY_SPLINE )
257  {
258  int lineWidth = mapWidth( attributes.getWidth() );
259  insertSpline( lineWidth );
260  }
261 
263 }
264 
265 
266 void DXF2BRD_CONVERTER::addCircle( const DL_CircleData& aData )
267 {
269  static_cast< DRAWSEGMENT* >( new EDGE_MODULE( NULL ) ) : new DRAWSEGMENT;
270 
271  segm->SetLayer( ToLAYER_ID( m_brdLayer ) );
272  segm->SetShape( S_CIRCLE );
273  wxPoint center( mapX( aData.cx ), mapY( aData.cy ) );
274  segm->SetCenter( center );
275  wxPoint circle_start( mapX( aData.cx + aData.radius ), mapY( aData.cy ) );
276  segm->SetArcStart( circle_start );
277  segm->SetWidth( mapWidth( attributes.getWidth() ) );
278  m_newItemsList.push_back( segm );
279 }
280 
281 
282 /*
283  * Import Arc entities.
284  */
285 void DXF2BRD_CONVERTER::addArc( const DL_ArcData& aData )
286 {
288  static_cast< DRAWSEGMENT* >( new EDGE_MODULE( NULL ) ) : new DRAWSEGMENT;
289 
290  segm->SetLayer( ToLAYER_ID( m_brdLayer ) );
291  segm->SetShape( S_ARC );
292 
293  // Init arc centre:
294  wxPoint center( mapX( aData.cx ), mapY( aData.cy ) );
295  segm->SetCenter( center );
296 
297  // Init arc start point
298  double arcStartx = aData.radius;
299  double arcStarty = 0;
300 
301  // aData.anglex is in degrees. Our internal units are 0.1 degree
302  // so convert DXF angles to our units
303  #define DXF2ANGLEUI 10
304  double startangle = aData.angle1 * DXF2ANGLEUI;
305  double endangle = aData.angle2 * DXF2ANGLEUI;
306 
307  RotatePoint( &arcStartx, &arcStarty, -startangle );
308  wxPoint arcStart( mapX( arcStartx + aData.cx ),
309  mapY( arcStarty + aData.cy ) );
310  segm->SetArcStart( arcStart );
311 
312  // calculate arc angle (arcs are CCW, and should be < 0 in Pcbnew)
313  double angle = -( endangle - startangle );
314 
315  if( angle > 0.0 )
316  angle -= 3600.0;
317 
318  segm->SetAngle( angle );
319 
320  segm->SetWidth( mapWidth( attributes.getWidth() ) );
321  m_newItemsList.push_back( segm );
322 }
323 
324 
325 void DXF2BRD_CONVERTER::addText( const DL_TextData& aData )
326 {
327  BOARD_ITEM* brdItem;
328  EDA_TEXT* textItem;
329 
331  {
332  TEXTE_MODULE* modText = new TEXTE_MODULE( NULL );
333  brdItem = static_cast< BOARD_ITEM* >( modText );
334  textItem = static_cast< EDA_TEXT* >( modText );
335  }
336  else
337  {
338  TEXTE_PCB* pcbText = new TEXTE_PCB( NULL );
339  brdItem = static_cast< BOARD_ITEM* >( pcbText );
340  textItem = static_cast< EDA_TEXT* >( pcbText );
341  }
342 
343  brdItem->SetLayer( ToLAYER_ID( m_brdLayer ) );
344 
345  wxPoint refPoint( mapX( aData.ipx ), mapY( aData.ipy ) );
346  wxPoint secPoint( mapX( aData.apx ), mapY( aData.apy ) );
347 
348  if( aData.vJustification != 0 || aData.hJustification != 0 || aData.hJustification == 4 )
349  {
350  if( aData.hJustification != 3 && aData.hJustification != 5 )
351  {
352  wxPoint tmp = secPoint;
353  secPoint = refPoint;
354  refPoint = tmp;
355  }
356  }
357 
358  switch( aData.vJustification )
359  {
360  case 0: //DRW_Text::VBaseLine:
362  break;
363 
364  case 1: //DRW_Text::VBottom:
366  break;
367 
368  case 2: //DRW_Text::VMiddle:
370  break;
371 
372  case 3: //DRW_Text::VTop:
374  break;
375  }
376 
377  switch( aData.hJustification )
378  {
379  case 0: //DRW_Text::HLeft:
381  break;
382 
383  case 1: //DRW_Text::HCenter:
385  break;
386 
387  case 2: //DRW_Text::HRight:
389  break;
390 
391  case 3: //DRW_Text::HAligned:
392  // no equivalent options in text pcb.
394  break;
395 
396  case 4: //DRW_Text::HMiddle:
397  // no equivalent options in text pcb.
399  break;
400 
401  case 5: //DRW_Text::HFit:
402  // no equivalent options in text pcb.
404  break;
405  }
406 
407 #if 0
408  wxString sty = wxString::FromUTF8( aData.style.c_str() );
409  sty = sty.ToLower();
410 
411  if( aData.textgen == 2 )
412  {
413  // Text dir = left to right;
414  } else if( aData.textgen == 4 )
415  {
416  // Text dir = top to bottom;
417  } else
418  {
419  }
420 #endif
421 
422  wxString text = toNativeString( wxString::FromUTF8( aData.text.c_str() ) );
423 
424  textItem->SetTextPos( refPoint );
425  textItem->SetTextAngle( aData.angle * 10 );
426 
427  // The 0.8 factor gives a better height/width ratio with our font
428  textItem->SetTextWidth( mapDim( aData.height * 0.8 ) );
429  textItem->SetTextHeight( mapDim( aData.height ) );
430  textItem->SetThickness( mapWidth( aData.height * DEFAULT_TEXT_WIDTH ) ); // Gives a reasonable text thickness
431  textItem->SetText( text );
432 
433  m_newItemsList.push_back( static_cast< BOARD_ITEM* >( brdItem ) );
434 }
435 
436 
437 void DXF2BRD_CONVERTER::addMText( const DL_MTextData& aData )
438 {
439  wxString text = toNativeString( wxString::FromUTF8( aData.text.c_str() ) );
440  wxString attrib, tmp;
441 
442  /* Some texts start by '\' and have formating chars (font name, font option...)
443  * ending with ';'
444  * Here are some mtext formatting codes:
445  * Format code Purpose
446  * \0...\o Turns overline on and off
447  * \L...\l Turns underline on and off
448  * \~ Inserts a nonbreaking space
449  \\ Inserts a backslash
450  \\\{...\} Inserts an opening and closing brace
451  \\ \File name; Changes to the specified font file
452  \\ \Hvalue; Changes to the text height specified in drawing units
453  \\ \Hvaluex; Changes the text height to a multiple of the current text height
454  \\ \S...^...; Stacks the subsequent text at the \, #, or ^ symbol
455  \\ \Tvalue; Adjusts the space between characters, from.75 to 4 times
456  \\ \Qangle; Changes obliquing angle
457  \\ \Wvalue; Changes width factor to produce wide text
458  \\ \A Sets the alignment value; valid values: 0, 1, 2 (bottom, center, top) while( text.StartsWith( wxT("\\") ) )
459  */
460  while( text.StartsWith( wxT( "\\" ) ) )
461  {
462  attrib << text.BeforeFirst( ';' );
463  tmp = text.AfterFirst( ';' );
464  text = tmp;
465  }
466 
467  BOARD_ITEM* brdItem;
468  EDA_TEXT* textItem;
469 
471  {
472  TEXTE_MODULE* modText = new TEXTE_MODULE( NULL );
473  brdItem = static_cast< BOARD_ITEM* >( modText );
474  textItem = static_cast< EDA_TEXT* >( modText );
475  }
476  else
477  {
478  TEXTE_PCB* pcbText = new TEXTE_PCB( NULL );
479  brdItem = static_cast< BOARD_ITEM* >( pcbText );
480  textItem = static_cast< EDA_TEXT* >( pcbText );
481  }
482 
483  brdItem->SetLayer( ToLAYER_ID( m_brdLayer ) );
484  wxPoint textpos( mapX( aData.ipx ), mapY( aData.ipy ) );
485 
486  textItem->SetTextPos( textpos );
487  textItem->SetTextAngle( aData.angle * 10 );
488 
489  // The 0.8 factor gives a better height/width ratio with our font
490  textItem->SetTextWidth( mapDim( aData.height * 0.8 ) );
491  textItem->SetTextHeight( mapDim( aData.height ) );
492  textItem->SetThickness( mapWidth( aData.height * DEFAULT_TEXT_WIDTH ) ); // Gives a reasonable text thickness
493  textItem->SetText( text );
494 
495  // Initialize text justifications:
496  if( aData.attachmentPoint <= 3 )
497  {
499  }
500  else if( aData.attachmentPoint <= 6 )
501  {
503  }
504  else
505  {
507  }
508 
509  if( aData.attachmentPoint % 3 == 1 )
510  {
512  }
513  else if( aData.attachmentPoint % 3 == 2 )
514  {
516  }
517  else
518  {
520  }
521 
522 #if 0 // These setting have no meaning in Pcbnew
523  if( data.alignH == 1 )
524  {
525  // Text is left to right;
526  }
527  else if( data.alignH == 3 )
528  {
529  // Text is top to bottom;
530  }
531  else
532  {
533  // use ByStyle;
534  }
535 
536  if( aData.alignV == 1 )
537  {
538  // use AtLeast;
539  }
540  else
541  {
542  // useExact;
543  }
544 #endif
545 
546  m_newItemsList.push_back( static_cast< BOARD_ITEM* >( brdItem ) );
547 }
548 
549 
550 void DXF2BRD_CONVERTER::setVariableInt( const std::string& key, int value, int code )
551 {
552  // Called for every int variable in the DXF file (e.g. "$INSUNITS").
553 
554  if( key == "$DWGCODEPAGE" )
555  {
556  m_codePage = value;
557  return;
558  }
559 
560  if( key == "$INSUNITS" ) // Drawing units
561  {
562  switch( value )
563  {
564  case 1: // inches
565  m_DXF2mm = 25.4;
566  break;
567 
568  case 2: // feet
569  m_DXF2mm = 304.8;
570  break;
571 
572  case 4: // mm
573  m_DXF2mm = 1.0;
574  break;
575 
576  case 5: // centimeters
577  m_DXF2mm = 10.0;
578  break;
579 
580  case 6: // meters
581  m_DXF2mm = 1000.0;
582  break;
583 
584  case 8: // microinches
585  m_DXF2mm = 2.54e-5;
586  break;
587 
588  case 9: // mils
589  m_DXF2mm = 0.0254;
590  break;
591 
592  case 10: // yards
593  m_DXF2mm = 914.4;
594  break;
595 
596  case 11: // Angstroms
597  m_DXF2mm = 1.0e-7;
598  break;
599 
600  case 12: // nanometers
601  m_DXF2mm = 1.0e-6;
602  break;
603 
604  case 13: // micrometers
605  m_DXF2mm = 1.0e-3;
606  break;
607 
608  case 14: // decimeters
609  m_DXF2mm = 100.0;
610  break;
611 
612  default:
613  // use the default of 1.0 for:
614  // 0: Unspecified Units
615  // 3: miles
616  // 7: kilometers
617  // 15: decameters
618  // 16: hectometers
619  // 17: gigameters
620  // 18: AU
621  // 19: lightyears
622  // 20: parsecs
623  m_DXF2mm = 1.0;
624  break;
625  }
626 
627  return;
628  }
629 }
630 
631 
632 void DXF2BRD_CONVERTER::setVariableString( const std::string& key, const std::string& value,
633  int code )
634 {
635  // Called for every string variable in the DXF file (e.g. "$ACADVER").
636 }
637 
638 
639 wxString DXF2BRD_CONVERTER::toDxfString( const wxString& aStr )
640 {
641  wxString res;
642  int j = 0;
643 
644  for( unsigned i = 0; i<aStr.length(); ++i )
645  {
646  int c = aStr[i];
647 
648  if( c > 175 || c < 11 )
649  {
650  res.append( aStr.Mid( j, i - j ) );
651  j = i;
652 
653  switch( c )
654  {
655  case 0x0A:
656  res += wxT( "\\P" );
657  break;
658 
659  // diameter:
660 #ifdef __WINDOWS_
661  // windows, as always, is special.
662  case 0x00D8:
663 #else
664  case 0x2205:
665 #endif
666  res += wxT( "%%C" );
667  break;
668 
669  // degree:
670  case 0x00B0:
671  res += wxT( "%%D" );
672  break;
673 
674  // plus/minus
675  case 0x00B1:
676  res += wxT( "%%P" );
677  break;
678 
679  default:
680  j--;
681  break;
682  }
683 
684  j++;
685  }
686  }
687 
688  res.append( aStr.Mid( j ) );
689  return res;
690 }
691 
692 
693 wxString DXF2BRD_CONVERTER::toNativeString( const wxString& aData )
694 {
695  wxString res;
696 
697  // Ignore font tags:
698  int j = 0;
699 
700  for( unsigned i = 0; i < aData.length(); ++i )
701  {
702  if( aData[ i ] == 0x7B ) // is '{' ?
703  {
704  if( aData[ i + 1 ] == 0x5c && aData[ i + 2 ] == 0x66 ) // is "\f" ?
705  {
706  // found font tag, append parsed part
707  res.append( aData.Mid( j, i - j ) );
708 
709  // skip to ';'
710  for( unsigned k = i + 3; k < aData.length(); ++k )
711  {
712  if( aData[ k ] == 0x3B )
713  {
714  i = j = ++k;
715  break;
716  }
717  }
718 
719  // add to '}'
720  for( unsigned k = i; k < aData.length(); ++k )
721  {
722  if( aData[ k ] == 0x7D )
723  {
724  res.append( aData.Mid( i, k - i ) );
725  i = j = ++k;
726  break;
727  }
728  }
729  }
730  }
731  }
732 
733  res.append( aData.Mid( j ) );
734 
735 #if 1
736  wxRegEx regexp;
737  // Line feed:
738  regexp.Compile( wxT( "\\\\P" ) );
739  regexp.Replace( &res, wxT( "\n" ) );
740 
741  // Space:
742  regexp.Compile( wxT( "\\\\~" ) );
743  regexp.Replace( &res, wxT( " " ) );
744 
745  // diameter:
746  regexp.Compile( wxT( "%%[cC]" ) );
747 #ifdef __WINDOWS__
748  // windows, as always, is special.
749  regexp.Replace( &res, wxChar( 0xD8 ) );
750 #else
751  // Empty_set, diameter is 0x2300
752  regexp.Replace( &res, wxChar( 0x2205 ) );
753 #endif
754 
755  // degree:
756  regexp.Compile( wxT( "%%[dD]" ) );
757  regexp.Replace( &res, wxChar( 0x00B0 ) );
758  // plus/minus
759  regexp.Compile( wxT( "%%[pP]" ) );
760  regexp.Replace( &res, wxChar( 0x00B1 ) );
761 #endif
762 
763  return res;
764 }
765 
766 
767 void DXF2BRD_CONVERTER::addTextStyle( const DL_StyleData& aData )
768 {
769  // TODO
770 }
771 
772 
773 void DXF2BRD_CONVERTER::insertLine( const wxRealPoint& aSegStart,
774  const wxRealPoint& aSegEnd, int aWidth )
775 {
777  static_cast< DRAWSEGMENT* >( new EDGE_MODULE( NULL ) ) : new DRAWSEGMENT;
778  wxPoint segment_startpoint( Millimeter2iu( aSegStart.x ), Millimeter2iu( aSegStart.y ) );
779  wxPoint segment_endpoint( Millimeter2iu( aSegEnd.x ), Millimeter2iu( aSegEnd.y ) );
780 
781  segm->SetLayer( ToLAYER_ID( m_brdLayer ) );
782  segm->SetStart( segment_startpoint );
783  segm->SetEnd( segment_endpoint );
784  segm->SetWidth( aWidth );
785 
786  m_newItemsList.push_back( segm );
787 }
788 
789 
790 void DXF2BRD_CONVERTER::insertArc( const wxRealPoint& aSegStart, const wxRealPoint& aSegEnd,
791  double aBulge, int aWidth )
792 {
794  static_cast< DRAWSEGMENT* >( new EDGE_MODULE( NULL ) ) : new DRAWSEGMENT;
795 
796  wxPoint segment_startpoint( Millimeter2iu( aSegStart.x ), Millimeter2iu( aSegStart.y ) );
797  wxPoint segment_endpoint( Millimeter2iu( aSegEnd.x ), Millimeter2iu( aSegEnd.y ) );
798 
799  // ensure aBulge represents an angle from +/- ( 0 .. approx 359.8 deg )
800  if( aBulge < -2000.0 )
801  aBulge = -2000.0;
802  else if( aBulge > 2000.0 )
803  aBulge = 2000.0;
804 
805  double ang = 4.0 * atan( aBulge );
806 
807  // reflect the Y values to put everything in a RHCS
808  wxRealPoint sp( aSegStart.x, -aSegStart.y );
809  wxRealPoint ep( aSegEnd.x, -aSegEnd.y );
810  // angle from end->start
811  double offAng = atan2( ep.y - sp.y, ep.x - sp.x );
812  // length of subtended segment = 1/2 distance between the 2 points
813  double d = 0.5 * sqrt( (sp.x - ep.x) * (sp.x - ep.x) + (sp.y - ep.y) * (sp.y - ep.y) );
814  // midpoint of the subtended segment
815  double xm = ( sp.x + ep.x ) * 0.5;
816  double ym = ( sp.y + ep.y ) * 0.5;
817  double radius = d / sin( ang * 0.5 );
818 
819  if( radius < 0.0 )
820  radius = -radius;
821 
822  // calculate the height of the triangle with base d and hypotenuse r
823  double dh2 = radius * radius - d * d;
824 
825  // this should only ever happen due to rounding errors when r == d
826  if( dh2 < 0.0 )
827  dh2 = 0.0;
828 
829  double h = sqrt( dh2 );
830 
831  if( ang < 0.0 )
832  offAng -= M_PI_2;
833  else
834  offAng += M_PI_2;
835 
836  // for angles greater than 180 deg we need to flip the
837  // direction in which the arc center is found relative
838  // to the midpoint of the subtended segment.
839  if( ang < -M_PI )
840  offAng += M_PI;
841  else if( ang > M_PI )
842  offAng -= M_PI;
843 
844  // center point
845  double cx = h * cos( offAng ) + xm;
846  double cy = h * sin( offAng ) + ym;
847 
848  segm->SetLayer( ToLAYER_ID( m_brdLayer ) );
849  segm->SetShape( S_ARC );
850  segm->SetCenter( wxPoint( Millimeter2iu( cx ), Millimeter2iu( -cy ) ) );
851 
852  if( ang < 0.0 )
853  {
854  segm->SetArcStart( wxPoint( Millimeter2iu( ep.x ), Millimeter2iu( -ep.y ) ) );
855  segm->SetAngle( RAD2DECIDEG( ang ) );
856  }
857  else
858  {
859  segm->SetArcStart( wxPoint( Millimeter2iu( sp.x ), Millimeter2iu( -sp.y ) ) );
860  segm->SetAngle( RAD2DECIDEG( -ang ) );
861  }
862 
863  segm->SetWidth( aWidth );
864 
865  m_newItemsList.push_back( segm );
866  return;
867 }
868 
869 
870 #include "tinyspline_lib/tinysplinecpp.h"
871 
873 {
874  #if 0 // Debug only
875  wxLogMessage("spl deg %d kn %d ctr %d fit %d",
880  #endif
881 
882  // Very basic conversion to segments
883  unsigned imax = m_curr_entity.m_SplineControlPointList.size();
884 
885  if( imax < 2 ) // malformed spline
886  return;
887 
888 #if 0 // set to 1 to approximate the spline by segments between 2 control points
889  wxPoint startpoint( mapX( m_curr_entity.m_SplineControlPointList[0].m_x ),
891 
892  for( unsigned int ii = 1; ii < imax; ++ii )
893  {
894  wxPoint endpoint( mapX( m_curr_entity.m_SplineControlPointList[ii].m_x ),
896 
897  if( startpoint != endpoint )
898  {
900  static_cast< DRAWSEGMENT* >( new EDGE_MODULE( NULL ) ) :
901  new DRAWSEGMENT;
902  segm->SetLayer( ToLAYER_ID( m_brdLayer ) );
903  segm->SetStart( startpoint );
904  segm->SetEnd( endpoint );
905  segm->SetWidth( aWidth );
906  m_newItemsList.push_back( segm );
907  startpoint = endpoint;
908  }
909  }
910 #else // Use bezier curves, supported by pcbnew, to approximate the spline
911  tinyspline::BSpline dxfspline( m_curr_entity.m_SplineControlPointList.size(),
912  /* coord dim */ 2, m_curr_entity.m_SplineDegree );
913  std::vector<double> ctrlp;
914 
915  for( unsigned ii = 0; ii < imax; ++ii )
916  {
917  ctrlp.push_back( m_curr_entity.m_SplineControlPointList[ii].m_x );
918  ctrlp.push_back( m_curr_entity.m_SplineControlPointList[ii].m_y );
919  }
920 
921  dxfspline.setCtrlp( ctrlp );
922  dxfspline.setKnots( m_curr_entity.m_SplineKnotsList );
923  tinyspline::BSpline beziers( dxfspline.toBeziers() );
924 
925  std::vector<double> coords = beziers.ctrlp();
926 
927  // Each Bezier curve uses 4 vertices (a start point, 2 control points and a end point).
928  // So we can have more than one Bezier curve ( there are one curve each four vertices)
929  for( unsigned ii = 0; ii < coords.size(); ii += 8 )
930  {
932  static_cast< DRAWSEGMENT* >( new EDGE_MODULE( NULL ) ) :
933  new DRAWSEGMENT;
934  segm->SetLayer( ToLAYER_ID( m_brdLayer ) );
935  segm->SetShape( S_CURVE );
936  segm->SetStart( wxPoint( mapX( coords[ii] ), mapY( coords[ii+1] ) ) );
937  segm->SetBezControl1( wxPoint( mapX( coords[ii+2] ), mapY( coords[ii+3] ) ) );
938  segm->SetBezControl2( wxPoint( mapX( coords[ii+4] ), mapY( coords[ii+5] ) ) );
939  segm->SetEnd( wxPoint( mapX( coords[ii+6] ), mapY( coords[ii+7] ) ) );
940  segm->SetWidth( aWidth );
941  segm->RebuildBezierToSegmentsPointsList( aWidth );
942  m_newItemsList.push_back( segm );
943  }
944 #endif
945 }
946 
void SetTextAngle(double aAngle)
Definition: eda_text.h:169
wxRealPoint m_PolylineStart
Definition: dxf2brd_items.h:65
bool m_importAsfootprintGraphicItems
#define DXF2ANGLEUI
void SetShape(STROKE_T aShape)
virtual void addCircle(const DL_CircleData &aData) override
TEXTE_PCB class definition.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown...
Definition: common.h:179
void SetArcStart(const wxPoint &aArcStartPoint)
Initialize the start arc point.
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class...
wxRealPoint m_LastCoordinate
Definition: dxf2brd_items.h:64
unsigned int m_SplineFitCount
Definition: dxf2brd_items.h:72
Class BOARD to handle a board.
std::string m_codePage
void insertSpline(int aWidth)
std::vector< wxRealPoint > m_SplineFitPointList
Definition: dxf2brd_items.h:83
unsigned int m_SplineControlCount
Definition: dxf2brd_items.h:71
void RebuildBezierToSegmentsPointsList(int aMinSegLen)
Rebuild the m_BezierPoints vertex list that approximate the Bezier curve by a list of segments Has me...
A helper class to store a spline control point (in X,Y plane only)
Definition: dxf2brd_items.h:40
void SetTextPos(const wxPoint &aPoint)
Definition: eda_text.h:236
static wxString toDxfString(const wxString &aStr)
Converts a native unicode string into a DXF encoded string.
double RAD2DECIDEG(double rad)
Definition: trigo.h:204
void insertArc(const wxRealPoint &aSegStart, const wxRealPoint &aSegEnd, double aBulge, int aWidth)
static wxString toNativeString(const wxString &aData)
Converts a DXF encoded string into a native Unicode string.
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:216
virtual void addVertex(const DL_VertexData &aData) override
Called for every polyline vertex.
void SetCenter(const wxPoint &aCenterPoint)
For arcs and circles:
#define abs(a)
Definition: auxiliary.h:84
void SetBezControl2(const wxPoint &aPoint)
int mapDim(double aDxfValue)
virtual void addLine(const DL_LineData &aData) override
This file contains miscellaneous commonly used macros and functions.
void reportMsg(const char *aMessage)
Class EDA_TEXT is a mix-in class (via multiple inheritance) that handles texts such as labels...
Definition: eda_text.h:127
#define DEFAULT_TEXT_WIDTH
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes...
Definition: macros.h:47
virtual void addLayer(const DL_LayerData &aData) override
int mapY(double aDxfCoordY)
std::string m_messages
Footprint text class description.
std::list< BOARD_ITEM * > m_newItemsList
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:207
Arcs (with rounded ends)
unsigned int m_SplineKnotsCount
Definition: dxf2brd_items.h:70
unsigned int m_SplineDegree
Definition: dxf2brd_items.h:69
bool ImportDxfFile(const wxString &aFile)
Implementation of the method used for communicate with this filter.
virtual void addControlPoint(const DL_ControlPointData &aData) override
Called for every spline control point.
int mapX(double aDxfCoordX)
virtual void addMText(const DL_MTextData &aData) override
Bezier Curve.
#define MIN_BULGE
double m_SplineTangentStartX
Definition: dxf2brd_items.h:73
void SetStart(const wxPoint &aStart)
virtual void addFitPoint(const DL_FitPointData &aData) override
Called for every spline fit point.
virtual void addArc(const DL_ArcData &aData) override
void SetTextWidth(int aWidth)
Definition: eda_text.h:230
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.
void insertLine(const wxRealPoint &aSegStart, const wxRealPoint &aSegEnd, int aWidth)
virtual void addPolyline(const DL_PolylineData &aData) override
virtual void endEntity() override
Class to handle a graphic segment.
const char * name
Definition: DXF_plotter.cpp:61
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:206
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
size_t i
Definition: json11.cpp:597
void SetTextHeight(int aHeight)
Definition: eda_text.h:233
The common library.
void SetEnd(const wxPoint &aEnd)
void SetAngle(double aAngle)
Function SetAngle sets the angle for arcs, and normalizes it within the range 0 - 360 degrees...
virtual void addTextStyle(const DL_StyleData &aData) override
virtual void setVariableInt(const std::string &key, int value, int code) override
Called for every int variable in the DXF file (e.g.
int mapWidth(double aDxfWidth)
EDGE_MODULE class definition.
virtual void addText(const DL_TextData &aData) override
std::vector< double > m_SplineKnotsList
Definition: dxf2brd_items.h:79
virtual void addSpline(const DL_SplineData &aData) override
Called for every spline.
virtual void addKnot(const DL_KnotData &aData) override
Called for every spline knot value.
std::vector< SPLINE_CTRL_POINT > m_SplineControlPointList
Definition: dxf2brd_items.h:81
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:810
double m_SplineTangentStartY
Definition: dxf2brd_items.h:74
void SetThickness(int aNewThickness)
Function SetThickness sets pen width.
Definition: eda_text.h:161
void SetBezControl1(const wxPoint &aPoint)
virtual void SetText(const wxString &aText)
Definition: eda_text.h:154
DXF2BRD_ENTITY_DATA m_curr_entity
void SetWidth(int aWidth)