44 else if( aId ==
B_Cu )
47 return StrPrintf(
"INNER%d", aCuCount - aId - 1 );
60 case B_Adhes: txt =
"B.Adhes";
break;
61 case F_Adhes: txt =
"F.Adhes";
break;
62 case B_Paste: txt =
"SOLDERPASTE_BOTTOM";
break;
63 case F_Paste: txt =
"SOLDERPASTE_TOP";
break;
64 case B_SilkS: txt =
"SILKSCREEN_BOTTOM";
break;
65 case F_SilkS: txt =
"SILKSCREEN_TOP";
break;
66 case B_Mask: txt =
"SOLDERMASK_BOTTOM";
break;
67 case F_Mask: txt =
"SOLDERMASK_TOP";
break;
75 case Margin: txt =
"Margin";
break;
78 case F_CrtYd: txt =
"F_CrtYd";
break;
79 case B_CrtYd: txt =
"B_CrtYd";
break;
80 case F_Fab: txt =
"F_Fab";
break;
81 case B_Fab: txt =
"B_Fab";
break;
84 wxASSERT_MSG( 0, wxT(
"aId UNEXPECTED" ) );
85 txt =
"BAD-INDEX!";
break;
96 if( 1<= aId && aId <= 14 )
105 wxString
copy( aString );
106 copy.Replace( wxT(
"\"" ), wxT(
"\\\"" ) );
114 retv.erase( 0, retv.find_first_not_of(
'0' ) );
126 static const wxString invalid(
"invalid" );
134 auto itName =
shapeNames.find( itShape->second );
135 wxCHECK( itName !=
shapeNames.end(), invalid );
137 return itName->second;
162 m_file = wxFopen( aFullFileName, wxT(
"wt" ) );
181 footprint->SetFlag( 0 );
183 if( footprint->GetLayer() ==
B_Cu )
186 footprint->SetFlag( 1 );
225 if( footprint->GetFlag() )
228 footprint->SetFlag( 0 );
258 fmt::print(
m_file,
"$ARTWORKS\n" );
259 fmt::print(
m_file,
"$ENDARTWORKS\n\n" );
268 std::vector<PAD*> padstacks;
269 std::vector<PCB_VIA*> vias;
270 std::vector<PCB_VIA*> viastacks;
272 padstacks.resize( 1 );
274 LSEQ gc_seq =
m_board->GetEnabledLayers().CuStack();
275 std::reverse(gc_seq.begin(), gc_seq.end());
278 LSET master_layermask =
m_board->GetDesignSettings().GetEnabledLayers();
279 int cu_count =
m_board->GetCopperLayerCount();
281 fmt::print(
m_file,
"$PADS\n" );
284 std::vector<PAD*> pads =
m_board->GetPads();
285 std::sort( pads.begin(), pads.end(), [](
const PAD* a,
const PAD* b )
287 return PAD::Compare( a, b ) < 0;
294 vias.push_back(
via );
297 std::sort( vias.begin(), vias.end(),
viaSort );
298 vias.erase( std::unique( vias.begin(), vias.end(), [](
const PCB_VIA* a,
const PCB_VIA* b )
300 return viaSort( a, b ) == false;
307 viastacks.push_back(
via );
308 fmt::print(
m_file,
"PAD V{}.{}.{} ROUND {}\nCIRCLE 0 0 {}\n",
310 via->GetDrillValue(),
311 fmt_mask(
via->GetLayerSet() & master_layermask ).c_str(),
317 PAD* old_pad =
nullptr;
318 int pad_name_number = 0;
320 for(
unsigned i = 0; i<pads.size(); ++i )
325 pad->SetSubRatsnest( pad_name_number );
335 pad->SetSubRatsnest( pad_name_number );
337 fmt::print(
m_file,
"PAD P{}",
pad->GetSubRatsnest() );
339 padstacks.push_back(
pad );
350 fmt::print(
m_file,
" ROUND {}\n",
354 fmt::print(
m_file,
"CIRCLE {} {} {}\n",
361 fmt::print(
m_file,
" RECTANGULAR {}\n",
365 fmt::print(
m_file,
"RECTANGLE {} {} {} {}\n",
375 int radius = std::min( size.
x, size.
y ) / 2;
382 int lineX = size.
x / 2 -
radius;
383 int lineY = size.
y / 2 -
radius;
388 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
399 fmt::print(
m_file,
"LINE {} {} {} {}\n",
407 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
418 fmt::print(
m_file,
"LINE {} {} {} {}\n",
426 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
437 fmt::print(
m_file,
"LINE {} {} {} {}\n",
445 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
456 fmt::print(
m_file,
"LINE {} {} {} {}\n",
474 poly[0] =
VECTOR2I( -dx + ddy, dy + ddx );
475 poly[1] =
VECTOR2I( dx - ddy, dy - ddx );
476 poly[2] =
VECTOR2I( dx + ddy, -dy + ddx );
477 poly[3] =
VECTOR2I( -dx - ddy, -dy - ddx );
479 for(
int cur = 0; cur < 4; ++cur )
481 int next = ( cur + 1 ) % 4;
482 fmt::print(
m_file,
"LINE {} {} {} {}\n",
501 pad->GetOrientation(),
512 for(
int ii = 0; ii < pointCount; ii++ )
514 int next = ( ii + 1 ) % pointCount;
515 fmt::print(
m_file,
"LINE {} {} {} {}\n",
531 pad->MergePrimitivesAsPolygon(
F_Cu, &outline );
538 for(
int ii = 0; ii < pointCount; ii++ )
540 int next = ( ii + 1 ) % pointCount;
541 fmt::print(
m_file,
"LINE {} {} {} {}\n",
554 fmt::print(
m_file,
"\n$ENDPADS\n\n" );
557 fmt::print(
m_file,
"$PADSTACKS\n" );
560 for(
unsigned i = 0; i < viastacks.size(); i++ )
564 LSET mask =
via->GetLayerSet() & master_layermask;
566 fmt::print(
m_file,
"PADSTACK VIA{}.{}.{} {}\n",
568 via->GetDrillValue(),
574 fmt::print(
m_file,
"PAD V{}.{}.{} {} 0 0\n",
576 via->GetDrillValue(),
587 for(
unsigned i = 1; i < padstacks.size(); i++ )
592 fmt::print(
m_file,
"PADSTACK PAD{} {}\n",
596 LSET pad_set =
pad->GetLayerSet() & master_layermask;
601 fmt::print(
m_file,
"PAD P{} {} 0 0\n",
609 fmt::print(
m_file,
"PADSTACK PAD{}F {}\n",
616 fmt::print(
m_file,
"PAD P{} {} 0 0\n",
623 fputs(
"$ENDPADSTACKS\n\n",
m_file );
630 size_t ret = 0x11223344;
637 for(
PAD* i : aFootprint->
Pads() )
648 const char* mirror =
"0";
649 std::map<wxString, size_t> shapes;
651 fmt::print(
m_file,
"$SHAPES\n" );
661 wxString shapeName = footprint->GetFPID().Format();
663 auto shapeIt = shapes.find( shapeName );
666 if( shapeIt != shapes.end() )
668 if( modHash != shapeIt->second )
672 wxString newShapeName;
678 newShapeName = wxString::Format( wxT(
"%s_%d" ), shapeName, suffix );
679 shapeIt = shapes.find( newShapeName );
682 while( shapeIt != shapes.end() && shapeIt->second != modHash );
684 shapeName = newShapeName;
687 if( shapeIt != shapes.end() && modHash == shapeIt->second )
698 shapes[shapeName] = modHash;
707 std::set<wxString> pins;
709 for(
PAD*
pad : footprint->Pads() )
715 pinname =
pad->GetNumber();
717 if( pinname.IsEmpty() )
718 pinname = wxT(
"none" );
723 wxString origPinname( pinname );
725 auto it = pins.find( pinname );
727 while( it != pins.end() )
729 pinname = wxString::Format( wxT(
"%s_%d" ), origPinname, suffix );
731 it = pins.find( pinname );
734 pins.insert( pinname );
737 EDA_ANGLE orient =
pad->GetOrientation() - footprint->GetOrientation();
742 std::string flipStr = (
m_flipBottomPads && footprint->GetFlag() ) ?
"F" :
"";
746 "PIN \"{}\" PAD{}{} {} {} {} {} {}\n",
748 pad->GetSubRatsnest(),
758 fmt::print(
m_file,
"$ENDSHAPES\n\n" );
764 fmt::print(
m_file,
"$COMPONENTS\n" );
766 int cu_count =
m_board->GetCopperLayerCount();
772 EDA_ANGLE fp_orient = footprint->GetOrientation();
774 if( footprint->GetFlag() )
786 fmt::print(
m_file,
"\nCOMPONENT \"{}\"\n",
788 fmt::print(
m_file,
"DEVICE \"DEV_{}\"\n",
790 fmt::print(
m_file,
"PLACE {} {}\n",
791 mapXTo( footprint->GetPosition().x ),
792 mapYTo( footprint->GetPosition().y ) );
793 fmt::print(
m_file,
"LAYER {}\n",
794 footprint->GetFlag() ?
"BOTTOM" :
"TOP" );
795 fmt::print(
m_file,
"ROTATION {}\n",
797 fmt::print(
m_file,
"SHAPE \"{}\" {} {}\n",
802 for(
PCB_TEXT* textItem : { &footprint->Reference(), &footprint->Value() } )
806 fmt::print(
m_file,
"TEXT {} {} {} {} {} {} \"{}\"",
810 textItem->GetTextAngle().AsDegrees(),
815 BOX2I textBox = textItem->GetTextBox(
nullptr );
817 fmt::print(
m_file,
" 0 0 {} {}\n",
823 fmt::print(
m_file,
"SHEET \"RefDes: {}, Value: {}\"\n",
824 TO_UTF8( footprint->GetReference() ),
825 TO_UTF8( footprint->GetValue() ) );
828 fmt::print(
m_file,
"$ENDCOMPONENTS\n\n" );
841 fmt::print(
m_file,
"$SIGNALS\n" );
843 for(
unsigned ii = 0; ii <
m_board->GetNetCount(); ii++ )
851 msg.Printf( wxT(
"NoConnection%d" ), NbNoConn++ );
860 fmt::print(
m_file,
"\n" );
864 for(
PAD*
pad : footprint->Pads() )
869 msg.Printf( wxT(
"NODE \"%s\" \"%s\"" ),
874 fmt::print(
m_file,
"\n" );
880 fmt::print(
m_file,
"$ENDSIGNALS\n\n" );
886 fmt::print(
m_file,
"$HEADER\n" );
887 fmt::print(
m_file,
"GENCAD 1.4\n" );
892 fmt::print(
m_file,
"DRAWING \"{}\"\n",
m_board->GetFileName() );
897 fmt::print(
m_file,
"REVISION \"{} {}\"\n", rev, date );
898 fmt::print(
m_file,
"UNITS INCH\n" );
904 fmt::print(
m_file,
"INTERTRACK 0\n" );
905 fmt::print(
m_file,
"$ENDHEADER\n\n" );
914 int old_netcode, old_width, old_layer;
915 LSET master_layermask =
m_board->GetDesignSettings().GetEnabledLayers();
916 int cu_count =
m_board->GetCopperLayerCount();
919 std::sort( tracks.begin(), tracks.end(),
925 if( a->Type() == PCB_VIA_T )
926 widthA = static_cast<const PCB_VIA*>( a )->GetWidth( PADSTACK::ALL_LAYERS );
928 widthA = a->GetWidth();
930 if( b->Type() == PCB_VIA_T )
931 widthB = static_cast<const PCB_VIA*>( b )->GetWidth( PADSTACK::ALL_LAYERS );
933 widthB = b->GetWidth();
935 if( a->GetNetCode() == b->GetNetCode() )
937 if( widthA == widthB )
938 return ( a->GetLayer() < b->GetLayer() );
940 return ( widthA < widthB );
946 fmt::print( m_file,
"$ROUTES\n" );
954 if( old_netcode != track->GetNetCode() )
956 old_netcode = track->GetNetCode();
960 if( net && (net->
GetNetname() != wxEmptyString) )
963 netname = wxT(
"_noname_" );
968 int currentWidth = 0;
975 if( old_width != currentWidth )
977 old_width = currentWidth;
978 fmt::print( m_file,
"TRACK TRACK{}\n", currentWidth );
983 if( old_layer != track->GetLayer() )
985 old_layer = track->GetLayer();
986 fmt::print( m_file,
"LAYER {}\n",
990 fmt::print( m_file,
"LINE {} {} {} {}\n",
991 mapXTo( track->GetStart().x ), mapYTo( track->GetStart().y ),
992 mapXTo( track->GetEnd().x ), mapYTo( track->GetEnd().y ) );
996 if( old_layer != track->GetLayer() )
998 old_layer = track->GetLayer();
999 fmt::print( m_file,
"LAYER {}\n",
1003 VECTOR2I start = track->GetStart();
1010 std::swap( start,
end );
1014 fmt::print( m_file,
"ARC {} {} {} {} {} {}\n",
1015 mapXTo( start.
x ), mapYTo( start.
y ),
1016 mapXTo(
end.x ), mapYTo(
end.y ),
1023 LSET vset =
via->GetLayerSet() & master_layermask;
1025 fmt::print( m_file,
"VIA VIA{}.{}.{} {} {} ALL {} via{}\n",
1027 via->GetDrillValue(),
1029 mapXTo(
via->GetStart().x ), mapYTo(
via->GetStart().y ),
1035 fmt::print( m_file,
"$ENDROUTES\n\n" );
1041 std::set<wxString> emitted;
1043 fmt::print(
m_file,
"$DEVICES\n" );
1054 const wxString& shapeName =
shapeNames[componentShape.second];
1056 std::tie( std::ignore, newDevice ) = emitted.insert( shapeName );
1061 const FOOTPRINT* footprint = componentShape.first;
1064 txt.Printf(
"\nDEVICE \"DEV_%s\"\n",
escapeString( shapeName ) );
1073 for( wxString& item : data )
1076 fmt::print(
m_file,
"$ENDDEVICES\n\n" );
1084 fmt::print(
m_file,
"$BOARD\n" );
1088 m_board->GetBoardPolygonOutlines( outline );
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)
int StrPrintf(std::string *result, const char *format,...)
This is like sprintf() but the output is appended to a std::string instead of to a character array.
#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