42 else if( aId ==
B_Cu )
45 return StrPrintf(
"INNER%d", aCuCount - aId - 1 );
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;
130 if( 1<= aId && aId <= 14 )
139 wxString
copy( aString );
140 copy.Replace( wxT(
"\"" ), wxT(
"\\\"" ) );
158 static const wxString invalid(
"invalid" );
166 auto itName =
shapeNames.find( itShape->second );
167 wxCHECK( itName !=
shapeNames.end(), invalid );
169 return itName->second;
197 m_file = wxFopen( aFullFileName, wxT(
"wt" ) );
218 footprint->SetFlag( 0 );
220 if( footprint->GetLayer() ==
B_Cu )
222 footprint->Flip( footprint->GetPosition(),
false );
223 footprint->SetFlag( 1 );
254 if( footprint->GetFlag() )
256 footprint->Flip( footprint->GetPosition(),
false );
257 footprint->SetFlag( 0 );
287 fputs(
"$ARTWORKS\n",
m_file );
288 fputs(
"$ENDARTWORKS\n\n",
m_file );
297 std::vector<PAD*> padstacks;
298 std::vector<PCB_VIA*> vias;
299 std::vector<PCB_VIA*> viastacks;
301 padstacks.resize( 1 );
307 fputs(
"$PADS\n",
m_file );
312 std::sort( pads.begin(), pads.end(), [](
const PAD* a,
const PAD* b )
314 return PAD::Compare( a, b ) < 0;
321 if(
PCB_VIA*
via = dyn_cast<PCB_VIA*>( track ) )
322 vias.push_back(
via );
325 std::sort( vias.begin(), vias.end(),
ViaSort );
326 vias.erase( std::unique( vias.begin(), vias.end(), [](
const PCB_VIA* a,
const PCB_VIA* b )
328 return ViaSort( a, b ) == false;
335 viastacks.push_back(
via );
336 fprintf(
m_file,
"PAD V%d.%d.%s ROUND %g\nCIRCLE 0 0 %g\n",
337 via->GetWidth(),
via->GetDrillValue(),
338 fmt_mask(
via->GetLayerSet() & master_layermask ).c_str(),
344 PAD* old_pad =
nullptr;
345 int pad_name_number = 0;
347 for(
unsigned i = 0; i<pads.size(); ++i )
352 pad->SetSubRatsnest( pad_name_number );
362 pad->SetSubRatsnest( pad_name_number );
364 fprintf(
m_file,
"PAD P%d",
pad->GetSubRatsnest() );
366 padstacks.push_back(
pad );
367 int dx =
pad->GetSize().x / 2;
368 int dy =
pad->GetSize().y / 2;
370 switch(
pad->GetShape() )
376 case PAD_SHAPE::CIRCLE:
377 fprintf(
m_file,
" ROUND %g\n",
381 fprintf(
m_file,
"CIRCLE %g %g %g\n",
387 case PAD_SHAPE::RECTANGLE:
388 fprintf(
m_file,
" RECTANGULAR %g\n",
392 fprintf(
m_file,
"RECTANGLE %g %g %g %g\n",
398 case PAD_SHAPE::ROUNDRECT:
399 case PAD_SHAPE::OVAL:
402 int radius = std::min( size.
x, size.
y ) / 2;
404 if(
pad->GetShape() == PAD_SHAPE::ROUNDRECT )
406 radius =
pad->GetRoundRectCornerRadius();
409 int lineX = size.
x / 2 - radius;
410 int lineY = size.
y / 2 - radius;
415 fprintf(
m_file,
"ARC %g %g %g %g %g %g\n",
424 fprintf(
m_file,
"LINE %g %g %g %g\n",
432 fprintf(
m_file,
"ARC %g %g %g %g %g %g\n",
442 fprintf(
m_file,
"LINE %g %g %g %g\n",
450 fprintf(
m_file,
"ARC %g %g %g %g %g %g\n",
459 fprintf(
m_file,
"LINE %g %g %g %g\n"
467 fprintf(
m_file,
"ARC %g %g %g %g %g %g\n",
477 fprintf(
m_file,
"LINE %g %g %g %g\n",
487 case PAD_SHAPE::TRAPEZOID:
491 int ddx =
pad->GetDelta().x / 2;
492 int ddy =
pad->GetDelta().y / 2;
495 poly[0] =
VECTOR2I( -dx + ddy, dy + ddx );
496 poly[1] =
VECTOR2I( dx - ddy, dy - ddx );
497 poly[2] =
VECTOR2I( dx + ddy, -dy + ddx );
498 poly[3] =
VECTOR2I( -dx - ddy, -dy - ddx );
500 for(
int cur = 0; cur < 4; ++cur )
502 int next = ( cur + 1 ) % 4;
503 fprintf(
m_file,
"LINE %g %g %g %g\n",
513 case PAD_SHAPE::CHAMFERED_RECT:
522 pad->GetOrientation(),
523 pad->GetRoundRectCornerRadius(),
524 pad->GetChamferRectRatio(),
525 pad->GetChamferPositions(), 0, maxError,
533 for(
int ii = 0; ii < pointCount; ii++ )
535 int next = ( ii + 1 ) % pointCount;
536 fprintf(
m_file,
"LINE %g %g %g %g\n",
547 case PAD_SHAPE::CUSTOM:
552 pad->MergePrimitivesAsPolygon( &outline );
559 for(
int ii = 0; ii < pointCount; ii++ )
561 int next = ( ii + 1 ) % pointCount;
562 fprintf(
m_file,
"LINE %g %g %g %g\n",
575 fputs(
"\n$ENDPADS\n\n",
m_file );
578 fputs(
"$PADSTACKS\n",
m_file );
581 for(
unsigned i = 0; i < viastacks.size(); i++ )
585 LSET mask =
via->GetLayerSet() & master_layermask;
587 fprintf(
m_file,
"PADSTACK VIA%d.%d.%s %g\n",
588 via->GetWidth(),
via->GetDrillValue(),
596 fprintf(
m_file,
"PAD V%d.%d.%s %s 0 0\n",
597 via->GetWidth(),
via->GetDrillValue(),
608 for(
unsigned i = 1; i < padstacks.size(); i++ )
615 LSET pad_set =
pad->GetLayerSet() & master_layermask;
631 for(
LSEQ seq = pad_set.
Seq(); seq; ++seq )
635 fprintf(
m_file,
"PAD P%u %s 0 0\n", i,
641 fputs(
"$ENDPADSTACKS\n\n",
m_file );
648 size_t ret = 0x11223344;
658 for(
PAD* i : aFootprint->
Pads() )
673 const char* mirror =
"0";
674 std::map<wxString, size_t> shapes;
676 fputs(
"$SHAPES\n",
m_file );
686 wxString shapeName = footprint->GetFPID().Format();
688 auto shapeIt = shapes.find( shapeName );
691 if( shapeIt != shapes.end() )
693 if( modHash != shapeIt->second )
697 wxString newShapeName;
703 newShapeName = wxString::Format( wxT(
"%s_%d" ), shapeName, suffix );
704 shapeIt = shapes.find( newShapeName );
707 while( shapeIt != shapes.end() && shapeIt->second != modHash );
709 shapeName = newShapeName;
712 if( shapeIt != shapes.end() && modHash == shapeIt->second )
723 shapes[shapeName] = modHash;
732 std::set<wxString> pins;
734 for(
PAD*
pad : footprint->Pads() )
740 pinname =
pad->GetNumber();
742 if( pinname.IsEmpty() )
743 pinname = wxT(
"none" );
748 wxString origPinname( pinname );
750 auto it = pins.find( pinname );
752 while( it != pins.end() )
754 pinname = wxString::Format( wxT(
"%s_%d" ), origPinname, suffix );
756 it = pins.find( pinname );
759 pins.insert( pinname );
762 EDA_ANGLE orient =
pad->GetOrientation() - footprint->GetOrientation();
769 "PIN \"%s\" PAD%dF %g %g %s %g %s\n" :
770 "PIN \"%s\" PAD%d %g %g %s %g %s\n",
778 fputs(
"$ENDSHAPES\n\n",
m_file );
789 fputs(
"$COMPONENTS\n",
m_file );
797 EDA_ANGLE fp_orient = footprint->GetOrientation();
799 if( footprint->GetFlag() )
811 fprintf(
m_file,
"\nCOMPONENT \"%s\"\n",
813 fprintf(
m_file,
"DEVICE \"DEV_%s\"\n",
815 fprintf(
m_file,
"PLACE %g %g\n",
816 MapXTo( footprint->GetPosition().x ),
817 MapYTo( footprint->GetPosition().y ) );
818 fprintf(
m_file,
"LAYER %s\n",
819 footprint->GetFlag() ?
"BOTTOM" :
"TOP" );
820 fprintf(
m_file,
"ROTATION %g\n",
822 fprintf(
m_file,
"SHAPE \"%s\" %s %s\n",
827 for(
PCB_TEXT* textItem : { &footprint->Reference(), &footprint->Value() } )
832 fprintf(
m_file,
"TEXT %g %g %g %g %s %s \"%s\"",
836 textItem->GetTextAngle().AsDegrees(),
841 BOX2I textBox = textItem->GetTextBox();
843 fprintf(
m_file,
" 0 0 %g %g\n",
849 fprintf(
m_file,
"SHEET \"RefDes: %s, Value: %s\"\n",
850 TO_UTF8( footprint->GetReference() ),
851 TO_UTF8( footprint->GetValue() ) );
854 fputs(
"$ENDCOMPONENTS\n\n",
m_file );
867 fputs(
"$SIGNALS\n",
m_file );
877 msg.Printf( wxT(
"NoConnection%d" ), NbNoConn++ );
890 for(
PAD*
pad : footprint->Pads() )
895 msg.Printf( wxT(
"NODE \"%s\" \"%s\"" ),
906 fputs(
"$ENDSIGNALS\n\n",
m_file );
914 fputs(
"$HEADER\n",
m_file );
915 fputs(
"GENCAD 1.4\n",
m_file );
926 msg = wxT(
"REVISION \"" ) + rev + wxT(
" " ) + date + wxT(
"\"\n" );
929 fputs(
"UNITS INCH\n",
m_file );
932 msg.Printf( wxT(
"ORIGIN %g %g\n" ),
937 fputs(
"INTERTRACK 0\n",
m_file );
938 fputs(
"$ENDHEADER\n\n",
m_file );
957 int old_netcode, old_width, old_layer;
963 std::sort( tracks.begin(), tracks.end(),
966 if( a->GetNetCode() == b->GetNetCode() )
968 if( a->GetWidth() == b->GetWidth() )
969 return ( a->GetLayer() < b->GetLayer() );
971 return ( a->GetWidth() < b->GetWidth() );
977 fputs(
"$ROUTES\n", m_file );
979 old_netcode = -1; old_width = -1; old_layer = -1;
983 if( old_netcode != track->GetNetCode() )
985 old_netcode = track->GetNetCode();
989 if( net && (net->
GetNetname() != wxEmptyString) )
992 netname = wxT(
"_noname_" );
997 if( old_width != track->GetWidth() )
999 old_width = track->GetWidth();
1000 fprintf( m_file,
"TRACK TRACK%d\n", track->GetWidth() );
1005 if( old_layer != track->GetLayer() )
1007 old_layer = track->GetLayer();
1008 fprintf( m_file,
"LAYER %s\n",
1012 fprintf( m_file,
"LINE %g %g %g %g\n",
1013 MapXTo( track->GetStart().x ), MapYTo( track->GetStart().y ),
1014 MapXTo( track->GetEnd().x ), MapYTo( track->GetEnd().y ) );
1021 LSET vset =
via->GetLayerSet() & master_layermask;
1023 fprintf( m_file,
"VIA VIA%d.%d.%s %g %g ALL %g via%d\n",
1024 via->GetWidth(),
via->GetDrillValue(),
1026 MapXTo(
via->GetStart().x ), MapYTo(
via->GetStart().y ),
1031 fputs(
"$ENDROUTES\n\n", m_file );
1041 std::set<wxString> emitted;
1043 fputs(
"$DEVICES\n",
m_file );
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 fputs(
"$ENDDEVICES\n\n",
m_file );
1085 fputs(
"$BOARD\n",
m_file );
1094 fprintf(
m_file,
"LINE %g %g %g %g\n",
1099 fputs(
"$ENDBOARD\n\n",
m_file );
1116 std::set<int> trackinfo;
1119 trackinfo.insert( track->GetWidth() );
1122 fputs(
"$TRACKS\n",
m_file );
1124 for(
int size : trackinfo )
1127 fputs(
"$ENDTRACKS\n\n",
m_file );
1142 fprintf(
m_file,
"INSERT TH\n" );
1144 fprintf(
m_file,
"INSERT SMD\n" );
1153 && ( item->GetLayer() ==
F_SilkS || item->GetLayer() ==
B_SilkS ) )
1166 case SHAPE_T::SEGMENT:
1167 fprintf(
m_file,
"LINE %g %g %g %g\n",
1174 case SHAPE_T::RECTANGLE:
1175 fprintf(
m_file,
"LINE %g %g %g %g\n",
1180 fprintf(
m_file,
"LINE %g %g %g %g\n",
1185 fprintf(
m_file,
"LINE %g %g %g %g\n",
1190 fprintf(
m_file,
"LINE %g %g %g %g\n",
1197 case SHAPE_T::CIRCLE:
1201 fprintf(
m_file,
"CIRCLE %g %g %g\n",
1210 std::swap( start, end );
1212 fprintf(
m_file,
"ARC %g %g %g %g %g %g\n",
1226 wxFAIL_MSG( wxString::Format( wxT(
"Shape type %d invalid." ), item->Type() ) );
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
constexpr EDA_IU_SCALE pcbIUScale
wxString GetBuildVersion()
Get the full KiCad version string.
LSET GetEnabledLayers() const
Return a bit-mask of all the layers that are enabled.
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.
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr, bool aAllowUseArcsInPolygons=false, bool aIncludeNPTHAsOutlines=false)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
const std::vector< PAD * > GetPads() const
Return a reference to a list of all the pads.
TITLE_BLOCK & GetTitleBlock()
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
int GetCopperLayerCount() const
const FOOTPRINTS & Footprints() const
const TRACKS & Tracks() const
const wxString & GetFileName() const
PROJECT * GetProject() const
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
unsigned GetNetCount() const
size_type GetHeight() const
size_type GetWidth() 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 CreateComponentsSection()
void CreateBoardSection()
const wxString getShapeName(FOOTPRINT *aFootprint)
void CreateTracksInfoData()
void CreateShapesSection()
void CreateArtworksSection()
bool CreateHeaderInfoData()
Creates the header section.
void CreateSignalsSection()
void CreatePadsShapesSection()
void CreateRoutesSection()
void CreateDevicesSection()
bool m_useIndividualShapes
bool WriteFile(wxString &aFullFileName)
Export a genCAD file.
void FootprintWriteShape(FOOTPRINT *aFootprint, const wxString &aShapeName)
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
LSET is a set of PCB_LAYER_IDs.
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
std::string FmtBin() const
Return a binary string showing contents of this LSEQ.
Handle the data for a net.
const wxString & GetNetname() const
static int Compare(const PAD *aPadRef, const PAD *aPadCmp)
Compare two pads and return 0 if they are equal.
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
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)
const wxString & GetRevision() const
const wxString & GetDate() const
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject)
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
static std::map< int, wxString > shapeNames
static bool ViaSort(const PCB_VIA *aPadref, const PCB_VIA *aPadcmp)
static std::string GenCADLayerName(int aCuCount, PCB_LAYER_ID aId)
static const PCB_LAYER_ID gc_seq[]
static const double SCALE_FACTOR
static size_t hashFootprint(const FOOTPRINT *aFootprint)
Compute hashes for footprints without taking into account their position, rotation or layer.
static std::string fmt_mask(LSET aSet)
static std::map< FOOTPRINT *, int > componentShapes
static std::string GenCADLayerNameFlipped(int aCuCount, PCB_LAYER_ID aId)
static wxString escapeString(const wxString &aString)
size_t hash_fp_item(const EDA_ITEM *aItem, int aFlags)
Calculate hash of an EDA_ITEM.
@ HASH_POS
use coordinates relative to the parent object
@ REL_COORD
use coordinates relative to the shape position
bool IsCopperLayer(int aLayerId)
Tests 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)
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.
double GetLineLength(const VECTOR2I &aPointA, const VECTOR2I &aPointB)
Return the length of a line segment defined by aPointA and aPointB.
@ 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_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".