42 else if( aId ==
B_Cu )
45 return fmt::format(
"INNER{}", aCuCount - aId - 1 );
47 return fmt::format(
"LAYER{}",
static_cast<int>( aId ) );
58 case B_Adhes: txt =
"B.Adhes";
break;
59 case F_Adhes: txt =
"F.Adhes";
break;
60 case B_Paste: txt =
"SOLDERPASTE_BOTTOM";
break;
61 case F_Paste: txt =
"SOLDERPASTE_TOP";
break;
62 case B_SilkS: txt =
"SILKSCREEN_BOTTOM";
break;
63 case F_SilkS: txt =
"SILKSCREEN_TOP";
break;
64 case B_Mask: txt =
"SOLDERMASK_BOTTOM";
break;
65 case F_Mask: txt =
"SOLDERMASK_TOP";
break;
73 case Margin: txt =
"Margin";
break;
76 case F_CrtYd: txt =
"F_CrtYd";
break;
77 case B_CrtYd: txt =
"B_CrtYd";
break;
78 case F_Fab: txt =
"F_Fab";
break;
79 case B_Fab: txt =
"B_Fab";
break;
82 wxASSERT_MSG( 0, wxT(
"aId UNEXPECTED" ) );
83 txt =
"BAD-INDEX!";
break;
94 if( 1<= aId && aId <= 14 )
95 return fmt::format(
"INNER{}", 14 - aId );
103 wxString
copy( aString );
104 copy.Replace( wxT(
"\"" ), wxT(
"\\\"" ) );
112 retv.erase( 0, retv.find_first_not_of(
'0' ) );
124 static const wxString invalid(
"invalid" );
132 auto itName =
shapeNames.find( itShape->second );
133 wxCHECK( itName !=
shapeNames.end(), invalid );
135 return itName->second;
160 m_file = wxFopen( aFullFileName, wxT(
"wt" ) );
179 footprint->SetFlag( 0 );
181 if( footprint->GetLayer() ==
B_Cu )
184 footprint->SetFlag( 1 );
223 if( footprint->GetFlag() )
226 footprint->SetFlag( 0 );
256 fmt::print(
m_file,
"$ARTWORKS\n" );
257 fmt::print(
m_file,
"$ENDARTWORKS\n\n" );
266 std::vector<PAD*> padstacks;
267 std::vector<PCB_VIA*> vias;
268 std::vector<PCB_VIA*> viastacks;
270 padstacks.resize( 1 );
272 LSEQ gc_seq =
m_board->GetEnabledLayers().CuStack();
273 std::reverse(gc_seq.begin(), gc_seq.end());
276 LSET master_layermask =
m_board->GetDesignSettings().GetEnabledLayers();
277 int cu_count =
m_board->GetCopperLayerCount();
279 fmt::print(
m_file,
"$PADS\n" );
282 std::vector<PAD*> pads =
m_board->GetPads();
283 std::sort( pads.begin(), pads.end(), [](
const PAD* a,
const PAD* b )
285 return PAD::Compare( a, b ) < 0;
292 vias.push_back(
via );
295 std::sort( vias.begin(), vias.end(),
viaSort );
296 vias.erase( std::unique( vias.begin(), vias.end(), [](
const PCB_VIA* a,
const PCB_VIA* b )
298 return viaSort( a, b ) == false;
305 viastacks.push_back(
via );
306 fmt::print(
m_file,
"PAD V{}.{}.{} ROUND {}\nCIRCLE 0 0 {}\n",
308 via->GetDrillValue(),
309 fmt_mask(
via->GetLayerSet() & master_layermask ).c_str(),
315 PAD* old_pad =
nullptr;
316 int pad_name_number = 0;
318 for(
unsigned i = 0; i<pads.size(); ++i )
323 pad->SetSubRatsnest( pad_name_number );
333 pad->SetSubRatsnest( pad_name_number );
335 fmt::print(
m_file,
"PAD P{}",
pad->GetSubRatsnest() );
337 padstacks.push_back(
pad );
348 fmt::print(
m_file,
" ROUND {}\n",
352 fmt::print(
m_file,
"CIRCLE {} {} {}\n",
359 fmt::print(
m_file,
" RECTANGULAR {}\n",
363 fmt::print(
m_file,
"RECTANGLE {} {} {} {}\n",
373 int radius = std::min( size.
x, size.
y ) / 2;
380 int lineX = size.
x / 2 -
radius;
381 int lineY = size.
y / 2 -
radius;
386 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
397 fmt::print(
m_file,
"LINE {} {} {} {}\n",
405 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
416 fmt::print(
m_file,
"LINE {} {} {} {}\n",
424 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
435 fmt::print(
m_file,
"LINE {} {} {} {}\n",
443 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
454 fmt::print(
m_file,
"LINE {} {} {} {}\n",
472 poly[0] =
VECTOR2I( -dx + ddy, dy + ddx );
473 poly[1] =
VECTOR2I( dx - ddy, dy - ddx );
474 poly[2] =
VECTOR2I( dx + ddy, -dy + ddx );
475 poly[3] =
VECTOR2I( -dx - ddy, -dy - ddx );
477 for(
int cur = 0; cur < 4; ++cur )
479 int next = ( cur + 1 ) % 4;
480 fmt::print(
m_file,
"LINE {} {} {} {}\n",
499 pad->GetOrientation(),
510 for(
int ii = 0; ii < pointCount; ii++ )
512 int next = ( ii + 1 ) % pointCount;
513 fmt::print(
m_file,
"LINE {} {} {} {}\n",
529 pad->MergePrimitivesAsPolygon(
F_Cu, &outline );
536 for(
int ii = 0; ii < pointCount; ii++ )
538 int next = ( ii + 1 ) % pointCount;
539 fmt::print(
m_file,
"LINE {} {} {} {}\n",
552 fmt::print(
m_file,
"\n$ENDPADS\n\n" );
555 fmt::print(
m_file,
"$PADSTACKS\n" );
558 for(
unsigned i = 0; i < viastacks.size(); i++ )
562 LSET mask =
via->GetLayerSet() & master_layermask;
564 fmt::print(
m_file,
"PADSTACK VIA{}.{}.{} {}\n",
566 via->GetDrillValue(),
572 fmt::print(
m_file,
"PAD V{}.{}.{} {} 0 0\n",
574 via->GetDrillValue(),
585 for(
unsigned i = 1; i < padstacks.size(); i++ )
590 fmt::print(
m_file,
"PADSTACK PAD{} {}\n",
594 LSET pad_set =
pad->GetLayerSet() & master_layermask;
599 fmt::print(
m_file,
"PAD P{} {} 0 0\n",
607 fmt::print(
m_file,
"PADSTACK PAD{}F {}\n",
614 fmt::print(
m_file,
"PAD P{} {} 0 0\n",
621 fputs(
"$ENDPADSTACKS\n\n",
m_file );
628 size_t ret = 0x11223344;
635 for(
PAD* i : aFootprint->
Pads() )
646 const char* mirror =
"0";
647 std::map<wxString, size_t> shapes;
649 fmt::print(
m_file,
"$SHAPES\n" );
659 wxString shapeName = footprint->GetFPID().Format();
661 auto shapeIt = shapes.find( shapeName );
664 if( shapeIt != shapes.end() )
666 if( modHash != shapeIt->second )
670 wxString newShapeName;
676 newShapeName = wxString::Format( wxT(
"%s_%d" ), shapeName, suffix );
677 shapeIt = shapes.find( newShapeName );
680 while( shapeIt != shapes.end() && shapeIt->second != modHash );
682 shapeName = newShapeName;
685 if( shapeIt != shapes.end() && modHash == shapeIt->second )
696 shapes[shapeName] = modHash;
705 std::set<wxString> pins;
707 for(
PAD*
pad : footprint->Pads() )
713 pinname =
pad->GetNumber();
715 if( pinname.IsEmpty() )
716 pinname = wxT(
"none" );
721 wxString origPinname( pinname );
723 auto it = pins.find( pinname );
725 while( it != pins.end() )
727 pinname = wxString::Format( wxT(
"%s_%d" ), origPinname, suffix );
729 it = pins.find( pinname );
732 pins.insert( pinname );
735 EDA_ANGLE orient =
pad->GetOrientation() - footprint->GetOrientation();
740 std::string flipStr = (
m_flipBottomPads && footprint->GetFlag() ) ?
"F" :
"";
744 "PIN \"{}\" PAD{}{} {} {} {} {} {}\n",
746 pad->GetSubRatsnest(),
756 fmt::print(
m_file,
"$ENDSHAPES\n\n" );
762 fmt::print(
m_file,
"$COMPONENTS\n" );
764 int cu_count =
m_board->GetCopperLayerCount();
770 EDA_ANGLE fp_orient = footprint->GetOrientation();
772 if( footprint->GetFlag() )
784 fmt::print(
m_file,
"\nCOMPONENT \"{}\"\n",
786 fmt::print(
m_file,
"DEVICE \"DEV_{}\"\n",
788 fmt::print(
m_file,
"PLACE {} {}\n",
789 mapXTo( footprint->GetPosition().x ),
790 mapYTo( footprint->GetPosition().y ) );
791 fmt::print(
m_file,
"LAYER {}\n",
792 footprint->GetFlag() ?
"BOTTOM" :
"TOP" );
793 fmt::print(
m_file,
"ROTATION {}\n",
795 fmt::print(
m_file,
"SHAPE \"{}\" {} {}\n",
800 for(
PCB_TEXT* textItem : { &footprint->Reference(), &footprint->Value() } )
804 fmt::print(
m_file,
"TEXT {} {} {} {} {} {} \"{}\"",
808 textItem->GetTextAngle().AsDegrees(),
813 BOX2I textBox = textItem->GetTextBox(
nullptr );
815 fmt::print(
m_file,
" 0 0 {} {}\n",
821 fmt::print(
m_file,
"SHEET \"RefDes: {}, Value: {}\"\n",
822 TO_UTF8( footprint->GetReference() ),
823 TO_UTF8( footprint->GetValue() ) );
826 fmt::print(
m_file,
"$ENDCOMPONENTS\n\n" );
839 fmt::print(
m_file,
"$SIGNALS\n" );
841 for(
unsigned ii = 0; ii <
m_board->GetNetCount(); ii++ )
849 msg.Printf( wxT(
"NoConnection%d" ), NbNoConn++ );
858 fmt::print(
m_file,
"\n" );
862 for(
PAD*
pad : footprint->Pads() )
867 msg.Printf( wxT(
"NODE \"%s\" \"%s\"" ),
872 fmt::print(
m_file,
"\n" );
878 fmt::print(
m_file,
"$ENDSIGNALS\n\n" );
884 fmt::print(
m_file,
"$HEADER\n" );
885 fmt::print(
m_file,
"GENCAD 1.4\n" );
890 fmt::print(
m_file,
"DRAWING \"{}\"\n",
m_board->GetFileName() );
895 fmt::print(
m_file,
"REVISION \"{} {}\"\n", rev, date );
896 fmt::print(
m_file,
"UNITS INCH\n" );
902 fmt::print(
m_file,
"INTERTRACK 0\n" );
903 fmt::print(
m_file,
"$ENDHEADER\n\n" );
912 int old_netcode, old_width, old_layer;
913 LSET master_layermask =
m_board->GetDesignSettings().GetEnabledLayers();
914 int cu_count =
m_board->GetCopperLayerCount();
917 std::sort( tracks.begin(), tracks.end(),
923 if( a->Type() == PCB_VIA_T )
924 widthA = static_cast<const PCB_VIA*>( a )->GetWidth( PADSTACK::ALL_LAYERS );
926 widthA = a->GetWidth();
928 if( b->Type() == PCB_VIA_T )
929 widthB = static_cast<const PCB_VIA*>( b )->GetWidth( PADSTACK::ALL_LAYERS );
931 widthB = b->GetWidth();
933 if( a->GetNetCode() == b->GetNetCode() )
935 if( widthA == widthB )
936 return ( a->GetLayer() < b->GetLayer() );
938 return ( widthA < widthB );
944 fmt::print( m_file,
"$ROUTES\n" );
952 if( old_netcode != track->GetNetCode() )
954 old_netcode = track->GetNetCode();
958 if( net && (net->
GetNetname() != wxEmptyString) )
961 netname = wxT(
"_noname_" );
966 int currentWidth = 0;
973 if( old_width != currentWidth )
975 old_width = currentWidth;
976 fmt::print( m_file,
"TRACK TRACK{}\n", currentWidth );
981 if( old_layer != track->GetLayer() )
983 old_layer = track->GetLayer();
984 fmt::print( m_file,
"LAYER {}\n",
988 fmt::print( m_file,
"LINE {} {} {} {}\n",
989 mapXTo( track->GetStart().x ), mapYTo( track->GetStart().y ),
990 mapXTo( track->GetEnd().x ), mapYTo( track->GetEnd().y ) );
994 if( old_layer != track->GetLayer() )
996 old_layer = track->GetLayer();
997 fmt::print( m_file,
"LAYER {}\n",
1001 VECTOR2I start = track->GetStart();
1008 std::swap( start,
end );
1012 fmt::print( m_file,
"ARC {} {} {} {} {} {}\n",
1013 mapXTo( start.
x ), mapYTo( start.
y ),
1014 mapXTo(
end.x ), mapYTo(
end.y ),
1021 LSET vset =
via->GetLayerSet() & master_layermask;
1023 fmt::print( m_file,
"VIA VIA{}.{}.{} {} {} ALL {} via{}\n",
1025 via->GetDrillValue(),
1027 mapXTo(
via->GetStart().x ), mapYTo(
via->GetStart().y ),
1033 fmt::print( m_file,
"$ENDROUTES\n\n" );
1039 std::set<wxString> emitted;
1041 fmt::print(
m_file,
"$DEVICES\n" );
1052 const wxString& shapeName =
shapeNames[componentShape.second];
1054 std::tie( std::ignore, newDevice ) = emitted.insert( shapeName );
1059 const FOOTPRINT* footprint = componentShape.first;
1062 txt.Printf(
"\nDEVICE \"DEV_%s\"\n",
escapeString( shapeName ) );
1071 for( wxString& item : data )
1074 fmt::print(
m_file,
"$ENDDEVICES\n\n" );
1082 fmt::print(
m_file,
"$BOARD\n" );
1087 if( !
m_board->GetBoardPolygonOutlines( outline,
true ) )
1088 wxLogError(
_(
"Board outline is malformed. Run DRC for a full analysis." ) );
1093 fmt::print(
m_file,
"LINE {} {} {} {}\n",
1098 fmt::print(
m_file,
"$ENDBOARD\n\n" );
1105 std::set<int> trackinfo;
1112 trackinfo.insert( track->GetWidth() );
1116 fmt::print(
m_file,
"$TRACKS\n" );
1118 for(
int size : trackinfo )
1121 fmt::print(
m_file,
"$ENDTRACKS\n\n" );
1131 fmt::print(
m_file,
"INSERT TH\n" );
1133 fmt::print(
m_file,
"INSERT SMD\n" );
1155 fmt::print(
m_file,
"LINE {} {} {} {}\n",
1163 fmt::print(
m_file,
"LINE {} {} {} {}\n",
1168 fmt::print(
m_file,
"LINE {} {} {} {}\n",
1173 fmt::print(
m_file,
"LINE {} {} {} {}\n",
1178 fmt::print(
m_file,
"LINE {} {} {} {}\n",
1189 fmt::print(
m_file,
"CIRCLE {} {} {}\n",
1198 std::swap( start,
end );
1200 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
1214 wxFAIL_MSG( wxString::Format( wxT(
"Shape type %d invalid." ), item->Type() ) );
constexpr EDA_IU_SCALE pcbIUScale
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
wxString GetBuildVersion()
Get the full KiCad version string.
std::string FmtBin() const
Return a binary string showing contents of this set.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Information pertinent to a Pcbnew printed circuit board.
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
const FOOTPRINTS & Footprints() const
constexpr size_type GetWidth() const
constexpr size_type GetHeight() const
EDA_ANGLE GetArcAngle() const
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
void createRoutesSection()
Create the $ROUTES section.
void createTracksInfoData()
Create the "$TRACKS" section.
void createShapesSection()
Create the footprint shape list.
const wxString getShapeName(FOOTPRINT *aFootprint)
void createDevicesSection()
Create the $DEVICES section.
bool createHeaderInfoData()
Creates the header section.
double mapXTo(int aX)
Helper functions to calculate coordinates of footprints in GenCAD values.
void createArtworksSection()
void createBoardSection()
void footprintWriteShape(FOOTPRINT *aFootprint, const wxString &aShapeName)
Create the shape of a footprint (SHAPE section)
void createPadsShapesSection()
bool m_useIndividualShapes
void createSignalsSection()
bool WriteFile(const wxString &aFullFileName)
Export a GenCAD file.
void createComponentsSection()
Create the $COMPONENTS GenCAD section.
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
LSET is a set of PCB_LAYER_IDs.
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Handle the data for a net.
const wxString & GetNetname() const
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
static int Compare(const PAD *aPadRef, const PAD *aPadCmp)
Compare two pads and return 0 if they are equal.
virtual VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
int GetWidth() const override
int GetDrillValue() const
Calculate the drill value for vias (m_drill if > 0, or default drill value for the board).
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int PointCount() const
Return the number of points (vertices) in this line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
Represent a set of closed polygons.
int OutlineCount() const
Return the number of outlines in the set.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
SEGMENT_ITERATOR IterateSegmentsWithHoles()
Returns an iterator object, for all outlines in the set (with holes)
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, int aFlags)
void TransformRoundChamferedRectToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aPosition, const VECTOR2I &aSize, const EDA_ANGLE &aRotation, int aCornerRadius, double aChamferRatio, int aChamferCorners, int aInflate, int aError, ERROR_LOC aErrorLoc)
Convert a rectangle with rounded corners and/or chamfered corners to a polygon.
static constexpr EDA_ANGLE ANGLE_0
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
static std::string genCADLayerNameFlipped(int aCuCount, PCB_LAYER_ID aId)
The flipped layer name for GenCAD export (to make CAM350 imports correct).
static std::map< int, wxString > shapeNames
static std::string genCADLayerName(int aCuCount, PCB_LAYER_ID aId)
Layer names for GenCAD export.
static size_t hashFootprint(const FOOTPRINT *aFootprint)
Compute hashes for footprints without taking into account their position, rotation or layer.
static std::map< FOOTPRINT *, int > componentShapes
Association between shape names (using shapeName index) and components.
static std::string fmt_mask(const LSET &aSet)
static bool viaSort(const PCB_VIA *aPadref, const PCB_VIA *aPadcmp)
Sort vias for uniqueness.
static wxString escapeString(const wxString &aString)
size_t hash_fp_item(const EDA_ITEM *aItem, int aFlags)
Calculate hash of an EDA_ITEM.
Hashing functions for EDA_ITEMs.
@ REL_COORD
Use coordinates relative to the parent object.
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
#define UNIMPLEMENTED_FOR(type)
@ TOP_BOTTOM
Flip top to bottom (around the X axis)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
void vset(double *v, double x, double y, double z)
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Casted dyn_cast(From aObject)
A lightweight dynamic downcast.
VECTOR2< int32_t > VECTOR2I