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