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) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 1992-2016 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 "libdxfrw.h"
39 #include "dxf2brd_items.h"
40 #include <wx/arrstr.h>
41 #include <wx/regex.h>
42 
43 #include <trigo.h>
44 #include <macros.h>
45 #include <class_board.h>
46 #include <class_drawsegment.h>
47 #include <class_edge_mod.h>
48 #include <class_pcb_text.h>
49 #include <class_text_mod.h>
50 #include "common.h"
51 #include <drw_base.h>
52 
53 // minimum bulge value before resorting to a line segment;
54 // the value 0.0218 is equivalent to about 5 degrees arc,
55 #define MIN_BULGE 0.0218
56 
58 {
59  m_xOffset = 0.0; // X coord offset for conversion (in mm)
60  m_yOffset = 0.0; // Y coord offset for conversion (in mm)
61  m_DXF2mm = 1.0; // The scale factor to convert DXF units to mm
62  m_version = 0; // the dxf version, not yet used
63  m_brdLayer = Dwgs_User; // The default import layer
65 }
66 
67 
69 {
70 }
71 
72 
73 // coordinate conversions from dxf to internal units
74 int DXF2BRD_CONVERTER::mapX( double aDxfCoordX )
75 {
76  return Millimeter2iu( m_xOffset + ( aDxfCoordX * m_DXF2mm ) );
77 }
78 
79 
80 int DXF2BRD_CONVERTER::mapY( double aDxfCoordY )
81 {
82  return Millimeter2iu( m_yOffset - ( aDxfCoordY * m_DXF2mm ) );
83 }
84 
85 
86 int DXF2BRD_CONVERTER::mapDim( double aDxfValue )
87 {
88  return Millimeter2iu( aDxfValue * m_DXF2mm );
89 }
90 
91 
92 int DXF2BRD_CONVERTER::mapWidth( double aDxfWidth )
93 {
94  // mapWidth returns the aDxfValue if aDxfWidth > 0 m_defaultThickness
95  if( aDxfWidth > 0.0 )
96  return Millimeter2iu( aDxfWidth * m_DXF2mm );
97 
98  return Millimeter2iu( m_defaultThickness );
99 }
100 
101 bool DXF2BRD_CONVERTER::ImportDxfFile( const wxString& aFile )
102 {
103  LOCALE_IO locale;
104  dxfRW* dxf = new dxfRW( aFile.ToUTF8() );
105  bool success = dxf->read( this, true );
106 
107  delete dxf;
108 
109  return success;
110 }
111 
112 
113 void DXF2BRD_CONVERTER::addLayer( const DRW_Layer& aData )
114 {
115  // Not yet useful in Pcbnew.
116 #if 0
117  wxString name = wxString::FromUTF8( aData.name.c_str() );
118  wxLogMessage( name );
119 #endif
120 }
121 
122 
123 void DXF2BRD_CONVERTER::addLine( const DRW_Line& aData )
124 {
126  static_cast< DRAWSEGMENT* >( new EDGE_MODULE( NULL ) ) : new DRAWSEGMENT;
127 
128  segm->SetLayer( ToLAYER_ID( m_brdLayer ) );
129  wxPoint start( mapX( aData.basePoint.x ), mapY( aData.basePoint.y ) );
130  segm->SetStart( start );
131  wxPoint end( mapX( aData.secPoint.x ), mapY( aData.secPoint.y ) );
132  segm->SetEnd( end );
133  segm->SetWidth( mapWidth( aData.thickness ) );
134  m_newItemsList.push_back( segm );
135 }
136 
137 void DXF2BRD_CONVERTER::addPolyline(const DRW_Polyline& aData )
138 {
139  // Convert DXF Polylines into a series of KiCad Lines and Arcs.
140  // A Polyline (as opposed to a LWPolyline) may be a 3D line or
141  // even a 3D Mesh. The only type of Polyline which is guaranteed
142  // to import correctly is a 2D Polyline in X and Y, which is what
143  // we assume of all Polylines. The width used is the width of the
144  // Polyline; per-vertex line widths, if present, are ignored.
145 
146  wxRealPoint seg_start;
147  wxRealPoint poly_start;
148  double bulge = 0.0;
149  int lineWidth = mapWidth( aData.thickness );
150 
151  for( unsigned ii = 0; ii < aData.vertlist.size(); ii++ )
152  {
153  DRW_Vertex* vertex = aData.vertlist[ii];
154 
155  if( ii == 0 )
156  {
157  seg_start.x = m_xOffset + vertex->basePoint.x * m_DXF2mm;
158  seg_start.y = m_yOffset - vertex->basePoint.y * m_DXF2mm;
159  bulge = vertex->bulge;
160  poly_start = seg_start;
161  continue;
162  }
163 
164  wxRealPoint seg_end( m_xOffset + vertex->basePoint.x * m_DXF2mm,
165  m_yOffset - vertex->basePoint.y * m_DXF2mm );
166 
167  if( std::abs( bulge ) < MIN_BULGE )
168  insertLine( seg_start, seg_end, lineWidth );
169  else
170  insertArc( seg_start, seg_end, bulge, lineWidth );
171 
172  bulge = vertex->bulge;
173  seg_start = seg_end;
174  }
175 
176  // LWPolyline flags bit 0 indicates closed (1) or open (0) polyline
177  if( aData.flags & 1 )
178  {
179  if( std::abs( bulge ) < MIN_BULGE )
180  insertLine( seg_start, poly_start, lineWidth );
181  else
182  insertArc( seg_start, poly_start, bulge, lineWidth );
183  }
184 }
185 
186 
187 void DXF2BRD_CONVERTER::addLWPolyline(const DRW_LWPolyline& aData )
188 {
189  // Currently, Pcbnew does not know polylines, for boards.
190  // So we have to convert a polyline to a set of segments.
191  // The import is a simplified import: the width of segment is
192  // (obviously constant and is the width of the DRW_LWPolyline.
193  // the variable width of each vertex (when exists) is not used.
194  wxRealPoint seg_start;
195  wxRealPoint poly_start;
196  double bulge = 0.0;
197  int lineWidth = mapWidth( aData.thickness );
198 
199  for( unsigned ii = 0; ii < aData.vertlist.size(); ii++ )
200  {
201  DRW_Vertex2D* vertex = aData.vertlist[ii];
202 
203  if( ii == 0 )
204  {
205  seg_start.x = m_xOffset + vertex->x * m_DXF2mm;
206  seg_start.y = m_yOffset - vertex->y * m_DXF2mm;
207  bulge = vertex->bulge;
208  poly_start = seg_start;
209  continue;
210  }
211 
212  wxRealPoint seg_end( m_xOffset + vertex->x * m_DXF2mm, m_yOffset - vertex->y * m_DXF2mm );
213 
214  if( std::abs( bulge ) < MIN_BULGE )
215  insertLine( seg_start, seg_end, lineWidth );
216  else
217  insertArc( seg_start, seg_end, bulge, lineWidth );
218 
219  bulge = vertex->bulge;
220  seg_start = seg_end;
221  }
222 
223  // LWPolyline flags bit 0 indicates closed (1) or open (0) polyline
224  if( aData.flags & 1 )
225  {
226  if( std::abs( bulge ) < MIN_BULGE )
227  insertLine( seg_start, poly_start, lineWidth );
228  else
229  insertArc( seg_start, poly_start, bulge, lineWidth );
230  }
231 }
232 
233 
234 void DXF2BRD_CONVERTER::addCircle( const DRW_Circle& aData )
235 {
237  static_cast< DRAWSEGMENT* >( new EDGE_MODULE( NULL ) ) : new DRAWSEGMENT;
238 
239  segm->SetLayer( ToLAYER_ID( m_brdLayer ) );
240  segm->SetShape( S_CIRCLE );
241  wxPoint center( mapX( aData.basePoint.x ), mapY( aData.basePoint.y ) );
242  segm->SetCenter( center );
243  wxPoint circle_start( mapX( aData.basePoint.x + aData.radious ), mapY( aData.basePoint.y ) );
244  segm->SetArcStart( circle_start );
245  segm->SetWidth( mapWidth( aData.thickness ) );
246  m_newItemsList.push_back( segm );
247 }
248 
249 
250 /*
251  * Import Arc entities.
252  */
253 void DXF2BRD_CONVERTER::addArc( const DRW_Arc& data )
254 {
256  static_cast< DRAWSEGMENT* >( new EDGE_MODULE( NULL ) ) : new DRAWSEGMENT;
257 
258  segm->SetLayer( ToLAYER_ID( m_brdLayer ) );
259  segm->SetShape( S_ARC );
260 
261  // Init arc centre:
262  wxPoint center( mapX( data.basePoint.x ), mapY( data.basePoint.y ) );
263  segm->SetCenter( center );
264 
265  // Init arc start point
266  double arcStartx = data.radious;
267  double arcStarty = 0;
268  double startangle = data.staangle;
269  double endangle = data.endangle;
270 
271  RotatePoint( &arcStartx, &arcStarty, -RAD2DECIDEG( startangle ) );
272  wxPoint arcStart( mapX( arcStartx + data.basePoint.x ),
273  mapY( arcStarty + data.basePoint.y ) );
274  segm->SetArcStart( arcStart );
275 
276  // calculate arc angle (arcs are CCW, and should be < 0 in Pcbnew)
277  double angle = -RAD2DECIDEG( endangle - startangle );
278 
279  if( angle > 0.0 )
280  angle -= 3600.0;
281 
282  segm->SetAngle( angle );
283 
284  segm->SetWidth( mapWidth( data.thickness ) );
285  m_newItemsList.push_back( segm );
286 }
287 
288 
289 void DXF2BRD_CONVERTER::addText( const DRW_Text& aData )
290 {
291  BOARD_ITEM* brdItem;
292  EDA_TEXT* textItem;
293 
295  {
296  TEXTE_MODULE* modText = new TEXTE_MODULE( NULL );
297  brdItem = static_cast< BOARD_ITEM* >( modText );
298  textItem = static_cast< EDA_TEXT* >( modText );
299  }
300  else
301  {
302  TEXTE_PCB* pcbText = new TEXTE_PCB( NULL );
303  brdItem = static_cast< BOARD_ITEM* >( pcbText );
304  textItem = static_cast< EDA_TEXT* >( pcbText );
305  }
306 
307  brdItem->SetLayer( ToLAYER_ID( m_brdLayer ) );
308 
309  wxPoint refPoint( mapX( aData.basePoint.x ), mapY( aData.basePoint.y ) );
310  wxPoint secPoint( mapX( aData.secPoint.x ), mapY( aData.secPoint.y ) );
311 
312  if( aData.alignV != 0 || aData.alignH != 0 || aData.alignH == DRW_Text::HMiddle )
313  {
314  if( aData.alignH != DRW_Text::HAligned && aData.alignH != DRW_Text::HFit )
315  {
316  wxPoint tmp = secPoint;
317  secPoint = refPoint;
318  refPoint = tmp;
319  }
320  }
321 
322  switch( aData.alignV )
323  {
324  case DRW_Text::VBaseLine:
326  break;
327 
328  case DRW_Text::VBottom:
330  break;
331 
332  case DRW_Text::VMiddle:
334  break;
335 
336  case DRW_Text::VTop:
338  break;
339  }
340 
341  switch( aData.alignH )
342  {
343  case DRW_Text::HLeft:
345  break;
346 
347  case DRW_Text::HCenter:
349  break;
350 
351  case DRW_Text::HRight:
353  break;
354 
355  case DRW_Text::HAligned:
356  // no equivalent options in text pcb.
358  break;
359 
360  case DRW_Text::HMiddle:
361  // no equivalent options in text pcb.
363  break;
364 
365  case DRW_Text::HFit:
366  // no equivalent options in text pcb.
368  break;
369  }
370 
371 #if 0
372  wxString sty = wxString::FromUTF8( aData.style.c_str() );
373  sty = sty.ToLower();
374 
375  if( aData.textgen == 2 )
376  {
377  // Text dir = left to right;
378  } else if( aData.textgen == 4 )
379  {
380  // Text dir = top to bottom;
381  } else
382  {
383  }
384 #endif
385 
386  wxString text = toNativeString( wxString::FromUTF8( aData.text.c_str() ) );
387 
388  textItem->SetTextPos( refPoint );
389  textItem->SetTextAngle( aData.angle * 10 );
390 
391  // The 0.8 factor gives a better height/width ratio with our font
392  textItem->SetTextWidth( mapDim( aData.height * 0.8 ) );
393  textItem->SetTextHeight( mapDim( aData.height ) );
394  textItem->SetThickness( mapWidth( aData.thickness ) );
395  textItem->SetText( text );
396 
397  m_newItemsList.push_back( static_cast< BOARD_ITEM* >( brdItem ) );
398 }
399 
400 
401 void DXF2BRD_CONVERTER::addMText( const DRW_MText& aData )
402 {
403  wxString text = toNativeString( wxString::FromUTF8( aData.text.c_str() ) );
404  wxString attrib, tmp;
405 
406  /* Some texts start by '\' and have formating chars (font name, font option...)
407  * ending with ';'
408  * Here are some mtext formatting codes:
409  * Format code Purpose
410  * \0...\o Turns overline on and off
411  * \L...\l Turns underline on and off
412  * \~ Inserts a nonbreaking space
413  \\ Inserts a backslash
414  \\\{...\} Inserts an opening and closing brace
415  \\ \File name; Changes to the specified font file
416  \\ \Hvalue; Changes to the text height specified in drawing units
417  \\ \Hvaluex; Changes the text height to a multiple of the current text height
418  \\ \S...^...; Stacks the subsequent text at the \, #, or ^ symbol
419  \\ \Tvalue; Adjusts the space between characters, from.75 to 4 times
420  \\ \Qangle; Changes obliquing angle
421  \\ \Wvalue; Changes width factor to produce wide text
422  \\ \A Sets the alignment value; valid values: 0, 1, 2 (bottom, center, top) while( text.StartsWith( wxT("\\") ) )
423  */
424  while( text.StartsWith( wxT( "\\" ) ) )
425  {
426  attrib << text.BeforeFirst( ';' );
427  tmp = text.AfterFirst( ';' );
428  text = tmp;
429  }
430 
431  BOARD_ITEM* brdItem;
432  EDA_TEXT* textItem;
433 
435  {
436  TEXTE_MODULE* modText = new TEXTE_MODULE( NULL );
437  brdItem = static_cast< BOARD_ITEM* >( modText );
438  textItem = static_cast< EDA_TEXT* >( modText );
439  }
440  else
441  {
442  TEXTE_PCB* pcbText = new TEXTE_PCB( NULL );
443  brdItem = static_cast< BOARD_ITEM* >( pcbText );
444  textItem = static_cast< EDA_TEXT* >( pcbText );
445  }
446 
447  brdItem->SetLayer( ToLAYER_ID( m_brdLayer ) );
448  wxPoint textpos( mapX( aData.basePoint.x ), mapY( aData.basePoint.y ) );
449 
450  textItem->SetTextPos( textpos );
451  textItem->SetTextAngle( aData.angle * 10 );
452 
453  // The 0.8 factor gives a better height/width ratio with our font
454  textItem->SetTextWidth( mapDim( aData.height * 0.8 ) );
455  textItem->SetTextHeight( mapDim( aData.height ) );
456  textItem->SetThickness( mapWidth( aData.thickness ) );
457  textItem->SetText( text );
458 
459  // Initialize text justifications:
460  if( aData.textgen <= 3 )
461  {
463  }
464  else if( aData.textgen <= 6 )
465  {
467  }
468  else
469  {
471  }
472 
473  if( aData.textgen % 3 == 1 )
474  {
476  }
477  else if( aData.textgen % 3 == 2 )
478  {
480  }
481  else
482  {
484  }
485 
486 #if 0 // These setting have no mening in Pcbnew
487  if( data.alignH == 1 )
488  {
489  // Text is left to right;
490  }
491  else if( data.alignH == 3 )
492  {
493  // Text is top to bottom;
494  }
495  else
496  {
497  // use ByStyle;
498  }
499 
500  if( aData.alignV == 1 )
501  {
502  // use AtLeast;
503  }
504  else
505  {
506  // useExact;
507  }
508 #endif
509 
510  m_newItemsList.push_back( static_cast< BOARD_ITEM* >( brdItem ) );
511 }
512 
513 
514 void DXF2BRD_CONVERTER::addHeader( const DRW_Header* data )
515 {
516  std::map<std::string, DRW_Variant*>::const_iterator it;
517  m_DXF2mm = 1.0; // assume no scale factor
518 
519  for( it = data->vars.begin(); it != data->vars.end(); ++it )
520  {
521  std::string key = ( (*it).first ).c_str();
522 
523  if( key == "$DWGCODEPAGE" )
524  {
525  DRW_Variant* var = (*it).second;
526  m_codePage = ( *var->content.s );
527  }
528  else if( key == "$INSUNITS" )
529  {
530  DRW_Variant* var = (*it).second;
531 
532  switch( var->content.i )
533  {
534  case 1: // inches
535  m_DXF2mm = 25.4;
536  break;
537 
538  case 2: // feet
539  m_DXF2mm = 304.8;
540  break;
541 
542  case 5: // centimeters
543  m_DXF2mm = 10.0;
544  break;
545 
546  case 6: // meters
547  m_DXF2mm = 1000.0;
548  break;
549 
550  case 8: // microinches
551  m_DXF2mm = 2.54e-5;
552  break;
553 
554  case 9: // mils
555  m_DXF2mm = 0.0254;
556  break;
557 
558  case 10: // yards
559  m_DXF2mm = 914.4;
560  break;
561 
562  case 11: // Angstroms
563  m_DXF2mm = 1.0e-7;
564  break;
565 
566  case 12: // nanometers
567  m_DXF2mm = 1.0e-6;
568  break;
569 
570  case 13: // micrometers
571  m_DXF2mm = 1.0e-3;
572  break;
573 
574  case 14: // decimeters
575  m_DXF2mm = 100.0;
576  break;
577 
578  default:
579  // use the default of 1.0 for:
580  // 0: Unspecified Units
581  // 4: mm
582  // 3: miles
583  // 7: kilometers
584  // 15: decameters
585  // 16: hectometers
586  // 17: gigameters
587  // 18: AU
588  // 19: lightyears
589  // 20: parsecs
590  break;
591  }
592  }
593  }
594 }
595 
596 
597 wxString DXF2BRD_CONVERTER::toDxfString( const wxString& aStr )
598 {
599  wxString res;
600  int j = 0;
601 
602  for( unsigned i = 0; i<aStr.length(); ++i )
603  {
604  int c = aStr[i];
605 
606  if( c > 175 || c < 11 )
607  {
608  res.append( aStr.Mid( j, i - j ) );
609  j = i;
610 
611  switch( c )
612  {
613  case 0x0A:
614  res += wxT( "\\P" );
615  break;
616 
617  // diameter:
618 #ifdef __WINDOWS_
619  // windows, as always, is special.
620  case 0x00D8:
621 #else
622  case 0x2205:
623 #endif
624  res += wxT( "%%C" );
625  break;
626 
627  // degree:
628  case 0x00B0:
629  res += wxT( "%%D" );
630  break;
631 
632  // plus/minus
633  case 0x00B1:
634  res += wxT( "%%P" );
635  break;
636 
637  default:
638  j--;
639  break;
640  }
641 
642  j++;
643  }
644  }
645 
646  res.append( aStr.Mid( j ) );
647  return res;
648 }
649 
650 
651 wxString DXF2BRD_CONVERTER::toNativeString( const wxString& aData )
652 {
653  wxString res;
654 
655  // Ignore font tags:
656  int j = 0;
657 
658  for( unsigned i = 0; i < aData.length(); ++i )
659  {
660  if( aData[ i ] == 0x7B ) // is '{' ?
661  {
662  if( aData[ i + 1 ] == 0x5c && aData[ i + 2 ] == 0x66 ) // is "\f" ?
663  {
664  // found font tag, append parsed part
665  res.append( aData.Mid( j, i - j ) );
666 
667  // skip to ';'
668  for( unsigned k = i + 3; k < aData.length(); ++k )
669  {
670  if( aData[ k ] == 0x3B )
671  {
672  i = j = ++k;
673  break;
674  }
675  }
676 
677  // add to '}'
678  for( unsigned k = i; k < aData.length(); ++k )
679  {
680  if( aData[ k ] == 0x7D )
681  {
682  res.append( aData.Mid( i, k - i ) );
683  i = j = ++k;
684  break;
685  }
686  }
687  }
688  }
689  }
690 
691  res.append( aData.Mid( j ) );
692 
693 #if 1
694  wxRegEx regexp;
695  // Line feed:
696  regexp.Compile( wxT( "\\\\P" ) );
697  regexp.Replace( &res, wxT( "\n" ) );
698 
699  // Space:
700  regexp.Compile( wxT( "\\\\~" ) );
701  regexp.Replace( &res, wxT( " " ) );
702 
703  // diameter:
704  regexp.Compile( wxT( "%%[cC]" ) );
705 #ifdef __WINDOWS__
706  // windows, as always, is special.
707  regexp.Replace( &res, wxChar( 0xD8 ) );
708 #else
709  // Empty_set, diameter is 0x2300
710  regexp.Replace( &res, wxChar( 0x2205 ) );
711 #endif
712 
713  // degree:
714  regexp.Compile( wxT( "%%[dD]" ) );
715  regexp.Replace( &res, wxChar( 0x00B0 ) );
716  // plus/minus
717  regexp.Compile( wxT( "%%[pP]" ) );
718  regexp.Replace( &res, wxChar( 0x00B1 ) );
719 #endif
720 
721  return res;
722 }
723 
724 
725 void DXF2BRD_CONVERTER::addTextStyle( const DRW_Textstyle& aData )
726 {
727  // TODO
728 }
729 
730 
731 void DXF2BRD_CONVERTER::insertLine( const wxRealPoint& aSegStart,
732  const wxRealPoint& aSegEnd, int aWidth )
733 {
735  static_cast< DRAWSEGMENT* >( new EDGE_MODULE( NULL ) ) : new DRAWSEGMENT;
736  wxPoint segment_startpoint( Millimeter2iu( aSegStart.x ), Millimeter2iu( aSegStart.y ) );
737  wxPoint segment_endpoint( Millimeter2iu( aSegEnd.x ), Millimeter2iu( aSegEnd.y ) );
738 
739  segm->SetLayer( ToLAYER_ID( m_brdLayer ) );
740  segm->SetStart( segment_startpoint );
741  segm->SetEnd( segment_endpoint );
742  segm->SetWidth( aWidth );
743 
744  m_newItemsList.push_back( segm );
745  return;
746 }
747 
748 
749 void DXF2BRD_CONVERTER::insertArc( const wxRealPoint& aSegStart, const wxRealPoint& aSegEnd,
750  double aBulge, int aWidth )
751 {
753  static_cast< DRAWSEGMENT* >( new EDGE_MODULE( NULL ) ) : new DRAWSEGMENT;
754 
755  wxPoint segment_startpoint( Millimeter2iu( aSegStart.x ), Millimeter2iu( aSegStart.y ) );
756  wxPoint segment_endpoint( Millimeter2iu( aSegEnd.x ), Millimeter2iu( aSegEnd.y ) );
757 
758  // ensure aBulge represents an angle from +/- ( 0 .. approx 359.8 deg )
759  if( aBulge < -2000.0 )
760  aBulge = -2000.0;
761  else if( aBulge > 2000.0 )
762  aBulge = 2000.0;
763 
764  double ang = 4.0 * atan( aBulge );
765 
766  // reflect the Y values to put everything in a RHCS
767  wxRealPoint sp( aSegStart.x, -aSegStart.y );
768  wxRealPoint ep( aSegEnd.x, -aSegEnd.y );
769  // angle from end->start
770  double offAng = atan2( ep.y - sp.y, ep.x - sp.x );
771  // length of subtended segment = 1/2 distance between the 2 points
772  double d = 0.5 * sqrt( (sp.x - ep.x) * (sp.x - ep.x) + (sp.y - ep.y) * (sp.y - ep.y) );
773  // midpoint of the subtended segment
774  double xm = ( sp.x + ep.x ) * 0.5;
775  double ym = ( sp.y + ep.y ) * 0.5;
776  double radius = d / sin( ang * 0.5 );
777 
778  if( radius < 0.0 )
779  radius = -radius;
780 
781  // calculate the height of the triangle with base d and hypotenuse r
782  double dh2 = radius * radius - d * d;
783 
784  // this should only ever happen due to rounding errors when r == d
785  if( dh2 < 0.0 )
786  dh2 = 0.0;
787 
788  double h = sqrt( dh2 );
789 
790  if( ang < 0.0 )
791  offAng -= M_PI_2;
792  else
793  offAng += M_PI_2;
794 
795  // for angles greater than 180 deg we need to flip the
796  // direction in which the arc center is found relative
797  // to the midpoint of the subtended segment.
798  if( ang < -M_PI )
799  offAng += M_PI;
800  else if( ang > M_PI )
801  offAng -= M_PI;
802 
803  // center point
804  double cx = h * cos( offAng ) + xm;
805  double cy = h * sin( offAng ) + ym;
806 
807  segm->SetLayer( ToLAYER_ID( m_brdLayer ) );
808  segm->SetShape( S_ARC );
809  segm->SetCenter( wxPoint( Millimeter2iu( cx ), Millimeter2iu( -cy ) ) );
810 
811  if( ang < 0.0 )
812  {
813  segm->SetArcStart( wxPoint( Millimeter2iu( ep.x ), Millimeter2iu( -ep.y ) ) );
814  segm->SetAngle( RAD2DECIDEG( ang ) );
815  }
816  else
817  {
818  segm->SetArcStart( wxPoint( Millimeter2iu( sp.x ), Millimeter2iu( -sp.y ) ) );
819  segm->SetAngle( RAD2DECIDEG( -ang ) );
820  }
821 
822  segm->SetWidth( aWidth );
823 
824  m_newItemsList.push_back( segm );
825  return;
826 }
virtual void addLWPolyline(const DRW_LWPolyline &aData) override
void SetTextAngle(double aAngle)
Definition: eda_text.h:156
bool m_importAsfootprintGraphicItems
Definition: dxf2brd_items.h:53
virtual void addArc(const DRW_Arc &aData) override
virtual void addTextStyle(const DRW_Textstyle &aData) override
void SetShape(STROKE_T aShape)
TEXTE_PCB class definition.
Class LOCALE_IO is a class that can be instantiated within a scope in which you are expecting excepti...
Definition: common.h:165
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...
Class BOARD to handle a board.
virtual void addCircle(const DRW_Circle &aData) override
std::string m_codePage
Definition: dxf2brd_items.h:52
void SetTextPos(const wxPoint &aPoint)
Definition: eda_text.h:223
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.
virtual void addMText(const DRW_MText &aData) override
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
void SetCenter(const wxPoint &aCenterPoint)
For arcs and circles:
#define abs(a)
Definition: auxiliary.h:84
int mapDim(double aDxfValue)
virtual void addText(const DRW_Text &aData) override
This file contains miscellaneous commonly used macros and functions.
Class EDA_TEXT is a mix-in class (via multiple inheritance) that handles texts such as labels...
Definition: eda_text.h:114
int mapY(double aDxfCoordY)
Footprint text class description.
virtual void addPolyline(const DRW_Polyline &aData) override
std::list< BOARD_ITEM * > m_newItemsList
Definition: dxf2brd_items.h:45
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:194
Arcs (with rounded ends)
bool ImportDxfFile(const wxString &aFile)
Implementation of the method used for communicate with this filter.
int mapX(double aDxfCoordX)
virtual void addLine(const DRW_Line &aData) override
#define MIN_BULGE
virtual void addHeader(const DRW_Header *aData) override
void SetStart(const wxPoint &aStart)
void SetTextWidth(int aWidth)
Definition: eda_text.h:217
void insertLine(const wxRealPoint &aSegStart, const wxRealPoint &aSegEnd, int aWidth)
Class to handle a graphic segment.
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:193
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
void SetTextHeight(int aHeight)
Definition: eda_text.h:220
The common library.
const char * name
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 addLayer(const DRW_Layer &aData) override
int mapWidth(double aDxfWidth)
EDGE_MODULE class definition.
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:774
double m_defaultThickness
Definition: dxf2brd_items.h:48
void SetThickness(int aNewThickness)
Function SetThickness sets pen width.
Definition: eda_text.h:148
virtual void SetText(const wxString &aText)
Definition: eda_text.h:141
void SetWidth(int aWidth)