43 else if( aId ==
B_Cu )
46 return StrPrintf(
"INNER%d", aCuCount - aId - 1 );
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 )
104 wxString
copy( aString );
105 copy.Replace( wxT(
"\"" ), wxT(
"\\\"" ) );
123 static const wxString invalid(
"invalid" );
131 auto itName =
shapeNames.find( itShape->second );
132 wxCHECK( itName !=
shapeNames.end(), invalid );
134 return itName->second;
162 m_file = wxFopen( aFullFileName, wxT(
"wt" ) );
183 footprint->SetFlag( 0 );
185 if( footprint->GetLayer() ==
B_Cu )
187 footprint->Flip( footprint->GetPosition(), FLIP_DIRECTION::TOP_BOTTOM );
188 footprint->SetFlag( 1 );
219 if( footprint->GetFlag() )
221 footprint->Flip( footprint->GetPosition(), FLIP_DIRECTION::TOP_BOTTOM );
222 footprint->SetFlag( 0 );
252 fputs(
"$ARTWORKS\n",
m_file );
253 fputs(
"$ENDARTWORKS\n\n",
m_file );
262 std::vector<PAD*> padstacks;
263 std::vector<PCB_VIA*> vias;
264 std::vector<PCB_VIA*> viastacks;
266 padstacks.resize( 1 );
269 std::reverse(gc_seq.begin(), gc_seq.end());
275 fputs(
"$PADS\n",
m_file );
280 std::sort( pads.begin(), pads.end(), [](
const PAD* a,
const PAD* b )
282 return PAD::Compare( a, b ) < 0;
289 if(
PCB_VIA*
via = dyn_cast<PCB_VIA*>( track ) )
290 vias.push_back(
via );
293 std::sort( vias.begin(), vias.end(),
ViaSort );
294 vias.erase( std::unique( vias.begin(), vias.end(), [](
const PCB_VIA* a,
const PCB_VIA* b )
296 return ViaSort( a, b ) == false;
303 viastacks.push_back(
via );
304 fprintf(
m_file,
"PAD V%d.%d.%s ROUND %g\nCIRCLE 0 0 %g\n",
306 fmt_mask(
via->GetLayerSet() & master_layermask ).c_str(),
312 PAD* old_pad =
nullptr;
313 int pad_name_number = 0;
315 for(
unsigned i = 0; i<pads.size(); ++i )
320 pad->SetSubRatsnest( pad_name_number );
330 pad->SetSubRatsnest( pad_name_number );
332 fprintf(
m_file,
"PAD P%d",
pad->GetSubRatsnest() );
334 padstacks.push_back(
pad );
344 case PAD_SHAPE::CIRCLE:
345 fprintf(
m_file,
" ROUND %g\n",
349 fprintf(
m_file,
"CIRCLE %g %g %g\n",
355 case PAD_SHAPE::RECTANGLE:
356 fprintf(
m_file,
" RECTANGULAR %g\n",
360 fprintf(
m_file,
"RECTANGLE %g %g %g %g\n",
366 case PAD_SHAPE::ROUNDRECT:
367 case PAD_SHAPE::OVAL:
370 int radius = std::min( size.
x, size.
y ) / 2;
377 int lineX = size.
x / 2 - radius;
378 int lineY = size.
y / 2 - radius;
383 fprintf(
m_file,
"ARC %g %g %g %g %g %g\n",
392 fprintf(
m_file,
"LINE %g %g %g %g\n",
400 fprintf(
m_file,
"ARC %g %g %g %g %g %g\n",
410 fprintf(
m_file,
"LINE %g %g %g %g\n",
418 fprintf(
m_file,
"ARC %g %g %g %g %g %g\n",
427 fprintf(
m_file,
"LINE %g %g %g %g\n"
435 fprintf(
m_file,
"ARC %g %g %g %g %g %g\n",
445 fprintf(
m_file,
"LINE %g %g %g %g\n",
455 case PAD_SHAPE::TRAPEZOID:
463 poly[0] =
VECTOR2I( -dx + ddy, dy + ddx );
464 poly[1] =
VECTOR2I( dx - ddy, dy - ddx );
465 poly[2] =
VECTOR2I( dx + ddy, -dy + ddx );
466 poly[3] =
VECTOR2I( -dx - ddy, -dy - ddx );
468 for(
int cur = 0; cur < 4; ++cur )
470 int next = ( cur + 1 ) % 4;
471 fprintf(
m_file,
"LINE %g %g %g %g\n",
481 case PAD_SHAPE::CHAMFERED_RECT:
491 pad->GetOrientation(),
502 for(
int ii = 0; ii < pointCount; ii++ )
504 int next = ( ii + 1 ) % pointCount;
505 fprintf(
m_file,
"LINE %g %g %g %g\n",
516 case PAD_SHAPE::CUSTOM:
521 pad->MergePrimitivesAsPolygon(
F_Cu, &outline );
528 for(
int ii = 0; ii < pointCount; ii++ )
530 int next = ( ii + 1 ) % pointCount;
531 fprintf(
m_file,
"LINE %g %g %g %g\n",
544 fputs(
"\n$ENDPADS\n\n",
m_file );
547 fputs(
"$PADSTACKS\n",
m_file );
550 for(
unsigned i = 0; i < viastacks.size(); i++ )
554 LSET mask =
via->GetLayerSet() & master_layermask;
556 fprintf(
m_file,
"PADSTACK VIA%d.%d.%s %g\n",
558 via->GetDrillValue(),
564 fprintf(
m_file,
"PAD V%d.%d.%s %s 0 0\n",
566 via->GetDrillValue(),
577 for(
unsigned i = 1; i < padstacks.size(); i++ )
584 LSET pad_set =
pad->GetLayerSet() & master_layermask;
600 fprintf(
m_file,
"PAD P%u %s 0 0\n", i,
606 fputs(
"$ENDPADSTACKS\n\n",
m_file );
613 size_t ret = 0x11223344;
623 for(
PAD* i : aFootprint->
Pads() )
638 const char* mirror =
"0";
639 std::map<wxString, size_t> shapes;
641 fputs(
"$SHAPES\n",
m_file );
651 wxString shapeName = footprint->GetFPID().Format();
653 auto shapeIt = shapes.find( shapeName );
656 if( shapeIt != shapes.end() )
658 if( modHash != shapeIt->second )
662 wxString newShapeName;
668 newShapeName = wxString::Format( wxT(
"%s_%d" ), shapeName, suffix );
669 shapeIt = shapes.find( newShapeName );
672 while( shapeIt != shapes.end() && shapeIt->second != modHash );
674 shapeName = newShapeName;
677 if( shapeIt != shapes.end() && modHash == shapeIt->second )
688 shapes[shapeName] = modHash;
697 std::set<wxString> pins;
699 for(
PAD*
pad : footprint->Pads() )
705 pinname =
pad->GetNumber();
707 if( pinname.IsEmpty() )
708 pinname = wxT(
"none" );
713 wxString origPinname( pinname );
715 auto it = pins.find( pinname );
717 while( it != pins.end() )
719 pinname = wxString::Format( wxT(
"%s_%d" ), origPinname, suffix );
721 it = pins.find( pinname );
724 pins.insert( pinname );
727 EDA_ANGLE orient =
pad->GetOrientation() - footprint->GetOrientation();
734 "PIN \"%s\" PAD%dF %g %g %s %g %s\n" :
735 "PIN \"%s\" PAD%d %g %g %s %g %s\n",
743 fputs(
"$ENDSHAPES\n\n",
m_file );
754 fputs(
"$COMPONENTS\n",
m_file );
762 EDA_ANGLE fp_orient = footprint->GetOrientation();
764 if( footprint->GetFlag() )
776 fprintf(
m_file,
"\nCOMPONENT \"%s\"\n",
778 fprintf(
m_file,
"DEVICE \"DEV_%s\"\n",
780 fprintf(
m_file,
"PLACE %g %g\n",
781 MapXTo( footprint->GetPosition().x ),
782 MapYTo( footprint->GetPosition().y ) );
783 fprintf(
m_file,
"LAYER %s\n",
784 footprint->GetFlag() ?
"BOTTOM" :
"TOP" );
785 fprintf(
m_file,
"ROTATION %g\n",
787 fprintf(
m_file,
"SHAPE \"%s\" %s %s\n",
792 for(
PCB_TEXT* textItem : { &footprint->Reference(), &footprint->Value() } )
797 fprintf(
m_file,
"TEXT %g %g %g %g %s %s \"%s\"",
801 textItem->GetTextAngle().AsDegrees(),
806 BOX2I textBox = textItem->GetTextBox();
808 fprintf(
m_file,
" 0 0 %g %g\n",
814 fprintf(
m_file,
"SHEET \"RefDes: %s, Value: %s\"\n",
815 TO_UTF8( footprint->GetReference() ),
816 TO_UTF8( footprint->GetValue() ) );
819 fputs(
"$ENDCOMPONENTS\n\n",
m_file );
832 fputs(
"$SIGNALS\n",
m_file );
842 msg.Printf( wxT(
"NoConnection%d" ), NbNoConn++ );
855 for(
PAD*
pad : footprint->Pads() )
860 msg.Printf( wxT(
"NODE \"%s\" \"%s\"" ),
871 fputs(
"$ENDSIGNALS\n\n",
m_file );
879 fputs(
"$HEADER\n",
m_file );
880 fputs(
"GENCAD 1.4\n",
m_file );
891 msg = wxT(
"REVISION \"" ) + rev + wxT(
" " ) + date + wxT(
"\"\n" );
894 fputs(
"UNITS INCH\n",
m_file );
897 msg.Printf( wxT(
"ORIGIN %g %g\n" ),
902 fputs(
"INTERTRACK 0\n",
m_file );
903 fputs(
"$ENDHEADER\n\n",
m_file );
922 int old_netcode, old_width, old_layer;
928 std::sort( tracks.begin(), tracks.end(),
931 if( a->GetNetCode() == b->GetNetCode() )
933 if( a->GetWidth() == b->GetWidth() )
934 return ( a->GetLayer() < b->GetLayer() );
936 return ( a->GetWidth() < b->GetWidth() );
942 fputs(
"$ROUTES\n", m_file );
944 old_netcode = -1; old_width = -1; old_layer = -1;
948 if( old_netcode != track->GetNetCode() )
950 old_netcode = track->GetNetCode();
954 if( net && (net->
GetNetname() != wxEmptyString) )
957 netname = wxT(
"_noname_" );
962 if( old_width != track->GetWidth() )
964 old_width = track->GetWidth();
965 fprintf( m_file,
"TRACK TRACK%d\n", track->GetWidth() );
970 if( old_layer != track->GetLayer() )
972 old_layer = track->GetLayer();
973 fprintf( m_file,
"LAYER %s\n",
977 fprintf( m_file,
"LINE %g %g %g %g\n",
978 MapXTo( track->GetStart().x ), MapYTo( track->GetStart().y ),
979 MapXTo( track->GetEnd().x ), MapYTo( track->GetEnd().y ) );
988 fprintf( m_file,
"VIA VIA%d.%d.%s %g %g ALL %g via%d\n",
991 MapXTo(
via->GetStart().x ), MapYTo(
via->GetStart().y ),
996 fputs(
"$ENDROUTES\n\n", m_file );
1006 std::set<wxString> emitted;
1008 fputs(
"$DEVICES\n",
m_file );
1019 const wxString& shapeName =
shapeNames[componentShape.second];
1021 std::tie( std::ignore, newDevice ) = emitted.insert( shapeName );
1026 const FOOTPRINT* footprint = componentShape.first;
1029 txt.Printf(
"\nDEVICE \"DEV_%s\"\n",
escapeString( shapeName ) );
1038 for( wxString& item : data )
1041 fputs(
"$ENDDEVICES\n\n",
m_file );
1050 fputs(
"$BOARD\n",
m_file );
1059 fprintf(
m_file,
"LINE %g %g %g %g\n",
1064 fputs(
"$ENDBOARD\n\n",
m_file );
1081 std::set<int> trackinfo;
1084 trackinfo.insert( track->GetWidth() );
1087 fputs(
"$TRACKS\n",
m_file );
1089 for(
int size : trackinfo )
1092 fputs(
"$ENDTRACKS\n\n",
m_file );
1107 fprintf(
m_file,
"INSERT TH\n" );
1109 fprintf(
m_file,
"INSERT SMD\n" );
1118 && ( item->GetLayer() ==
F_SilkS || item->GetLayer() ==
B_SilkS ) )
1131 case SHAPE_T::SEGMENT:
1132 fprintf(
m_file,
"LINE %g %g %g %g\n",
1139 case SHAPE_T::RECTANGLE:
1140 fprintf(
m_file,
"LINE %g %g %g %g\n",
1145 fprintf(
m_file,
"LINE %g %g %g %g\n",
1150 fprintf(
m_file,
"LINE %g %g %g %g\n",
1155 fprintf(
m_file,
"LINE %g %g %g %g\n",
1162 case SHAPE_T::CIRCLE:
1166 fprintf(
m_file,
"CIRCLE %g %g %g\n",
1175 std::swap( start, end );
1177 fprintf(
m_file,
"ARC %g %g %g %g %g %g\n",
1191 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.
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...
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
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
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 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(const 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 CuStack() const
Return a sequence of copper layers in starting from the front/top and extending to the back/bottom.
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
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.
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)
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, 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
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 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.
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)
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)
VECTOR2< int32_t > VECTOR2I