20#include <boost/test/unit_test.hpp>
40constexpr const char* PCB_HEADER = R
"(
44 (generator_version "9.99")
52constexpr int MM = 1000000;
55std::unique_ptr<BOARD> loadFromString(
const std::string& aPcbText,
56 const std::string& aSubdir )
58 namespace fs = std::filesystem;
59 fs::path tmpDir = fs::temp_directory_path() / aSubdir;
60 fs::create_directories( tmpDir );
61 fs::path pcbPath = tmpDir /
"topo.kicad_pcb";
64 std::ofstream out( pcbPath );
69 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
70 plugin.
LoadBoard( pcbPath.string(), board.get() );
71 board->BuildConnectivity();
73 fs::remove( pcbPath );
78std::set<BOARD_CONNECTED_ITEM*> chainItems(
BOARD* aBoard,
const wxString& aChain )
80 std::set<BOARD_CONNECTED_ITEM*> items;
84 if( t->GetNet() && t->GetNet()->GetNetChain() == aChain )
90 for(
PAD* p : fp->Pads() )
92 if( p->GetNet() && p->GetNet()->GetNetChain() == aChain )
104void tagChain(
BOARD* aBoard,
const wxString& aChain,
const wxString& aFirstFpRef,
105 const wxString& aLastFpRef )
109 if( n && n->GetNetname().StartsWith( wxS(
"/NET_" ) ) )
110 n->SetNetChain( aChain );
113 PAD* termA =
nullptr;
114 PAD* termB =
nullptr;
118 if( fp->GetReference() == aFirstFpRef && !fp->Pads().empty() )
119 termA = fp->Pads().front();
121 if( fp->GetReference() == aLastFpRef && !fp->Pads().empty() )
122 termB = fp->Pads().back();
128 if( n && n->GetNetChain() == aChain )
129 n->SetTerminalPad( 0, termA );
135 if( n && n->GetNetChain() == aChain )
136 n->SetTerminalPad( 1, termB );
143std::string passive(
const wxString& aRef,
double aXmm,
double aYmm,
145 int aNetA,
const wxString& aNetAName,
146 int aNetB,
const wxString& aNetBName )
148 return wxString::Format(
150 (footprint "Passive" (layer "F.Cu") (uuid "00000000-0000-0000-0000-000000%06d")
152 (property "Reference" "%s" (at 0 -1) (layer "F.Cu") (hide yes) (uuid "00000000-0000-0000-0000-000000%06da") (effects (font (size 1 1) (thickness 0.15))))
153 (pad "1" smd rect (at %f 0) (size 0.8 0.8) (layers "F.Cu") (net %d "%s") (uuid "00000000-0000-0000-0000-000000%06d1"))
154 (pad "2" smd rect (at %f 0) (size 0.8 0.8) (layers "F.Cu") (net %d "%s") (uuid "00000000-0000-0000-0000-000000%06d2"))
156)", static_cast<int>( aXmm ), aXmm, aYmm, aRef,
static_cast<int>( aXmm ),
157 -aPadSpanMm / 2, aNetA, aNetAName,
static_cast<int>( aXmm ),
158 aPadSpanMm / 2, aNetB, aNetBName,
static_cast<int>( aXmm ) ).ToStdString();
162std::string segment(
double aX1mm,
double aY1mm,
double aX2mm,
double aY2mm,
int aNet )
164 return wxString::Format(
165 " (segment (start %f %f) (end %f %f) (width 0.2) (layer \"F.Cu\") (net %d))\n",
166 aX1mm, aY1mm, aX2mm, aY2mm, aNet ).ToStdString();
180 std::string pcb = std::string( PCB_HEADER ) +
186 (gr_line (start -5 -5) (end 110 -5) (layer "Edge.Cuts") (width 0.05))
187 (gr_line (start 110 -5) (end 110 5) (layer "Edge.Cuts") (width 0.05))
188 (gr_line (start 110 5) (end -5 5) (layer "Edge.Cuts") (width 0.05))
189 (gr_line (start -5 5) (end -5 -5) (layer "Edge.Cuts") (width 0.05))
191 passive( wxS( "FP_START" ), 0.0, 0.0, 0.0,
192 1, wxS(
"/NET_A" ), 1, wxS(
"/NET_A" ) ) +
193 passive( wxS(
"R1" ), 32.5, 0.0, 5.0,
194 1, wxS(
"/NET_A" ), 2, wxS(
"/NET_B" ) ) +
195 passive( wxS(
"R2" ), 67.5, 0.0, 5.0,
196 2, wxS(
"/NET_B" ), 3, wxS(
"/NET_C" ) ) +
197 passive( wxS(
"FP_END" ), 100.0, 0.0, 0.0,
198 3, wxS(
"/NET_C" ), 3, wxS(
"/NET_C" ) ) +
199 segment( 0.0, 0.0, 30.0, 0.0, 1 ) +
200 segment( 35.0, 0.0, 65.0, 0.0, 2 ) +
201 segment( 70.0, 0.0, 100.0, 0.0, 3 ) +
204 auto board = loadFromString( pcb,
"kicad_drc_topo_simple_trunk" );
205 tagChain( board.get(), wxS(
"SIG" ), wxS(
"FP_START" ), wxS(
"FP_END" ) );
207 auto items = chainItems( board.get(), wxS(
"SIG" ) );
214 BOOST_CHECK( topo.
Stubs().empty() );
221 std::string pcb = std::string( PCB_HEADER ) +
225 (gr_line (start -5 -10) (end 60 -10) (layer "Edge.Cuts") (width 0.05))
226 (gr_line (start 60 -10) (end 60 15) (layer "Edge.Cuts") (width 0.05))
227 (gr_line (start 60 15) (end -5 15) (layer "Edge.Cuts") (width 0.05))
228 (gr_line (start -5 15) (end -5 -10) (layer "Edge.Cuts") (width 0.05))
230 passive( wxS( "FP_START" ), 0.0, 0.0, 0.0,
231 1, wxS(
"/NET_A" ), 1, wxS(
"/NET_A" ) ) +
232 passive( wxS(
"FP_END" ), 50.0, 0.0, 0.0,
233 1, wxS(
"/NET_A" ), 1, wxS(
"/NET_A" ) ) +
235 segment( 0.0, 0.0, 50.0, 0.0, 1 ) +
236 segment( 25.0, 0.0, 25.0, 5.0, 1 ) +
239 auto board = loadFromString( pcb,
"kicad_drc_topo_t_stub" );
240 tagChain( board.get(), wxS(
"TSIG" ), wxS(
"FP_START" ), wxS(
"FP_END" ) );
242 auto items = chainItems( board.get(), wxS(
"TSIG" ) );
246 BOOST_REQUIRE_EQUAL( topo.
Stubs().size(), 1u );
251 BOOST_CHECK_CLOSE( stub.
length, 5.0 *
MM, 5.0 );
261 std::string pcb = std::string( PCB_HEADER ) +
265 (gr_line (start -5 -5) (end 40 -5) (layer "Edge.Cuts") (width 0.05))
266 (gr_line (start 40 -5) (end 40 5) (layer "Edge.Cuts") (width 0.05))
267 (gr_line (start 40 5) (end -5 5) (layer "Edge.Cuts") (width 0.05))
268 (gr_line (start -5 5) (end -5 -5) (layer "Edge.Cuts") (width 0.05))
270 passive( wxS( "FP_START" ), 0.0, 0.0, 0.0,
271 1, wxS(
"/NET_A" ), 1, wxS(
"/NET_A" ) ) +
272 segment( 0.0, 0.0, 30.0, 0.0, 1 ) +
275 auto board = loadFromString( pcb,
"kicad_drc_topo_missing_term" );
279 if( n && n->GetNetname().StartsWith( wxS(
"/NET_" ) ) )
280 n->SetNetChain( wxS(
"MISSING" ) );
283 PAD* termA = board->Footprints().empty()
285 : board->Footprints().front()->Pads().empty()
287 : board->Footprints().front()->Pads().front();
292 if( n && n->GetNetChain() == wxS(
"MISSING" ) )
293 n->SetTerminalPad( 0, termA );
296 auto items = chainItems( board.get(), wxS(
"MISSING" ) );
307 std::string pcb = std::string( PCB_HEADER ) +
311 (gr_line (start -5 -5) (end 110 -5) (layer "Edge.Cuts") (width 0.05))
312 (gr_line (start 110 -5) (end 110 5) (layer "Edge.Cuts") (width 0.05))
313 (gr_line (start 110 5) (end -5 5) (layer "Edge.Cuts") (width 0.05))
314 (gr_line (start -5 5) (end -5 -5) (layer "Edge.Cuts") (width 0.05))
316 passive( wxS( "FP_START" ), 0.0, 0.0, 0.0,
317 1, wxS(
"/NET_A" ), 1, wxS(
"/NET_A" ) ) +
318 passive( wxS(
"FP_END" ), 100.0, 0.0, 0.0,
319 1, wxS(
"/NET_A" ), 1, wxS(
"/NET_A" ) ) +
322 auto board = loadFromString( pcb,
"kicad_drc_topo_disconnected" );
323 tagChain( board.get(), wxS(
"DISC" ), wxS(
"FP_START" ), wxS(
"FP_END" ) );
325 auto items = chainItems( board.get(), wxS(
"DISC" ) );
336 std::string pcb = std::string( PCB_HEADER ) +
340 (gr_line (start -5 -10) (end 60 -10) (layer "Edge.Cuts") (width 0.05))
341 (gr_line (start 60 -10) (end 60 10) (layer "Edge.Cuts") (width 0.05))
342 (gr_line (start 60 10) (end -5 10) (layer "Edge.Cuts") (width 0.05))
343 (gr_line (start -5 10) (end -5 -10) (layer "Edge.Cuts") (width 0.05))
345 passive( wxS( "FP_START" ), 0.0, 0.0, 0.0,
346 1, wxS(
"/NET_A" ), 1, wxS(
"/NET_A" ) ) +
347 passive( wxS(
"FP_END" ), 50.0, 0.0, 0.0,
348 1, wxS(
"/NET_A" ), 1, wxS(
"/NET_A" ) ) +
350 segment( 0.0, 0.0, 25.0, 5.0, 1 ) +
351 segment( 25.0, 5.0, 50.0, 0.0, 1 ) +
352 segment( 0.0, 0.0, 25.0, -5.0, 1 ) +
353 segment( 25.0, -5.0, 50.0, 0.0, 1 ) +
356 auto board = loadFromString( pcb,
"kicad_drc_topo_cycle" );
357 tagChain( board.get(), wxS(
"LOOP" ), wxS(
"FP_START" ), wxS(
"FP_END" ) );
359 auto items = chainItems( board.get(), wxS(
"LOOP" ) );
Information pertinent to a Pcbnew printed circuit board.
const NETINFO_LIST & GetNetInfo() const
const FOOTPRINTS & Footprints() const
const TRACKS & Tracks() const
Build a topological view of a single named net chain's routed copper.
const std::vector< STUB > & Stubs() const
double TrunkLength() const
Handle the data for a net.
A #PLUGIN derivation for saving and loading Pcbnew s-expression formatted files.
BOARD * LoadBoard(const wxString &aFileName, BOARD *aAppendToMe, const std::map< std::string, UTF8 > *aProperties=nullptr, PROJECT *aProject=nullptr) override
Load information from some input file format that this PCB_IO implementation knows about into either ...
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_CASE(TopologyTreeOnSimpleTrunk)
BOOST_AUTO_TEST_SUITE_END()
static const long long MM
BOOST_CHECK_EQUAL(result, "25.4")