44 else if( aId ==
B_Cu )
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;
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" ) );
180 footprint->SetFlag( 0 );
182 if( footprint->GetLayer() ==
B_Cu )
185 footprint->SetFlag( 1 );
224 if( footprint->GetFlag() )
227 footprint->SetFlag( 0 );
251 if( refLayers != cmpLayers )
252 return refLayers < cmpLayers;
285 std::string
name =
"VIA";
290 name += fmt::format(
"{}.", aVia->
GetWidth( aViaLayer ) );
305 width = std::max( width, aVia->
GetWidth( aViaLayer ) );
315 fmt::print(
m_file,
"$ARTWORKS\n" );
316 fmt::print(
m_file,
"$ENDARTWORKS\n\n" );
324 int dx = aPad->
GetSize( aPadLayer ).
x / 2;
325 int dy = aPad->
GetSize( aPadLayer ).
y / 2;
327 fmt::print(
m_file,
"PAD {}", aName );
329 switch( aPad->
GetShape( aPadLayer ) )
336 fmt::print(
m_file,
" ROUND {}\n",
340 fmt::print(
m_file,
"CIRCLE {} {} {}\n",
347 fmt::print(
m_file,
" RECTANGULAR {}\n",
351 fmt::print(
m_file,
"RECTANGLE {} {} {} {}\n",
361 int radius = std::min( size.
x, size.
y ) / 2;
366 int lineX = size.
x / 2 -
radius;
367 int lineY = size.
y / 2 -
radius;
372 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
383 fmt::print(
m_file,
"LINE {} {} {} {}\n",
391 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
402 fmt::print(
m_file,
"LINE {} {} {} {}\n",
410 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
421 fmt::print(
m_file,
"LINE {} {} {} {}\n",
429 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
440 fmt::print(
m_file,
"LINE {} {} {} {}\n",
454 int ddx = aPad->
GetDelta( aPadLayer ).
x / 2;
455 int ddy = aPad->
GetDelta( aPadLayer ).
y / 2;
458 poly[0] =
VECTOR2I( -dx + ddy, dy + ddx );
459 poly[1] =
VECTOR2I( dx - ddy, dy - ddx );
460 poly[2] =
VECTOR2I( dx + ddy, -dy + ddx );
461 poly[3] =
VECTOR2I( -dx - ddy, -dy - ddx );
463 for(
int cur = 0; cur < 4; ++cur )
465 int next = ( cur + 1 ) % 4;
466 fmt::print(
m_file,
"LINE {} {} {} {}\n",
496 for(
int ii = 0; ii < pointCount; ii++ )
498 int next = ( ii + 1 ) % pointCount;
499 fmt::print(
m_file,
"LINE {} {} {} {}\n",
522 for(
int ii = 0; ii < pointCount; ii++ )
524 int next = ( ii + 1 ) % pointCount;
525 fmt::print(
m_file,
"LINE {} {} {} {}\n",
544 std::vector<PAD*> padstacks;
545 std::vector<PCB_VIA*> vias;
546 std::vector<PCB_VIA*> viastacks;
548 padstacks.resize( 1 );
550 LSEQ gc_seq =
m_board->GetEnabledLayers().CuStack();
551 std::reverse(gc_seq.begin(), gc_seq.end());
554 LSET master_layermask =
m_board->GetDesignSettings().GetEnabledLayers();
555 int cu_count =
m_board->GetCopperLayerCount();
557 fmt::print(
m_file,
"$PADS\n" );
560 std::vector<PAD*> pads =
m_board->GetPads();
561 std::sort( pads.begin(), pads.end(), [](
const PAD* a,
const PAD* b )
563 return PAD::Compare( a, b ) < 0;
570 vias.push_back(
via );
573 std::sort( vias.begin(), vias.end(),
viaSort );
574 vias.erase( std::unique( vias.begin(), vias.end(), [](
const PCB_VIA* a,
const PCB_VIA* b )
576 return viaSort( a, b ) == false;
583 LSET mask =
via->GetLayerSet() & master_layermask;
585 viastacks.push_back(
via );
589 std::set<std::string> emitted;
591 via->Padstack().ForEachUniqueLayer(
596 if( !emitted.insert( stem ).second )
599 fmt::print(
m_file,
"PAD {} ROUND {}\nCIRCLE 0 0 {}\n",
607 PAD* old_pad =
nullptr;
608 int pad_name_number = 0;
610 for(
unsigned i = 0; i<pads.size(); ++i )
614 pad->SetSubRatsnest( pad_name_number );
624 pad->SetSubRatsnest( pad_name_number );
626 padstacks.push_back(
pad );
629 std::string stem = fmt::format(
"P{}",
pad->GetSubRatsnest() );
631 pad->Padstack().ForEachUniqueLayer(
639 fmt::print(
m_file,
"\n$ENDPADS\n\n" );
642 fmt::print(
m_file,
"$PADSTACKS\n" );
645 for(
unsigned i = 0; i < viastacks.size(); i++ )
649 LSET mask =
via->GetLayerSet() & master_layermask;
651 fmt::print(
m_file,
"PADSTACK {} {}\n",
657 fmt::print(
m_file,
"PAD {} {} 0 0\n",
668 for(
unsigned i = 1; i < padstacks.size(); i++ )
673 fmt::print(
m_file,
"PADSTACK PAD{} {}\n",
677 LSET pad_set =
pad->GetLayerSet() & master_layermask;
678 std::string stem = fmt::format(
"P{}", i );
683 fmt::print(
m_file,
"PAD {} {} 0 0\n",
685 pad->Padstack().EffectiveLayerFor( layer ) ),
692 fmt::print(
m_file,
"PADSTACK PAD{}F {}\n",
699 fmt::print(
m_file,
"PAD {} {} 0 0\n",
701 pad->Padstack().EffectiveLayerFor( layer ) ),
707 fputs(
"$ENDPADSTACKS\n\n",
m_file );
714 size_t ret = 0x11223344;
721 for(
PAD* i : aFootprint->
Pads() )
732 const char* mirror =
"0";
733 std::map<wxString, size_t> shapes;
735 fmt::print(
m_file,
"$SHAPES\n" );
745 wxString shapeName = footprint->GetFPID().Format();
747 auto shapeIt = shapes.find( shapeName );
750 if( shapeIt != shapes.end() )
752 if( modHash != shapeIt->second )
756 wxString newShapeName;
762 newShapeName = wxString::Format( wxT(
"%s_%d" ), shapeName, suffix );
763 shapeIt = shapes.find( newShapeName );
766 while( shapeIt != shapes.end() && shapeIt->second != modHash );
768 shapeName = newShapeName;
771 if( shapeIt != shapes.end() && modHash == shapeIt->second )
782 shapes[shapeName] = modHash;
791 std::set<wxString> pins;
793 for(
PAD*
pad : footprint->Pads() )
799 pinname =
pad->GetNumber();
801 if( pinname.IsEmpty() )
802 pinname = wxT(
"none" );
807 wxString origPinname( pinname );
809 auto it = pins.find( pinname );
811 while( it != pins.end() )
813 pinname = wxString::Format( wxT(
"%s_%d" ), origPinname, suffix );
815 it = pins.find( pinname );
818 pins.insert( pinname );
821 EDA_ANGLE orient =
pad->GetOrientation() - footprint->GetOrientation();
826 std::string flipStr = (
m_flipBottomPads && footprint->GetFlag() ) ?
"F" :
"";
830 "PIN \"{}\" PAD{}{} {} {} {} {} {}\n",
832 pad->GetSubRatsnest(),
842 fmt::print(
m_file,
"$ENDSHAPES\n\n" );
848 fmt::print(
m_file,
"$COMPONENTS\n" );
850 int cu_count =
m_board->GetCopperLayerCount();
856 EDA_ANGLE fp_orient = footprint->GetOrientation();
858 if( footprint->GetFlag() )
870 fmt::print(
m_file,
"\nCOMPONENT \"{}\"\n",
872 fmt::print(
m_file,
"DEVICE \"DEV_{}\"\n",
874 fmt::print(
m_file,
"PLACE {} {}\n",
875 mapXTo( footprint->GetPosition().x ),
876 mapYTo( footprint->GetPosition().y ) );
877 fmt::print(
m_file,
"LAYER {}\n",
878 footprint->GetFlag() ?
"BOTTOM" :
"TOP" );
879 fmt::print(
m_file,
"ROTATION {}\n",
881 fmt::print(
m_file,
"SHAPE \"{}\" {} {}\n",
886 for(
PCB_TEXT* textItem : { &footprint->Reference(), &footprint->Value() } )
890 fmt::print(
m_file,
"TEXT {} {} {} {} {} {} \"{}\"",
894 textItem->GetTextAngle().AsDegrees(),
899 BOX2I textBox = textItem->GetTextBox(
nullptr );
901 fmt::print(
m_file,
" 0 0 {} {}\n",
907 fmt::print(
m_file,
"SHEET \"RefDes: {}, Value: {}\"\n",
908 TO_UTF8( footprint->GetReference() ),
909 TO_UTF8( footprint->GetValue() ) );
912 fmt::print(
m_file,
"$ENDCOMPONENTS\n\n" );
925 fmt::print(
m_file,
"$SIGNALS\n" );
927 for(
unsigned ii = 0; ii <
m_board->GetNetCount(); ii++ )
935 msg.Printf( wxT(
"NoConnection%d" ), NbNoConn++ );
944 fmt::print(
m_file,
"\n" );
948 for(
PAD*
pad : footprint->Pads() )
953 msg.Printf( wxT(
"NODE \"%s\" \"%s\"" ),
958 fmt::print(
m_file,
"\n" );
964 fmt::print(
m_file,
"$ENDSIGNALS\n\n" );
970 fmt::print(
m_file,
"$HEADER\n" );
971 fmt::print(
m_file,
"GENCAD 1.4\n" );
976 fmt::print(
m_file,
"DRAWING \"{}\"\n",
m_board->GetFileName() );
981 fmt::print(
m_file,
"REVISION \"{} {}\"\n", rev, date );
982 fmt::print(
m_file,
"UNITS INCH\n" );
988 fmt::print(
m_file,
"INTERTRACK 0\n" );
989 fmt::print(
m_file,
"$ENDHEADER\n\n" );
998 int old_netcode, old_width, old_layer;
999 LSET master_layermask =
m_board->GetDesignSettings().GetEnabledLayers();
1000 int cu_count =
m_board->GetCopperLayerCount();
1003 std::sort( tracks.begin(), tracks.end(),
1009 if( a->Type() == PCB_VIA_T )
1010 widthA = viaNominalWidth( static_cast<const PCB_VIA*>( a ) );
1012 widthA = a->GetWidth();
1014 if( b->Type() == PCB_VIA_T )
1015 widthB = viaNominalWidth( static_cast<const PCB_VIA*>( b ) );
1017 widthB = b->GetWidth();
1019 if( a->GetNetCode() == b->GetNetCode() )
1021 if( widthA == widthB )
1022 return ( a->GetLayer() < b->GetLayer() );
1024 return ( widthA < widthB );
1030 fmt::print( m_file,
"$ROUTES\n" );
1038 if( old_netcode != track->GetNetCode() )
1040 old_netcode = track->GetNetCode();
1044 if( net && (net->
GetNetname() != wxEmptyString) )
1047 netname = wxT(
"_noname_" );
1052 int currentWidth = 0;
1057 currentWidth = track->GetWidth();
1059 if( old_width != currentWidth )
1061 old_width = currentWidth;
1062 fmt::print( m_file,
"TRACK TRACK{}\n", currentWidth );
1067 if( old_layer != track->GetLayer() )
1069 old_layer = track->GetLayer();
1070 fmt::print( m_file,
"LAYER {}\n",
1074 fmt::print( m_file,
"LINE {} {} {} {}\n",
1075 mapXTo( track->GetStart().x ), mapYTo( track->GetStart().y ),
1076 mapXTo( track->GetEnd().x ), mapYTo( track->GetEnd().y ) );
1080 if( old_layer != track->GetLayer() )
1082 old_layer = track->GetLayer();
1083 fmt::print( m_file,
"LAYER {}\n",
1087 VECTOR2I start = track->GetStart();
1094 std::swap( start,
end );
1098 fmt::print( m_file,
"ARC {} {} {} {} {} {}\n",
1099 mapXTo( start.
x ), mapYTo( start.
y ),
1100 mapXTo(
end.x ), mapYTo(
end.y ),
1107 LSET vset =
via->GetLayerSet() & master_layermask;
1109 fmt::print( m_file,
"VIA {} {} {} ALL {} via{}\n",
1111 mapXTo(
via->GetStart().x ), mapYTo(
via->GetStart().y ),
1117 fmt::print( m_file,
"$ENDROUTES\n\n" );
1123 std::set<wxString> emitted;
1125 fmt::print(
m_file,
"$DEVICES\n" );
1136 const wxString& shapeName =
shapeNames[componentShape.second];
1138 std::tie( std::ignore, newDevice ) = emitted.insert( shapeName );
1143 const FOOTPRINT* footprint = componentShape.first;
1146 txt.Printf(
"\nDEVICE \"DEV_%s\"\n",
escapeString( shapeName ) );
1155 for( wxString& item : data )
1158 fmt::print(
m_file,
"$ENDDEVICES\n\n" );
1166 fmt::print(
m_file,
"$BOARD\n" );
1171 if( !
m_board->GetBoardPolygonOutlines( outline,
true ) )
1172 wxLogError(
_(
"Board outline is malformed. Run DRC for a full analysis." ) );
1177 fmt::print(
m_file,
"LINE {} {} {} {}\n",
1182 fmt::print(
m_file,
"$ENDBOARD\n\n" );
1189 std::set<int> trackinfo;
1196 trackinfo.insert( track->GetWidth() );
1200 fmt::print(
m_file,
"$TRACKS\n" );
1202 for(
int size : trackinfo )
1205 fmt::print(
m_file,
"$ENDTRACKS\n\n" );
1215 fmt::print(
m_file,
"INSERT TH\n" );
1217 fmt::print(
m_file,
"INSERT SMD\n" );
1239 fmt::print(
m_file,
"LINE {} {} {} {}\n",
1247 fmt::print(
m_file,
"LINE {} {} {} {}\n",
1252 fmt::print(
m_file,
"LINE {} {} {} {}\n",
1257 fmt::print(
m_file,
"LINE {} {} {} {}\n",
1262 fmt::print(
m_file,
"LINE {} {} {} {}\n",
1273 fmt::print(
m_file,
"CIRCLE {} {} {}\n",
1282 std::swap( start,
end );
1284 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
1298 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.
const FOOTPRINTS & Footprints() const
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false, bool aPhysicalLayersOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
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 writePadShape(const std::string &aName, PAD *aPad, PCB_LAYER_ID aPadLayer)
Write one "PAD" entry for the copper aPad carries on aPadLayer, named aName as referenced from a PADS...
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.
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Handle the data for a net.
const wxString & GetNetname() const
A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of the word.
void ForEachUniqueLayer(const std::function< void(PCB_LAYER_ID)> &aMethod) const
Runs the given callable for each active unique copper layer in this padstack, meaning F_Cu for MODE::...
std::vector< PCB_LAYER_ID > UniqueLayers() const
@ NORMAL
Shape is the same on all layers.
static wxString ShowPadShape(PAD_SHAPE aShape)
void MergePrimitivesAsPolygon(PCB_LAYER_ID aLayer, SHAPE_POLY_SET *aMergedPolygon, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Merge all basic shapes to a SHAPE_POLY_SET.
int GetRoundRectCornerRadius(PCB_LAYER_ID aLayer) const
static int Compare(const PAD *aPadRef, const PAD *aPadCmp)
Compare two pads and return 0 if they are equal.
const VECTOR2I & GetDelta(PCB_LAYER_ID aLayer) const
VECTOR2I GetOffset(PCB_LAYER_ID aLayer) const
VECTOR2I GetDrillSize() const
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
VECTOR2I GetSize(PCB_LAYER_ID aLayer) const
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
int GetChamferPositions(PCB_LAYER_ID aLayer) const
double GetChamferRectRatio(PCB_LAYER_ID aLayer) const
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.
const PADSTACK & Padstack() const
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, RESOLUTION_CONTEXT aContext)
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 std::string viaShapeStem(const PCB_VIA *aVia, PCB_LAYER_ID aViaLayer, const LSET &aMask)
static std::string viaStackName(const PCB_VIA *aVia, const LSET &aMask)
The name carries every distinct diameter, or two vias that differ on one inner layer collide.
static std::string padShapeName(const std::string &aStem, const PADSTACK &aPadstack, PCB_LAYER_ID aPadLayer)
A uniform padstack keeps the bare name, so it still reads as one shape and not as a stack.
static size_t hashFootprint(const FOOTPRINT *aFootprint)
Compute hashes for footprints without taking into account their position, rotation or layer.
static int viaNominalWidth(const PCB_VIA *aVia)
The padstack describes the copper, so the one width a route entry holds is the widest.
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.
size_t CopperLayerToOrdinal(PCB_LAYER_ID aLayer)
Converts KiCad copper layer enum to an ordinal between the front and back layers.
bool IsInnerCopperLayer(int aLayerId)
Test whether a layer is an inner (In1_Cu to In30_Cu) 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)
std::deque< PCB_TRACK * > TRACKS
#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