42#include <wx/filename.h>
43#include <wx/wfstream.h>
84 uint16_t v =
static_cast<uint16_t
>(
m_pos[0] )
85 | (
static_cast<uint16_t
>(
m_pos[1] ) << 8 );
96 uint32_t v =
static_cast<uint32_t
>(
m_pos[0] )
97 | (
static_cast<uint32_t
>(
m_pos[1] ) << 8 )
98 | (
static_cast<uint32_t
>(
m_pos[2] ) << 16 )
99 | (
static_cast<uint32_t
>(
m_pos[3] ) << 24 );
115 std::memcpy( &v, &bits,
sizeof( v ) );
125 uint64_t bits =
static_cast<uint64_t
>(
m_pos[0] )
126 | (
static_cast<uint64_t
>(
m_pos[1] ) << 8 )
127 | (
static_cast<uint64_t
>(
m_pos[2] ) << 16 )
128 | (
static_cast<uint64_t
>(
m_pos[3] ) << 24 )
129 | (
static_cast<uint64_t
>(
m_pos[4] ) << 32 )
130 | (
static_cast<uint64_t
>(
m_pos[5] ) << 40 )
131 | (
static_cast<uint64_t
>(
m_pos[6] ) << 48 )
132 | (
static_cast<uint64_t
>(
m_pos[7] ) << 56 );
136 std::memcpy( &v, &bits,
sizeof( v ) );
144 size_t len = std::min( rawLen, aMaxLen );
149 std::string s(
reinterpret_cast<const char*
>(
m_pos ), len );
165 std::string s(
reinterpret_cast<const char*
>(
m_pos ), len );
186 wxFFileInputStream stream( aFileName );
189 THROW_IO_ERROR( wxString::Format(
_(
"Cannot open file '%s'" ), aFileName ) );
191 size_t fileSize = stream.GetLength();
194 THROW_IO_ERROR( wxString::Format(
_(
"File '%s' is too small to be a Sprint Layout file" ), aFileName ) );
197 stream.Read(
m_buffer.data(), fileSize );
199 if( stream.LastRead() != fileSize )
200 THROW_IO_ERROR( wxString::Format(
_(
"Failed to read file '%s'" ), aFileName ) );
212 if(
m_fileData.version > 6 || magic1 != 0x33 || magic2 != 0xAA || magic3 != 0xFF )
217 if( numBoards == 0 || numBoards > 100 )
222 for( uint32_t b = 0; b < numBoards; b++ )
226 uint32_t numConnections = 0;
228 for(
auto& obj :
m_fileData.boards[b].objects )
235 for( uint32_t c = 0; c < numConnections; c++ )
240 skip( connCount *
sizeof( uint32_t ) );
262 for(
int i = 0; i < 7; i++ )
299 aBoard.
objects.resize( numObjects );
301 for( uint32_t i = 0; i < numObjects; i++ )
325 THROW_IO_ERROR( wxString::Format(
_(
"Unknown object type %d in Sprint Layout file" ),
364 aObj.
groups.resize( groupCount );
366 for( uint32_t i = 0; i < groupCount; i++ )
381 THROW_IO_ERROR(
_(
"Too many text children in Sprint Layout object" ) );
385 for( uint32_t i = 0; i < childCount; i++ )
414 aObj.
points.resize( pointCount );
416 for( uint32_t i = 0; i < pointCount; i++ )
440 switch( aSprintLayer )
449 default:
return F_Cu;
458 double nm =
static_cast<double>( aValue ) * 100.0;
460 if( nm > std::numeric_limits<int>::max() || nm < std::numeric_limits<int>::min() )
461 THROW_IO_ERROR(
_(
"Coordinate value out of range in Sprint Layout file" ) );
475 std::map<wxString, std::unique_ptr<FOOTPRINT>>& aFootprintMap,
size_t aBoardIndex )
480 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
484 bool hasInnerLayers =
false;
486 for(
const auto& obj : boardData.
objects )
490 hasInnerLayers =
true;
496 board->SetCopperLayerCount( 4 );
498 board->SetCopperLayerCount( 2 );
501 std::map<uint16_t, FOOTPRINT*> componentMap;
502 std::vector<std::vector<VECTOR2I>> outlineSegments;
505 for(
const auto& obj : boardData.
objects )
508 && obj.component.valid )
510 if( componentMap.find( obj.component_id ) == componentMap.end() )
514 fp->
SetValue( wxString::FromUTF8( obj.component.comment ) );
516 if( !obj.component.package.empty() )
521 double rotDeg = obj.component.rotation;
531 componentMap[obj.component_id] = fp;
534 wxString fpKey = wxString::Format( wxS(
"SprintLayout_%s" ),
535 wxString::FromUTF8( obj.text ) );
536 aFootprintMap[fpKey] = std::unique_ptr<FOOTPRINT>(
543 for(
const auto& obj : boardData.
objects )
549 addPadToBoard( board.get(), obj, componentMap, aFootprintMap );
573 buildOutline( board.get(), outlineSegments, boardData );
582 } groundPlaneMap[] = {
589 for(
const auto& gp : groundPlaneMap )
597 if( w <= 0 || h <= 0 )
600 ZONE* zone =
new ZONE( board.get() );
603 zone->
SetZoneName( wxString::Format( wxS(
"GND_PLANE_%s" ),
604 board->GetLayerName( gp.layer ) ) );
622 BOX2I bbox = board->ComputeBoundingBox(
true );
629 for(
FOOTPRINT* fp : board->Footprints() )
630 fp->Move( centerOffset );
632 for(
ZONE* zone : board->Zones() )
633 zone->Move( centerOffset );
636 item->Move( centerOffset );
639 return board.release();
645 std::map<uint16_t, FOOTPRINT*>& aComponentMap,
646 std::map<wxString, std::unique_ptr<FOOTPRINT>>& aFootprintMap )
655 if( it != aComponentMap.end() )
674 static_cast<int>( aBoard->
Footprints().size() ) ) );
689 double cx = 0, cy = 0;
691 for(
const auto& pt : aObj.
points )
697 cx /=
static_cast<double>( aObj.
points.size() );
698 cy /=
static_cast<double>( aObj.
points.size() );
699 pos =
sprintToKicadPos(
static_cast<float>( cx ),
static_cast<float>( cy ) );
706 pad->SetPosition( pos );
708 if( fp->
Pads().empty() )
724 pad->SetDrillSize(
VECTOR2I( drillDia, drillDia ) );
755 else if( thStyle == 2 )
793 pad->Padstack().FrontOuterLayers().has_solder_mask =
false;
794 pad->Padstack().BackOuterLayers().has_solder_mask =
false;
801 pad->SetLocalClearance( std::optional<int>(
clearance ) );
808 pad->SetLocalThermalSpokeWidthOverride( std::optional<int>( spokeWidth ) );
814 wxString netName = wxString::FromUTF8( aObj.
net_name );
826 pad->SetNumber( wxString::Format( wxS(
"%d" ),
827 static_cast<int>( fp->
Pads().size() + 1 ) ) );
835 std::vector<std::vector<VECTOR2I>>& aOutlineSegments )
837 if( aObj.
points.size() < 2 )
844 std::vector<VECTOR2I> segment;
846 for(
const auto& pt : aObj.
points )
849 aOutlineSegments.push_back( std::move( segment ) );
858 for(
size_t i = 0; i + 1 < aObj.
points.size(); i++ )
866 aBoard->
Add( shape );
873 std::vector<std::vector<VECTOR2I>>& aOutlineSegments )
875 if( aObj.
points.size() < 2 )
882 std::vector<VECTOR2I> segment;
884 for(
const auto& pt : aObj.
points )
887 aOutlineSegments.push_back( std::move( segment ) );
891 bool isFilled = ( aObj.
filled != 0 );
892 bool isCutout = ( aObj.
keepout != 0 );
909 for(
const auto& pt : aObj.
points )
929 for(
const auto& pt : aObj.
points )
939 wxString netName = wxString::FromUTF8( aObj.
net_name );
953 else if( isFilled && aObj.
points.size() >= 3 )
965 for(
const auto& pt : aObj.
points )
972 aBoard->
Add( shape );
982 for(
size_t i = 0; i + 1 < aObj.
points.size(); i++ )
990 aBoard->
Add( shape );
998 std::vector<std::vector<VECTOR2I>>& aOutlineSegments )
1013 int32_t endAngle =
static_cast<int32_t
>( aObj.
line_width );
1015 bool isFullCircle = ( startAngle == 0 && endAngle == 0 )
1016 || ( endAngle - startAngle >= 360000 )
1017 || ( startAngle == endAngle );
1022 std::vector<VECTOR2I> segment;
1026 for(
int i = 0; i <= 24; i++ )
1028 double angle = (
static_cast<double>( i ) / 24.0 ) * 2.0 *
M_PI;
1029 int px =
center.x +
static_cast<int>( std::cos( angle ) * kiRadius );
1030 int py =
center.y -
static_cast<int>( std::sin( angle ) * kiRadius );
1031 segment.emplace_back( px, py );
1036 int32_t sa = startAngle;
1037 int32_t ea = endAngle;
1042 for( int32_t a = sa; a <= ea; a += 15000 )
1044 double rad = (
static_cast<double>( a ) / 1000.0 ) *
M_PI / 180.0;
1045 int px =
center.x +
static_cast<int>( std::cos( rad ) * kiRadius );
1046 int py =
center.y -
static_cast<int>( std::sin( rad ) * kiRadius );
1047 segment.emplace_back( px, py );
1050 double endRad = (
static_cast<double>( ea ) / 1000.0 ) *
M_PI / 180.0;
1051 int epx =
center.x +
static_cast<int>( std::cos( endRad ) * kiRadius );
1052 int epy =
center.y -
static_cast<int>( std::sin( endRad ) * kiRadius );
1053 segment.emplace_back( epx, epy );
1056 aOutlineSegments.push_back( std::move( segment ) );
1076 double startRad = (
static_cast<double>( startAngle ) / 1000.0 ) *
M_PI / 180.0;
1077 int sx =
center.x +
static_cast<int>( std::cos( startRad ) * kiRadius );
1078 int sy =
center.y -
static_cast<int>( std::sin( startRad ) * kiRadius );
1081 int32_t ea = endAngle;
1083 if( ea <= startAngle )
1087 double arcAngle = -
static_cast<double>( ea - startAngle ) / 1000.0;
1091 aBoard->
Add( shape );
1098 if( aObj.
text.empty() )
1111 text->SetLayer( layer );
1112 text->SetText( wxString::FromUTF8( aObj.
text ) );
1115 text->SetPosition( pos );
1126 if( thickness <= 0 )
1127 thickness = std::max( 1, height / 8 );
1129 text->SetTextThickness( thickness );
1133 double angleDeg =
static_cast<double>( aObj.
rotation ) / 1000.0;
1138 text->SetMirrored(
true );
1145 BOARD* aBoard, std::vector<std::vector<VECTOR2I>>& aOutlineSegments,
1150 static const int PROXIMITY_DELTA = 100;
1159 for(
size_t iterations = 0; iterations < aOutlineSegments.size(); iterations++ )
1161 bool joined =
false;
1163 for(
auto& seg : aOutlineSegments )
1165 if( seg.size() < 2 )
1168 for(
auto& other : aOutlineSegments )
1170 if( &seg == &other || other.empty() )
1173 bool frontMatch = closeEnough( seg.back(), other.front(), PROXIMITY_DELTA );
1174 bool backMatch = !frontMatch
1175 && closeEnough( seg.back(), other.back(), PROXIMITY_DELTA );
1179 std::reverse( other.begin(), other.end() );
1186 if( seg.back() == other.front() )
1187 seg.insert( seg.end(), other.begin() + 1, other.end() );
1189 seg.insert( seg.end(), other.begin(), other.end() );
1201 bool hasOutline =
false;
1203 for(
const auto& seg : aOutlineSegments )
1205 if( seg.size() < 2 )
1210 for(
size_t i = 0; i + 1 < seg.size(); i++ )
1217 shape->
SetEnd( seg[i + 1] );
1218 aBoard->
Add( shape );
1228 if( w > 0 && h > 0 )
1237 for(
int i = 0; i < 4; i++ )
1244 shape->
SetEnd( corners[( i + 1 ) % 4] );
1245 aBoard->
Add( shape );
constexpr EDA_IU_SCALE pcbIUScale
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the item.
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.
Information pertinent to a Pcbnew printed circuit board.
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
const FOOTPRINTS & Footprints() const
constexpr size_type GetWidth() const
constexpr const Vec GetCenter() const
constexpr size_type GetHeight() const
void SetCenter(const VECTOR2I &aCenter)
void SetPolyShape(const SHAPE_POLY_SET &aShape)
virtual void SetFilled(bool aFlag)
void SetStart(const VECTOR2I &aStart)
void SetShape(SHAPE_T aShape)
void SetEnd(const VECTOR2I &aEnd)
void SetArcAngleAndEnd(const EDA_ANGLE &aAngle, bool aCheckNegativeAngle=false)
Set the end point from the angle center and start.
void SetWidth(int aWidth)
LSET is a set of PCB_LAYER_IDs.
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Handle the data for a net.
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
static LSET PTHMask()
layer set for a through hole pad
static LSET SMDMask()
layer set for a SMD pad on Front layer
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Represent a set of closed polygons.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
int NewOutline()
Creates a new empty polygon in the set and returns its index.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
void addLineToBoard(BOARD *aBoard, const SPRINT_LAYOUT::OBJECT &aObj, std::vector< std::vector< VECTOR2I > > &aOutlineSegments)
SPRINT_LAYOUT::FILE_DATA m_fileData
PCB_LAYER_ID mapLayer(uint8_t aSprintLayer) const
void addPolyToBoard(BOARD *aBoard, const SPRINT_LAYOUT::OBJECT &aObj, std::vector< std::vector< VECTOR2I > > &aOutlineSegments)
std::string readFixedString(size_t aMaxLen)
bool Parse(const wxString &aFileName)
void buildOutline(BOARD *aBoard, std::vector< std::vector< VECTOR2I > > &aOutlineSegments, const SPRINT_LAYOUT::BOARD_DATA &aBoardData)
void addTextToBoard(BOARD *aBoard, const SPRINT_LAYOUT::OBJECT &aObj)
void parseObject(SPRINT_LAYOUT::OBJECT &aObject, bool aIsTextChild=false)
void addPadToBoard(BOARD *aBoard, const SPRINT_LAYOUT::OBJECT &aObj, std::map< uint16_t, FOOTPRINT * > &aComponentMap, std::map< wxString, std::unique_ptr< FOOTPRINT > > &aFootprintMap)
BOARD * CreateBoard(std::map< wxString, std::unique_ptr< FOOTPRINT > > &aFootprintMap, size_t aBoardIndex=0)
void parseBoardHeader(SPRINT_LAYOUT::BOARD_DATA &aBoard)
void addCircleToBoard(BOARD *aBoard, const SPRINT_LAYOUT::OBJECT &aObj, std::vector< std::vector< VECTOR2I > > &aOutlineSegments)
VECTOR2I sprintToKicadPos(float aX, float aY) const
int sprintToKicadCoord(float aValue) const
std::vector< uint8_t > m_buffer
std::string readVarString()
Handle a list of polygons defining a copper zone.
void SetDoNotAllowPads(bool aEnable)
void SetLocalClearance(std::optional< int > aClearance)
void AddPolygon(std::vector< VECTOR2I > &aPolygon)
Add a polygon to the zone outline.
void SetThermalReliefSpokeWidth(int aThermalReliefSpokeWidth)
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void SetIsRuleArea(bool aEnable)
void SetDoNotAllowTracks(bool aEnable)
void SetDoNotAllowVias(bool aEnable)
void SetThermalReliefGap(int aThermalReliefGap)
void SetDoNotAllowFootprints(bool aEnable)
void SetDoNotAllowZoneFills(bool aEnable)
void SetAssignedPriority(unsigned aPriority)
void SetZoneName(const wxString &aName)
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
PCB_LAYER_ID
A quick note on layer IDs:
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
@ SMD
Smd pad, appears on the solder paste layer (default)
@ PTH
Plated through hole pad.
static constexpr uint32_t MAX_CHILDREN
static constexpr uint32_t MAX_GROUPS
static constexpr uint32_t MAX_OBJECTS
static constexpr uint32_t MAX_POINTS
std::vector< OBJECT > objects
std::vector< POINT > points
std::vector< OBJECT > text_children
std::vector< uint32_t > groups
VECTOR2< int32_t > VECTOR2I
@ THERMAL
Use thermal relief for pads.
@ NONE
Pads are not covered.
@ FULL
pads are covered by copper