KiCad PCB EDA Suite
export_gencad.cpp File Reference

Export GenCAD 1.4 format. More...

#include <build_version.h>
#include <class_board.h>
#include <class_edge_mod.h>
#include <class_module.h>
#include <class_track.h>
#include <confirm.h>
#include <dialogs/dialog_gencad_export_options.h>
#include <fctsys.h>
#include <gestfich.h>
#include <hash_eda.h>
#include <macros.h>
#include <math/util.h>
#include <pcb_edit_frame.h>
#include <pcbnew.h>
#include <pcbnew_settings.h>
#include <pgm_base.h>
#include <project/project_file.h>
#include <trigo.h>

Go to the source code of this file.

Functions

static bool CreateHeaderInfoData (FILE *aFile, PCB_EDIT_FRAME *frame)
 
static void CreateArtworksSection (FILE *aFile)
 
static void CreateTracksInfoData (FILE *aFile, BOARD *aPcb)
 
static void CreateBoardSection (FILE *aFile, BOARD *aPcb)
 
static void CreateComponentsSection (FILE *aFile, BOARD *aPcb)
 
static void CreateDevicesSection (FILE *aFile, BOARD *aPcb)
 
static void CreateRoutesSection (FILE *aFile, BOARD *aPcb)
 
static void CreateSignalsSection (FILE *aFile, BOARD *aPcb)
 
static void CreateShapesSection (FILE *aFile, BOARD *aPcb)
 
static void CreatePadsShapesSection (FILE *aFile, BOARD *aPcb)
 
static void FootprintWriteShape (FILE *File, MODULE *module, const wxString &aShapeName)
 
static std::string GenCADLayerName (int aCuCount, PCB_LAYER_ID aId)
 
static std::string GenCADLayerNameFlipped (int aCuCount, PCB_LAYER_ID aId)
 
static wxString escapeString (const wxString &aString)
 
static std::string fmt_mask (LSET aSet)
 
static const wxString getShapeName (MODULE *aModule)
 
static double MapXTo (int aX)
 
static double MapYTo (int aY)
 
static bool ViaSort (const VIA *aPadref, const VIA *aPadcmp)
 
static size_t hashModule (const MODULE *aModule)
 Compute hashes for modules without taking into account their position, rotation or layer. More...
 

Variables

static const PCB_LAYER_ID gc_seq []
 
static bool flipBottomPads
 
static bool uniquePins
 
static bool individualShapes
 
static bool storeOriginCoords
 
static int GencadOffsetX
 
static int GencadOffsetY
 
static std::map< MODULE *, int > componentShapes
 
static std::map< int, wxString > shapeNames
 
static const double SCALE_FACTOR = 1000.0 * IU_PER_MILS
 

Detailed Description

Export GenCAD 1.4 format.

Definition in file export_gencad.cpp.

Function Documentation

◆ CreateArtworksSection()

static void CreateArtworksSection ( FILE *  aFile)
static

Definition at line 361 of file export_gencad.cpp.

362 {
363  /* The artworks section is empty */
364  fputs( "$ARTWORKS\n", aFile );
365  fputs( "$ENDARTWORKS\n\n", aFile );
366 }

Referenced by PCB_EDIT_FRAME::ExportToGenCAD().

◆ CreateBoardSection()

static void CreateBoardSection ( FILE *  aFile,
BOARD aPcb 
)
static

Definition at line 1108 of file export_gencad.cpp.

1109 {
1110  fputs( "$BOARD\n", aFile );
1111 
1112  // Extract the board edges
1113  for( auto drawing : aPcb->Drawings() )
1114  {
1115  if( drawing->Type() == PCB_LINE_T )
1116  {
1117  DRAWSEGMENT* drawseg = static_cast<DRAWSEGMENT*>( drawing );
1118  if( drawseg->GetLayer() == Edge_Cuts )
1119  {
1120  // XXX GenCAD supports arc boundaries but I've seen nothing that reads them
1121  fprintf( aFile, "LINE %g %g %g %g\n",
1122  MapXTo( drawseg->GetStart().x ), MapYTo( drawseg->GetStart().y ),
1123  MapXTo( drawseg->GetEnd().x ), MapYTo( drawseg->GetEnd().y ) );
1124  }
1125  }
1126  }
1127 
1128  fputs( "$ENDBOARD\n\n", aFile );
1129 }
static double MapYTo(int aY)
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
class DRAWSEGMENT, a segment not on copper layers
Definition: typeinfo.h:91
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
DRAWINGS & Drawings()
Definition: class_board.h:275
static double MapXTo(int aX)

References BOARD::Drawings(), Edge_Cuts, DRAWSEGMENT::GetEnd(), BOARD_ITEM::GetLayer(), DRAWSEGMENT::GetStart(), MapXTo(), MapYTo(), PCB_LINE_T, wxPoint::x, and wxPoint::y.

Referenced by PCB_EDIT_FRAME::ExportToGenCAD().

◆ CreateComponentsSection()

static void CreateComponentsSection ( FILE *  aFile,
BOARD aPcb 
)
static

Definition at line 818 of file export_gencad.cpp.

819 {
820  fputs( "$COMPONENTS\n", aFile );
821 
822  int cu_count = aPcb->GetCopperLayerCount();
823 
824  for( auto module : aPcb->Modules() )
825  {
826  const char* mirror;
827  const char* flip;
828  double fp_orient = module->GetOrientation();
829 
830  if( module->GetFlag() )
831  {
832  mirror = "MIRRORX";
833  flip = "FLIP";
834  NEGATE_AND_NORMALIZE_ANGLE_POS( fp_orient );
835  }
836  else
837  {
838  mirror = "0";
839  flip = "0";
840  }
841 
842  fprintf( aFile, "\nCOMPONENT \"%s\"\n",
843  TO_UTF8( escapeString( module->GetReference() ) ) );
844  fprintf( aFile, "DEVICE \"DEV_%s\"\n",
845  TO_UTF8( escapeString( getShapeName( module ) ) ) );
846  fprintf( aFile, "PLACE %g %g\n",
847  MapXTo( module->GetPosition().x ),
848  MapYTo( module->GetPosition().y ) );
849  fprintf( aFile, "LAYER %s\n",
850  module->GetFlag() ? "BOTTOM" : "TOP" );
851  fprintf( aFile, "ROTATION %g\n",
852  fp_orient / 10.0 );
853  fprintf( aFile, "SHAPE \"%s\" %s %s\n",
854  TO_UTF8( escapeString( getShapeName( module ) ) ),
855  mirror, flip );
856 
857  // Text on silk layer: RefDes and value (are they actually useful?)
858  TEXTE_MODULE *textmod = &module->Reference();
859 
860  for( int ii = 0; ii < 2; ii++ )
861  {
862  double txt_orient = textmod->GetTextAngle();
863  std::string layer = GenCADLayerName( cu_count, module->GetFlag() ? B_SilkS : F_SilkS );
864 
865  fprintf( aFile, "TEXT %g %g %g %g %s %s \"%s\"",
866  textmod->GetPos0().x / SCALE_FACTOR,
867  -textmod->GetPos0().y / SCALE_FACTOR,
868  textmod->GetTextWidth() / SCALE_FACTOR,
869  txt_orient / 10.0,
870  mirror,
871  layer.c_str(),
872  TO_UTF8( escapeString( textmod->GetText() ) ) );
873 
874  // Please note, the width is approx
875  fprintf( aFile, " 0 0 %g %g\n",
876  ( textmod->GetTextWidth() * textmod->GetLength() ) / SCALE_FACTOR,
877  textmod->GetTextHeight() / SCALE_FACTOR );
878 
879  textmod = &module->Value(); // Dirty trick for the second iteration
880  }
881 
882  // The SHEET is a 'generic description' for referencing the component
883  fprintf( aFile, "SHEET \"RefDes: %s, Value: %s\"\n",
884  TO_UTF8( module->GetReference() ),
885  TO_UTF8( module->GetValue() ) );
886  }
887 
888  fputs( "$ENDCOMPONENTS\n\n", aFile );
889 }
static const wxString getShapeName(MODULE *aModule)
static double MapYTo(int aY)
double GetTextAngle() const
Definition: eda_text.h:174
static wxString escapeString(const wxString &aString)
int GetTextHeight() const
Definition: eda_text.h:245
MODULES & Modules()
Definition: class_board.h:266
const wxPoint & GetPos0() const
static std::string GenCADLayerName(int aCuCount, PCB_LAYER_ID aId)
void NEGATE_AND_NORMALIZE_ANGLE_POS(T &Angle)
Definition: trigo.h:322
int GetLength() const
int GetTextWidth() const
Definition: eda_text.h:242
int GetCopperLayerCount() const
Function GetCopperLayerCount.
#define TO_UTF8(wxstring)
static const double SCALE_FACTOR
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:127
static double MapXTo(int aX)

References B_SilkS, escapeString(), F_SilkS, GenCADLayerName(), BOARD::GetCopperLayerCount(), TEXTE_MODULE::GetLength(), TEXTE_MODULE::GetPos0(), getShapeName(), EDA_TEXT::GetText(), EDA_TEXT::GetTextAngle(), EDA_TEXT::GetTextHeight(), EDA_TEXT::GetTextWidth(), MapXTo(), MapYTo(), BOARD::Modules(), NEGATE_AND_NORMALIZE_ANGLE_POS(), SCALE_FACTOR, TO_UTF8, wxPoint::x, and wxPoint::y.

Referenced by PCB_EDIT_FRAME::ExportToGenCAD().

◆ CreateDevicesSection()

static void CreateDevicesSection ( FILE *  aFile,
BOARD aPcb 
)
static

Definition at line 1070 of file export_gencad.cpp.

1071 {
1072  std::set<wxString> emitted;
1073  fputs( "$DEVICES\n", aFile );
1074 
1075  for( const auto& componentShape : componentShapes )
1076  {
1077  const wxString& shapeName = shapeNames[componentShape.second];
1078  bool newDevice;
1079  std::tie( std::ignore, newDevice ) = emitted.insert( shapeName );
1080 
1081  if( !newDevice ) // do not repeat device definitions
1082  continue;
1083 
1084  const MODULE* module = componentShape.first;
1085  fprintf( aFile, "\nDEVICE \"DEV_%s\"\n", TO_UTF8( escapeString( shapeName ) ) );
1086  fprintf( aFile, "PART \"%s\"\n", TO_UTF8( escapeString( module->GetValue() ) ) );
1087  fprintf( aFile, "PACKAGE \"%s\"\n", TO_UTF8( escapeString( module->GetFPID().Format() ) ) );
1088 
1089  // The TYPE attribute is almost freeform
1090  const char* ty = "TH";
1091 
1092  if( module->GetAttributes() & MOD_CMS )
1093  ty = "SMD";
1094 
1095  if( module->GetAttributes() & MOD_VIRTUAL )
1096  ty = "VIRTUAL";
1097 
1098  fprintf( aFile, "TYPE %s\n", ty );
1099  }
1100 
1101  fputs( "$ENDDEVICES\n\n", aFile );
1102 }
int GetAttributes() const
Definition: class_module.h:266
const wxString GetValue() const
Function GetValue.
Definition: class_module.h:469
Set for modules listed in the automatic insertion list (usually SMD footprints)
Definition: class_module.h:68
const LIB_ID & GetFPID() const
Definition: class_module.h:225
static wxString escapeString(const wxString &aString)
UTF8 Format() const
Definition: lib_id.cpp:237
Virtual component: when created by copper shapes on board (Like edge card connectors,...
Definition: class_module.h:70
#define TO_UTF8(wxstring)
static std::map< MODULE *, int > componentShapes
static std::map< int, wxString > shapeNames

References componentShapes, escapeString(), LIB_ID::Format(), MODULE::GetAttributes(), MODULE::GetFPID(), MODULE::GetValue(), MOD_CMS, MOD_VIRTUAL, shapeNames, and TO_UTF8.

Referenced by PCB_EDIT_FRAME::ExportToGenCAD().

◆ CreateHeaderInfoData()

static bool CreateHeaderInfoData ( FILE *  aFile,
PCB_EDIT_FRAME frame 
)
static

Definition at line 941 of file export_gencad.cpp.

942 {
943  wxString msg;
944  BOARD *board = aFrame->GetBoard();
945 
946  fputs( "$HEADER\n", aFile );
947  fputs( "GENCAD 1.4\n", aFile );
948 
949  // Please note: GenCAD syntax requires quoted strings if they can contain spaces
950  msg.Printf( wxT( "USER \"%s %s\"\n" ),
951  GetChars( Pgm().App().GetAppName() ),
952  GetChars( GetBuildVersion() ) );
953  fputs( TO_UTF8( msg ), aFile );
954 
955  msg = wxT( "DRAWING \"" ) + board->GetFileName() + wxT( "\"\n" );
956  fputs( TO_UTF8( msg ), aFile );
957 
958  const TITLE_BLOCK& tb = aFrame->GetTitleBlock();
959 
960  msg = wxT( "REVISION \"" ) + tb.GetRevision() + wxT( " " ) + tb.GetDate() + wxT( "\"\n" );
961 
962  fputs( TO_UTF8( msg ), aFile );
963  fputs( "UNITS INCH\n", aFile );
964 
965  // giving 0 as the argument to Map{X,Y}To returns the scaled origin point
966  msg.Printf( wxT( "ORIGIN %g %g\n" ),
967  storeOriginCoords ? MapXTo( 0 ) : 0,
968  storeOriginCoords ? MapYTo( 0 ) : 0 );
969  fputs( TO_UTF8( msg ), aFile );
970 
971  fputs( "INTERTRACK 0\n", aFile );
972  fputs( "$ENDHEADER\n\n", aFile );
973 
974  return true;
975 }
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:104
static double MapYTo(int aY)
const wxString & GetFileName() const
Definition: class_board.h:255
TITLE_BLOCK holds the information shown in the lower right corner of a plot, printout,...
Definition: title_block.h:40
wxString GetBuildVersion()
Get the full KiCad version string.
const wxString & GetRevision() const
Definition: title_block.h:89
virtual BOARD * GetBoard() const
Function GetBoard returns the BOARD in which this BOARD_ITEM resides, or NULL if none.
static bool storeOriginCoords
const wxString & GetDate() const
Definition: title_block.h:79
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:153
BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:180
#define TO_UTF8(wxstring)
static double MapXTo(int aX)

References PCB_BASE_FRAME::GetBoard(), GetBuildVersion(), GetChars(), TITLE_BLOCK::GetDate(), BOARD::GetFileName(), TITLE_BLOCK::GetRevision(), PCB_BASE_FRAME::GetTitleBlock(), MapXTo(), MapYTo(), Pgm(), storeOriginCoords, and TO_UTF8.

Referenced by PCB_EDIT_FRAME::ExportToGenCAD().

◆ CreatePadsShapesSection()

static void CreatePadsShapesSection ( FILE *  aFile,
BOARD aPcb 
)
static

Definition at line 371 of file export_gencad.cpp.

372 {
373  std::vector<D_PAD*> padstacks;
374  std::vector<VIA*> vias;
375  std::vector<VIA*> viastacks;
376 
377  padstacks.resize( 1 ); // We count pads from 1
378 
379  // The master layermask (i.e. the enabled layers) for padstack generation
380  LSET master_layermask = aPcb->GetDesignSettings().GetEnabledLayers();
381  int cu_count = aPcb->GetCopperLayerCount();
382 
383  fputs( "$PADS\n", aFile );
384 
385  // Enumerate and sort the pads
386 
387  auto pads( aPcb->GetPads() );
388  std::sort( pads.begin(), pads.end(),
389  []( const D_PAD* a, const D_PAD* b ) { return D_PAD::Compare( a, b ) < 0; } );
390 
391 
392  // The same for vias
393  for( auto track : aPcb->Tracks() )
394  {
395  if( auto via = dyn_cast<VIA*>( track ) )
396  vias.push_back( via );
397  }
398 
399  std::sort( vias.begin(), vias.end(), ViaSort );
400  vias.erase( std::unique( vias.begin(), vias.end(),
401  []( const VIA* a, const VIA* b ) { return ViaSort( a, b ) == false; } ),
402  vias.end() );
403 
404  // Emit vias pads
405 
406  for( auto item : vias )
407  {
408  VIA* via = static_cast<VIA*>( item );
409 
410  viastacks.push_back( via );
411  fprintf( aFile, "PAD V%d.%d.%s ROUND %g\nCIRCLE 0 0 %g\n",
412  via->GetWidth(), via->GetDrillValue(),
413  fmt_mask( via->GetLayerSet() & master_layermask ).c_str(),
414  via->GetDrillValue() / SCALE_FACTOR,
415  via->GetWidth() / (SCALE_FACTOR * 2) );
416  }
417 
418  // Emit component pads
419  D_PAD* old_pad = 0;
420  int pad_name_number = 0;
421 
422  for( unsigned i = 0; i<pads.size(); ++i )
423  {
424  D_PAD* pad = pads[i];
425  const wxPoint& off = pad->GetOffset();
426 
427  pad->SetSubRatsnest( pad_name_number );
428 
429  if( old_pad && 0==D_PAD::Compare( old_pad, pad ) )
430  continue; // already created
431 
432  old_pad = pad;
433 
434  pad_name_number++;
435  pad->SetSubRatsnest( pad_name_number );
436 
437  fprintf( aFile, "PAD P%d", pad->GetSubRatsnest() );
438 
439  padstacks.push_back( pad ); // Will have its own padstack later
440  int dx = pad->GetSize().x / 2;
441  int dy = pad->GetSize().y / 2;
442 
443  switch( pad->GetShape() )
444  {
445  default:
446  wxASSERT_MSG( false, "Pad type not implemented" );
448 
449  case PAD_SHAPE_CIRCLE:
450  fprintf( aFile, " ROUND %g\n",
451  pad->GetDrillSize().x / SCALE_FACTOR );
452  /* Circle is center, radius */
453  fprintf( aFile, "CIRCLE %g %g %g\n",
454  off.x / SCALE_FACTOR,
455  -off.y / SCALE_FACTOR,
456  pad->GetSize().x / (SCALE_FACTOR * 2) );
457  break;
458 
459  case PAD_SHAPE_RECT:
460  fprintf( aFile, " RECTANGULAR %g\n",
461  pad->GetDrillSize().x / SCALE_FACTOR );
462 
463  // Rectangle is begin, size *not* begin, end!
464  fprintf( aFile, "RECTANGLE %g %g %g %g\n",
465  (-dx + off.x ) / SCALE_FACTOR,
466  (-dy - off.y ) / SCALE_FACTOR,
467  dx / (SCALE_FACTOR / 2), dy / (SCALE_FACTOR / 2) );
468  break;
469 
470  case PAD_SHAPE_ROUNDRECT:
471  case PAD_SHAPE_OVAL:
472  {
473  const wxSize& size = pad->GetSize();
474  int radius;
475 
476  if( pad->GetShape() == PAD_SHAPE_ROUNDRECT )
477  radius = pad->GetRoundRectCornerRadius();
478  else
479  radius = std::min( size.x, size.y ) / 2;
480 
481  int lineX = size.x / 2 - radius;
482  int lineY = size.y / 2 - radius;
483 
484  fprintf( aFile, " POLYGON %g\n", pad->GetDrillSize().x / SCALE_FACTOR );
485 
486  // bottom left arc
487  fprintf( aFile, "ARC %g %g %g %g %g %g\n",
488  ( off.x - lineX - radius ) / SCALE_FACTOR,
489  ( -off.y - lineY ) / SCALE_FACTOR, ( off.x - lineX ) / SCALE_FACTOR,
490  ( -off.y - lineY - radius ) / SCALE_FACTOR,
491  ( off.x - lineX ) / SCALE_FACTOR, ( -off.y - lineY ) / SCALE_FACTOR );
492 
493  // bottom line
494  if( lineX > 0 )
495  {
496  fprintf( aFile, "LINE %g %g %g %g\n",
497  ( off.x - lineX ) / SCALE_FACTOR,
498  ( -off.y - lineY - radius ) / SCALE_FACTOR,
499  ( off.x + lineX ) / SCALE_FACTOR,
500  ( -off.y - lineY - radius ) / SCALE_FACTOR );
501  }
502 
503  // bottom right arc
504  fprintf( aFile, "ARC %g %g %g %g %g %g\n",
505  ( off.x + lineX ) / SCALE_FACTOR,
506  ( -off.y - lineY - radius ) / SCALE_FACTOR,
507  ( off.x + lineX + radius ) / SCALE_FACTOR,
508  ( -off.y - lineY ) / SCALE_FACTOR, ( off.x + lineX ) / SCALE_FACTOR,
509  ( -off.y - lineY ) / SCALE_FACTOR );
510 
511  // right line
512  if( lineY > 0 )
513  {
514  fprintf( aFile, "LINE %g %g %g %g\n",
515  ( off.x + lineX + radius ) / SCALE_FACTOR,
516  ( -off.y + lineY ) / SCALE_FACTOR,
517  ( off.x + lineX + radius ) / SCALE_FACTOR,
518  ( -off.y - lineY ) / SCALE_FACTOR );
519  }
520 
521  // top right arc
522  fprintf( aFile, "ARC %g %g %g %g %g %g\n",
523  ( off.x + lineX + radius ) / SCALE_FACTOR,
524  ( -off.y + lineY ) / SCALE_FACTOR, ( off.x + lineX ) / SCALE_FACTOR,
525  ( -off.y + lineY + radius ) / SCALE_FACTOR,
526  ( off.x + lineX ) / SCALE_FACTOR, ( -off.y + lineY ) / SCALE_FACTOR );
527 
528  // top line
529  if( lineX > 0 )
530  {
531  fprintf( aFile, "LINE %g %g %g %g\n"
532  , ( off.x - lineX ) / SCALE_FACTOR,
533  ( -off.y + lineY + radius ) / SCALE_FACTOR,
534  ( off.x + lineX ) / SCALE_FACTOR,
535  ( -off.y + lineY + radius ) / SCALE_FACTOR );
536  }
537 
538  // top left arc
539  fprintf( aFile, "ARC %g %g %g %g %g %g\n",
540  ( off.x - lineX ) / SCALE_FACTOR,
541  ( -off.y + lineY + radius ) / SCALE_FACTOR,
542  ( off.x - lineX - radius ) / SCALE_FACTOR,
543  ( -off.y + lineY ) / SCALE_FACTOR, ( off.x - lineX ) / SCALE_FACTOR,
544  ( -off.y + lineY ) / SCALE_FACTOR );
545 
546  // left line
547  if( lineY > 0 )
548  {
549  fprintf( aFile, "LINE %g %g %g %g\n",
550  ( off.x - lineX - radius ) / SCALE_FACTOR,
551  ( -off.y - lineY ) / SCALE_FACTOR,
552  ( off.x - lineX - radius ) / SCALE_FACTOR,
553  ( -off.y + lineY ) / SCALE_FACTOR );
554  }
555  }
556  break;
557 
558  case PAD_SHAPE_TRAPEZOID:
559  {
560  fprintf( aFile, " POLYGON %g\n", pad->GetDrillSize().x / SCALE_FACTOR );
561 
562  int ddx = pad->GetDelta().x / 2;
563  int ddy = pad->GetDelta().y / 2;
564 
565  wxPoint poly[4];
566  poly[0] = wxPoint( -dx + ddy, dy + ddx );
567  poly[1] = wxPoint( dx - ddy, dy - ddx );
568  poly[2] = wxPoint( dx + ddy, -dy + ddx );
569  poly[3] = wxPoint( -dx - ddy, -dy - ddx );
570 
571  for( int cur = 0; cur < 4; ++cur )
572  {
573  int next = ( cur + 1 ) % 4;
574  fprintf( aFile, "LINE %g %g %g %g\n",
575  ( off.x + poly[cur].x ) / SCALE_FACTOR,
576  ( -off.y - poly[cur].y ) / SCALE_FACTOR,
577  ( off.x + poly[next].x ) / SCALE_FACTOR,
578  ( -off.y - poly[next].y ) / SCALE_FACTOR );
579  }
580  }
581  break;
582 
583  case PAD_SHAPE_CUSTOM:
584  {
585  fprintf( aFile, " POLYGON %g\n", pad->GetDrillSize().x / SCALE_FACTOR );
586 
587  SHAPE_POLY_SET outline;
588  pad->MergePrimitivesAsPolygon( &outline );
589 
590  for( int jj = 0; jj < outline.OutlineCount(); ++jj )
591  {
592  const SHAPE_LINE_CHAIN& poly = outline.COutline( jj );
593  int pointCount = poly.PointCount();
594 
595  for( int ii = 0; ii < pointCount; ii++ )
596  {
597  int next = ( ii + 1 ) % pointCount;
598  fprintf( aFile, "LINE %g %g %g %g\n",
599  ( off.x + poly.CPoint( ii ).x ) / SCALE_FACTOR,
600  ( -off.y - poly.CPoint( ii ).y ) / SCALE_FACTOR,
601  ( off.x + poly.CPoint( next ).x ) / SCALE_FACTOR,
602  ( -off.y - poly.CPoint( next ).y ) / SCALE_FACTOR );
603  }
604  }
605  }
606  break;
607  }
608  }
609 
610  fputs( "\n$ENDPADS\n\n", aFile );
611 
612  // Now emit the padstacks definitions, using the combined layer masks
613  fputs( "$PADSTACKS\n", aFile );
614 
615  // Via padstacks
616  for( unsigned i = 0; i < viastacks.size(); i++ )
617  {
618  VIA* via = viastacks[i];
619 
620  LSET mask = via->GetLayerSet() & master_layermask;
621 
622  fprintf( aFile, "PADSTACK VIA%d.%d.%s %g\n",
623  via->GetWidth(), via->GetDrillValue(),
624  fmt_mask( mask ).c_str(),
625  via->GetDrillValue() / SCALE_FACTOR );
626 
627  for( LSEQ seq = mask.Seq( gc_seq, arrayDim( gc_seq ) ); seq; ++seq )
628  {
629  PCB_LAYER_ID layer = *seq;
630 
631  fprintf( aFile, "PAD V%d.%d.%s %s 0 0\n",
632  via->GetWidth(), via->GetDrillValue(),
633  fmt_mask( mask ).c_str(),
634  GenCADLayerName( cu_count, layer ).c_str()
635  );
636  }
637  }
638 
639  /* Component padstacks
640  * Older versions of CAM350 don't apply correctly the FLIP semantics for
641  * padstacks, i.e. doesn't swap the top and bottom layers... so I need to
642  * define the shape as MIRRORX and define a separate 'flipped' padstack...
643  * until it appears yet another noncompliant importer */
644  for( unsigned i = 1; i < padstacks.size(); i++ )
645  {
646  D_PAD* pad = padstacks[i];
647 
648  // Straight padstack
649  fprintf( aFile, "PADSTACK PAD%u %g\n", i, pad->GetDrillSize().x / SCALE_FACTOR );
650 
651  LSET pad_set = pad->GetLayerSet() & master_layermask;
652 
653  // the special gc_seq
654  for( LSEQ seq = pad_set.Seq( gc_seq, arrayDim( gc_seq ) ); seq; ++seq )
655  {
656  PCB_LAYER_ID layer = *seq;
657 
658  fprintf( aFile, "PAD P%u %s 0 0\n", i, GenCADLayerName( cu_count, layer ).c_str() );
659  }
660 
661  // Flipped padstack
662  if( flipBottomPads )
663  {
664  fprintf( aFile, "PADSTACK PAD%uF %g\n", i, pad->GetDrillSize().x / SCALE_FACTOR );
665 
666  // the normal PCB_LAYER_ID sequence is inverted from gc_seq[]
667  for( LSEQ seq = pad_set.Seq(); seq; ++seq )
668  {
669  PCB_LAYER_ID layer = *seq;
670 
671  fprintf( aFile, "PAD P%u %s 0 0\n", i, GenCADLayerNameFlipped( cu_count, layer ).c_str() );
672  }
673  }
674  }
675 
676  fputs( "$ENDPADSTACKS\n\n", aFile );
677 }
CITER next(CITER it)
Definition: ptree.cpp:130
void MergePrimitivesAsPolygon(SHAPE_POLY_SET *aMergedPolygon) const
Merge all basic shapes to a SHAPE_POLY_SET Note: The corners coordinates are relative to the pad posi...
#define KI_FALLTHROUGH
virtual LSET GetLayerSet() const override
Function GetLayerSet returns a std::bitset of all layers on which the item physically resides.
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:553
void SetSubRatsnest(int aSubRatsnest)
Definition: class_pad.h:503
static bool flipBottomPads
int PointCount() const
Function PointCount()
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Function Seq returns an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:377
const VECTOR2I & CPoint(int aIndex) const
Function Point()
static std::string GenCADLayerNameFlipped(int aCuCount, PCB_LAYER_ID aId)
PCB_LAYER_ID
A quick note on layer IDs:
LSET is a set of PCB_LAYER_IDs.
int GetDrillValue() const
Function GetDrillValue "calculates" the drill value for vias (m-Drill if > 0, or default drill value ...
SHAPE_POLY_SET.
static int Compare(const D_PAD *padref, const D_PAD *padcmp)
Function Compare compares two pads and return 0 if they are equal.
Definition: class_pad.cpp:948
const wxPoint & GetOffset() const
Definition: class_pad.h:233
static const PCB_LAYER_ID gc_seq[]
LSET GetLayerSet() const override
Function GetLayerSet returns a std::bitset of all layers on which the item physically resides.
Definition: class_pad.h:335
const wxSize & GetDelta() const
Definition: class_pad.h:227
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Definition: macros.h:160
static std::string GenCADLayerName(int aCuCount, PCB_LAYER_ID aId)
const std::vector< D_PAD * > GetPads()
Function GetPads returns a reference to a list of all the pads.
int GetWidth() const
Definition: class_track.h:110
static bool ViaSort(const VIA *aPadref, const VIA *aPadcmp)
LSET GetEnabledLayers() const
Function GetEnabledLayers returns a bit-mask of all the layers that are enabled.
SHAPE_LINE_CHAIN.
int GetCopperLayerCount() const
Function GetCopperLayerCount.
const wxSize & GetDrillSize() const
Definition: class_pad.h:230
int GetSubRatsnest() const
Function GetSubRatsnest.
Definition: class_pad.h:502
static const double SCALE_FACTOR
int GetRoundRectCornerRadius() const
Definition: class_pad.cpp:218
static std::string fmt_mask(LSET aSet)
PAD_SHAPE_T GetShape() const
Definition: class_pad.h:157
const wxSize & GetSize() const
Definition: class_pad.h:224
TRACKS & Tracks()
Definition: class_board.h:257

References arrayDim(), D_PAD::Compare(), SHAPE_LINE_CHAIN::CPoint(), flipBottomPads, fmt_mask(), gc_seq, GenCADLayerName(), GenCADLayerNameFlipped(), BOARD::GetCopperLayerCount(), D_PAD::GetDelta(), BOARD::GetDesignSettings(), D_PAD::GetDrillSize(), VIA::GetDrillValue(), BOARD_DESIGN_SETTINGS::GetEnabledLayers(), D_PAD::GetLayerSet(), VIA::GetLayerSet(), D_PAD::GetOffset(), BOARD::GetPads(), D_PAD::GetRoundRectCornerRadius(), D_PAD::GetShape(), D_PAD::GetSize(), D_PAD::GetSubRatsnest(), TRACK::GetWidth(), KI_FALLTHROUGH, D_PAD::MergePrimitivesAsPolygon(), next(), PAD_SHAPE_CIRCLE, PAD_SHAPE_CUSTOM, PAD_SHAPE_OVAL, PAD_SHAPE_RECT, PAD_SHAPE_ROUNDRECT, PAD_SHAPE_TRAPEZOID, SHAPE_LINE_CHAIN::PointCount(), SCALE_FACTOR, LSET::Seq(), D_PAD::SetSubRatsnest(), BOARD::Tracks(), ViaSort(), wxPoint::x, VECTOR2< T >::x, wxPoint::y, and VECTOR2< T >::y.

Referenced by PCB_EDIT_FRAME::ExportToGenCAD().

◆ CreateRoutesSection()

static void CreateRoutesSection ( FILE *  aFile,
BOARD aPcb 
)
static

Definition at line 987 of file export_gencad.cpp.

988 {
989  int vianum = 1;
990  int old_netcode, old_width, old_layer;
991  LSET master_layermask = aPcb->GetDesignSettings().GetEnabledLayers();
992 
993  int cu_count = aPcb->GetCopperLayerCount();
994 
995  TRACKS tracks( aPcb->Tracks() );
996  std::sort( tracks.begin(), tracks.end(), []( const TRACK* a, const TRACK* b ) {
997  if( a->GetNetCode() == b->GetNetCode() )
998  {
999  if( a->GetWidth() == b->GetWidth() )
1000  return ( a->GetLayer() < b->GetLayer() );
1001 
1002  return ( a->GetWidth() < b->GetWidth() );
1003  }
1004 
1005  return ( a->GetNetCode() < b->GetNetCode() );
1006  } );
1007 
1008  fputs( "$ROUTES\n", aFile );
1009 
1010  old_netcode = -1; old_width = -1; old_layer = -1;
1011 
1012  for( auto track : tracks )
1013  {
1014  if( old_netcode != track->GetNetCode() )
1015  {
1016  old_netcode = track->GetNetCode();
1017  NETINFO_ITEM* net = track->GetNet();
1018  wxString netname;
1019 
1020  if( net && (net->GetNetname() != wxEmptyString) )
1021  netname = net->GetNetname();
1022  else
1023  netname = wxT( "_noname_" );
1024 
1025  fprintf( aFile, "ROUTE \"%s\"\n", TO_UTF8( escapeString( netname ) ) );
1026  }
1027 
1028  if( old_width != track->GetWidth() )
1029  {
1030  old_width = track->GetWidth();
1031  fprintf( aFile, "TRACK TRACK%d\n", track->GetWidth() );
1032  }
1033 
1034  if( track->Type() == PCB_TRACE_T )
1035  {
1036  if( old_layer != track->GetLayer() )
1037  {
1038  old_layer = track->GetLayer();
1039  fprintf( aFile, "LAYER %s\n",
1040  GenCADLayerName( cu_count, track->GetLayer() ).c_str() );
1041  }
1042 
1043  fprintf( aFile, "LINE %g %g %g %g\n",
1044  MapXTo( track->GetStart().x ), MapYTo( track->GetStart().y ),
1045  MapXTo( track->GetEnd().x ), MapYTo( track->GetEnd().y ) );
1046  }
1047 
1048  if( track->Type() == PCB_VIA_T )
1049  {
1050  const VIA* via = static_cast<const VIA*>(track);
1051 
1052  LSET vset = via->GetLayerSet() & master_layermask;
1053 
1054  fprintf( aFile, "VIA VIA%d.%d.%s %g %g ALL %g via%d\n",
1055  via->GetWidth(), via->GetDrillValue(),
1056  fmt_mask( vset ).c_str(),
1057  MapXTo( via->GetStart().x ), MapYTo( via->GetStart().y ),
1058  via->GetDrillValue() / SCALE_FACTOR, vianum++ );
1059  }
1060  }
1061 
1062  fputs( "$ENDROUTES\n\n", aFile );
1063 }
int GetNetCode() const
Function GetNetCode.
virtual LSET GetLayerSet() const override
Function GetLayerSet returns a std::bitset of all layers on which the item physically resides.
const wxPoint & GetStart() const
Definition: class_track.h:116
static double MapYTo(int aY)
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:553
static wxString escapeString(const wxString &aString)
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
void vset(double *v, double x, double y, double z)
Definition: trackball.cpp:82
LSET is a set of PCB_LAYER_IDs.
int GetDrillValue() const
Function GetDrillValue "calculates" the drill value for vias (m-Drill if > 0, or default drill value ...
const wxString & GetNetname() const
Function GetNetname.
Definition: netinfo.h:231
static std::string GenCADLayerName(int aCuCount, PCB_LAYER_ID aId)
NETINFO_ITEM handles the data for a net.
Definition: netinfo.h:65
int GetWidth() const
Definition: class_track.h:110
int GetNet() const
Function GetNet.
Definition: netinfo.h:223
LSET GetEnabledLayers() const
Function GetEnabledLayers returns a bit-mask of all the layers that are enabled.
int GetCopperLayerCount() const
Function GetCopperLayerCount.
#define TO_UTF8(wxstring)
static const double SCALE_FACTOR
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
static std::string fmt_mask(LSET aSet)
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
TRACKS & Tracks()
Definition: class_board.h:257
static double MapXTo(int aX)

References escapeString(), fmt_mask(), GenCADLayerName(), BOARD::GetCopperLayerCount(), BOARD::GetDesignSettings(), VIA::GetDrillValue(), BOARD_DESIGN_SETTINGS::GetEnabledLayers(), BOARD_ITEM::GetLayer(), VIA::GetLayerSet(), NETINFO_ITEM::GetNet(), BOARD_CONNECTED_ITEM::GetNetCode(), NETINFO_ITEM::GetNetname(), TRACK::GetStart(), TRACK::GetWidth(), MapXTo(), MapYTo(), PCB_TRACE_T, PCB_VIA_T, SCALE_FACTOR, TO_UTF8, BOARD::Tracks(), vset(), wxPoint::x, and wxPoint::y.

Referenced by PCB_EDIT_FRAME::ExportToGenCAD().

◆ CreateShapesSection()

static void CreateShapesSection ( FILE *  aFile,
BOARD aPcb 
)
static

Definition at line 702 of file export_gencad.cpp.

703 {
704  const char* layer;
705  wxString pinname;
706  const char* mirror = "0";
707  std::map<wxString, size_t> shapes;
708 
709  fputs( "$SHAPES\n", aFile );
710 
711  for( auto module : aPcb->Modules() )
712  {
713  if( !individualShapes )
714  {
715  // Check if such shape has been already generated, and if so - reuse it
716  // It is necessary to compute hash (i.e. check all children objects) as
717  // certain components instances might have been modified on the board.
718  // In such case the shape will be different despite the same LIB_ID.
719  wxString shapeName = module->GetFPID().Format();
720 
721  auto shapeIt = shapes.find( shapeName );
722  size_t modHash = hashModule( module );
723 
724  if( shapeIt != shapes.end() )
725  {
726  if( modHash != shapeIt->second )
727  {
728  // there is an entry for this footprint, but it has a modified shape,
729  // so we need to create a new entry
730  wxString newShapeName;
731  int suffix = 0;
732 
733  // find an unused name or matching entry
734  do
735  {
736  newShapeName = wxString::Format( "%s_%d", shapeName, suffix );
737  shapeIt = shapes.find( newShapeName );
738  ++suffix;
739  }
740  while( shapeIt != shapes.end() && shapeIt->second != modHash );
741 
742  shapeName = newShapeName;
743  }
744 
745  if( shapeIt != shapes.end() && modHash == shapeIt->second )
746  {
747  // shape found, so reuse it
748  componentShapes[module] = modHash;
749  continue;
750  }
751  }
752 
753  // new shape
754  componentShapes[module] = modHash;
755  shapeNames[modHash] = shapeName;
756  shapes[shapeName] = modHash;
757  FootprintWriteShape( aFile, module, shapeName );
758  }
759  else // individual shape for each component
760  {
761  FootprintWriteShape( aFile, module, module->GetReference() );
762  }
763 
764  // set of already emitted pins to check for duplicates
765  std::set<wxString> pins;
766 
767  for( auto pad : module->Pads() )
768  {
769  /* Padstacks are defined using the correct layers for the pads, therefore to
770  * all pads need to be marked as TOP to use the padstack information correctly.
771  */
772  layer = "TOP";
773  pinname = pad->GetName();
774 
775  if( pinname.IsEmpty() )
776  pinname = wxT( "none" );
777 
778  if( uniquePins )
779  {
780  int suffix = 0;
781  wxString origPinname( pinname );
782 
783  auto it = pins.find( pinname );
784 
785  while( it != pins.end() )
786  {
787  pinname = wxString::Format( "%s_%d", origPinname, suffix );
788  ++suffix;
789  it = pins.find( pinname );
790  }
791 
792  pins.insert( pinname );
793  }
794 
795  double orient = pad->GetOrientation() - module->GetOrientation();
796  NORMALIZE_ANGLE_POS( orient );
797 
798  // Bottom side modules use the flipped padstack
799  fprintf( aFile, ( flipBottomPads && module->GetFlag() ) ?
800  "PIN \"%s\" PAD%dF %g %g %s %g %s\n" :
801  "PIN \"%s\" PAD%d %g %g %s %g %s\n",
802  TO_UTF8( escapeString( pinname ) ), pad->GetSubRatsnest(),
803  pad->GetPos0().x / SCALE_FACTOR,
804  -pad->GetPos0().y / SCALE_FACTOR,
805  layer, orient / 10.0, mirror );
806  }
807  }
808 
809  fputs( "$ENDSHAPES\n\n", aFile );
810 }
static bool uniquePins
static wxString escapeString(const wxString &aString)
void NORMALIZE_ANGLE_POS(T &Angle)
Definition: trigo.h:257
static bool flipBottomPads
static bool individualShapes
MODULES & Modules()
Definition: class_board.h:266
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
static size_t hashModule(const MODULE *aModule)
Compute hashes for modules without taking into account their position, rotation or layer.
static void FootprintWriteShape(FILE *File, MODULE *module, const wxString &aShapeName)
#define TO_UTF8(wxstring)
static const double SCALE_FACTOR
static std::map< MODULE *, int > componentShapes
static std::map< int, wxString > shapeNames

References componentShapes, escapeString(), flipBottomPads, FootprintWriteShape(), Format(), hashModule(), individualShapes, BOARD::Modules(), NORMALIZE_ANGLE_POS(), SCALE_FACTOR, shapeNames, TO_UTF8, and uniquePins.

Referenced by PCB_EDIT_FRAME::ExportToGenCAD().

◆ CreateSignalsSection()

static void CreateSignalsSection ( FILE *  aFile,
BOARD aPcb 
)
static

Definition at line 894 of file export_gencad.cpp.

895 {
896  wxString msg;
897  NETINFO_ITEM* net;
898  int NbNoConn = 1;
899 
900  fputs( "$SIGNALS\n", aFile );
901 
902  for( unsigned ii = 0; ii < aPcb->GetNetCount(); ii++ )
903  {
904  net = aPcb->FindNet( ii );
905 
906  if( net->GetNetname() == wxEmptyString ) // dummy netlist (no connection)
907  {
908  msg.Printf( "NoConnection%d", NbNoConn++ );
909  }
910 
911  if( net->GetNet() <= 0 ) // dummy netlist (no connection)
912  continue;
913 
914  msg = wxT( "SIGNAL \"" ) + escapeString( net->GetNetname() ) + "\"";
915 
916  fputs( TO_UTF8( msg ), aFile );
917  fputs( "\n", aFile );
918 
919  for( auto module : aPcb->Modules() )
920  {
921  for( auto pad : module->Pads() )
922  {
923  if( pad->GetNetCode() != net->GetNet() )
924  continue;
925 
926  msg.Printf( wxT( "NODE \"%s\" \"%s\"" ),
927  GetChars( escapeString( module->GetReference() ) ),
928  GetChars( escapeString( pad->GetName() ) ) );
929 
930  fputs( TO_UTF8( msg ), aFile );
931  fputs( "\n", aFile );
932  }
933  }
934  }
935 
936  fputs( "$ENDSIGNALS\n\n", aFile );
937 }
NETINFO_ITEM * FindNet(int aNetcode) const
Function FindNet searches for a net with the given netcode.
static wxString escapeString(const wxString &aString)
unsigned GetNetCount() const
Function GetNetCount.
Definition: class_board.h:775
MODULES & Modules()
Definition: class_board.h:266
const wxString & GetNetname() const
Function GetNetname.
Definition: netinfo.h:231
NETINFO_ITEM handles the data for a net.
Definition: netinfo.h:65
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:153
int GetNet() const
Function GetNet.
Definition: netinfo.h:223
#define TO_UTF8(wxstring)

References escapeString(), BOARD::FindNet(), GetChars(), NETINFO_ITEM::GetNet(), BOARD::GetNetCount(), NETINFO_ITEM::GetNetname(), BOARD::Modules(), and TO_UTF8.

Referenced by PCB_EDIT_FRAME::ExportToGenCAD().

◆ CreateTracksInfoData()

static void CreateTracksInfoData ( FILE *  aFile,
BOARD aPcb 
)
static

Definition at line 1142 of file export_gencad.cpp.

1143 {
1144  // Find thickness used for traces
1145 
1146  std::set<int> trackinfo;
1147 
1148  for( auto track : aPcb->Tracks() )
1149  trackinfo.insert( track->GetWidth() );
1150 
1151  // Write data
1152  fputs( "$TRACKS\n", aFile );
1153 
1154  for( auto size : trackinfo )
1155  fprintf( aFile, "TRACK TRACK%d %g\n", size, size / SCALE_FACTOR );
1156 
1157  fputs( "$ENDTRACKS\n\n", aFile );
1158 }
static const double SCALE_FACTOR
TRACKS & Tracks()
Definition: class_board.h:257

References SCALE_FACTOR, and BOARD::Tracks().

Referenced by PCB_EDIT_FRAME::ExportToGenCAD().

◆ escapeString()

static wxString escapeString ( const wxString &  aString)
static

Definition at line 173 of file export_gencad.cpp.

174 {
175  wxString copy( aString );
176  copy.Replace( "\"", "\\\"" );
177  return copy;
178 }

Referenced by CreateComponentsSection(), CreateDevicesSection(), CreateRoutesSection(), CreateShapesSection(), CreateSignalsSection(), and FootprintWriteShape().

◆ fmt_mask()

static std::string fmt_mask ( LSET  aSet)
static

Definition at line 181 of file export_gencad.cpp.

182 {
183 #if 0
184  return aSet.FmtHex();
185 #else
186  return StrPrintf( "%08x", (unsigned) ( aSet & LSET::AllCuMask() ).to_ulong() );
187 #endif
188 }
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Function AllCuMask returns a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:712
int StrPrintf(std::string *aResult, const char *aFormat,...)
Function StrPrintf is like sprintf() but the output is appended to a std::string instead of to a char...
Definition: richio.cpp:74
std::string FmtHex() const
Function FmtHex returns a hex string showing contents of this LSEQ.
Definition: lset.cpp:288

References LSET::AllCuMask(), LSET::FmtHex(), and numEval::StrPrintf().

Referenced by CreatePadsShapesSection(), and CreateRoutesSection().

◆ FootprintWriteShape()

static void FootprintWriteShape ( FILE *  File,
MODULE module,
const wxString &  aShapeName 
)
static

Definition at line 1166 of file export_gencad.cpp.

1167 {
1168  EDGE_MODULE* PtEdge;
1169 
1170  /* creates header: */
1171  fprintf( aFile, "\nSHAPE \"%s\"\n", TO_UTF8( escapeString( aShapeName ) ) );
1172 
1173  if( module->GetAttributes() & MOD_VIRTUAL )
1174  {
1175  fprintf( aFile, "INSERT SMD\n" );
1176  }
1177  else
1178  {
1179  if( module->GetAttributes() & MOD_CMS )
1180  {
1181  fprintf( aFile, "INSERT SMD\n" );
1182  }
1183  else
1184  {
1185  fprintf( aFile, "INSERT TH\n" );
1186  }
1187  }
1188 
1189 #if 0 /* ATTRIBUTE name and value is unspecified and the original exporter
1190  * got the syntax wrong, so CAM350 rejected the whole shape! */
1191 
1192  if( module->m_Attributs != MOD_DEFAULT )
1193  {
1194  fprintf( aFile, "ATTRIBUTE" );
1195 
1196  if( module->m_Attributs & MOD_CMS )
1197  fprintf( aFile, " PAD_SMD" );
1198 
1199  if( module->m_Attributs & MOD_VIRTUAL )
1200  fprintf( aFile, " VIRTUAL" );
1201 
1202  fprintf( aFile, "\n" );
1203  }
1204 #endif
1205 
1206  // Silk outline; wildly interpreted by various importers:
1207  // CAM350 read it right but only closed shapes
1208  // ProntoPlace double-flip it (at least the pads are correct)
1209  // GerberTool usually get it right...
1210  for( auto PtStruct : module->GraphicalItems() )
1211  {
1212  switch( PtStruct->Type() )
1213  {
1214  case PCB_MODULE_TEXT_T:
1215 
1216  // If we wanted to export text, this is not the correct section
1217  break;
1218 
1219  case PCB_MODULE_EDGE_T:
1220  PtEdge = (EDGE_MODULE*) PtStruct;
1221  if( PtEdge->GetLayer() == F_SilkS
1222  || PtEdge->GetLayer() == B_SilkS )
1223  {
1224  switch( PtEdge->GetShape() )
1225  {
1226  case S_SEGMENT:
1227  fprintf( aFile, "LINE %g %g %g %g\n",
1228  PtEdge->m_Start0.x / SCALE_FACTOR,
1229  -PtEdge->m_Start0.y / SCALE_FACTOR,
1230  PtEdge->m_End0.x / SCALE_FACTOR,
1231  -PtEdge->m_End0.y / SCALE_FACTOR );
1232  break;
1233 
1234  case S_RECT:
1235  {
1236  fprintf( aFile, "LINE %g %g %g %g\n",
1237  PtEdge->m_Start0.x / SCALE_FACTOR,
1238  -PtEdge->m_Start0.y / SCALE_FACTOR,
1239  PtEdge->m_End0.x / SCALE_FACTOR,
1240  -PtEdge->m_Start0.y / SCALE_FACTOR );
1241  fprintf( aFile, "LINE %g %g %g %g\n",
1242  PtEdge->m_End0.x / SCALE_FACTOR,
1243  -PtEdge->m_Start0.y / SCALE_FACTOR,
1244  PtEdge->m_End0.x / SCALE_FACTOR,
1245  -PtEdge->m_End0.y / SCALE_FACTOR );
1246  fprintf( aFile, "LINE %g %g %g %g\n",
1247  PtEdge->m_End0.x / SCALE_FACTOR,
1248  -PtEdge->m_End0.y / SCALE_FACTOR,
1249  PtEdge->m_Start0.x / SCALE_FACTOR,
1250  -PtEdge->m_End0.y / SCALE_FACTOR );
1251  fprintf( aFile, "LINE %g %g %g %g\n",
1252  PtEdge->m_Start0.x / SCALE_FACTOR,
1253  -PtEdge->m_End0.y / SCALE_FACTOR,
1254  PtEdge->m_Start0.x / SCALE_FACTOR,
1255  -PtEdge->m_Start0.y / SCALE_FACTOR );
1256  }
1257  break;
1258 
1259  case S_CIRCLE:
1260  {
1261  int radius = KiROUND( GetLineLength( PtEdge->m_End0,
1262  PtEdge->m_Start0 ) );
1263  fprintf( aFile, "CIRCLE %g %g %g\n",
1264  PtEdge->m_Start0.x / SCALE_FACTOR,
1265  -PtEdge->m_Start0.y / SCALE_FACTOR,
1266  radius / SCALE_FACTOR );
1267  break;
1268  }
1269 
1270  case S_ARC:
1271  {
1272  int arcendx, arcendy;
1273  arcendx = PtEdge->m_End0.x - PtEdge->m_Start0.x;
1274  arcendy = PtEdge->m_End0.y - PtEdge->m_Start0.y;
1275  RotatePoint( &arcendx, &arcendy, -PtEdge->GetAngle() );
1276  arcendx += PtEdge->GetStart0().x;
1277  arcendy += PtEdge->GetStart0().y;
1278 
1279  fprintf( aFile, "ARC %g %g %g %g %g %g\n",
1280  PtEdge->m_End0.x / SCALE_FACTOR,
1281  -PtEdge->GetEnd0().y / SCALE_FACTOR,
1282  arcendx / SCALE_FACTOR,
1283  -arcendy / SCALE_FACTOR,
1284  PtEdge->GetStart0().x / SCALE_FACTOR,
1285  -PtEdge->GetStart0().y / SCALE_FACTOR );
1286  break;
1287  }
1288 
1289  case S_POLYGON:
1290  // Not exported (TODO)
1291  break;
1292 
1293  default:
1294  DisplayError( NULL, wxString::Format( "Type Edge Module %d invalid.", PtStruct->Type() ) );
1295  break;
1296  }
1297  }
1298  break;
1299 
1300  default:
1301  break;
1302  }
1303  }
1304 }
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:239
int GetAttributes() const
Definition: class_module.h:266
double GetLineLength(const wxPoint &aPointA, const wxPoint &aPointB)
Return the length of a line segment defined by aPointA and aPointB.
Definition: trigo.h:206
STROKE_T GetShape() const
polygon (not yet used for tracks, but could be in microwave apps)
Set for modules listed in the automatic insertion list (usually SMD footprints)
Definition: class_module.h:68
usual segment : line with rounded ends
static wxString escapeString(const wxString &aString)
DRAWINGS & GraphicalItems()
Definition: class_module.h:183
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:208
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:94
wxPoint m_End0
End point, relative to module origin, orient 0.
const wxPoint & GetStart0() const
segment with non rounded ends
#define NULL
Arcs (with rounded ends)
default
Definition: class_module.h:67
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:93
double GetAngle() const
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
Virtual component: when created by copper shapes on board (Like edge card connectors,...
Definition: class_module.h:70
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:68
#define TO_UTF8(wxstring)
static const double SCALE_FACTOR
const wxPoint & GetEnd0() const
wxPoint m_Start0
Start point or center, relative to module origin, orient 0.
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
int m_Attributs
Definition: class_module.h:711

References B_SilkS, DisplayError(), escapeString(), F_SilkS, Format(), DRAWSEGMENT::GetAngle(), MODULE::GetAttributes(), EDGE_MODULE::GetEnd0(), BOARD_ITEM::GetLayer(), GetLineLength(), DRAWSEGMENT::GetShape(), EDGE_MODULE::GetStart0(), MODULE::GraphicalItems(), KiROUND(), MODULE::m_Attributs, EDGE_MODULE::m_End0, EDGE_MODULE::m_Start0, MOD_CMS, MOD_DEFAULT, MOD_VIRTUAL, NULL, PCB_MODULE_EDGE_T, PCB_MODULE_TEXT_T, RotatePoint(), S_ARC, S_CIRCLE, S_POLYGON, S_RECT, S_SEGMENT, SCALE_FACTOR, TO_UTF8, wxPoint::x, and wxPoint::y.

Referenced by CreateShapesSection().

◆ GenCADLayerName()

static std::string GenCADLayerName ( int  aCuCount,
PCB_LAYER_ID  aId 
)
static

Definition at line 65 of file export_gencad.cpp.

66 {
67  if( IsCopperLayer( aId ) )
68  {
69  if( aId == F_Cu )
70  return "TOP";
71  else if( aId == B_Cu )
72  return "BOTTOM";
73 
74  else if( aId <= 14 )
75  {
76  return StrPrintf( "INNER%d", aCuCount - aId - 1 );
77  }
78  else
79  {
80  return StrPrintf( "LAYER%d", aId );
81  }
82  }
83 
84  else
85  {
86  const char* txt;
87 
88  // using a switch to clearly show mapping & catch out of bounds index.
89  switch( aId )
90  {
91  // Technicals
92  case B_Adhes: txt = "B.Adhes"; break;
93  case F_Adhes: txt = "F.Adhes"; break;
94  case B_Paste: txt = "SOLDERPASTE_BOTTOM"; break;
95  case F_Paste: txt = "SOLDERPASTE_TOP"; break;
96  case B_SilkS: txt = "SILKSCREEN_BOTTOM"; break;
97  case F_SilkS: txt = "SILKSCREEN_TOP"; break;
98  case B_Mask: txt = "SOLDERMASK_BOTTOM"; break;
99  case F_Mask: txt = "SOLDERMASK_TOP"; break;
100 
101  // Users
102  case Dwgs_User: txt = "Dwgs.User"; break;
103  case Cmts_User: txt = "Cmts.User"; break;
104  case Eco1_User: txt = "Eco1.User"; break;
105  case Eco2_User: txt = "Eco2.User"; break;
106  case Edge_Cuts: txt = "Edge.Cuts"; break;
107  case Margin: txt = "Margin"; break;
108 
109  // Footprint
110  case F_CrtYd: txt = "F_CrtYd"; break;
111  case B_CrtYd: txt = "B_CrtYd"; break;
112  case F_Fab: txt = "F_Fab"; break;
113  case B_Fab: txt = "B_Fab"; break;
114 
115  default:
116  wxASSERT_MSG( 0, wxT( "aId UNEXPECTED" ) );
117  txt = "BAD-INDEX!"; break;
118  }
119 
120  return txt;
121  }
122 }
int StrPrintf(std::string *aResult, const char *aFormat,...)
Function StrPrintf is like sprintf() but the output is appended to a std::string instead of to a char...
Definition: richio.cpp:74
bool IsCopperLayer(LAYER_NUM aLayerId)
Function IsCopperLayer tests whether a layer is a copper layer.

References B_Adhes, B_CrtYd, B_Cu, B_Fab, B_Mask, B_Paste, B_SilkS, Cmts_User, Dwgs_User, Eco1_User, Eco2_User, Edge_Cuts, F_Adhes, F_CrtYd, F_Cu, F_Fab, F_Mask, F_Paste, F_SilkS, IsCopperLayer(), Margin, and numEval::StrPrintf().

Referenced by CreateComponentsSection(), CreatePadsShapesSection(), CreateRoutesSection(), and GenCADLayerNameFlipped().

◆ GenCADLayerNameFlipped()

static std::string GenCADLayerNameFlipped ( int  aCuCount,
PCB_LAYER_ID  aId 
)
static

Definition at line 162 of file export_gencad.cpp.

163 {
164  if( 1<= aId && aId <= 14 )
165  {
166  return StrPrintf( "INNER%d", 14 - aId );
167  }
168 
169  return GenCADLayerName( aCuCount, aId );
170 }
int StrPrintf(std::string *aResult, const char *aFormat,...)
Function StrPrintf is like sprintf() but the output is appended to a std::string instead of to a char...
Definition: richio.cpp:74
static std::string GenCADLayerName(int aCuCount, PCB_LAYER_ID aId)

References GenCADLayerName(), and numEval::StrPrintf().

Referenced by CreatePadsShapesSection().

◆ getShapeName()

static const wxString getShapeName ( MODULE aModule)
static

Definition at line 203 of file export_gencad.cpp.

204 {
205  static const wxString invalid( "invalid" );
206 
207  if( individualShapes )
208  return aModule->GetReference();
209 
210  auto itShape = componentShapes.find( aModule );
211  wxCHECK( itShape != componentShapes.end(), invalid );
212 
213  auto itName = shapeNames.find( itShape->second );
214  wxCHECK( itName != shapeNames.end(), invalid );
215 
216  return itName->second;
217 }
const wxString GetReference() const
Function GetReference.
Definition: class_module.h:444
static bool individualShapes
static std::map< MODULE *, int > componentShapes
static std::map< int, wxString > shapeNames

References componentShapes, MODULE::GetReference(), individualShapes, and shapeNames.

Referenced by CreateComponentsSection().

◆ hashModule()

static size_t hashModule ( const MODULE aModule)
static

Compute hashes for modules without taking into account their position, rotation or layer.

Definition at line 681 of file export_gencad.cpp.

682 {
683  size_t ret = 0x11223344;
684  constexpr int flags = HASH_FLAGS::HASH_POS | HASH_FLAGS::REL_COORD
686 
687 
688  for( auto i : aModule->GraphicalItems() )
689  ret += hash_eda( i, flags );
690 
691  for( auto i : aModule->Pads() )
692  ret += hash_eda( i, flags );
693 
694  return ret;
695 }
use coordinates relative to the parent object
Definition: hash_eda.h:44
PADS & Pads()
Definition: class_module.h:173
DRAWINGS & GraphicalItems()
Definition: class_module.h:183
size_t hash_eda(const EDA_ITEM *aItem, int aFlags)
Calculates hash of an EDA_ITEM.
Definition: hash_eda.cpp:49

References MODULE::GraphicalItems(), hash_eda(), HASH_LAYER, HASH_POS, HASH_ROT, MODULE::Pads(), and REL_COORD.

Referenced by CreateShapesSection().

◆ MapXTo()

static double MapXTo ( int  aX)
static

Definition at line 225 of file export_gencad.cpp.

226 {
227  return (aX - GencadOffsetX) / SCALE_FACTOR;
228 }
static const double SCALE_FACTOR
static int GencadOffsetX

References GencadOffsetX, and SCALE_FACTOR.

Referenced by CreateBoardSection(), CreateComponentsSection(), CreateHeaderInfoData(), and CreateRoutesSection().

◆ MapYTo()

static double MapYTo ( int  aY)
static

Definition at line 231 of file export_gencad.cpp.

232 {
233  return (GencadOffsetY - aY) / SCALE_FACTOR;
234 }
static int GencadOffsetY
static const double SCALE_FACTOR

References GencadOffsetY, and SCALE_FACTOR.

Referenced by CreateBoardSection(), CreateComponentsSection(), CreateHeaderInfoData(), and CreateRoutesSection().

◆ ViaSort()

static bool ViaSort ( const VIA aPadref,
const VIA aPadcmp 
)
static

Definition at line 345 of file export_gencad.cpp.

346 {
347  if( aPadref->GetWidth() != aPadcmp->GetWidth() )
348  return aPadref->GetWidth() < aPadcmp->GetWidth();
349 
350  if( aPadref->GetDrillValue() != aPadcmp->GetDrillValue() )
351  return aPadref->GetDrillValue() < aPadcmp->GetDrillValue();
352 
353  if( aPadref->GetLayerSet() != aPadcmp->GetLayerSet() )
354  return aPadref->GetLayerSet().FmtBin().compare( aPadcmp->GetLayerSet().FmtBin() ) < 0;
355 
356  return false;
357 }
virtual LSET GetLayerSet() const override
Function GetLayerSet returns a std::bitset of all layers on which the item physically resides.
int GetDrillValue() const
Function GetDrillValue "calculates" the drill value for vias (m-Drill if > 0, or default drill value ...
int GetWidth() const
Definition: class_track.h:110
std::string FmtBin() const
Function FmtBin returns a binary string showing contents of this LSEQ.
Definition: lset.cpp:264

References LSET::FmtBin(), VIA::GetDrillValue(), VIA::GetLayerSet(), and TRACK::GetWidth().

Referenced by CreatePadsShapesSection().

Variable Documentation

◆ componentShapes

std::map<MODULE*, int> componentShapes
static

◆ flipBottomPads

bool flipBottomPads
static

◆ gc_seq

const PCB_LAYER_ID gc_seq[]
static

Definition at line 125 of file export_gencad.cpp.

Referenced by CreatePadsShapesSection().

◆ GencadOffsetX

int GencadOffsetX
static

Definition at line 197 of file export_gencad.cpp.

Referenced by PCB_EDIT_FRAME::ExportToGenCAD(), and MapXTo().

◆ GencadOffsetY

int GencadOffsetY
static

Definition at line 197 of file export_gencad.cpp.

Referenced by PCB_EDIT_FRAME::ExportToGenCAD(), and MapYTo().

◆ individualShapes

bool individualShapes
static

◆ SCALE_FACTOR

◆ shapeNames

std::map<int, wxString> shapeNames
static

◆ storeOriginCoords

bool storeOriginCoords
static

Definition at line 194 of file export_gencad.cpp.

Referenced by CreateHeaderInfoData(), and PCB_EDIT_FRAME::ExportToGenCAD().

◆ uniquePins

bool uniquePins
static

Definition at line 192 of file export_gencad.cpp.

Referenced by CreateShapesSection(), and PCB_EDIT_FRAME::ExportToGenCAD().