KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_io_sprint_layout.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
22
23#include <board.h>
24#include <footprint.h>
25#include <pcb_group.h>
26#include <zone.h>
27#include <font/fontconfig.h>
28#include <gestfich.h>
29#include <reporter.h>
30
31#include <ranges>
32#include <wx/filename.h>
33#include <wx/wfstream.h>
34#include <wx/dir.h>
35
36
38 PCB_IO( wxS( "Sprint Layout" ) )
39{
40}
41
42
43void PCB_IO_SPRINT_LAYOUT::FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibraryPath,
44 bool aBestEfforts, const std::map<std::string, UTF8>* aProperties )
45{
46 wxFileName libFn( aLibraryPath );
47
48 if( libFn.FileExists() && libFn.GetExt().Upper() == wxS( "LMK" ) )
49 {
50 aFootprintNames.Add( libFn.GetName() );
51 return;
52 }
53
54 if( wxDir::Exists( aLibraryPath ) )
55 {
56 wxArrayString files;
57 CollectFilesLoopSafe( aLibraryPath, files, wxEmptyString, wxDIR_FILES | wxDIR_DIRS );
58
59 for( const wxString& filePath : files )
60 {
61 wxFileName file( filePath );
62
63 if( file.GetExt().Upper() != wxS( "LMK" ) )
64 continue;
65
66 file.MakeRelativeTo( aLibraryPath );
67 aFootprintNames.Add( file.GetFullPath().BeforeLast( '.' ) );
68 }
69 }
70}
71
72
73std::unique_ptr<FOOTPRINT> PCB_IO_SPRINT_LAYOUT::FootprintLoad( const wxString& aLibraryPath,
74 const wxString& aFootprintName, bool aKeepUUID,
75 const std::map<std::string, UTF8>* aProperties )
76{
77 wxFileName libFn( aLibraryPath );
78 wxFileName lmkPath;
79
80 if( libFn.FileExists() && libFn.GetExt().Upper() == wxS( "LMK" ) )
81 {
82 lmkPath = libFn;
83 }
84 else
85 {
86 if( !wxDir::Exists( aLibraryPath ) )
87 return nullptr;
88
89 lmkPath = wxFileName( aLibraryPath + wxFileName::GetPathSeparator() + aFootprintName + wxS( ".LMK" ) );
90
91 if( !lmkPath.FileExists() )
92 {
93 lmkPath.SetExt( "lmk" );
94
95 if( !lmkPath.FileExists() )
96 return nullptr;
97 }
98 }
99
101
102 if( !parser.ParseMacroFile( lmkPath.GetFullPath() ) )
103 return nullptr;
104
105 return parser.CreateFootprint();
106}
107
108
110{
111 for( std::unique_ptr<FOOTPRINT>& fp : m_loadedFootprints | std::views::values )
112 fp->SetParent( nullptr );
113}
114
115
116bool PCB_IO_SPRINT_LAYOUT::CanReadBoard( const wxString& aFileName ) const
117{
118 const wxFileName fn( aFileName );
119
120 if( !fn.FileExists() )
121 return false;
122
123 wxString ext = fn.GetExt().Lower();
124
125 if( ext != wxS( "lay6" ) && ext != wxS( "lay" ) )
126 return false;
127
128 // Check magic bytes: version (<=6), 0x33, 0xAA, 0xFF
129 wxFFileInputStream stream( aFileName );
130
131 if( !stream.IsOk() || stream.GetLength() < 8 )
132 return false;
133
134 uint8_t header[4];
135 stream.Read( header, 4 );
136
137 if( stream.LastRead() != 4 )
138 return false;
139
140 if( header[0] > 6 || header[1] != 0x33 || header[2] != 0xAA || header[3] != 0xFF )
141 return false;
142
143 return true;
144}
145
146
147void PCB_IO_SPRINT_LAYOUT::loadBoard( const wxString& aFileName, BOARD& aBoard, bool aIsNewLoad,
148 const std::map<std::string, UTF8>* aProperties, PROJECT* aProject )
149{
151
152 m_props = aProperties;
153 m_loadedFootprints.clear();
154
156
157 if( !parser.ParseBoard( aFileName ) )
158 THROW_IO_ERRORF( _( "Failed to parse Sprint Layout file '%s'" ), aFileName );
159
160 const auto& fileData = parser.GetFileData();
161 size_t boardIndex = 0;
162
163 if( m_props && m_props->contains( "pcb_id" ) )
164 {
165 unsigned long idx = std::stoul( m_props->at( "pcb_id" ) );
166 boardIndex = static_cast<size_t>( idx );
167 }
168 else if( fileData.boards.size() > 1 && m_choose_project_handler )
169 {
170 std::vector<IMPORT_PROJECT_DESC> options;
171
172 for( size_t i = 0; i < fileData.boards.size(); i++ )
173 {
175 wxString name = wxString::FromUTF8( fileData.boards[i].name );
176
177 if( name.empty() )
178 name = wxString::Format( wxS( "Board %zu" ), i + 1 );
179
180 desc.PCBName = name;
181 desc.PCBId = wxString::Format( wxS( "%zu" ), i );
182 options.push_back( desc );
183 }
184
185 std::vector<IMPORT_PROJECT_DESC> chosen = m_choose_project_handler( options );
186
187 if( chosen.empty() )
189
190 unsigned long idx = std::stoul( chosen[0].PCBId.ToStdString() );
191 boardIndex = static_cast<size_t>( idx );
192 }
193
194 if( aIsNewLoad )
195 {
196 if( !parser.CreateBoard( aBoard, m_loadedFootprints, boardIndex ) )
197 THROW_IO_ERRORF( _( "Failed to create board from Sprint Layout file '%s'" ), aFileName );
198 }
199 else
200 {
201 // Parse into a scratch board, then copy the design's items into the caller's
202 // board. The destination keeps its own setup when merging.
203 std::unique_ptr<BOARD> scratchBoard = std::make_unique<BOARD>();
204 std::map<EDA_ITEM*, EDA_ITEM*> ptrMap;
205
206 if( !parser.CreateBoard( *scratchBoard, m_loadedFootprints, boardIndex ) )
207 THROW_IO_ERRORF( _( "Failed to create board from Sprint Layout file '%s'" ), aFileName );
208
209 for( NETINFO_ITEM* netInfo : scratchBoard->GetNetInfo() )
210 {
211 NETINFO_ITEM* newNetInfo = static_cast<NETINFO_ITEM*>( netInfo->Clone() );
212 ptrMap[netInfo] = newNetInfo;
213 aBoard.Add( newNetInfo );
214 }
215
216 for( FOOTPRINT* fp : scratchBoard->Footprints() )
217 {
218 FOOTPRINT* newFP = static_cast<FOOTPRINT*>( fp->Clone() );
219 ptrMap[ fp ] = newFP;
220 aBoard.Add( newFP );
221 }
222
223 for( BOARD_ITEM* drawing : scratchBoard->Drawings() )
224 {
225 BOARD_ITEM* newDrawing = static_cast<BOARD_ITEM*>( drawing->Clone() );
226 ptrMap[drawing] = newDrawing;
227 aBoard.Add( newDrawing );
228 }
229
230 for( ZONE* zone : scratchBoard->Zones() )
231 {
232 ZONE* newZone = static_cast<ZONE*>( zone->Clone() );
233 ptrMap[zone] = newZone;
234 aBoard.Add( newZone );
235 }
236
237 for( PCB_GROUP* group : scratchBoard->Groups() )
238 {
239 PCB_GROUP* newGroup = static_cast<PCB_GROUP*>( group->Clone() );
240 ptrMap[group] = newGroup;
241 aBoard.Add( newGroup );
242 }
243
244 // Rebuild groups
245 for( PCB_GROUP* group : scratchBoard->Groups() )
246 {
247 PCB_GROUP* newGroup = static_cast<PCB_GROUP*>( ptrMap[ group ] );
248
249 newGroup->GetItems().clear();
250
251 for( EDA_ITEM* member : group->GetItems() )
252 {
253 if( ptrMap.count( member ) )
254 newGroup->AddItem( ptrMap[ member ] );
255 }
256 }
257
258 // Rebuild zone nets
259 for( ZONE* zone : scratchBoard->Zones() )
260 {
261 ZONE* newZone = static_cast<ZONE*>( ptrMap[zone] );
262
263 if( newZone && newZone->GetNet() )
264 newZone->SetNet( static_cast<NETINFO_ITEM*>( ptrMap[ newZone->GetNet() ] ) );
265 }
266 }
267}
268
269
271{
272 std::vector<FOOTPRINT*> result;
273
274 for( auto& [name, footprint] : m_loadedFootprints )
275 result.push_back( static_cast<FOOTPRINT*>( footprint->Clone() ) );
276
277 return result;
278}
const char * name
NETINFO_ITEM * GetNet() const
Return NETINFO_ITEM object for a given item.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:85
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:411
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition board.cpp:1520
std::unordered_set< EDA_ITEM * > & GetItems()
Definition eda_group.h:78
void AddItem(EDA_ITEM *aItem)
Add item to group.
Definition eda_group.cpp:58
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:153
RAII class to set and restore the fontconfig reporter.
Definition reporter.h:385
static LOAD_INFO_REPORTER & GetInstance()
Definition reporter.cpp:351
Handle the data for a net.
Definition netinfo.h:50
A set of BOARD_ITEMs (i.e., without duplicates).
Definition pcb_group.h:51
std::unique_ptr< FOOTPRINT > FootprintLoad(const wxString &aLibraryPath, const wxString &aFootprintName, bool aKeepUUID=false, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Load a footprint having aFootprintName from the aLibraryPath containing a library format that this PC...
std::vector< FOOTPRINT * > GetImportedCachedLibraryFootprints() override
Return a container with the cached library footprints generated in the last call to Load.
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.
bool CanReadBoard(const wxString &aFileName) const override
std::map< wxString, std::unique_ptr< FOOTPRINT > > m_loadedFootprints
void FootprintEnumerate(wxArrayString &aFootprintNames, const wxString &aLibraryPath, bool aBestEfforts, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Return a list of footprint names contained within the library at aLibraryPath.
PCB_IO(const wxString &aName)
Definition pcb_io.h:383
const std::map< std::string, UTF8 > * m_props
Properties passed via Save() or Load(), no ownership, may be NULL.
Definition pcb_io.h:407
CHOOSE_PROJECT_HANDLER m_choose_project_handler
Callback to choose projects to import.
Container for project specific data.
Definition project.h:63
std::unique_ptr< FOOTPRINT > CreateFootprint()
bool CreateBoard(BOARD &aBoard, std::map< wxString, std::unique_ptr< FOOTPRINT > > &aFootprintMap, size_t aBoardIndex=0)
const SPRINT_LAYOUT::FILE_DATA & GetFileData() const
bool ParseMacroFile(const wxString &aFileName)
bool ParseBoard(const wxString &aFileName)
Handle a list of polygons defining a copper zone.
Definition zone.h:70
void SetNet(NETINFO_ITEM *aNetInfo) override
Override that drops aNetInfo when this zone is in copper-thieving fill mode.
Definition zone.cpp:666
#define _(s)
void CollectFilesLoopSafe(const wxString &aRoot, wxArrayString &aFiles, const wxString &aFileSpec, int aFlags)
Recursively collect every file under aRoot, deduplicating subdirectories by their resolved path.
#define THROW_IO_ERRORF(msg,...)
#define THROW_IO_CANCELLED()
Class to handle a set of BOARD_ITEMs.
Describes how non-KiCad boards and schematics should be imported as KiCad projects.
wxString result
Test unit parsing edge cases and error handling.