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(),
594 fprintf(
m_file,
"PAD V%d.%d.%s %s 0 0\n",
595 via->GetWidth(),
via->GetDrillValue(),
606 for(
unsigned i = 1; i < padstacks.size(); i++ )
613 LSET pad_set =
pad->GetLayerSet() & master_layermask;
629 fprintf(
m_file,
"PAD P%u %s 0 0\n", i,
635 fputs(
"$ENDPADSTACKS\n\n",
m_file );
642 size_t ret = 0x11223344;
652 for(
PAD* i : aFootprint->
Pads() )
667 const char* mirror =
"0";
668 std::map<wxString, size_t> shapes;
670 fputs(
"$SHAPES\n",
m_file );
680 wxString shapeName = footprint->GetFPID().Format();
682 auto shapeIt = shapes.find( shapeName );
685 if( shapeIt != shapes.end() )
687 if( modHash != shapeIt->second )
691 wxString newShapeName;
697 newShapeName = wxString::Format( wxT(
"%s_%d" ), shapeName, suffix );
698 shapeIt = shapes.find( newShapeName );
701 while( shapeIt != shapes.end() && shapeIt->second != modHash );
703 shapeName = newShapeName;
706 if( shapeIt != shapes.end() && modHash == shapeIt->second )
717 shapes[shapeName] = modHash;
726 std::set<wxString> pins;
728 for(
PAD*
pad : footprint->Pads() )
734 pinname =
pad->GetNumber();
736 if( pinname.IsEmpty() )
737 pinname = wxT(
"none" );
742 wxString origPinname( pinname );
744 auto it = pins.find( pinname );
746 while( it != pins.end() )
748 pinname = wxString::Format( wxT(
"%s_%d" ), origPinname, suffix );
750 it = pins.find( pinname );
753 pins.insert( pinname );
756 EDA_ANGLE orient =
pad->GetOrientation() - footprint->GetOrientation();
763 "PIN \"%s\" PAD%dF %g %g %s %g %s\n" :
764 "PIN \"%s\" PAD%d %g %g %s %g %s\n",
772 fputs(
"$ENDSHAPES\n\n",
m_file );
783 fputs(
"$COMPONENTS\n",
m_file );
791 EDA_ANGLE fp_orient = footprint->GetOrientation();
793 if( footprint->GetFlag() )
805 fprintf(
m_file,
"\nCOMPONENT \"%s\"\n",
807 fprintf(
m_file,
"DEVICE \"DEV_%s\"\n",
809 fprintf(
m_file,
"PLACE %g %g\n",
810 MapXTo( footprint->GetPosition().x ),
811 MapYTo( footprint->GetPosition().y ) );
812 fprintf(
m_file,
"LAYER %s\n",
813 footprint->GetFlag() ?
"BOTTOM" :
"TOP" );
814 fprintf(
m_file,
"ROTATION %g\n",
816 fprintf(
m_file,
"SHAPE \"%s\" %s %s\n",
821 for(
PCB_TEXT* textItem : { &footprint->Reference(), &footprint->Value() } )
826 fprintf(
m_file,
"TEXT %g %g %g %g %s %s \"%s\"",
830 textItem->GetTextAngle().AsDegrees(),
835 BOX2I textBox = textItem->GetTextBox();
837 fprintf(
m_file,
" 0 0 %g %g\n",
843 fprintf(
m_file,
"SHEET \"RefDes: %s, Value: %s\"\n",
844 TO_UTF8( footprint->GetReference() ),
845 TO_UTF8( footprint->GetValue() ) );
848 fputs(
"$ENDCOMPONENTS\n\n",
m_file );
861 fputs(
"$SIGNALS\n",
m_file );
871 msg.Printf( wxT(
"NoConnection%d" ), NbNoConn++ );
884 for(
PAD*
pad : footprint->Pads() )
889 msg.Printf( wxT(
"NODE \"%s\" \"%s\"" ),
900 fputs(
"$ENDSIGNALS\n\n",
m_file );
908 fputs(
"$HEADER\n",
m_file );
909 fputs(
"GENCAD 1.4\n",
m_file );
920 msg = wxT(
"REVISION \"" ) + rev + wxT(
" " ) + date + wxT(
"\"\n" );
923 fputs(
"UNITS INCH\n",
m_file );
926 msg.Printf( wxT(
"ORIGIN %g %g\n" ),
931 fputs(
"INTERTRACK 0\n",
m_file );
932 fputs(
"$ENDHEADER\n\n",
m_file );
951 int old_netcode, old_width, old_layer;
957 std::sort( tracks.begin(), tracks.end(),
960 if( a->GetNetCode() == b->GetNetCode() )
962 if( a->GetWidth() == b->GetWidth() )
963 return ( a->GetLayer() < b->GetLayer() );
965 return ( a->GetWidth() < b->GetWidth() );
971 fputs(
"$ROUTES\n", m_file );
973 old_netcode = -1; old_width = -1; old_layer = -1;
977 if( old_netcode != track->GetNetCode() )
979 old_netcode = track->GetNetCode();
983 if( net && (net->
GetNetname() != wxEmptyString) )
986 netname = wxT(
"_noname_" );
991 if( old_width != track->GetWidth() )
993 old_width = track->GetWidth();
994 fprintf( m_file,
"TRACK TRACK%d\n", track->GetWidth() );
999 if( old_layer != track->GetLayer() )
1001 old_layer = track->GetLayer();
1002 fprintf( m_file,
"LAYER %s\n",
1006 fprintf( m_file,
"LINE %g %g %g %g\n",
1007 MapXTo( track->GetStart().x ), MapYTo( track->GetStart().y ),
1008 MapXTo( track->GetEnd().x ), MapYTo( track->GetEnd().y ) );
1015 LSET vset =
via->GetLayerSet() & master_layermask;
1017 fprintf( m_file,
"VIA VIA%d.%d.%s %g %g ALL %g via%d\n",
1018 via->GetWidth(),
via->GetDrillValue(),
1020 MapXTo(
via->GetStart().x ), MapYTo(
via->GetStart().y ),
1025 fputs(
"$ENDROUTES\n\n", m_file );
1035 std::set<wxString> emitted;
1037 fputs(
"$DEVICES\n",
m_file );
1048 const wxString& shapeName =
shapeNames[componentShape.second];
1050 std::tie( std::ignore, newDevice ) = emitted.insert( shapeName );
1055 const FOOTPRINT* footprint = componentShape.first;
1058 txt.Printf(
"\nDEVICE \"DEV_%s\"\n",
escapeString( shapeName ) );
1067 for( wxString& item : data )
1070 fputs(
"$ENDDEVICES\n\n",
m_file );
1079 fputs(
"$BOARD\n",
m_file );
1088 fprintf(
m_file,
"LINE %g %g %g %g\n",
1093 fputs(
"$ENDBOARD\n\n",
m_file );
1110 std::set<int> trackinfo;
1113 trackinfo.insert( track->GetWidth() );
1116 fputs(
"$TRACKS\n",
m_file );
1118 for(
int size : trackinfo )
1121 fputs(
"$ENDTRACKS\n\n",
m_file );
1136 fprintf(
m_file,
"INSERT TH\n" );
1138 fprintf(
m_file,
"INSERT SMD\n" );
1147 && ( item->GetLayer() ==
F_SilkS || item->GetLayer() ==
B_SilkS ) )
1160 case SHAPE_T::SEGMENT:
1161 fprintf(
m_file,
"LINE %g %g %g %g\n",
1168 case SHAPE_T::RECTANGLE:
1169 fprintf(
m_file,
"LINE %g %g %g %g\n",
1174 fprintf(
m_file,
"LINE %g %g %g %g\n",
1179 fprintf(
m_file,
"LINE %g %g %g %g\n",
1184 fprintf(
m_file,
"LINE %g %g %g %g\n",
1191 case SHAPE_T::CIRCLE:
1195 fprintf(
m_file,
"CIRCLE %g %g %g\n",
1204 std::swap( start, end );
1206 fprintf(
m_file,
"ARC %g %g %g %g %g %g\n",
1220 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.
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false, bool aIncludeHiddenText=false) const
Calculate the bounding box containing all board items (or board edge segments).
const std::vector< PAD * > GetPads() const
Return a reference to a list of all the pads.
TITLE_BLOCK & GetTitleBlock()
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.
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
double Distance(const VECTOR2< extended_type > &aVector) const
Compute the distance between two vectors.
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.
@ 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".
VECTOR2< int32_t > VECTOR2I