KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pns_log_file.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.
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
20
21// WARNING - this Tom's crappy PNS hack tool code. Please don't complain about its quality
22// (unless you want to improve it).
23
24#include <wx/filename.h>
25#include <wx/ffile.h>
26#include <wx/stdstream.h>
27#include <wx/wfstream.h>
28
29#include "pns_log_file.h"
30#include "pns_arc.h"
31
32#include <router/pns_segment.h>
33#include <router/pns_hole.h>
34
36
39
40#include <project.h>
43
45
46std::vector<BOARD_CONNECTED_ITEM*> PNS_LOG_FILE::ItemsById( const PNS::LOGGER::EVENT_ENTRY& evt )
47{
48 std::vector<BOARD_CONNECTED_ITEM*> parents;
49
50 parents.resize( evt.uuids.size() );
51
52 for( BOARD_CONNECTED_ITEM* item : m_board->AllConnectedItems() )
53 {
54 for( int i = 0; i < evt.uuids.size(); i++ )
55 {
56 if( item->m_Uuid == evt.uuids[i] )
57 {
58 parents[i] = item;
59 break;
60 };
61 }
62 }
63
64 return parents;
65}
66
68{
69 auto parents = ItemsById( evt );
70 if ( parents.size() > 0 )
71 return parents[0];
72
73 return nullptr;
74}
75
76
77static const wxString readLine( FILE* f )
78{
79 char str[16384];
80 fgets( str, sizeof( str ) - 1, f );
81 return wxString( str );
82}
83
84
86 m_mode( PNS::ROUTER_MODE::PNS_MODE_ROUTE_SINGLE )
87{
88 m_routerSettings.reset( new PNS::ROUTING_SETTINGS( nullptr, "" ) );
89}
90
91
92std::shared_ptr<SHAPE> PNS_LOG_FILE::parseShape( const nlohmann::json& aJSON )
93{
94 const wxString type = static_cast<wxString>( aJSON.at( "type" ).get<wxString>() );
95
96 if( type == wxT("segment") )
97 {
98 std::shared_ptr<SHAPE_SEGMENT> sh( new SHAPE_SEGMENT );
99 sh->SetSeg( SEG( aJSON.at( "start" ).get<VECTOR2I>(), aJSON.at( "end" ).get<VECTOR2I>() ) );
100 sh->SetWidth( aJSON.at( "width" ).get<int>() );
101 return sh;
102 }
103 else if( type == wxT("circle") )
104 {
105 std::shared_ptr<SHAPE_CIRCLE> sh( new SHAPE_CIRCLE );
106 sh->SetCenter( aJSON.at( "center" ).get<VECTOR2I>() );
107 sh->SetRadius( aJSON.at( "radius" ).get<int>() );
108 return sh;
109 }
110 else if( type == wxT("arc") )
111 {
112 VECTOR2I start = aJSON.at( "start" ).get<VECTOR2I>();
113 VECTOR2I mid = aJSON.at( "mid" ).get<VECTOR2I>();
114 VECTOR2I end = aJSON.at( "end" ).get<VECTOR2I>();
115 int width = aJSON.at( "width" ).get<int>();
116
117 std::shared_ptr<SHAPE_ARC> sh( new SHAPE_ARC( start, mid, end, width ) );
118 return sh;
119 }
120 else if( type == wxT("line_chain") )
121 {
122 std::shared_ptr<SHAPE_LINE_CHAIN> sh( new SHAPE_LINE_CHAIN );
123 for( const nlohmann::json& p : aJSON.at( "points" ) )
124 sh->Append( p.get<VECTOR2I>(), true );
125
126 return sh;
127 }
128
129 return nullptr;
130}
131
132
133std::shared_ptr<SHAPE> PNS_LOG_FILE::parseLegacyShape( SHAPE_TYPE expectedType, wxStringTokenizer& aTokens )
134{
135 SHAPE_TYPE type = static_cast<SHAPE_TYPE> ( wxAtoi( aTokens.GetNextToken() ) );
136
137 if( type == SHAPE_TYPE::SH_SEGMENT )
138 {
139 std::shared_ptr<SHAPE_SEGMENT> sh( new SHAPE_SEGMENT );
140 VECTOR2I a, b;
141 a.x = wxAtoi( aTokens.GetNextToken() );
142 a.y = wxAtoi( aTokens.GetNextToken() );
143 b.x = wxAtoi( aTokens.GetNextToken() );
144 b.y = wxAtoi( aTokens.GetNextToken() );
145 int width = wxAtoi( aTokens.GetNextToken() );
146 sh->SetSeg( SEG( a, b ));
147 sh->SetWidth( width );
148 return sh;
149 }
150 else if( type == SHAPE_TYPE::SH_CIRCLE )
151 {
152 std::shared_ptr<SHAPE_CIRCLE> sh( new SHAPE_CIRCLE );
153 VECTOR2I a;
154 a.x = wxAtoi( aTokens.GetNextToken() );
155 a.y = wxAtoi( aTokens.GetNextToken() );
156 int radius = wxAtoi( aTokens.GetNextToken() );
157 sh->SetCenter( a );
158 sh->SetRadius( radius );
159 return sh;
160 }
161
162 return nullptr;
163}
164
165bool PNS_LOG_FILE::parseLegacyCommonPnsProps( PNS::ITEM* aItem, const wxString& cmd,
166 wxStringTokenizer& aTokens )
167{
168 if( cmd == wxS( "net" ) )
169 {
170 aItem->SetNet( m_board->FindNet( wxAtoi( aTokens.GetNextToken() ) ) );
171 return true;
172 }
173 else if( cmd == wxS( "layers" ) )
174 {
175 int start = wxAtoi( aTokens.GetNextToken() );
176 int end = wxAtoi( aTokens.GetNextToken() );
177 aItem->SetLayers( PNS_LAYER_RANGE( start, end ) );
178 return true;
179 }
180 return false;
181}
182
183
184bool PNS_LOG_FILE::parseCommonPnsProps( const nlohmann::json& aJSON, PNS::ITEM* aItem )
185{
186 aItem->SetNet( m_board->FindNet( aJSON.at( "net" ).get<wxString>() ) );
187 aItem->SetLayers(
188 PNS_LAYER_RANGE( aJSON.at( "layers" ).at( 0 ).get<int>(), aJSON.at( "layers" ).at( 1 ).get<int>() ) );
189
190 return true;
191}
192
193std::unique_ptr<PNS::SEGMENT> PNS_LOG_FILE::parseLegacyPnsSegmentFromString( wxStringTokenizer& aTokens )
194{
195 std::unique_ptr<PNS::SEGMENT> seg( new PNS::SEGMENT() );
196
197 while( aTokens.CountTokens() )
198 {
199 wxString cmd = aTokens.GetNextToken();
200
201 if( !parseLegacyCommonPnsProps( seg.get(), cmd, aTokens ) )
202 {
203 if( cmd == wxS( "shape" ) )
204 {
205 std::shared_ptr<SHAPE> sh = parseLegacyShape( SH_SEGMENT, aTokens );
206
207 if( !sh )
208 return nullptr;
209
210 seg->SetShape( *static_cast<SHAPE_SEGMENT*>( sh.get() ) );
211
212 }
213 }
214 }
215
216 return seg;
217}
218
219std::unique_ptr<PNS::VIA> PNS_LOG_FILE::parseLegacyPnsViaFromString( wxStringTokenizer& aTokens )
220{
221 std::unique_ptr<PNS::VIA> via( new PNS::VIA() );
222
223 while( aTokens.CountTokens() )
224 {
225 wxString cmd = aTokens.GetNextToken();
226
227 if( !parseLegacyCommonPnsProps( via.get(), cmd, aTokens ) )
228 {
229 if( cmd == wxS( "shape" ) )
230 {
231 std::shared_ptr<SHAPE> sh = parseLegacyShape( SH_CIRCLE, aTokens );
232
233 if( !sh )
234 return nullptr;
235
236 SHAPE_CIRCLE* sc = static_cast<SHAPE_CIRCLE*>( sh.get() );
237
238 via->SetPos( sc->GetCenter() );
239 via->SetDiameter( PNS::VIA::ALL_LAYERS, 2 * sc->GetRadius() );
240 }
241 else if( cmd == wxS( "drill" ) )
242 {
243 via->SetDrill( wxAtoi( aTokens.GetNextToken() ) );
244 }
245 }
246 }
247
248 return via;
249}
250
251std::unique_ptr<PNS::ITEM> PNS_LOG_FILE::parseItem( const nlohmann::json& aJSON )
252{
253 wxString kind = aJSON.at("kind").get<wxString>();
254
255 if( kind == wxT("segment") )
256 {
257 auto parsedShape = parseShape( aJSON.at("shape") );
258
259 if( !parsedShape )
260 return nullptr;
261
262 auto shape = static_cast<const SHAPE_SEGMENT*>( parsedShape.get() );
263 std::unique_ptr<PNS::SEGMENT> seg( new PNS::SEGMENT( *shape, nullptr ) );
264 parseCommonPnsProps( aJSON, seg.get() );
265 return std::move( seg );
266 }
267 else if ( kind == wxT( "arc" ) )
268 {
269 auto parsedShape = parseShape( aJSON.at("shape") );
270
271 if( !parsedShape )
272 return nullptr;
273
274 auto shape = static_cast<const SHAPE_ARC*>( parsedShape.get() );
275 std::unique_ptr<PNS::ARC> arc( new PNS::ARC( *shape, nullptr ) );
276 parseCommonPnsProps( aJSON, arc.get() );
277 return std::move( arc );
278 }
279 else if ( kind == wxT( "via" ) )
280 {
281 auto parsedShape = parseShape( aJSON.at("shape") );
282
283 if( !parsedShape )
284 return nullptr;
285
286 auto shape = static_cast<const SHAPE_CIRCLE*>( parsedShape.get() );
287 std::unique_ptr<PNS::VIA> via( new PNS::VIA() );
288 parseCommonPnsProps( aJSON, via.get() );
289 via->SetPos( shape->Centre() );
290 via->SetDiameter( via->Layers().Start(), shape->GetRadius() * 2 );
291 via->SetDrill( aJSON.at("drill").get<int>() );
292 return std::move(via);
293 }
294 else if ( kind == wxT( "hole" ) )
295 {
296 auto parsedShape = parseShape( aJSON.at("shape") );
297
298 if( !parsedShape )
299 return nullptr;
300
301 if( parsedShape->Type() == SH_CIRCLE )
302 {
303 auto shape = static_cast<const SHAPE_CIRCLE*>( parsedShape.get() );
304 std::unique_ptr<PNS::HOLE> hole( new PNS::HOLE( parsedShape->Clone() ) );
305 parseCommonPnsProps( aJSON, hole.get() );
306 hole->SetCenter( shape->GetCenter() );
307 hole->SetRadius( shape->GetRadius() );
308 return std::move( hole );
309 }
310 }
311 else if( kind == wxT("line") )
312 {
313 auto parsedShape = parseShape( aJSON.at("shape") );
314
315 if( !parsedShape )
316 return nullptr;
317
318 auto shape = static_cast<const SHAPE_LINE_CHAIN*>( parsedShape.get() );
319 std::unique_ptr<PNS::LINE> line( new PNS::LINE() );
320 line->SetShape( *shape );
321 line->SetWidth( aJSON.at("width").get<int>() );
322
323 parseCommonPnsProps( aJSON, line.get() );
324
325 return std::move( line );
326 }
327 return nullptr;
328}
329
330
331std::unique_ptr<PNS::ITEM> PNS_LOG_FILE::parseLegacyItemFromString( wxStringTokenizer& aTokens )
332{
333 wxString type = aTokens.GetNextToken();
334
335 if( type == wxS( "segment" ) )
336 return parseLegacyPnsSegmentFromString( aTokens );
337 else if( type == wxS( "via" ) )
338 return parseLegacyPnsViaFromString( aTokens );
339
340 return nullptr;
341}
342
343bool comparePnsItems( const PNS::ITEM* a , const PNS::ITEM* b )
344{
345 if( !a || !b )
346 return false;
347
348 if( a->Kind() != b->Kind() )
349 return false;
350
351 if( a->Kind() != PNS::ITEM::HOLE_T && a->Net() != b->Net() )
352 return false;
353
354 if( a->Layers() != b->Layers() )
355 return false;
356
357 if( a->Kind() == PNS::ITEM::VIA_T )
358 {
359 const PNS::VIA* va = static_cast<const PNS::VIA*>(a);
360 const PNS::VIA* vb = static_cast<const PNS::VIA*>(b);
361
362 // TODO(JE) padstacks
364 return false;
365
366 if( va->Drill() != vb->Drill() )
367 return false;
368
369 if( va->Pos() != vb->Pos() )
370 return false;
371
372 }
373 else if ( a->Kind() == PNS::ITEM::SEGMENT_T )
374 {
375 const PNS::SEGMENT* sa = static_cast<const PNS::SEGMENT*>(a);
376 const PNS::SEGMENT* sb = static_cast<const PNS::SEGMENT*>(b);
377
378 if( sa->Seg() != sb->Seg() )
379 return false;
380
381 if( sa->Width() != sb->Width() )
382 return false;
383 }
384 else if( a->Kind() == PNS::ITEM::HOLE_T )
385 {
386 const PNS::HOLE* ha = static_cast<const PNS::HOLE*>( a );
387 const PNS::HOLE* hb = static_cast<const PNS::HOLE*>( b );
388
389 if( ha->Radius() != hb->Radius() )
390 return false;
391
392 const SHAPE* sa = ha->Shape( -1 );
393 const SHAPE* sb = hb->Shape( -1 );
394
395 if( sa && sb && sa->Type() == SH_CIRCLE && sb->Type() == SH_CIRCLE )
396 {
397 const SHAPE_CIRCLE* ca = static_cast<const SHAPE_CIRCLE*>( sa );
398 const SHAPE_CIRCLE* cb = static_cast<const SHAPE_CIRCLE*>( sb );
399
400 if( ca->GetCenter() != cb->GetCenter() )
401 return false;
402 }
403 }
404
405 return true;
406}
407
408
409const std::set<PNS::ITEM*> deduplicate( const std::vector<PNS::ITEM*>& items )
410{
411 std::set<PNS::ITEM*> rv;
412
413 for( PNS::ITEM* item : items )
414 {
415 bool isDuplicate = false;
416
417 for( PNS::ITEM* ritem : rv )
418 {
419 if( comparePnsItems( ritem, item) )
420 {
421 isDuplicate = true;
422 break;
423 }
424 }
425
426 if( !isDuplicate )
427 rv.insert( item );
428 }
429
430 return rv;
431}
432
433
435{
436 COMMIT_STATE check( aOther );
437
438 for( const KIID& uuid : m_removedIds )
439 {
440 if( check.m_removedIds.find( uuid ) != check.m_removedIds.end() )
441 check.m_removedIds.erase( uuid );
442 else
443 return false; // removed twice? wtf
444 }
445
446 std::set<PNS::ITEM*> addedItems = deduplicate( m_addedItems );
447 std::set<PNS::ITEM*> chkAddedItems = deduplicate( check.m_addedItems );
448
449
450 for( PNS::ITEM* item : addedItems )
451 {
452 bool matched = false;
453
454 for( PNS::ITEM* chk : chkAddedItems )
455 {
456 if( comparePnsItems( item, chk ) )
457 {
458 chkAddedItems.erase( chk );
459 matched = true;
460 break;
461 }
462 }
463
464 if( !matched )
465 return false;
466 }
467
468 if( !aSkipHeads )
469 {
470 if( m_heads.size() != check.m_heads.size() )
471 return false;
472
473 for( int headIdx = 0; headIdx < m_heads.size(); headIdx ++)
474 {
475 const SHAPE_LINE_CHAIN& headRef = static_cast<const PNS::LINE*> ( m_heads[ headIdx ] )->CLine();
476 const SHAPE_LINE_CHAIN& headChk = static_cast<const PNS::LINE*> ( aOther.m_heads[ headIdx ] )->CLine();
477 if ( ! headRef.CompareGeometry( headChk ) )
478 return false;
479 }
480 }
481
482 if( chkAddedItems.empty() && check.m_removedIds.empty() )
483 return true;
484 else
485 return false; // Set breakpoint here to trap failing tests
486}
487
488
489bool PNS_LOG_FILE::SaveLog( const wxFileName& logFileName, REPORTER* aRpt )
490{
491 PNS::LOGGER::LOG_DATA logData;
492
493 logData.m_AddedItems = m_commitState.m_addedItems;
494 logData.m_RemovedItems = m_commitState.m_removedIds;
495 logData.m_Heads = m_commitState.m_heads;
496 logData.m_BoardHash = m_boardHash;
498 logData.m_Events = m_events;
499 logData.m_Mode = m_mode;
500
501 wxString logString = PNS::LOGGER::FormatLogFileAsJSON( logData );
502
503 wxFFileOutputStream fp( logFileName.GetFullPath(), wxT( "wt" ) );
504
505 if( !fp.IsOk() )
506 {
507 if( aRpt )
508 {
509 aRpt->Report( wxString::Format( wxT("Failed to write log file: %s"), logFileName.GetFullPath() ), RPT_SEVERITY_ERROR );
510 }
511 return false;
512 }
513
514 wxScopedCharBuffer utf8 = logString.ToUTF8();
515 fp.Write( utf8.data(), utf8.length() );
516 fp.Close();
517
518 return true;
519}
520
521
522bool PNS_LOG_FILE::Load( const wxFileName& logFileName, REPORTER* aRpt, const wxString boardFileName )
523{
524 wxFileName fname_log( logFileName );
525 fname_log.SetExt( wxT( "log" ) );
526
527 wxFileName fname_dump( logFileName );
528 fname_dump.SetExt( wxT( "dump" ) );
529
530 if( !boardFileName.IsEmpty() )
531 {
532 fname_dump = boardFileName;
533 }
534
535 if( !fname_dump.IsFileReadable() )
536 {
537 aRpt->Report( wxT( "Could not load board file" ), RPT_SEVERITY_ERROR );
538 return false;
539 }
540
541 wxFileName fname_project( logFileName );
542 fname_project.SetExt( wxT( "kicad_pro" ) );
543 fname_project.MakeAbsolute();
544
545 wxFileName fname_settings( logFileName );
546 fname_settings.SetExt( wxT( "settings" ) );
547
548 aRpt->Report( wxString::Format( wxT( "Loading router settings from '%s'" ),
549 fname_settings.GetFullPath() ) );
550
551 bool ok = m_routerSettings->LoadFromRawFile( fname_settings.GetFullPath() );
552
553 if( !ok )
554 {
555 aRpt->Report( wxT( "Failed to load routing settings. Using defaults." ),
557 }
558
559 aRpt->Report( wxString::Format( wxT( "Loading project settings from '%s'" ),
560 fname_settings.GetFullPath() ) );
561
562 m_settingsMgr.reset( new SETTINGS_MANAGER );
563 m_settingsMgr->LoadProject( fname_project.GetFullPath() );
564 PROJECT* project = m_settingsMgr->GetProject( fname_project.GetFullPath() );
565 project->SetReadOnly();
566
567 try
568 {
570 aRpt->Report( wxString::Format( wxT("Loading board snapshot from '%s'"),
571 fname_dump.GetFullPath() ) );
572
573 m_board = io.LoadBoard( fname_dump.GetFullPath() );
574 m_board->SetProject( project );
575
576 std::shared_ptr<DRC_ENGINE> drcEngine( new DRC_ENGINE );
577
578 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
579
580 bds.m_DRCEngine = drcEngine;
581 bds.m_UseConnectedTrackWidth = project->GetLocalSettings().m_AutoTrackWidth;
582
583 m_board->SynchronizeNetsAndNetClasses( true );
584
585 drcEngine->SetBoard( m_board.get() );
586 drcEngine->SetDesignSettings( &bds );
587 drcEngine->SetLogReporter( aRpt );
588
589 // Load the test case's custom DRC rules if it ships any.
590 wxFileName fname_rules( logFileName );
591 fname_rules.SetExt( FILEEXT::DesignRulesFileExtension );
592
593 if( fname_rules.FileExists() )
594 drcEngine->InitEngine( fname_rules );
595 else
596 drcEngine->InitEngine( wxFileName() );
597 }
598 catch( const PARSE_ERROR& parse_error )
599 {
600 aRpt->Report( wxString::Format( "parse error : %s (%s)\n",
601 parse_error.Problem(),
602 parse_error.What() ),
604
605 return false;
606 }
607
608
609 ok = loadJsonLog( logFileName.GetFullPath(), aRpt, false );
610 if( !ok && logFileName.FileExists() )
611 {
612 aRpt->Report("Falling back to legacy log format...\n", RPT_SEVERITY_WARNING);
613 ok = loadLegacyLog( logFileName.GetFullPath(), aRpt );
614 }
615
616 return ok;
617}
618
619
620bool PNS_LOG_FILE::loadJsonLog( const wxString& aFilename, REPORTER* aRpt, bool aHashOnly )
621{
622 wxFFileInputStream fp( aFilename, wxT( "rt" ) );
623 wxStdInputStream fstream( fp );
624
625
626 if ( aRpt )
627 {
628 aRpt->Report( wxString::Format( "Loading log from: %s", aFilename ) );
629 }
630
631 if( !fp.IsOk() )
632 {
633 if( aRpt )
634 aRpt->Report( wxT("Failed to load."), RPT_SEVERITY_ERROR );
635
636 return false;
637 }
638
639 try
640 {
641 nlohmann::json logJson = nlohmann::json::parse( fstream, nullptr,
642 /* allow_exceptions = */ true,
643 /* ignore_comments = */ true );
644
645 if( logJson.contains("board_hash") )
646 {
647 m_boardHash = logJson.at("board_hash").get<wxString>();
648 }
649
650 if( logJson.contains("test_case_type") )
651 {
652 m_testCaseType = static_cast<PNS::LOGGER::TEST_CASE_TYPE>( logJson.at("test_case_type").get<int>() );
653 }
654
655 if ( aHashOnly )
656 return true;
657
658 m_mode = static_cast<PNS::ROUTER_MODE>( logJson.at( "mode" ).get<int>() );
659
660 for( const nlohmann::json& event : logJson.at( "events" ) )
661 {
662 m_events.push_back( std::move( PNS::LOGGER::ParseEventFromJSON( event ) ) );
663 }
664
665 for( const nlohmann::json& addedItem : logJson.at( "addedItems" ) )
666 {
667 m_parsed_items.push_back( std::move( parseItem( addedItem ) ) );
668
669 if( m_parsed_items.back() )
670 m_commitState.m_addedItems.push_back( m_parsed_items.back().get() );
671 }
672
673 for( const nlohmann::json& addedItem : logJson.at( "removedItems" ) )
674 {
675 m_commitState.m_removedIds.insert( addedItem.get<KIID>() );
676 }
677
678
679 for( const nlohmann::json& headItem : logJson.at( "headItems" ) )
680 {
681 m_commitState.m_heads.push_back( parseItem( headItem ).release() );
682 }
683
684 if( aRpt )
685 {
686 aRpt->Report( wxString::Format( "JSON log load: %zu events, %zu added, %zu removed\n", m_events.size(),
687 m_commitState.m_addedItems.size(), m_commitState.m_removedIds.size() ),
689 }
690
691
692 }
693 catch( const std::exception& exc )
694 {
695 if( aRpt )
696 {
697 aRpt->Report( wxString::Format( "JSON log parse failure: %s\n", exc.what() ), RPT_SEVERITY_ERROR );
698 }
699 return false;
700 }
701
702 return true;
703}
704
705
706bool PNS_LOG_FILE::loadLegacyLog( const wxString& aFilename, REPORTER* aRpt )
707{
708 FILE* f = fopen( aFilename.c_str(), "rb" );
709
710 aRpt->Report( wxString::Format( "Loading log from '%s'", aFilename ) );
711
712 if( !f )
713 {
714 aRpt->Report( wxT( "Failed to load log file." ), RPT_SEVERITY_ERROR );
715 return false;
716 }
717
718 try
719 {
720 while( !feof( f ) )
721 {
722 wxString line = readLine( f );
723 wxStringTokenizer tokens( line );
724
725 if( !tokens.CountTokens() )
726 continue;
727
728 wxString cmd = tokens.GetNextToken();
729
730 if( cmd == wxT( "mode" ) )
731 {
732 m_mode = static_cast<PNS::ROUTER_MODE>( wxAtoi( tokens.GetNextToken() ) );
733 }
734 else if( cmd == wxT( "event" ) )
735 {
736 m_events.push_back( std::move( PNS::LOGGER::ParseEvent( line ) ) );
737 }
738 else if( cmd == wxT( "added" ) )
739 {
740 m_parsed_items.push_back( std::move( parseLegacyItemFromString( tokens ) ) );
741
742 if( m_parsed_items.back() )
743 m_commitState.m_addedItems.push_back( m_parsed_items.back().get() );
744 }
745 else if( cmd == wxT( "removed" ) )
746 {
747 m_commitState.m_removedIds.insert( KIID( tokens.GetNextToken() ) );
748 }
749 }
750 }
751 catch( ... )
752 {
753 return false;
754 }
755
756 fclose( f );
757 return true;
758}
759
760const std::optional<wxString> PNS_LOG_FILE::GetLogBoardHash( const wxString& logFileName )
761{
762 loadJsonLog( logFileName, nullptr, true );
763 return m_boardHash;
764}
765
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
Container for design settings for a BOARD object.
std::shared_ptr< DRC_ENGINE > m_DRCEngine
Design Rule Checker object that performs all the DRC tests.
Definition drc_engine.h:129
virtual const wxString What() const
A composite of Problem() and Where()
virtual const wxString Problem() const
what was the problem?
Definition kiid.h:46
A #PLUGIN derivation for saving and loading Pcbnew s-expression formatted files.
std::unique_ptr< BOARD > LoadBoard(const wxString &aFileName, const std::map< std::string, UTF8 > *aProperties=nullptr, PROJECT *aProject=nullptr)
Load information from some input file format that this PCB_IO implementation knows about into new BOA...
Definition pcb_io.cpp:72
int Radius() const
Definition pns_hole.cpp:103
const SHAPE * Shape(int aLayer) const override
Return the geometrical shape of the item.
Definition pns_hole.h:69
Base class for PNS router board items.
Definition pns_item.h:98
void SetLayers(const PNS_LAYER_RANGE &aLayers)
Definition pns_item.h:213
const PNS_LAYER_RANGE & Layers() const
Definition pns_item.h:212
virtual NET_HANDLE Net() const
Definition pns_item.h:210
PnsKind Kind() const
Return the type (kind) of the item.
Definition pns_item.h:173
void SetNet(NET_HANDLE aNet)
Definition pns_item.h:209
Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads,...
Definition pns_line.h:62
static wxString FormatLogFileAsJSON(const LOG_DATA &aLogData)
static EVENT_ENTRY ParseEventFromJSON(const nlohmann::json &aJSON)
static EVENT_ENTRY ParseEvent(const wxString &aLine)
Contain all persistent settings of the router, such as the mode, optimization effort,...
const SEG & Seg() const
int Width() const override
Definition pns_segment.h:96
int Diameter(int aLayer) const
Definition pns_via.h:227
const VECTOR2I & Pos() const
Definition pns_via.h:206
int Drill() const
Definition pns_via.h:247
static constexpr int ALL_LAYERS
Definition pns_via.h:78
Represent a contiguous set of PCB layers.
bool parseCommonPnsProps(const nlohmann::json &aJSON, PNS::ITEM *aItem)
BOARD_CONNECTED_ITEM * ItemById(const PNS::LOGGER::EVENT_ENTRY &evt)
std::unique_ptr< PNS::VIA > parseLegacyPnsViaFromString(wxStringTokenizer &aTokens)
const std::optional< wxString > GetLogBoardHash(const wxString &logFileName)
bool SaveLog(const wxFileName &logFileName, REPORTER *aRpt)
bool loadLegacyLog(const wxString &aFilename, REPORTER *aRpt)
PNS::ROUTER_MODE m_mode
std::shared_ptr< BOARD > m_board
bool parseLegacyCommonPnsProps(PNS::ITEM *aItem, const wxString &cmd, wxStringTokenizer &aTokens)
std::shared_ptr< SETTINGS_MANAGER > m_settingsMgr
std::shared_ptr< SHAPE > parseShape(const nlohmann::json &aJSON)
std::unique_ptr< PNS::ITEM > parseItem(const nlohmann::json &aJSON)
std::shared_ptr< SHAPE > parseLegacyShape(SHAPE_TYPE expectedType, wxStringTokenizer &aTokens)
std::vector< std::unique_ptr< PNS::ITEM > > m_parsed_items
std::optional< wxString > m_boardHash
COMMIT_STATE m_commitState
bool loadJsonLog(const wxString &aFilename, REPORTER *aRpt, bool aHashOnly=false)
std::vector< PNS::LOGGER::EVENT_ENTRY > m_events
std::vector< BOARD_CONNECTED_ITEM * > ItemsById(const PNS::LOGGER::EVENT_ENTRY &evt)
std::unique_ptr< PNS::SEGMENT > parseLegacyPnsSegmentFromString(wxStringTokenizer &aTokens)
std::optional< PNS::LOGGER::TEST_CASE_TYPE > m_testCaseType
std::unique_ptr< PNS::ROUTING_SETTINGS > m_routerSettings
bool Load(const wxFileName &logFileName, REPORTER *aRpt, const wxString boardFileName=wxT(""))
std::unique_ptr< PNS::ITEM > parseLegacyItemFromString(wxStringTokenizer &aTokens)
Container for project specific data.
Definition project.h:63
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:102
Definition seg.h:38
SHAPE_TYPE Type() const
Return the type of the shape.
Definition shape.h:96
int GetRadius() const
const VECTOR2I GetCenter() const
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
bool CompareGeometry(const SHAPE_LINE_CHAIN &aOther, bool aCyclicalCompare=false, int aEpsilon=0) const
Compare this line chain with another one.
An abstract shape on 2D plane.
Definition shape.h:124
static const std::string DesignRulesFileExtension
Push and Shove diff pair dimensions (gap) settings dialog.
ROUTER_MODE
Definition pns_router.h:67
bool comparePnsItems(const PNS::ITEM *a, const PNS::ITEM *b)
static const wxString readLine(FILE *f)
const std::set< PNS::ITEM * > deduplicate(const std::vector< PNS::ITEM * > &items)
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_INFO
SHAPE_TYPE
Lists all supported shapes.
Definition shape.h:42
@ SH_CIRCLE
circle
Definition shape.h:46
@ SH_SEGMENT
line segment
Definition shape.h:44
A filename or source description, a problem input line, a line number, a byte offset,...
Definition pns_logger.h:71
std::vector< KIID > uuids
Definition pns_logger.h:74
std::optional< wxString > m_BoardHash
Definition pns_logger.h:101
std::optional< TEST_CASE_TYPE > m_TestCaseType
Definition pns_logger.h:106
std::vector< ITEM * > m_AddedItems
Definition pns_logger.h:102
std::vector< EVENT_ENTRY > m_Events
Definition pns_logger.h:105
std::set< KIID > m_RemovedItems
Definition pns_logger.h:103
std::vector< ITEM * > m_Heads
Definition pns_logger.h:104
std::set< KIID > m_removedIds
bool Compare(const COMMIT_STATE &aOther, bool aSkipHeads=false)
std::vector< PNS::ITEM * > m_addedItems
std::vector< PNS::ITEM * > m_heads
int radius
VECTOR2I end
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
Definition of file extensions used in Kicad.