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