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(
"\\\"" ) );
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" ) );
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 );
279 std::sort( pads.begin(), pads.end(), [](
const PAD* a,
const PAD* b )
281 return PAD::Compare( a, b ) < 0;
287 if(
PCB_VIA*
via = dyn_cast<PCB_VIA*>( track ) )
288 vias.push_back(
via );
291 std::sort( vias.begin(), vias.end(),
viaSort );
292 vias.erase( std::unique( vias.begin(), vias.end(), [](
const PCB_VIA* a,
const PCB_VIA* b )
294 return viaSort( a, b ) == false;
301 viastacks.push_back(
via );
302 fprintf(
m_file,
"PAD V%d.%d.%s ROUND %g\nCIRCLE 0 0 %g\n",
304 via->GetDrillValue(),
305 fmt_mask(
via->GetLayerSet() & master_layermask ).c_str(),
311 PAD* old_pad =
nullptr;
312 int pad_name_number = 0;
314 for(
unsigned i = 0; i<pads.size(); ++i )
319 pad->SetSubRatsnest( pad_name_number );
329 pad->SetSubRatsnest( pad_name_number );
331 fprintf(
m_file,
"PAD P%d",
pad->GetSubRatsnest() );
333 padstacks.push_back(
pad );
343 case PAD_SHAPE::CIRCLE:
344 fprintf(
m_file,
" ROUND %g\n",
348 fprintf(
m_file,
"CIRCLE %g %g %g\n",
354 case PAD_SHAPE::RECTANGLE:
355 fprintf(
m_file,
" RECTANGULAR %g\n",
359 fprintf(
m_file,
"RECTANGLE %g %g %g %g\n",
365 case PAD_SHAPE::ROUNDRECT:
366 case PAD_SHAPE::OVAL:
369 int radius = std::min( size.
x, size.
y ) / 2;
376 int lineX = size.
x / 2 -
radius;
377 int lineY = size.
y / 2 -
radius;
382 fprintf(
m_file,
"ARC %g %g %g %g %g %g\n",
393 fprintf(
m_file,
"LINE %g %g %g %g\n",
401 fprintf(
m_file,
"ARC %g %g %g %g %g %g\n",
412 fprintf(
m_file,
"LINE %g %g %g %g\n",
420 fprintf(
m_file,
"ARC %g %g %g %g %g %g\n",
431 fprintf(
m_file,
"LINE %g %g %g %g\n",
439 fprintf(
m_file,
"ARC %g %g %g %g %g %g\n",
450 fprintf(
m_file,
"LINE %g %g %g %g\n",
460 case PAD_SHAPE::TRAPEZOID:
468 poly[0] =
VECTOR2I( -dx + ddy, dy + ddx );
469 poly[1] =
VECTOR2I( dx - ddy, dy - ddx );
470 poly[2] =
VECTOR2I( dx + ddy, -dy + ddx );
471 poly[3] =
VECTOR2I( -dx - ddy, -dy - ddx );
473 for(
int cur = 0; cur < 4; ++cur )
475 int next = ( cur + 1 ) % 4;
476 fprintf(
m_file,
"LINE %g %g %g %g\n",
486 case PAD_SHAPE::CHAMFERED_RECT:
495 pad->GetOrientation(),
506 for(
int ii = 0; ii < pointCount; ii++ )
508 int next = ( ii + 1 ) % pointCount;
509 fprintf(
m_file,
"LINE %g %g %g %g\n",
520 case PAD_SHAPE::CUSTOM:
525 pad->MergePrimitivesAsPolygon(
F_Cu, &outline );
532 for(
int ii = 0; ii < pointCount; ii++ )
534 int next = ( ii + 1 ) % pointCount;
535 fprintf(
m_file,
"LINE %g %g %g %g\n",
548 fputs(
"\n$ENDPADS\n\n",
m_file );
551 fputs(
"$PADSTACKS\n",
m_file );
554 for(
unsigned i = 0; i < viastacks.size(); i++ )
558 LSET mask =
via->GetLayerSet() & master_layermask;
560 fprintf(
m_file,
"PADSTACK VIA%d.%d.%s %g\n",
562 via->GetDrillValue(),
568 fprintf(
m_file,
"PAD V%d.%d.%s %s 0 0\n",
570 via->GetDrillValue(),
581 for(
unsigned i = 1; i < padstacks.size(); i++ )
586 fprintf(
m_file,
"PADSTACK PAD%u %g\n",
590 LSET pad_set =
pad->GetLayerSet() & master_layermask;
595 fprintf(
m_file,
"PAD P%u %s 0 0\n",
603 fprintf(
m_file,
"PADSTACK PAD%uF %g\n",
610 fprintf(
m_file,
"PAD P%u %s 0 0\n",
617 fputs(
"$ENDPADSTACKS\n\n",
m_file );
624 size_t ret = 0x11223344;
631 for(
PAD* i : aFootprint->
Pads() )
642 const char* mirror =
"0";
643 std::map<wxString, size_t> shapes;
645 fputs(
"$SHAPES\n",
m_file );
655 wxString shapeName = footprint->GetFPID().Format();
657 auto shapeIt = shapes.find( shapeName );
660 if( shapeIt != shapes.end() )
662 if( modHash != shapeIt->second )
666 wxString newShapeName;
672 newShapeName = wxString::Format( wxT(
"%s_%d" ), shapeName, suffix );
673 shapeIt = shapes.find( newShapeName );
676 while( shapeIt != shapes.end() && shapeIt->second != modHash );
678 shapeName = newShapeName;
681 if( shapeIt != shapes.end() && modHash == shapeIt->second )
692 shapes[shapeName] = modHash;
701 std::set<wxString> pins;
703 for(
PAD*
pad : footprint->Pads() )
709 pinname =
pad->GetNumber();
711 if( pinname.IsEmpty() )
712 pinname = wxT(
"none" );
717 wxString origPinname( pinname );
719 auto it = pins.find( pinname );
721 while( it != pins.end() )
723 pinname = wxString::Format( wxT(
"%s_%d" ), origPinname, suffix );
725 it = pins.find( pinname );
728 pins.insert( pinname );
731 EDA_ANGLE orient =
pad->GetOrientation() - footprint->GetOrientation();
738 (
m_flipBottomPads && footprint->GetFlag() ) ?
"PIN \"%s\" PAD%dF %g %g %s %g %s\n"
739 :
"PIN \"%s\" PAD%d %g %g %s %g %s\n",
741 pad->GetSubRatsnest(),
750 fputs(
"$ENDSHAPES\n\n",
m_file );
756 fputs(
"$COMPONENTS\n",
m_file );
764 EDA_ANGLE fp_orient = footprint->GetOrientation();
766 if( footprint->GetFlag() )
778 fprintf(
m_file,
"\nCOMPONENT \"%s\"\n",
780 fprintf(
m_file,
"DEVICE \"DEV_%s\"\n",
782 fprintf(
m_file,
"PLACE %g %g\n",
783 mapXTo( footprint->GetPosition().x ),
784 mapYTo( footprint->GetPosition().y ) );
785 fprintf(
m_file,
"LAYER %s\n",
786 footprint->GetFlag() ?
"BOTTOM" :
"TOP" );
787 fprintf(
m_file,
"ROTATION %g\n",
789 fprintf(
m_file,
"SHAPE \"%s\" %s %s\n",
794 for(
PCB_TEXT* textItem : { &footprint->Reference(), &footprint->Value() } )
798 fprintf(
m_file,
"TEXT %g %g %g %g %s %s \"%s\"",
802 textItem->GetTextAngle().AsDegrees(),
807 BOX2I textBox = textItem->GetTextBox(
nullptr );
809 fprintf(
m_file,
" 0 0 %g %g\n",
815 fprintf(
m_file,
"SHEET \"RefDes: %s, Value: %s\"\n",
816 TO_UTF8( footprint->GetReference() ),
817 TO_UTF8( footprint->GetValue() ) );
820 fputs(
"$ENDCOMPONENTS\n\n",
m_file );
833 fputs(
"$SIGNALS\n",
m_file );
843 msg.Printf( wxT(
"NoConnection%d" ), NbNoConn++ );
856 for(
PAD*
pad : footprint->Pads() )
861 msg.Printf( wxT(
"NODE \"%s\" \"%s\"" ),
872 fputs(
"$ENDSIGNALS\n\n",
m_file );
880 fputs(
"$HEADER\n",
m_file );
881 fputs(
"GENCAD 1.4\n",
m_file );
892 msg = wxT(
"REVISION \"" ) + rev + wxT(
" " ) + date + wxT(
"\"\n" );
895 fputs(
"UNITS INCH\n",
m_file );
898 msg.Printf( wxT(
"ORIGIN %g %g\n" ),
903 fputs(
"INTERTRACK 0\n",
m_file );
904 fputs(
"$ENDHEADER\n\n",
m_file );
913 int old_netcode, old_width, old_layer;
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 fputs(
"$ROUTES\n", m_file );
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 fprintf( m_file,
"TRACK TRACK%d\n", currentWidth );
982 if( old_layer != track->GetLayer() )
984 old_layer = track->GetLayer();
985 fprintf( m_file,
"LAYER %s\n",
989 fprintf( m_file,
"LINE %g %g %g %g\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 fprintf( m_file,
"LAYER %s\n",
1002 VECTOR2I start = track->GetStart();
1009 std::swap( start,
end );
1013 fprintf( m_file,
"ARC %g %g %g %g %g %g\n",
1014 mapXTo( start.
x ), mapYTo( start.
y ),
1022 LSET vset =
via->GetLayerSet() & master_layermask;
1024 fprintf( m_file,
"VIA VIA%d.%d.%s %g %g ALL %g via%d\n",
1026 via->GetDrillValue(),
1028 mapXTo(
via->GetStart().x ), mapYTo(
via->GetStart().y ),
1034 fputs(
"$ENDROUTES\n\n", m_file );
1040 std::set<wxString> emitted;
1042 fputs(
"$DEVICES\n",
m_file );
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 fputs(
"$ENDDEVICES\n\n",
m_file );
1083 fputs(
"$BOARD\n",
m_file );
1092 fprintf(
m_file,
"LINE %g %g %g %g\n",
1097 fputs(
"$ENDBOARD\n\n",
m_file );
1104 std::set<int> trackinfo;
1111 trackinfo.insert( track->GetWidth() );
1115 fputs(
"$TRACKS\n",
m_file );
1117 for(
int size : trackinfo )
1120 fputs(
"$ENDTRACKS\n\n",
m_file );
1130 fprintf(
m_file,
"INSERT TH\n" );
1132 fprintf(
m_file,
"INSERT SMD\n" );
1153 case SHAPE_T::SEGMENT:
1154 fprintf(
m_file,
"LINE %g %g %g %g\n",
1161 case SHAPE_T::RECTANGLE:
1162 fprintf(
m_file,
"LINE %g %g %g %g\n",
1167 fprintf(
m_file,
"LINE %g %g %g %g\n",
1172 fprintf(
m_file,
"LINE %g %g %g %g\n",
1177 fprintf(
m_file,
"LINE %g %g %g %g\n",
1184 case SHAPE_T::CIRCLE:
1188 fprintf(
m_file,
"CIRCLE %g %g %g\n",
1197 std::swap( start,
end );
1199 fprintf(
m_file,
"ARC %g %g %g %g %g %g\n",
1213 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.
const 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
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
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 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.
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.
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)
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::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 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::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)
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)
VECTOR2< int32_t > VECTOR2I