diff --git a/eeschema/netlist_exporters/netlist_exporter_cadstar.cpp b/eeschema/netlist_exporters/netlist_exporter_cadstar.cpp index 12520e98a1..0aeeda79d6 100644 --- a/eeschema/netlist_exporters/netlist_exporter_cadstar.cpp +++ b/eeschema/netlist_exporters/netlist_exporter_cadstar.cpp @@ -67,7 +67,23 @@ bool NETLIST_EXPORTER_CADSTAR::WriteNetlist( const wxString& aOutFileName, for( const SCH_SHEET_PATH& sheet : m_schematic->Hierarchy() ) { - for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) ) + // The rtree returns items in a non-deterministic order (platform-dependent) + // Therefore we need to sort them before outputting to ensure file stability for version + // control and QA comparisons + std::vector<EDA_ITEM*> sheetItems; + + for( EDA_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) ) + sheetItems.push_back( item ); + + auto pred = []( const EDA_ITEM* item1, const EDA_ITEM* item2 ) + { + return item1->m_Uuid < item2->m_Uuid; + }; + + std::sort( sheetItems.begin(), sheetItems.end(), pred ); + + // Process symbol attributes + for( EDA_ITEM* item : sheetItems ) { symbol = findNextSymbol( item, sheet ); @@ -115,13 +131,16 @@ bool NETLIST_EXPORTER_CADSTAR::writeListOfNets( FILE* f ) wxString InitNetDesc = StartLine + wxT( "ADD_TER" ); wxString StartNetDesc = StartLine + wxT( "TER" ); wxString InitNetDescLine; - wxString netName; + + std::vector<std::pair<wxString, std::vector<std::pair<SCH_PIN*, SCH_SHEET_PATH>>>> all_nets; for( const auto& [ key, subgraphs ] : m_schematic->ConnectionGraph()->GetNetMap() ) { + wxString netName; netName.Printf( wxT( "\"%s\"" ), key.Name ); - std::vector<std::pair<SCH_PIN*, SCH_SHEET_PATH>> sorted_items; + all_nets.emplace_back( netName, std::vector<std::pair<SCH_PIN*, SCH_SHEET_PATH>>{} ); + std::vector<std::pair<SCH_PIN*, SCH_SHEET_PATH>>& sorted_items = all_nets.back().second; for( CONNECTION_SUBGRAPH* subgraph : subgraphs ) { @@ -134,7 +153,7 @@ bool NETLIST_EXPORTER_CADSTAR::writeListOfNets( FILE* f ) } } - // Netlist ordering: Net name, then ref des, then pin name + // Intra-net ordering: Ref des, then pin name std::sort( sorted_items.begin(), sorted_items.end(), []( std::pair<SCH_PIN*, SCH_SHEET_PATH> a, std::pair<SCH_PIN*, SCH_SHEET_PATH> b ) { @@ -159,7 +178,17 @@ bool NETLIST_EXPORTER_CADSTAR::writeListOfNets( FILE* f ) return ref_a == ref_b && a.first->GetShownNumber() == b.first->GetShownNumber(); } ), sorted_items.end() ); + } + // Inter-net ordering by net name + std::sort( all_nets.begin(), all_nets.end(), + []( const auto& a, const auto& b ) + { + return a.first < b.first; + } ); + + for( const auto& [netName, sorted_items] : all_nets ) + { print_ter = 0; for( const std::pair<SCH_PIN*, SCH_SHEET_PATH>& pair : sorted_items ) diff --git a/qa/data/cli/basic_test/basic_test.netlist.cadstar b/qa/data/cli/basic_test/basic_test.netlist.cadstar index 8493a84522..7224edba51 100644 --- a/qa/data/cli/basic_test/basic_test.netlist.cadstar +++ b/qa/data/cli/basic_test/basic_test.netlist.cadstar @@ -1,19 +1,22 @@ .HEA -.TIM 5/2/2023 8:59:04 PM -.APP "Eeschema 7.99.0-893-g4a5939297b-dirty" +.TIM 2024-12-20T00:07:25+0000 +.APP "Eeschema 8.99.0-3439-gc9d74d24f0-dirty" .TYP FULL -.ADD_COM R1 "10k" "Resistor_SMD:R_1206_3216Metric" +.ADD_COM J1 "Conn_01x01_Pin" "TestPoint:TestPoint_Pad_3.0x3.0mm" +.ADD_COM J2 "Conn_01x01_Pin" "TestPoint:TestPoint_Pad_3.0x3.0mm" +.ADD_COM J4 "Conn_01x01_Pin" "TestPoint:TestPoint_Pad_3.0x3.0mm" .ADD_COM C1 "10u" "Capacitor_SMD:C_1206_3216Metric" .ADD_COM R2 "10k" "Resistor_SMD:R_1206_3216Metric" -.ADD_COM J3 "Conn_01x01_Pin" "TestPoint:TestPoint_Pad_3.0x3.0mm" -.ADD_COM J2 "Conn_01x01_Pin" "TestPoint:TestPoint_Pad_3.0x3.0mm" -.ADD_COM J1 "Conn_01x01_Pin" "TestPoint:TestPoint_Pad_3.0x3.0mm" -.ADD_COM J4 "Conn_01x01_Pin" "TestPoint:TestPoint_Pad_3.0x3.0mm" .ADD_COM R3 "10k" "Resistor_SMD:R_1206_3216Metric" +.ADD_COM J3 "Conn_01x01_Pin" "TestPoint:TestPoint_Pad_3.0x3.0mm" .ADD_COM U1 "TLV2371DBV" "Package_TO_SOT_SMD:SOT-23-5" +.ADD_COM R1 "10k" "Resistor_SMD:R_1206_3216Metric" +.ADD_TER J2 1 "/IN" +.TER R3 1 + .ADD_TER J3 1 "/OUT" .TER R2 2 U1 1 @@ -21,6 +24,11 @@ .ADD_TER J1 1 "/VCC" .TER U1 5 +.ADD_TER C1 2 "GND" +.TER J4 1 + R1 1 + U1 2 + .ADD_TER C1 1 "Net-(U1-+)" .TER R3 2 U1 3 @@ -29,12 +37,4 @@ .TER R2 1 U1 4 -.ADD_TER C1 2 "GND" -.TER J4 1 - R1 1 - U1 2 - -.ADD_TER J2 1 "/IN" -.TER R3 1 - .END diff --git a/qa/tests/cli/test_sch.py b/qa/tests/cli/test_sch.py index 1553b48824..1a4e19770d 100644 --- a/qa/tests/cli/test_sch.py +++ b/qa/tests/cli/test_sch.py @@ -75,8 +75,7 @@ def test_sch_export_svg( kitest, [("cli/basic_test/basic_test.kicad_sch", "basic_test.netlist.kicadsexpr", 5, True, []), ("cli/basic_test/basic_test.kicad_sch", "basic_test.netlist.kicadsexpr", 5, True,["--format=kicadsexpr"]), ("cli/basic_test/basic_test.kicad_sch", "basic_test.netlist.kicadxml", 6, True,["--format=kicadxml"]), - # currently inconsistenly sorts nets between platforms (MSW/Linux) - ("cli/basic_test/basic_test.kicad_sch", "basic_test.netlist.cadstar", 3, True, ["--format=cadstar"]), + ("cli/basic_test/basic_test.kicad_sch", "basic_test.netlist.cadstar", 3, False, ["--format=cadstar"]), ("cli/basic_test/basic_test.kicad_sch", "basic_test.netlist.orcadpcb2", 1, False, ["--format=orcadpcb2"]) ]) def test_sch_export_netlist( kitest,