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