34#include <unordered_map>
45 else if( aId ==
B_Cu )
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;
105 wxString
copy( aString );
106 copy.Replace( wxT(
"\"" ), wxT(
"\\\"" ) );
114 retv.erase( 0, retv.find_first_not_of(
'0' ) );
126 static const wxString invalid(
"invalid" );
134 auto itName =
shapeNames.find( itShape->second );
135 wxCHECK( itName !=
shapeNames.end(), invalid );
137 return itName->second;
162 m_file = wxFopen( aFullFileName, wxT(
"wt" ) );
181 footprint->SetFlag( 0 );
183 if( footprint->GetLayer() ==
B_Cu )
186 footprint->SetFlag( 1 );
225 if( footprint->GetFlag() )
228 footprint->SetFlag( 0 );
252 if( refLayers != cmpLayers )
253 return refLayers < cmpLayers;
286 std::string
name =
"VIA";
291 name += fmt::format(
"{}.", aVia->
GetWidth( aViaLayer ) );
306 width = std::max( width, aVia->
GetWidth( aViaLayer ) );
316 fmt::print(
m_file,
"$ARTWORKS\n" );
317 fmt::print(
m_file,
"$ENDARTWORKS\n\n" );
325 int dx = aPad->
GetSize( aPadLayer ).
x / 2;
326 int dy = aPad->
GetSize( aPadLayer ).
y / 2;
328 fmt::print(
m_file,
"PAD {}", aName );
330 switch( aPad->
GetShape( aPadLayer ) )
337 fmt::print(
m_file,
" ROUND {}\n",
341 fmt::print(
m_file,
"CIRCLE {} {} {}\n",
348 fmt::print(
m_file,
" RECTANGULAR {}\n",
352 fmt::print(
m_file,
"RECTANGLE {} {} {} {}\n",
362 int radius = std::min( size.
x, size.
y ) / 2;
367 int lineX = size.
x / 2 -
radius;
368 int lineY = size.
y / 2 -
radius;
373 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
384 fmt::print(
m_file,
"LINE {} {} {} {}\n",
392 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
403 fmt::print(
m_file,
"LINE {} {} {} {}\n",
411 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
422 fmt::print(
m_file,
"LINE {} {} {} {}\n",
430 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
441 fmt::print(
m_file,
"LINE {} {} {} {}\n",
455 int ddx = aPad->
GetDelta( aPadLayer ).
x / 2;
456 int ddy = aPad->
GetDelta( aPadLayer ).
y / 2;
459 poly[0] =
VECTOR2I( -dx + ddy, dy + ddx );
460 poly[1] =
VECTOR2I( dx - ddy, dy - ddx );
461 poly[2] =
VECTOR2I( dx + ddy, -dy + ddx );
462 poly[3] =
VECTOR2I( -dx - ddy, -dy - ddx );
464 for(
int cur = 0; cur < 4; ++cur )
466 int next = ( cur + 1 ) % 4;
467 fmt::print(
m_file,
"LINE {} {} {} {}\n",
497 for(
int ii = 0; ii < pointCount; ii++ )
499 int next = ( ii + 1 ) % pointCount;
500 fmt::print(
m_file,
"LINE {} {} {} {}\n",
523 for(
int ii = 0; ii < pointCount; ii++ )
525 int next = ( ii + 1 ) % pointCount;
526 fmt::print(
m_file,
"LINE {} {} {} {}\n",
545 std::vector<PAD*> padstacks;
546 std::vector<PCB_VIA*> vias;
547 std::vector<PCB_VIA*> viastacks;
549 padstacks.resize( 1 );
551 LSEQ gc_seq =
m_board->GetEnabledLayers().CuStack();
552 std::reverse(gc_seq.begin(), gc_seq.end());
555 LSET master_layermask =
m_board->GetDesignSettings().GetEnabledLayers();
556 int cu_count =
m_board->GetCopperLayerCount();
558 fmt::print(
m_file,
"$PADS\n" );
561 std::vector<PAD*> pads =
m_board->GetPads();
562 std::sort( pads.begin(), pads.end(), [](
const PAD* a,
const PAD* b )
564 return PAD::Compare( a, b ) < 0;
571 vias.push_back(
via );
574 std::sort( vias.begin(), vias.end(),
viaSort );
575 vias.erase( std::unique( vias.begin(), vias.end(), [](
const PCB_VIA* a,
const PCB_VIA* b )
577 return viaSort( a, b ) == false;
584 LSET mask =
via->GetLayerSet() & master_layermask;
586 viastacks.push_back(
via );
590 std::set<std::string> emitted;
592 via->Padstack().ForEachUniqueLayer(
597 if( !emitted.insert( stem ).second )
600 fmt::print(
m_file,
"PAD {} ROUND {}\nCIRCLE 0 0 {}\n",
608 PAD* old_pad =
nullptr;
609 int pad_name_number = 0;
611 for(
unsigned i = 0; i<pads.size(); ++i )
615 pad->SetSubRatsnest( pad_name_number );
625 pad->SetSubRatsnest( pad_name_number );
627 padstacks.push_back(
pad );
630 std::string stem = fmt::format(
"P{}",
pad->GetSubRatsnest() );
632 pad->Padstack().ForEachUniqueLayer(
640 fmt::print(
m_file,
"\n$ENDPADS\n\n" );
643 fmt::print(
m_file,
"$PADSTACKS\n" );
646 for(
unsigned i = 0; i < viastacks.size(); i++ )
650 LSET mask =
via->GetLayerSet() & master_layermask;
652 fmt::print(
m_file,
"PADSTACK {} {}\n",
658 fmt::print(
m_file,
"PAD {} {} 0 0\n",
669 for(
unsigned i = 1; i < padstacks.size(); i++ )
674 fmt::print(
m_file,
"PADSTACK PAD{} {}\n",
678 LSET pad_set =
pad->GetLayerSet() & master_layermask;
679 std::string stem = fmt::format(
"P{}", i );
684 fmt::print(
m_file,
"PAD {} {} 0 0\n",
686 pad->Padstack().EffectiveLayerFor( layer ) ),
693 fmt::print(
m_file,
"PADSTACK PAD{}F {}\n",
700 fmt::print(
m_file,
"PAD {} {} 0 0\n",
702 pad->Padstack().EffectiveLayerFor( layer ) ),
708 fputs(
"$ENDPADSTACKS\n\n",
m_file );
715 size_t ret = 0x11223344;
722 for(
PAD* i : aFootprint->
Pads() )
733 const char* mirror =
"0";
734 std::map<wxString, size_t> shapes;
736 fmt::print(
m_file,
"$SHAPES\n" );
746 wxString shapeName = footprint->GetFPID().Format();
748 auto shapeIt = shapes.find( shapeName );
751 if( shapeIt != shapes.end() )
753 if( modHash != shapeIt->second )
757 wxString newShapeName;
763 newShapeName = wxString::Format( wxT(
"%s_%d" ), shapeName, suffix );
764 shapeIt = shapes.find( newShapeName );
767 while( shapeIt != shapes.end() && shapeIt->second != modHash );
769 shapeName = newShapeName;
772 if( shapeIt != shapes.end() && modHash == shapeIt->second )
783 shapes[shapeName] = modHash;
792 std::set<wxString> pins;
794 for(
PAD*
pad : footprint->Pads() )
800 pinname =
pad->GetNumber();
802 if( pinname.IsEmpty() )
803 pinname = wxT(
"none" );
808 wxString origPinname( pinname );
810 auto it = pins.find( pinname );
812 while( it != pins.end() )
814 pinname = wxString::Format( wxT(
"%s_%d" ), origPinname, suffix );
816 it = pins.find( pinname );
819 pins.insert( pinname );
822 EDA_ANGLE orient =
pad->GetOrientation() - footprint->GetOrientation();
827 std::string flipStr = (
m_flipBottomPads && footprint->GetFlag() ) ?
"F" :
"";
831 "PIN \"{}\" PAD{}{} {} {} {} {} {}\n",
833 pad->GetSubRatsnest(),
843 fmt::print(
m_file,
"$ENDSHAPES\n\n" );
849 fmt::print(
m_file,
"$COMPONENTS\n" );
851 int cu_count =
m_board->GetCopperLayerCount();
857 EDA_ANGLE fp_orient = footprint->GetOrientation();
859 if( footprint->GetFlag() )
871 fmt::print(
m_file,
"\nCOMPONENT \"{}\"\n",
873 fmt::print(
m_file,
"DEVICE \"DEV_{}\"\n",
875 fmt::print(
m_file,
"PLACE {} {}\n",
876 mapXTo( footprint->GetPosition().x ),
877 mapYTo( footprint->GetPosition().y ) );
878 fmt::print(
m_file,
"LAYER {}\n",
879 footprint->GetFlag() ?
"BOTTOM" :
"TOP" );
880 fmt::print(
m_file,
"ROTATION {}\n",
882 fmt::print(
m_file,
"SHAPE \"{}\" {} {}\n",
887 for(
PCB_TEXT* textItem : { &footprint->Reference(), &footprint->Value() } )
891 fmt::print(
m_file,
"TEXT {} {} {} {} {} {} \"{}\"",
895 textItem->GetTextAngle().AsDegrees(),
900 BOX2I textBox = textItem->GetTextBox(
nullptr );
902 fmt::print(
m_file,
" 0 0 {} {}\n",
908 fmt::print(
m_file,
"SHEET \"RefDes: {}, Value: {}\"\n",
909 TO_UTF8( footprint->GetReference() ),
910 TO_UTF8( footprint->GetValue() ) );
913 fmt::print(
m_file,
"$ENDCOMPONENTS\n\n" );
922 std::unordered_map<int, std::vector<std::pair<FOOTPRINT*, PAD*>>> padsByNet;
926 for(
PAD*
pad : footprint->Pads() )
928 if(
pad->GetNetCode() > 0 )
929 padsByNet[
pad->GetNetCode()].emplace_back( footprint,
pad );
936 fmt::print(
m_file,
"$SIGNALS\n" );
938 for(
unsigned ii = 0; ii <
m_board->GetNetCount(); ii++ )
950 fmt::print(
m_file,
"\n" );
952 auto pads = padsByNet.find( net->
GetNetCode() );
954 if( pads == padsByNet.end() )
957 for(
const auto& [footprint,
pad] : pads->second )
959 msg.Printf( wxT(
"NODE \"%s\" \"%s\"" ),
964 fmt::print(
m_file,
"\n" );
969 fmt::print(
m_file,
"$ENDSIGNALS\n\n" );
975 fmt::print(
m_file,
"$HEADER\n" );
976 fmt::print(
m_file,
"GENCAD 1.4\n" );
981 fmt::print(
m_file,
"DRAWING \"{}\"\n",
m_board->GetFileName() );
986 fmt::print(
m_file,
"REVISION \"{} {}\"\n", rev, date );
987 fmt::print(
m_file,
"UNITS INCH\n" );
993 fmt::print(
m_file,
"INTERTRACK 0\n" );
994 fmt::print(
m_file,
"$ENDHEADER\n\n" );
1003 int old_netcode, old_width, old_layer;
1004 LSET master_layermask =
m_board->GetDesignSettings().GetEnabledLayers();
1005 int cu_count =
m_board->GetCopperLayerCount();
1008 std::sort( tracks.begin(), tracks.end(),
1014 if( a->Type() == PCB_VIA_T )
1015 widthA = viaNominalWidth( static_cast<const PCB_VIA*>( a ) );
1017 widthA = a->GetWidth();
1019 if( b->Type() == PCB_VIA_T )
1020 widthB = viaNominalWidth( static_cast<const PCB_VIA*>( b ) );
1022 widthB = b->GetWidth();
1024 if( a->GetNetCode() == b->GetNetCode() )
1026 if( widthA == widthB )
1027 return ( a->GetLayer() < b->GetLayer() );
1029 return ( widthA < widthB );
1035 fmt::print( m_file,
"$ROUTES\n" );
1043 if( old_netcode != track->GetNetCode() )
1045 old_netcode = track->GetNetCode();
1049 if( net && (net->
GetNetname() != wxEmptyString) )
1052 netname = wxT(
"_noname_" );
1057 int currentWidth = 0;
1062 currentWidth = track->GetWidth();
1064 if( old_width != currentWidth )
1066 old_width = currentWidth;
1067 fmt::print( m_file,
"TRACK TRACK{}\n", currentWidth );
1072 if( old_layer != track->GetLayer() )
1074 old_layer = track->GetLayer();
1075 fmt::print( m_file,
"LAYER {}\n",
1079 fmt::print( m_file,
"LINE {} {} {} {}\n",
1080 mapXTo( track->GetStart().x ), mapYTo( track->GetStart().y ),
1081 mapXTo( track->GetEnd().x ), mapYTo( track->GetEnd().y ) );
1085 if( old_layer != track->GetLayer() )
1087 old_layer = track->GetLayer();
1088 fmt::print( m_file,
"LAYER {}\n",
1092 VECTOR2I start = track->GetStart();
1099 std::swap( start,
end );
1103 fmt::print( m_file,
"ARC {} {} {} {} {} {}\n",
1104 mapXTo( start.
x ), mapYTo( start.
y ),
1105 mapXTo(
end.x ), mapYTo(
end.y ),
1112 LSET vset =
via->GetLayerSet() & master_layermask;
1114 fmt::print( m_file,
"VIA {} {} {} ALL {} via{}\n",
1116 mapXTo(
via->GetStart().x ), mapYTo(
via->GetStart().y ),
1122 fmt::print( m_file,
"$ENDROUTES\n\n" );
1128 std::set<wxString> emitted;
1130 fmt::print(
m_file,
"$DEVICES\n" );
1141 const wxString& shapeName =
shapeNames[componentShape.second];
1143 std::tie( std::ignore, newDevice ) = emitted.insert( shapeName );
1148 const FOOTPRINT* footprint = componentShape.first;
1151 txt.Printf(
"\nDEVICE \"DEV_%s\"\n",
escapeString( shapeName ) );
1160 for( wxString& item : data )
1163 fmt::print(
m_file,
"$ENDDEVICES\n\n" );
1171 fmt::print(
m_file,
"$BOARD\n" );
1176 if( !
m_board->GetBoardPolygonOutlines( outline,
true ) )
1177 wxLogError(
_(
"Board outline is malformed. Run DRC for a full analysis." ) );
1182 fmt::print(
m_file,
"LINE {} {} {} {}\n",
1187 fmt::print(
m_file,
"$ENDBOARD\n\n" );
1194 std::set<int> trackinfo;
1201 trackinfo.insert( track->GetWidth() );
1205 fmt::print(
m_file,
"$TRACKS\n" );
1207 for(
int size : trackinfo )
1210 fmt::print(
m_file,
"$ENDTRACKS\n\n" );
1220 fmt::print(
m_file,
"INSERT TH\n" );
1222 fmt::print(
m_file,
"INSERT SMD\n" );
1244 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",
1267 fmt::print(
m_file,
"LINE {} {} {} {}\n",
1278 fmt::print(
m_file,
"CIRCLE {} {} {}\n",
1287 std::swap( start,
end );
1289 fmt::print(
m_file,
"ARC {} {} {} {} {} {}\n",
1303 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.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
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
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