43 else if( aId ==
B_Cu )
46 return fmt::format(
"INNER{}", aCuCount - aId - 1 );
48 return fmt::format(
"LAYER{}",
static_cast<int>( aId ) );
59 case B_Adhes: txt =
"B.Adhes";
break;
60 case F_Adhes: txt =
"F.Adhes";
break;
61 case B_Paste: txt =
"SOLDERPASTE_BOTTOM";
break;
62 case F_Paste: txt =
"SOLDERPASTE_TOP";
break;
63 case B_SilkS: txt =
"SILKSCREEN_BOTTOM";
break;
64 case F_SilkS: txt =
"SILKSCREEN_TOP";
break;
65 case B_Mask: txt =
"SOLDERMASK_BOTTOM";
break;
66 case F_Mask: txt =
"SOLDERMASK_TOP";
break;
74 case Margin: txt =
"Margin";
break;
77 case F_CrtYd: txt =
"F_CrtYd";
break;
78 case B_CrtYd: txt =
"B_CrtYd";
break;
79 case F_Fab: txt =
"F_Fab";
break;
80 case B_Fab: txt =
"B_Fab";
break;
83 wxASSERT_MSG( 0, wxT(
"aId UNEXPECTED" ) );
84 txt =
"BAD-INDEX!";
break;
95 if( 1<= aId && aId <= 14 )
96 return fmt::format(
"INNER{}", 14 - aId );
104 wxString
copy( aString );
105 copy.Replace( wxT(
"\"" ), wxT(
"\\\"" ) );
113 retv.erase( 0, retv.find_first_not_of(
'0' ) );
125 static const wxString invalid(
"invalid" );
133 auto itName =
shapeNames.find( itShape->second );
134 wxCHECK( itName !=
shapeNames.end(), invalid );
136 return itName->second;
161 m_file = wxFopen( aFullFileName, wxT(
"wt" ) );
180 footprint->SetFlag( 0 );
182 if( footprint->GetLayer() ==
B_Cu )
185 footprint->SetFlag( 1 );
224 if( footprint->GetFlag() )
227 footprint->SetFlag( 0 );
257 fmt::print(
m_file,
"$ARTWORKS\n" );
258 fmt::print(
m_file,
"$ENDARTWORKS\n\n" );
267 std::vector<PAD*> padstacks;
268 std::vector<PCB_VIA*> vias;
269 std::vector<PCB_VIA*> viastacks;
271 padstacks.resize( 1 );
273 LSEQ gc_seq =
m_board->GetEnabledLayers().CuStack();
274 std::reverse(gc_seq.begin(), gc_seq.end());
277 LSET master_layermask =
m_board->GetDesignSettings().GetEnabledLayers();
278 int cu_count =
m_board->GetCopperLayerCount();
280 fmt::print(
m_file,
"$PADS\n" );
283 std::vector<PAD*> pads =
m_board->GetPads();
284 std::sort( pads.begin(), pads.end(), [](
const PAD* a,
const PAD* b )
286 return PAD::Compare( a, b ) < 0;
293 vias.push_back(
via );
296 std::sort( vias.begin(), vias.end(),
viaSort );
297 vias.erase( std::unique( vias.begin(), vias.end(), [](
const PCB_VIA* a,
const PCB_VIA* b )
299 return viaSort( a, b ) == false;
306 viastacks.push_back(
via );
307 fmt::print(
m_file,
"PAD V{}.{}.{} ROUND {}\nCIRCLE 0 0 {}\n",
309 via->GetDrillValue(),
310 fmt_mask(
via->GetLayerSet() & master_layermask ).c_str(),
316 PAD* old_pad =
nullptr;
317 int pad_name_number = 0;
319 for(
unsigned i = 0; i<pads.size(); ++i )
324 pad->SetSubRatsnest( pad_name_number );
334 pad->SetSubRatsnest( pad_name_number );
336 fmt::print(
m_file,
"PAD P{}",
pad->GetSubRatsnest() );
338 padstacks.push_back(
pad );
349 fmt::print(
m_file,
" ROUND {}\n",
353 fmt::print(
m_file,
"CIRCLE {} {} {}\n",
360 fmt::print(
m_file,
" RECTANGULAR {}\n",
364 fmt::print(
m_file,
"RECTANGLE {} {} {} {}\n",
374 int radius = std::min( size.
x, size.
y ) / 2;
381 int lineX = size.
x / 2 -
radius;
382 int lineY = size.
y / 2 -
radius;
387 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
398 fmt::print(
m_file,
"LINE {} {} {} {}\n",
406 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
417 fmt::print(
m_file,
"LINE {} {} {} {}\n",
425 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
436 fmt::print(
m_file,
"LINE {} {} {} {}\n",
444 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
455 fmt::print(
m_file,
"LINE {} {} {} {}\n",
473 poly[0] =
VECTOR2I( -dx + ddy, dy + ddx );
474 poly[1] =
VECTOR2I( dx - ddy, dy - ddx );
475 poly[2] =
VECTOR2I( dx + ddy, -dy + ddx );
476 poly[3] =
VECTOR2I( -dx - ddy, -dy - ddx );
478 for(
int cur = 0; cur < 4; ++cur )
480 int next = ( cur + 1 ) % 4;
481 fmt::print(
m_file,
"LINE {} {} {} {}\n",
500 pad->GetOrientation(),
511 for(
int ii = 0; ii < pointCount; ii++ )
513 int next = ( ii + 1 ) % pointCount;
514 fmt::print(
m_file,
"LINE {} {} {} {}\n",
530 pad->MergePrimitivesAsPolygon(
F_Cu, &outline );
537 for(
int ii = 0; ii < pointCount; ii++ )
539 int next = ( ii + 1 ) % pointCount;
540 fmt::print(
m_file,
"LINE {} {} {} {}\n",
553 fmt::print(
m_file,
"\n$ENDPADS\n\n" );
556 fmt::print(
m_file,
"$PADSTACKS\n" );
559 for(
unsigned i = 0; i < viastacks.size(); i++ )
563 LSET mask =
via->GetLayerSet() & master_layermask;
565 fmt::print(
m_file,
"PADSTACK VIA{}.{}.{} {}\n",
567 via->GetDrillValue(),
573 fmt::print(
m_file,
"PAD V{}.{}.{} {} 0 0\n",
575 via->GetDrillValue(),
586 for(
unsigned i = 1; i < padstacks.size(); i++ )
591 fmt::print(
m_file,
"PADSTACK PAD{} {}\n",
595 LSET pad_set =
pad->GetLayerSet() & master_layermask;
600 fmt::print(
m_file,
"PAD P{} {} 0 0\n",
608 fmt::print(
m_file,
"PADSTACK PAD{}F {}\n",
615 fmt::print(
m_file,
"PAD P{} {} 0 0\n",
622 fputs(
"$ENDPADSTACKS\n\n",
m_file );
629 size_t ret = 0x11223344;
636 for(
PAD* i : aFootprint->
Pads() )
647 const char* mirror =
"0";
648 std::map<wxString, size_t> shapes;
650 fmt::print(
m_file,
"$SHAPES\n" );
660 wxString shapeName = footprint->GetFPID().Format();
662 auto shapeIt = shapes.find( shapeName );
665 if( shapeIt != shapes.end() )
667 if( modHash != shapeIt->second )
671 wxString newShapeName;
677 newShapeName = wxString::Format( wxT(
"%s_%d" ), shapeName, suffix );
678 shapeIt = shapes.find( newShapeName );
681 while( shapeIt != shapes.end() && shapeIt->second != modHash );
683 shapeName = newShapeName;
686 if( shapeIt != shapes.end() && modHash == shapeIt->second )
697 shapes[shapeName] = modHash;
706 std::set<wxString> pins;
708 for(
PAD*
pad : footprint->Pads() )
714 pinname =
pad->GetNumber();
716 if( pinname.IsEmpty() )
717 pinname = wxT(
"none" );
722 wxString origPinname( pinname );
724 auto it = pins.find( pinname );
726 while( it != pins.end() )
728 pinname = wxString::Format( wxT(
"%s_%d" ), origPinname, suffix );
730 it = pins.find( pinname );
733 pins.insert( pinname );
736 EDA_ANGLE orient =
pad->GetOrientation() - footprint->GetOrientation();
741 std::string flipStr = (
m_flipBottomPads && footprint->GetFlag() ) ?
"F" :
"";
745 "PIN \"{}\" PAD{}{} {} {} {} {} {}\n",
747 pad->GetSubRatsnest(),
757 fmt::print(
m_file,
"$ENDSHAPES\n\n" );
763 fmt::print(
m_file,
"$COMPONENTS\n" );
765 int cu_count =
m_board->GetCopperLayerCount();
771 EDA_ANGLE fp_orient = footprint->GetOrientation();
773 if( footprint->GetFlag() )
785 fmt::print(
m_file,
"\nCOMPONENT \"{}\"\n",
787 fmt::print(
m_file,
"DEVICE \"DEV_{}\"\n",
789 fmt::print(
m_file,
"PLACE {} {}\n",
790 mapXTo( footprint->GetPosition().x ),
791 mapYTo( footprint->GetPosition().y ) );
792 fmt::print(
m_file,
"LAYER {}\n",
793 footprint->GetFlag() ?
"BOTTOM" :
"TOP" );
794 fmt::print(
m_file,
"ROTATION {}\n",
796 fmt::print(
m_file,
"SHAPE \"{}\" {} {}\n",
801 for(
PCB_TEXT* textItem : { &footprint->Reference(), &footprint->Value() } )
805 fmt::print(
m_file,
"TEXT {} {} {} {} {} {} \"{}\"",
809 textItem->GetTextAngle().AsDegrees(),
814 BOX2I textBox = textItem->GetTextBox(
nullptr );
816 fmt::print(
m_file,
" 0 0 {} {}\n",
822 fmt::print(
m_file,
"SHEET \"RefDes: {}, Value: {}\"\n",
823 TO_UTF8( footprint->GetReference() ),
824 TO_UTF8( footprint->GetValue() ) );
827 fmt::print(
m_file,
"$ENDCOMPONENTS\n\n" );
840 fmt::print(
m_file,
"$SIGNALS\n" );
842 for(
unsigned ii = 0; ii <
m_board->GetNetCount(); ii++ )
850 msg.Printf( wxT(
"NoConnection%d" ), NbNoConn++ );
859 fmt::print(
m_file,
"\n" );
863 for(
PAD*
pad : footprint->Pads() )
868 msg.Printf( wxT(
"NODE \"%s\" \"%s\"" ),
873 fmt::print(
m_file,
"\n" );
879 fmt::print(
m_file,
"$ENDSIGNALS\n\n" );
885 fmt::print(
m_file,
"$HEADER\n" );
886 fmt::print(
m_file,
"GENCAD 1.4\n" );
891 fmt::print(
m_file,
"DRAWING \"{}\"\n",
m_board->GetFileName() );
896 fmt::print(
m_file,
"REVISION \"{} {}\"\n", rev, date );
897 fmt::print(
m_file,
"UNITS INCH\n" );
903 fmt::print(
m_file,
"INTERTRACK 0\n" );
904 fmt::print(
m_file,
"$ENDHEADER\n\n" );
913 int old_netcode, old_width, old_layer;
914 LSET master_layermask =
m_board->GetDesignSettings().GetEnabledLayers();
915 int cu_count =
m_board->GetCopperLayerCount();
918 std::sort( tracks.begin(), tracks.end(),
924 if( a->Type() == PCB_VIA_T )
925 widthA = static_cast<const PCB_VIA*>( a )->GetWidth( PADSTACK::ALL_LAYERS );
927 widthA = a->GetWidth();
929 if( b->Type() == PCB_VIA_T )
930 widthB = static_cast<const PCB_VIA*>( b )->GetWidth( PADSTACK::ALL_LAYERS );
932 widthB = b->GetWidth();
934 if( a->GetNetCode() == b->GetNetCode() )
936 if( widthA == widthB )
937 return ( a->GetLayer() < b->GetLayer() );
939 return ( widthA < widthB );
945 fmt::print( m_file,
"$ROUTES\n" );
953 if( old_netcode != track->GetNetCode() )
955 old_netcode = track->GetNetCode();
959 if( net && (net->
GetNetname() != wxEmptyString) )
962 netname = wxT(
"_noname_" );
967 int currentWidth = 0;
974 if( old_width != currentWidth )
976 old_width = currentWidth;
977 fmt::print( m_file,
"TRACK TRACK{}\n", currentWidth );
982 if( old_layer != track->GetLayer() )
984 old_layer = track->GetLayer();
985 fmt::print( m_file,
"LAYER {}\n",
989 fmt::print( m_file,
"LINE {} {} {} {}\n",
990 mapXTo( track->GetStart().x ), mapYTo( track->GetStart().y ),
991 mapXTo( track->GetEnd().x ), mapYTo( track->GetEnd().y ) );
995 if( old_layer != track->GetLayer() )
997 old_layer = track->GetLayer();
998 fmt::print( m_file,
"LAYER {}\n",
1002 VECTOR2I start = track->GetStart();
1009 std::swap( start,
end );
1013 fmt::print( m_file,
"ARC {} {} {} {} {} {}\n",
1014 mapXTo( start.
x ), mapYTo( start.
y ),
1015 mapXTo(
end.x ), mapYTo(
end.y ),
1022 LSET vset =
via->GetLayerSet() & master_layermask;
1024 fmt::print( m_file,
"VIA VIA{}.{}.{} {} {} ALL {} via{}\n",
1026 via->GetDrillValue(),
1028 mapXTo(
via->GetStart().x ), mapYTo(
via->GetStart().y ),
1034 fmt::print( m_file,
"$ENDROUTES\n\n" );
1040 std::set<wxString> emitted;
1042 fmt::print(
m_file,
"$DEVICES\n" );
1053 const wxString& shapeName =
shapeNames[componentShape.second];
1055 std::tie( std::ignore, newDevice ) = emitted.insert( shapeName );
1060 const FOOTPRINT* footprint = componentShape.first;
1063 txt.Printf(
"\nDEVICE \"DEV_%s\"\n",
escapeString( shapeName ) );
1072 for( wxString& item : data )
1075 fmt::print(
m_file,
"$ENDDEVICES\n\n" );
1083 fmt::print(
m_file,
"$BOARD\n" );
1088 if( !
m_board->GetBoardPolygonOutlines( outline,
true ) )
1089 wxLogError(
_(
"Board outline is malformed. Run DRC for a full analysis." ) );
1094 fmt::print(
m_file,
"LINE {} {} {} {}\n",
1099 fmt::print(
m_file,
"$ENDBOARD\n\n" );
1106 std::set<int> trackinfo;
1113 trackinfo.insert( track->GetWidth() );
1117 fmt::print(
m_file,
"$TRACKS\n" );
1119 for(
int size : trackinfo )
1122 fmt::print(
m_file,
"$ENDTRACKS\n\n" );
1132 fmt::print(
m_file,
"INSERT TH\n" );
1134 fmt::print(
m_file,
"INSERT SMD\n" );
1156 fmt::print(
m_file,
"LINE {} {} {} {}\n",
1164 fmt::print(
m_file,
"LINE {} {} {} {}\n",
1169 fmt::print(
m_file,
"LINE {} {} {} {}\n",
1174 fmt::print(
m_file,
"LINE {} {} {} {}\n",
1179 fmt::print(
m_file,
"LINE {} {} {} {}\n",
1190 fmt::print(
m_file,
"CIRCLE {} {} {}\n",
1199 std::swap( start,
end );
1201 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
1215 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