67 PCB_IO( wxS(
"Protel Autotrax" ) )
83static bool readFile(
const wxString& aFileName, wxString& aOut,
size_t aLimit = 0 )
85 std::ifstream file( aFileName.fn_str(), std::ios::binary );
95 file.read( raw.data(), aLimit );
96 raw.resize(
static_cast<size_t>( file.gcount() ) );
100 std::ostringstream ss;
105 aOut = wxString::FromUTF8( raw.data(), raw.size() );
107 if( aOut.IsEmpty() && !raw.empty() )
108 aOut = wxString::From8BitData( raw.data(), raw.size() );
123 if( !
readFile( aFileName, contents, 4096 ) )
131 const std::map<std::string, UTF8>* aProperties,
PROJECT* aProject )
148 if( !
readFile( aFileName, contents ) )
155 if( !parser.
Parse( contents, data ) )
156 THROW_IO_ERRORF(
_(
"'%s' is not a valid Protel Autotrax file." ), aFileName );
198 reporter().
Report( wxString::Format(
_(
"Autotrax import: %d pad(s) with a target shape were skipped." ),
205 reporter().
Report( wxString::Format(
_(
"Autotrax import: %d pad(s) on unsupported layers were skipped." ),
212 reporter().
Report( wxString::Format(
_(
"Autotrax import: %d pad(s) ask for a ground or power plane "
213 "connection, which is not imported." ),
220 reporter().
Report( wxString::Format(
_(
"Autotrax import: %d item(s) on a layer with no KiCad equivalent "
230 if( aNetName.IsEmpty() )
233 auto it =
m_nets.find( aNetName );
242 m_nets[aNetName] = existing;
262 aFootprint->
Add( aItem );
293 if( aSegments <= 0 || aSegments >= 15 )
294 return { { 0.0, 360.0 } };
296 auto isSet = [&](
int aQuadrant )
298 return ( aSegments >> ( ( aQuadrant + 4 ) % 4 ) ) & 1;
301 std::vector<ARC_SPAN> spans;
303 for(
int quadrant = 0; quadrant < 4; ++quadrant )
305 if( !isSet( quadrant ) || isSet( quadrant - 1 ) )
310 while( isSet( quadrant + length ) )
313 spans.push_back( { 90.0 * quadrant, 90.0 * length } );
328 for(
double deg = span.startDeg; deg <= span.startDeg + span.deltaDeg; deg += 90.0 )
330 double rad = deg *
M_PI / 180.0;
384 int width = std::max( 1,
toIU( aArc.
width ) );
389 auto pointAt = [&](
double aDeg )
391 double rad = aDeg *
M_PI / 180.0;
401 if( span.deltaDeg >= 360.0 )
410 shape->
SetArcGeometry( pointAt( span.startDeg ), pointAt( span.startDeg + span.deltaDeg / 2.0 ),
411 pointAt( span.startDeg + span.deltaDeg ) );
421 int drill = std::max( 1,
toIU( aVia.
drill ) );
422 int diameter = std::max( drill + 2,
toIU( aVia.
diameter ) );
443 via->SetDrill( drill );
481 bool standalone =
false;
532 pad->SetLayerSet( smdMask );
555 int minX = std::min( p1.
x, p2.
x );
556 int maxX = std::max( p1.
x, p2.
x );
557 int minY = std::min( p1.
y, p2.
y );
558 int maxY = std::max( p1.
y, p2.
y );
604 int height = std::max( 1,
toIU( aText.
height ) );
638 if( !aComp.
refdes.IsEmpty() )
641 if( !aComp.
value.IsEmpty() )
644 if( !aComp.
name.IsEmpty() )
657 for(
const ARC& a : aComp.
arcs )
660 for(
const VIA& v : aComp.
vias )
679 for(
const NET_NODE& node : aNodes )
682 std::vector<::PAD*> pads;
683 std::set<FOOTPRINT*> owners;
686 for(
size_t dash = node.node.find(
'-' ); dash != wxString::npos; dash = node.node.find(
'-', dash + 1 ) )
688 wxString padName = node.node.Mid( dash + 1 );
690 if( padName.IsEmpty() )
695 for(
auto it = first; it != last; ++it )
697 for(
::PAD*
pad : it->second->Pads() )
699 if(
pad->GetNumber() == padName )
701 pads.push_back(
pad );
702 owners.insert( it->second );
708 if( owners.size() == 1 )
713 else if( owners.empty() )
715 reporter().
Report( wxString::Format(
_(
"Autotrax import: net '%s' node '%s' matches no pad." ),
716 node.netName, node.node ),
721 reporter().
Report( wxString::Format(
_(
"Autotrax import: net '%s' node '%s' matches pads in more than "
722 "one footprint and was not connected." ),
723 node.netName, node.node ),
744 double maxYmils = 0.0;
747 bool boardLayerUsed =
false;
748 bool freeKeepoutUsed =
false;
749 bool componentKeepoutUsed =
false;
753 auto noteLayer = [&](
int aLayer,
bool aFree )
769 auto noteOutline = [&](
int aLayer,
bool aFree,
const BOX2D& aBox )
771 noteLayer( aLayer, aFree );
774 keepoutBox.
Merge( aBox );
777 auto noteText = [&](
const TEXT& aText,
bool aFree )
779 noteLayer( aText.
layer, aFree );
780 maxYmils = std::max( maxYmils, aText.
y );
785 auto scan = [&](
const auto& aContainer,
bool aFree )
787 for(
const TRACK& t : aContainer.tracks )
790 maxYmils = std::max( { maxYmils, t.
y1, t.
y2 } );
793 for(
const ARC& a : aContainer.arcs )
799 for(
const VIA& v : aContainer.vias )
802 maxYmils = std::max( maxYmils, v.
y );
809 maxYmils = std::max( maxYmils, p.
y );
812 for(
const FILL& f : aContainer.fills )
815 maxYmils = std::max( { maxYmils, f.
y1, f.
y2 } );
818 for(
const TEXT& s : aContainer.texts )
819 noteText( s, aFree );
831 noteText( **label,
false );
835 m_board->SetCopperLayerCount( 2 + innerNeeded );
839 bool keepoutIsEdge = keepoutBox.
IsValid() && !boardLayerUsed
849 if( componentKeepoutUsed || ( freeKeepoutUsed && !keepoutIsEdge ) )
860 for(
const ARC& a : aData.
arcs )
863 for(
const VIA& v : aData.
vias )
Line-oriented parser for Protel Autotrax / Easytrax PCB files.
static bool Sniff(const wxString &aContents)
Cheap content sniff: the first non-blank, non-comment line is the magic header "PCB FILE 4" (Autotrax...
bool Parse(const wxString &aContents, AUTOTRAX::BOARD_DATA &aBoard)
Parse aContents into aBoard.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
FOOTPRINT * GetParentFootprint() const
Information pertinent to a Pcbnew printed circuit board.
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
constexpr bool Contains(const Vec &aPoint) const
constexpr bool IsValid() const
void SetCenter(const VECTOR2I &aCenter)
virtual void SetFilled(bool aFlag)
void SetMirrored(bool isMirrored)
virtual void SetVisible(bool aVisible)
void SetKeepUpright(bool aKeepUpright)
REPORTER * m_reporter
Reporter to log errors/warnings to, may be nullptr.
A logical library item identifier and consists of various portions much like a URI.
LSET is a set of PCB_LAYER_IDs.
LSET & FlipStandardLayers(int aCopperLayersCount=0)
Flip the layers in this set.
Handle the data for a net.
static REPORTER & GetInstance()
@ NORMAL
Shape is the same on all layers.
static constexpr PCB_LAYER_ID ALL_LAYERS
! The layer identifier to use for the single defintion on normal padstacks
static LSET PTHMask()
layer set for a through hole pad
static LSET SMDMask()
layer set for a SMD pad on Front layer
void buildComponent(const AUTOTRAX::COMPONENT &aComp)
NETINFO_ITEM * getNet(const wxString &aNetName)
bool CanReadBoard(const wxString &aFileName) const override
std::map< wxString, NETINFO_ITEM * > m_nets
int m_targetPads
pads with a crosshair or moire target shape
static int toIU(double aMils)
Convert a mil value to KiCad internal units (nm).
void buildBoard(const AUTOTRAX::BOARD_DATA &aData)
BOARD_ITEM * parentOf(FOOTPRINT *aFootprint) const
Parent for a primitive: the owning footprint, or the board for free items.
bool applyText(const AUTOTRAX::TEXT &aText, PCB_TEXT *aTarget)
Apply an Autotrax string record's placement, size, rotation and layer to aText.
void assignNets(const std::vector< AUTOTRAX::NET_NODE > &aNodes)
Attach each NETDEF "refdes-pad" node to the matching imported pads.
PCB_LAYER_ID m_keepoutLayer
Edge_Cuts when the keepout outlines the board.
bool mapLayer(int aLayer, const FOOTPRINT *aFootprint, PCB_LAYER_ID &aResult) const
Map an Autotrax layer number to a KiCad layer for an item owned by aFootprint, or a free item when it...
void addItem(BOARD_ITEM *aItem, FOOTPRINT *aFootprint)
Attach an item to its footprint, or append it to the board.
int m_maxY
board Y extent in IU, used to flip the Y axis
~PCB_IO_AUTOTRAX() override
std::multimap< wxString, FOOTPRINT * > m_footprintsByRef
footprints created by this load
VECTOR2I toBoard(double aX, double aY) const
Convert an Autotrax point (mils, Y-up) to a board point (nm, Y-down).
void emitTrack(const AUTOTRAX::TRACK &aTrack, FOOTPRINT *aFootprint)
void emitFill(const AUTOTRAX::FILL &aFill, FOOTPRINT *aFootprint)
int m_unmappedItems
items on a layer with no KiCad equivalent
void emitPad(const AUTOTRAX::PAD &aPad, FOOTPRINT *aFootprint)
int m_offLayerPads
pads on a layer KiCad cannot place them on
void emitArc(const AUTOTRAX::ARC &aArc, FOOTPRINT *aFootprint)
void loadBoard(const wxString &aFileName, BOARD &aBoard, bool aIsNewLoad, const std::map< std::string, UTF8 > *aProperties=nullptr, PROJECT *aProject=nullptr) override
Parse aFileName into aBoard.
void emitText(const AUTOTRAX::TEXT &aText, FOOTPRINT *aFootprint)
void reportGaps() const
Report what the import dropped or could not represent.
int m_planePads
pads asking for a ground or power plane connection
void emitVia(const AUTOTRAX::VIA &aVia, FOOTPRINT *aFootprint)
REPORTER & reporter() const
BOARD * m_board
The board BOARD being worked on, no ownership here.
virtual bool CanReadBoard(const wxString &aFileName) const
PCB_IO(const wxString &aName)
const std::map< std::string, UTF8 > * m_props
Properties passed via Save() or Load(), no ownership, may be NULL.
void SetWidth(int aWidth) override
void SetShape(SHAPE_T aShape) override
void SetEnd(const VECTOR2I &aEnd) override
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void SetStart(const VECTOR2I &aStart) override
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd) override
Set the three controlling points for an arc.
void SetTextThickness(int aWidth) override
The TextThickness is that set by the user.
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true) override
void SetPosition(const VECTOR2I &aPos) override
void SetTextAngle(const EDA_ANGLE &aAngle) override
void SetEnd(const VECTOR2I &aEnd)
void SetStart(const VECTOR2I &aStart)
virtual void SetWidth(int aWidth)
Container for project specific data.
A pure virtual class used to derive REPORTER objects from.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
Represent a set of closed polygons.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
Handle a list of polygons defining a copper zone.
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void SetAssignedPriority(unsigned aPriority)
void SetOutline(SHAPE_POLY_SET *aOutline)
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
#define THROW_IO_ERRORF(msg,...)
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
@ SMD
Smd pad, appears on the solder paste layer (default)
@ PTH
Plated through hole pad.
static std::vector< ARC_SPAN > arcSpansFromSegments(int aSegments)
Translate an Autotrax arc quadrant bitmask into the arc spans it represents.
static bool readFile(const wxString &aFileName, wxString &aOut, size_t aLimit=0)
Read a file into aOut.
static BOX2D arcBox(const ARC &aArc)
Bounding box of an arc's drawn quadrants, in mils.
static BOX2D spanBox(double aX1, double aY1, double aX2, double aY2)
Bounding box of two points, in mils.
One arc as a (start angle, counterclockwise sweep) pair in the file's native Y-up frame.
Free or component arc (FA / CA).
int segments
quadrant bitmask; 15 = full circle
Everything parsed out of an Autotrax/Easytrax file, before any KiCad object is created.
std::vector< COMPONENT > components
std::vector< NET_NODE > netNodes
std::vector< TRACK > tracks
std::vector< TEXT > texts
std::vector< FILL > fills
A placed component (COMP .. ENDCOMP) holding its own primitives.
std::optional< TEXT > valueText
comment placement, text unused
std::vector< TRACK > tracks
std::optional< TEXT > refdesText
designator placement, text unused
std::vector< FILL > fills
std::vector< TEXT > texts
Free or component rectangular fill (FF / CF), Autotrax's only pour.
One refdes -> net membership row collected from the NETDEF section.
Free or component pad/pin (FP / CP).
int shape
1 round, 2 rect, 3 octagon, 4 round-rect
Free or component string (FS / CS).
int direction
0..3, multiplied by 90 degrees counterclockwise
Free or component track segment (FT / CT). All coordinates are in mils.
Free or component via (FV / CV).
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D