20#include <boost/test/unit_test.hpp>
31#include <wx/imagpng.h>
32#include <wx/mstream.h>
61#include <nlohmann/json.hpp>
119 DOWNGRADE_TARGET future = { wxT(
"future" ), wxT(
"future" ), 20260623, 20260629, 20260629 };
132 board.
Add( ellipse );
150 board.
Add( ellipse );
161 BOOST_CHECK_CLOSE( areaMM,
M_PI * 5.0 * 3.0, 2.0 );
185 BOOST_CHECK_GT( areaMM, 1.5 );
186 BOOST_CHECK_LT( areaMM, 2.6 );
196 board.
Add( textbox );
212 table->SetColCount( 1 );
216 table->AddCell( cell );
244 table->SetColCount( 1 );
248 table->AddCell( cell );
282 BOOST_CHECK_CLOSE( areaMM, 60.0 - ( 4.0 -
M_PI ), 2.0 );
333 const std::string src = ( tmp.
Path() /
"source.kicad_pcb" ).string();
337 std::unique_ptr<BOARD> current( io.
LoadBoard( src,
nullptr ) );
339 const auto& loadedDefaults = current->GetDesignSettings().m_ZoneLayerProperties;
343 BOOST_CHECK( current->GetDesignSettings().GetDefaultZoneSettings().m_LayerProperties.empty() );
348 const std::string dest = ( tmp.
Path() / ( target.m_id.ToStdString() +
".kicad_pcb" ) ).string();
350 std::unique_ptr<BOARD> reloaded( io.
LoadBoard( dest,
nullptr ) );
352 const auto& defaults = reloaded->GetDesignSettings().m_ZoneLayerProperties;
354 if( target.m_id == wxT(
"9.0" ) )
364 BOOST_CHECK( defaults.at(
F_Cu ).hatching_offset == loadedDefaults.at(
F_Cu ).hatching_offset );
365 BOOST_CHECK( defaults.at(
B_Cu ).hatching_offset == loadedDefaults.at(
B_Cu ).hatching_offset );
393 via->Padstack().Drill().is_capped =
true;
425 group->SetDesignBlockLibId(
LIB_ID( wxT(
"Lib" ), wxT(
"Block" ) ) );
491 const wxString dest = ( tmp.
Path() /
"out.kicad_pcb" ).wstring();
492 const wxString victim = ( tmp.
Path() /
"victim.txt" ).wstring();
495 wxFFile file( victim, wxT(
"wb" ) );
497 file.Write( wxT(
"untouched" ) );
500 const wxString decoy =
501 dest + wxString::Format( wxT(
".downgrade_tmp.%lu" ), (
unsigned long) wxGetProcessId() );
503 std::filesystem::create_symlink( victim.ToStdString(), decoy.ToStdString(), ec );
511 wxFFile file( victim, wxT(
"rb" ) );
518 const wxString reference = ( tmp.
Path() /
"reference.kicad_pcb" ).wstring();
520 std::unique_ptr<BOARD> board( io.
LoadBoard( dest,
nullptr ) );
524 BOOST_CHECK( std::filesystem::status( dest.ToStdString() ).permissions()
525 == std::filesystem::status( reference.ToStdString() ).permissions() );
543 const wxString src = ( tmp.
Path() /
"src.kicad_pcb" ).wstring();
544 const wxString dest = ( tmp.
Path() /
"out.kicad_pcb" ).wstring();
588 BOOST_CHECK( !
pad->Padstack().FrontPostMachining().mode.has_value() );
635 const std::string dest = ( tmp.
Path() /
"out.kicad_pcb" ).string();
642 std::unique_ptr<BOARD> exported( io.
LoadBoard( dest,
nullptr ) );
647 for(
size_t i = 0; i <
source->Footprints().size(); i++ )
650 FOOTPRINT* b = exported->Footprints()[i];
658 for(
size_t p = 0; p < a->
Pads().size(); p++ )
672 const std::string dest = ( tmp.
Path() /
"out.kicad_pcb" ).string();
679 std::unique_ptr<BOARD> exported( io.
LoadBoard( dest,
nullptr ) );
684 for(
size_t i = 0; i <
source->Footprints().size(); i++ )
687 FOOTPRINT* b = exported->Footprints()[i];
693 for(
size_t pd = 0; pd < a->
Pads().size(); pd++ )
738 board.
Add( barcode );
770 BOOST_CHECK_GT( polyCount, 1 );
771 BOOST_CHECK_GT( areaMM, 5.0 );
772 BOOST_CHECK_CLOSE( areaMM, expectedMM, 0.1 );
779 wxString projectPath = ( tmp.
Path() /
"source.kicad_pro" ).string();
780 wxString boardPath = ( tmp.
Path() /
"source.kicad_pcb" ).string();
781 wxString outputPath = ( tmp.
Path() /
"output.kicad_pcb" ).string();
784 std::ofstream
project( projectPath.ToStdString() );
785 project << R
"({"meta":{"version":3},"text_variables":{"SERIAL":"SERIAL123"}})";
799 board.
Add( barcode );
806 double expectedArea =
expected.Area();
814 int polygonCount = 0;
815 double resultArea = 0;
831 BOOST_CHECK_CLOSE( resultArea, expectedArea, 0.01 );
862 BOOST_CHECK_GT( polyCount, 1 );
874 std::unique_ptr<FOOTPRINT> fp( loader.
ImportFootprint( src, nameOut ) );
880 const wxString dest = ( tmp.
Path() /
"out.kicad_mod" ).wstring();
885 std::ifstream out( dest.ToStdString() );
886 std::string content( ( std::istreambuf_iterator<char>( out ) ), std::istreambuf_iterator<char>() );
887 BOOST_CHECK( content.find(
"(version " + std::to_string(
kicad9.m_boardVersion ) +
")" ) != std::string::npos );
891 std::unique_ptr<FOOTPRINT> reloaded( reader.
ImportFootprint( dest, reloadName ) );
905 std::unique_ptr<FOOTPRINT> fp( loader.
ImportFootprint( src, nameOut ) );
911 const wxString dest = ( tmp.
Path() /
"out.kicad_mod" ).wstring();
915 std::ifstream out( dest.ToStdString() );
916 std::string content( ( std::istreambuf_iterator<char>( out ) ), std::istreambuf_iterator<char>() );
917 BOOST_CHECK( content.find(
"(version " + std::to_string(
kicad10.m_boardVersion ) +
")" ) != std::string::npos );
921 std::unique_ptr<FOOTPRINT> reloaded( reader.
ImportFootprint( dest, reloadName ) );
951 std::string dest = ( tmp.
Path() /
"out.kicad_pcb" ).string();
956 std::unique_ptr<BOARD> reloaded( reader.
LoadBoard( dest,
nullptr ) );
968 std::unique_ptr<FOOTPRINT> fp = std::make_unique<FOOTPRINT>(
nullptr );
969 fp->GetFields().push_back(
nullptr );
972 const wxString dest = ( tmp.
Path() /
"out.kicad_mod" ).wstring();
976 BOOST_CHECK( std::filesystem::exists( dest.ToStdString() ) );
988 board.
Add( onBoard );
993 group->AddItem( onBoard );
994 group->AddItem( stale );
998 const std::string dest = ( tmp.
Path() /
"out.kicad_pcb" ).string();
1002 std::ifstream out( dest );
1003 std::string content( ( std::istreambuf_iterator<char>( out ) ), std::istreambuf_iterator<char>() );
1025 const std::string dest = ( tmp.
Path() /
"out.kicad_pcb" ).string();
1029 std::ifstream out( dest );
1030 std::string content( ( std::istreambuf_iterator<char>( out ) ), std::istreambuf_iterator<char>() );
1032 BOOST_CHECK( content.find(
"(remove_unused_layers yes)" ) != std::string::npos );
1033 BOOST_CHECK( content.find(
"(keep_end_layers yes)" ) != std::string::npos );
1036 std::unique_ptr<BOARD> reloaded( reader.
LoadBoard( dest,
nullptr ) );
1040 const PCB_VIA* reloadedVia =
static_cast<const PCB_VIA*
>( reloaded->Tracks().front() );
1057 board.
Add( otherImage );
1073 const std::string dest = ( tmp.
Path() /
"out.kicad_pcb" ).string();
1078 std::ifstream out( dest );
1079 std::string content( ( std::istreambuf_iterator<char>( out ) ), std::istreambuf_iterator<char>() );
1082 BOOST_CHECK_CLOSE( written, originalScale * legacyPPI / ppi, 0.1 );
1084 0.5 * legacyPPI / ppi, 0.1 );
1112 image->GetReferenceImage().SetOpacity( 0.4 );
1132 == wxT(
"transform" ) );
1149 const wxString rules = wxT(
"(version 2)\n"
1151 "(rule \"clearance_ok\"\n"
1152 " # chamfer runs at 45deg here\n"
1153 " (constraint clearance (min 0.2mm))\n"
1154 " (condition \"A.NetClass == 'HV'\"))\n"
1155 "(rule \"mask_check\"\n"
1156 " (constraint bridged_mask))\n"
1157 "(rule \"chain_check\"\n"
1158 " (condition \"inNetChain('x')\")\n"
1159 " (constraint clearance (min 0.1mm)))\n"
1160 "(rule \"delay_check\"\n"
1161 " (constraint skew (max 5ps)))\n" );
1175 "# (rule \"mask_check\"\n# (constraint bridged_mask))\n" ) ) );
1176 BOOST_CHECK(
result.m_text.Contains( wxT(
"# (rule \"chain_check\"\n# (condition \"inNetChain('x')\")\n" ) ) );
1177 BOOST_CHECK(
result.m_text.Contains( wxT(
"# (rule \"delay_check\"\n# (constraint skew (max 5ps)))\n" ) ) );
1185 std::vector<std::shared_ptr<DRC_RULE>> rules;
1188 return rules.size();
1194 const wxString rules = wxT(
"(version 2)\n"
1195 "(rule \"keep\" (constraint clearance (min 0.2mm)))\n"
1196 "# why the chain rule exists\n"
1198 " (constraint net_chain_length (max 10mm)))\n"
1199 "(rule \"glued\" (constraint net_chain_length (max 1mm)))"
1200 "(rule \"after\" (constraint clearance (min 0.1mm)))\n" );
1208 const wxString marker = wxT(
"# Not supported by " ) + target.m_name + wxT(
":\n" );
1209 const wxString
expected = wxT(
"(version 1)\n"
1210 "(rule \"keep\" (constraint clearance (min 0.2mm)))\n"
1211 "# why the chain rule exists\n" )
1213 + wxT(
"# (rule \"chain\"\n"
1214 "# (constraint net_chain_length (max 10mm)))\n" )
1216 + wxT(
"# (rule \"glued\" (constraint net_chain_length (max 1mm)))\n"
1217 "(rule \"after\" (constraint clearance (min 0.1mm)))\n" );
1226 const wxString rules = wxT(
"(version 2)"
1227 "(rule \"first\" (constraint net_chain_length (max 1mm)))"
1228 "(rule \"kept\" (constraint clearance (min 0.2mm)))"
1229 "(rule \"last\" (constraint net_chain_length (max 1mm)))" );
1236 const wxString marker = wxT(
"# Not supported by " ) + target.m_name + wxT(
":\n" );
1237 const wxString
expected = wxT(
"(version 1)\n" ) + marker
1238 + wxT(
"# (rule \"first\" (constraint net_chain_length (max 1mm)))\n"
1239 "(rule \"kept\" (constraint clearance (min 0.2mm)))\n" )
1240 + marker + wxT(
"# (rule \"last\" (constraint net_chain_length (max 1mm)))\n" );
1249 const wxString rules = wxT(
"(version 2)\r\n"
1250 " (rule \"messy\"\r\n"
1251 " # ) \" ( unmatched in a comment\r\n"
1252 " (condition \"A.NetName == 'a'\")\r\n"
1253 " (constraint net_chain_length (max 1mm)))\r\n"
1254 "(rule \"kept\" (constraint clearance (min 0.2mm)))\r\n" );
1263 const wxString
expected = wxT(
"(version 1)\r\n # Not supported by " ) + target.m_name
1265 "# (rule \"messy\"\r\n"
1266 "# # ) \" ( unmatched in a comment\r\n"
1267 "# (condition \"A.NetName == 'a'\")\r\n"
1268 "# (constraint net_chain_length (max 1mm)))\r\n"
1269 "(rule \"kept\" (constraint clearance (min 0.2mm)))\r\n" );
1278 const wxString rules = wxT(
"(version 2)\n"
1279 "(future_block \"x\" (constraint clearance (min 1mm)))\n"
1280 "(rule \"kept\" (constraint clearance (min 0.2mm)))\n" );
1287 BOOST_CHECK(
result.m_text.Contains( wxT(
"# (future_block \"x\" (constraint clearance (min 1mm)))\n"
1288 "(rule \"kept\"" ) ) );
1296 const wxString rules = wxT(
"(version 2)\n"
1297 "# why the chain rule exists\n"
1300 " (constraint net_chain_length (max 10mm)))\n"
1301 "(rule \"after\" (constraint clearance (min 0.1mm)))"
1302 "(rule \"last\" (constraint net_chain_length (max 1mm)))\n"
1303 "# trailing note\n" );
1310 BOOST_CHECK( first.
m_text.EndsWith( wxT(
"# (rule \"last\" (constraint net_chain_length (max 1mm)))\n"
1311 "# trailing note\n" ) ) );
1323 const wxString rules = wxT(
"(version 1)\n"
1324 "(rule \"return_path\" (constraint clearance (min 0.2mm)))\n"
1325 "(rule inNetChain (constraint clearance (min 0.2mm)))\n"
1326 "(rule \"literal\" (condition \"A.NetName == 'hasNetChain() 100 ps .Parent.'\")\n"
1327 " (constraint clearance (min 0.2mm)))\n" );
1341 const wxString rules = wxT(
"(version 1)\n"
1342 "(rule \"time\" (constraint length (min \"100 ps\")))\n"
1343 "(rule \"femtoseconds\" (constraint length (max \"2 * 100 fs\")))\n"
1344 "(rule \"angle\" (constraint track_angle (max \"90 deg\")))\n"
1345 "(rule \"ordinary\" (constraint clearance (min \"0.2 mm\")))\n" );
1362 const wxString rules = wxT(
"(version 2)\n"
1363 "(rule \"mask_check\" (constraint bridged_mask))\n"
1364 "(rule \"delay_check\" (constraint skew (max 5ps)))\n"
1365 "(rule \"chain_check\" (constraint net_chain_length (max 10mm)))\n" );
1380 const wxString kept = wxT(
"(rule \"clearance # literal\"\n"
1381 " # unmatched: ) (( \" \\\n"
1382 " (condition \"A.NetName == 'SIGNAL#1'\")\n"
1383 " # inNetChain('x')\n"
1384 " (constraint clearance (min 0.2mm))\n"
1387 "(rule \"second\" (constraint track_width (min 0.25mm)))" );
1388 const wxString input = wxT(
"(version 2)\n" ) + kept
1389 + wxT(
"\n(rule \"unsupported\"\n # ) \" (\n"
1390 " (constraint net_chain_length (max 10mm)))\n" );
1402 std::vector<std::shared_ptr<DRC_RULE>> rules;
1414 const wxString rules = wxT(
"# project rules\n"
1416 "(rule \"a\" (constraint clearance (min 0.2mm)))\n" );
1422 "(rule \"a\" (constraint clearance (min 0.2mm)))\n" ) );
1429 const wxString rules = wxT(
"# intro\n"
1430 "(rule \"a\" (constraint net_chain_length (max 1mm)))\n" );
1436 "# Not supported by KiCad 9.0:\n"
1437 "# (rule \"a\" (constraint net_chain_length (max 1mm)))\n" ) );
1444 const wxString rules = wxT(
"(version 2)(rule \"kept\" (constraint clearance (min 0.2mm)))" );
1448 BOOST_CHECK_EQUAL(
result.m_text, wxString(
"(version 1)(rule \"kept\" (constraint clearance (min 0.2mm)))\n" ) );
1455 const wxString rules = wxT(
"(version 1) # note\n(rule \"a\" (constraint clearance (min 0.2mm)))\n" );
1464 const wxString rules = wxT(
"(version 1)(rule \"c\" (condition \"A.Width > 5ps\") "
1465 "(constraint clearance (min 0.2mm)))" );
1474 const wxString rules = wxT(
"(version 1)\n"
1477 " (constraint clearance (min 0.2mm)))\n" );
1485 const wxString rules = wxT(
"(version 1)(rule \"f\" (condition \"A.InsideCourtyard('x')\") "
1486 "(constraint clearance (min 0.2mm)))" );
1495 const wxString rules = wxT(
"(version 1)(rule \"hv\" (condition \"A.memberOfFootprint('${Class:HV}')\") "
1496 "(constraint clearance (min 1mm)))" );
1505 const wxString parent = wxT(
"(version 1)(rule \"x\" (condition A.Parent.Reference==B.Reference) "
1506 "(constraint clearance (min 1mm)))" );
1507 const wxString assertion = wxT(
"(version 1)(rule \"x\" (constraint assertion A.Parent.Reference==B.Reference))" );
1508 const wxString plain = wxT(
"(version 1)(rule \"x\" (condition A.NetClass=='HV') "
1509 "(constraint clearance (min 1mm)))" );
1522 const wxString newItem = wxT(
"(version 1)(rule \"y\" (constraint disallow \"blind_via\"))" );
1523 const wxString oldItem = wxT(
"(version 1)(rule \"y\" (constraint disallow \"via\"))" );
1524 const wxString connection = wxT(
"(version 1)(rule \"z\" (constraint zone_connection \"thermal_reliefs\"))" );
1539 const wxString rules = wxT(
"(version 1)\n(rule \"a\" (condition \"A.NetClass ==\n 'HV'\") "
1540 "(constraint clearance (min 0.2mm)))\n" );
1549 const wxString rules = wxT(
"(version 1)\n"
1551 "# the head comes after this comment\n"
1552 "rule \"a\" (constraint clearance (min 0.2mm)))\n"
1554 "# so does this one\n"
1555 "rule \"b\" (constraint net_chain_length (max 1mm)))\n" );
1570 for(
const wxString& input : { wxT(
"(version 1)\n(rule \"inline\" # )\n (constraint clearance (min 0.2mm)))" ),
1571 wxT(
"(version 1)\n(rule \"missing_close\" (constraint clearance (min 0.2mm))" ),
1572 wxT(
"(version 1)\n(rule \"missing_quote" ) } )
1589 const std::string release = target.m_id == wxT(
"9.0" ) ?
"v9" :
"v10";
1594 release ==
"v9" ? 1 : 2 );
1624 nlohmann::json doc = {
1625 {
"meta", { {
"filename",
"p.kicad_pro" }, {
"version", 3 } } },
1626 {
"board", { {
"layer_presets", { { {
"name",
"P" }, {
"renderLayers", {
"tracks",
"vias" } } } } } } },
1628 { {
"meta", { {
"version", 5 } } },
1629 {
"classes", { { {
"name",
"Default" }, {
"priority", 0 }, {
"tuning_profile",
"tp" } } } },
1630 {
"net_chain_classes", { { {
"name",
"chainA" } } } } } },
1631 {
"tuning_profiles",
1632 { {
"meta", { {
"version", 1 } } },
1633 {
"tuning_profiles_impedance_geometric",
1634 { { {
"name",
"tp" }, {
"frequency", 1e9 }, {
"model_solder_mask",
false } } } } } },
1635 {
"component_class_settings", { {
"meta", { {
"version", 0 } } } } },
1637 { {
"top_level_sheets", {
"aaaa" } },
1638 {
"bus_aliases", nlohmann::json::array() },
1639 {
"variants", nlohmann::json::array() } } },
1649 const nlohmann::json& preset = doc[
"board"][
"layer_presets"][0];
1656 BOOST_CHECK( !doc[
"net_settings"][
"classes"][0].contains(
"tuning_profile" ) );
1657 BOOST_CHECK( doc[
"net_settings"][
"classes"][0].contains(
"name" ) );
1658 BOOST_CHECK( !doc[
"net_settings"].contains(
"net_chain_classes" ) );
1659 BOOST_CHECK( !doc.contains(
"tuning_profiles" ) );
1660 BOOST_CHECK( !doc.contains(
"component_class_settings" ) );
1661 BOOST_CHECK( !doc[
"schematic"].contains(
"top_level_sheets" ) );
1662 BOOST_CHECK( !doc[
"schematic"].contains(
"bus_aliases" ) );
1663 BOOST_CHECK( !doc[
"schematic"].contains(
"variants" ) );
1673 const nlohmann::json
empty = nlohmann::json::array();
1674 const std::vector<nlohmann::json> tuningDefaults = {
1676 nlohmann::json::object(),
1677 { {
"meta", { {
"version", 2 } } } },
1678 { {
"meta", { {
"version", 2 } } }, {
"tuning_profiles_impedance_geometric",
empty } },
1680 const std::vector<nlohmann::json> componentDefaults = {
1682 nlohmann::json::object(),
1683 { {
"meta", { {
"version", 0 } } } },
1684 { {
"assignments",
empty }, {
"sheet_component_classes", nlohmann::json::object() } },
1685 { {
"meta", { {
"version", 0 } } },
1686 {
"assignments",
empty },
1687 {
"sheet_component_classes", { {
"enabled",
false } } } },
1692 for(
const auto& tuning : tuningDefaults )
1694 for(
const auto& components : componentDefaults )
1696 nlohmann::json doc = {
1697 {
"meta", { {
"version", 4 } } },
1698 {
"board", { {
"design_settings", { {
"meta", { {
"version", 3 } } } } } } },
1699 {
"erc", { {
"meta", { {
"version", 1 } } }, {
"erc_exclusions",
empty } } },
1701 { {
"meta", { {
"version", 5 } } },
1702 {
"classes", { { {
"name",
"Default" }, {
"tuning_profile",
"" } } } } } },
1703 {
"tuning_profiles", tuning },
1704 {
"component_class_settings", components },
1714 BOOST_CHECK_EQUAL( doc[
"board"][
"design_settings"][
"meta"][
"version"].get<int>(), 2 );
1716 BOOST_CHECK_EQUAL( doc.contains(
"tuning_profiles" ), target.m_id == wxT(
"10.0" ) );
1717 BOOST_CHECK_EQUAL( doc.contains(
"component_class_settings" ), target.m_id == wxT(
"10.0" ) );
1719 const nlohmann::json once = doc;
1732 const nlohmann::json
empty = nlohmann::json::array();
1733 const nlohmann::json profile = {
1734 {
"profile_name",
"Default" },
1735 {
"frequency", 1e9 },
1736 {
"model_solder_mask",
false },
1737 {
"net_chain_bridge_prop_delay", 0 },
1739 const std::vector<nlohmann::json> meaningful = {
1740 { {
"tuning_profiles", { {
"tuning_profiles_impedance_geometric", { profile } } } } },
1741 { {
"net_settings", { {
"classes", { { {
"tuning_profile",
"Saved" } } } } } } },
1742 { {
"tuning_profiles", { {
"tuning_profiles_impedance_geometric",
empty } } },
1743 {
"net_settings", { {
"classes", { { {
"tuning_profile",
"Saved" } } } } } } },
1744 { {
"tuning_profiles", { {
"tuning_profiles_impedance_geometric", { profile } } } },
1746 { {
"classes", { { {
"tuning_profile",
"Default" } }, { {
"tuning_profile",
"Default" } } } } } } },
1747 { {
"component_class_settings",
1749 { { {
"component_class",
"Fast" }, {
"conditions_operator",
"ALL" }, {
"conditions",
empty } } } },
1750 {
"sheet_component_classes", { {
"enabled",
false } } } } } },
1751 { {
"component_class_settings",
1752 { {
"assignments",
empty }, {
"sheet_component_classes", { {
"enabled",
true } } } } } },
1755 for(
const auto&
source : meaningful )
1759 nlohmann::json doc =
source;
1766 const nlohmann::json once = doc;
1778 const nlohmann::json
source = {
1779 {
"meta", { {
"version", 4 } } },
1780 {
"component_class_settings", { {
"meta", { {
"version", 1 } } } } },
1785 nlohmann::json doc =
source;
1798 nlohmann::json metaIsString = {
1799 {
"meta",
"not an object" },
1800 {
"net_settings", { {
"meta",
"also a string" }, {
"classes",
"not an array" } } },
1801 {
"schematic",
"a string" },
1804 nlohmann::json profilesWrong = {
1805 {
"tuning_profiles",
1806 { {
"meta", 7 }, {
"tuning_profiles_impedance_geometric", {
"just",
"strings" } } } },
1818 nlohmann::json doc = {
1819 {
"net_settings", { {
"net_chain_classes", nlohmann::json::array() } } },
1825 BOOST_CHECK( !doc[
"net_settings"].contains(
"net_chain_classes" ) );
1832 nlohmann::json doc = {
1833 {
"tuning_profiles",
1834 { {
"meta", { {
"version", 1 } } },
1835 {
"tuning_profiles_impedance_geometric",
1836 { { {
"profile_name",
"5 GHz" }, {
"frequency", 5e9 }, {
"model_solder_mask",
true } },
1837 { {
"profile_name",
"Default" }, {
"frequency", 1e9 }, {
"model_solder_mask",
false } } } } } }
1845 for(
const auto& profile : doc[
"tuning_profiles"][
"tuning_profiles_impedance_geometric"] )
1848 BOOST_CHECK( !profile.contains(
"model_solder_mask" ) );
1859 nlohmann::json doc = {
1860 {
"meta", { {
"version", 3 } } },
1862 { {
"meta", { {
"version", 5 } } },
1863 {
"classes", { { {
"name",
"Default" }, {
"priority", 0 }, {
"tuning_profile",
"tp" } } } },
1864 {
"net_chain_classes", { { {
"name",
"chainA" } } } } } },
1865 {
"tuning_profiles",
1866 { {
"meta", { {
"version", 1 } } },
1867 {
"tuning_profiles_impedance_geometric",
1868 { { {
"name",
"tp" }, {
"frequency", 1e9 }, {
"model_solder_mask",
false } } } } } },
1877 BOOST_CHECK( doc[
"net_settings"][
"classes"][0].contains(
"tuning_profile" ) );
1878 BOOST_CHECK( !doc[
"net_settings"].contains(
"net_chain_classes" ) );
1881 BOOST_CHECK( !doc[
"tuning_profiles"][
"tuning_profiles_impedance_geometric"][0].contains(
"frequency" ) );
1882 BOOST_CHECK( !doc[
"tuning_profiles"][
"tuning_profiles_impedance_geometric"][0].contains(
"model_solder_mask" ) );
1914 BOOST_CHECK_GT( areaMM, 4.0 );
1915 BOOST_CHECK_LT( areaMM, 15.0 );
1939 BOOST_CHECK_CLOSE( ref.
GetImageScale(), 2.0 * legacyPPI / ppi, 0.1 );
1946 std::unique_ptr<FOOTPRINT> fp = std::make_unique<FOOTPRINT>(
nullptr );
1961 BOOST_CHECK_CLOSE( ref.
GetImageScale(), 2.0 * legacyPPI / ppi, 0.1 );
1988 const wxString src = ( tmp.
Path() /
"src.kicad_mod" ).wstring();
1989 const wxString dest = ( tmp.
Path() /
"out.kicad_mod" ).wstring();
1992 std::unique_ptr<FOOTPRINT> fp = std::make_unique<FOOTPRINT>(
nullptr );
2010 std::unique_ptr<FOOTPRINT> srcAgain( reader.
ImportFootprint( src, nameOut ) );
2011 std::unique_ptr<FOOTPRINT> converted( reader.
ImportFootprint( dest, nameOut ) );
2017 BOOST_CHECK_EQUAL( converted->Zones()[0]->GetLayerSet().count(), srcAgain->Zones()[0]->GetLayerSet().count() );
2026 const wxString dir = tmp.
Path().wstring();
2028 auto writeFile = [&](
const wxString& aName,
const wxString& aContent )
2030 wxFFile file( dir + wxFileName::GetPathSeparator() + aName, wxT(
"wb" ) );
2032 file.Write( aContent );
2035 writeFile( wxT(
"a.fake_mod" ), wxT(
"old a" ) );
2036 writeFile( wxT(
"b.fake_mod" ), wxT(
"old b" ) );
2038 auto noForbidden = [](
const wxString& )
2045 wxFFile out( aTmp, wxT(
"wb" ) );
2046 out.Write( wxT(
"(version 123) converted" ) );
2052 wxFFile check( dir + wxFileName::GetPathSeparator() + wxT(
"a.fake_mod" ), wxT(
"rb" ) );
2054 BOOST_REQUIRE( check.IsOpened() && check.ReadAll( &content ) );
2055 BOOST_CHECK( content.Contains( wxT(
"converted" ) ) );
2060 if( aFile.Contains( wxT(
"b.fake_mod" ) ) )
2063 wxFFile out( aTmp, wxT(
"wb" ) );
2064 out.Write( wxT(
"(version 123) second pass" ) );
2069 BOOST_CHECK( bad.Contains( wxT(
"b.fake_mod" ) ) );
2071 wxArrayString leftovers;
2072 wxDir::GetAllFiles( dir, &leftovers );
2075 wxFFile recheck( dir + wxFileName::GetPathSeparator() + wxT(
"a.fake_mod" ), wxT(
"rb" ) );
2077 BOOST_REQUIRE( recheck.IsOpened() && recheck.ReadAll( &unchanged ) );
2078 BOOST_CHECK( !unchanged.Contains( wxT(
"second pass" ) ) );
2114 for(
bool footprintOnly : {
false,
true } )
2131 parent->
Add( shape );
2132 group->AddItem( shape );
2136 parent->
Add( barcode );
2137 group->AddItem( barcode );
2140 textbox->
SetText( wxT(
"Do not retain as plain text" ) );
2141 parent->
Add( textbox );
2142 group->AddItem( textbox );
2145 parent->
Add( supported );
2146 group->AddItem( supported );
2147 const KIID supportedUuid = supported->
m_Uuid;
2155 for(
size_t i = 0; i <
normal.Entries().size(); ++i )
2160 BOOST_CHECK( !omit.Entries()[i].m_detail.IsEmpty() );
2188 parent->Add( hatch );
2190 table->SetColCount( 2 );
2193 knockout->
SetText( wxT(
"knockout" ) );
2194 table->AddCell( knockout );
2196 plain->
SetText( wxT(
"supported" ) );
2197 table->AddCell( plain );
2198 parent->Add(
table );
2224 for(
int ii = 0; ii < 3; ++ii )
2235 board.
Add( copper );
2237 for(
bool drop : {
false,
true } )
2253 for(
bool drop : {
false,
true } )
2261 std::vector<PCB_SHAPE*> copper;
2262 std::vector<PCB_SHAPE*> silk;
2270 parent->Add( onCopper );
2271 copper.push_back( onCopper );
2276 parent->Add( onSilk );
2277 silk.push_back( onSilk );
2294 for(
bool footprintOnly : {
false,
true } )
2305 pad->AddPrimitive(
F_Cu, rounded );
2307 pad->AddPrimitive(
F_Cu, supported );
2324 for(
bool drop : {
false,
true } )
2334 board.
Add( buried );
2336 board.
Add( supported );
2365 board.
Add( textbox );
2369 board.
Add( buried );
2401 const wxString board =
directory + wxT(
"/board.kicad_pcb" );
2403 auto write = [](
const wxString& aPath,
const wxString& aContent )
2405 wxFFile file( aPath, wxT(
"wb" ) );
2406 BOOST_REQUIRE( file.IsOpened() && file.Write( aContent ) && file.Close() );
2409 auto read = [](
const wxString& aPath )
2411 wxFFile file( aPath, wxT(
"rb" ) );
2413 BOOST_REQUIRE( file.IsOpened() && file.ReadAll( &content ) );
2417 auto noForbidden = [](
const wxString& )
2421 auto convert = [&](
const wxString&,
const wxString& aTemporary )
2423 write( aTemporary, wxT(
"(version 123) converted" ) );
2427 write(
library, wxT(
"original library" ) );
2428 write( board, wxT(
"original board" ) );
2447 wxString stagedBoard = transaction.
Stage( board );
2449 write( stagedBoard, wxT(
"converted board" ) );
2455 wxArrayString files;
2456 wxDir::GetAllFiles(
directory, &files );
2465 const wxString first =
directory + wxT(
"/first.kicad_pcb" );
2466 const wxString second =
directory + wxT(
"/second.kicad_pcb" );
2469 wxFFile file( first, wxT(
"wb" ) );
2470 BOOST_REQUIRE( file.IsOpened() && file.Write( wxT(
"original" ) ) && file.Close() );
2475 wxString stagedFirst = transaction.
Stage( first );
2476 wxString stagedSecond = transaction.
Stage( second );
2477 BOOST_REQUIRE( !stagedFirst.IsEmpty() && !stagedSecond.IsEmpty() );
2479 for(
const wxString& file : { stagedFirst, stagedSecond } )
2481 wxFFile output( file, wxT(
"wb" ) );
2482 BOOST_REQUIRE( output.IsOpened() && output.Write( wxT(
"converted" ) ) && output.Close() );
2486 BOOST_CHECK( wxFileName( transaction.
Commit() ).SameAs( wxFileName( second ) ) );
2490 wxFFile input( first, wxT(
"rb" ) );
2492 BOOST_REQUIRE( input.IsOpened() && input.ReadAll( &content ) );
2495 wxArrayString files;
2496 wxDir::GetAllFiles(
directory, &files );
2504 const wxString destination = temporary.
Path().wstring() + wxT(
"/board.kicad_pcb" );
2509 wxString firstTemporary = first.
Stage( destination );
2510 wxString secondTemporary = second.
Stage( destination );
2511 BOOST_REQUIRE( !firstTemporary.IsEmpty() && !secondTemporary.IsEmpty() );
2515 first.
Discard( firstTemporary );
2528 const auto original = temporary.
Path() / u8
"original-μ.kicad_mod";
2529 const auto alias = temporary.
Path() /
"alias.kicad_mod";
2530 const auto danglingAlias = temporary.
Path() /
"dangling.kicad_mod";
2533 wxFFile file( original.wstring(), wxT(
"wb" ) );
2534 BOOST_REQUIRE( file.IsOpened() && file.Write( wxT(
"original source" ) ) && file.Close() );
2537 std::error_code error;
2538 std::filesystem::create_symlink( original.filename(), alias, error );
2546 std::filesystem::create_symlink(
"missing.kicad_mod", danglingAlias, error );
2552 for(
const auto& destination : { alias, danglingAlias } )
2554 wxString staged = transaction.
Stage( destination.wstring() );
2556 wxFFile file( staged, wxT(
"wb" ) );
2557 BOOST_REQUIRE( file.IsOpened() && file.Write( wxT(
"converted output" ) ) && file.Close() );
2563 wxFFile file( original.wstring(), wxT(
"rb" ) );
2565 BOOST_REQUIRE( file.IsOpened() && file.ReadAll( &content ) );
2567 BOOST_CHECK( !std::filesystem::is_symlink( alias ) );
2568 BOOST_CHECK( !std::filesystem::is_symlink( danglingAlias ) );
2570 std::filesystem::directory_iterator() ),
2580 if( entry.m_feature == aName )
2589 BOOST_ERROR(
"Missing compatibility feature: " + aName.ToStdString() );
2597 for(
bool drop : {
false,
true } )
2603 std::vector<PCB_SHAPE*> shapes;
2611 parent->Add( shape );
2612 shapes.push_back( shape );
2615 parent->Add( constraint );
2639 for(
bool drop : {
false,
true } )
2666 for(
bool drop : {
false,
true } )
2673 board.
Add( stitch );
2677 std::vector<PCB_VIA*> vias;
2683 via->SetPosition(
VECTOR2I( 1000000 * ( vias.size() + 1 ), 2000000 ) );
2684 via->SetWidth(
F_Cu, 600000 );
2685 via->SetDrill( 300000 );
2687 generator->AddItem(
via );
2688 vias.push_back(
via );
2699 for(
size_t ii = 0; ii < vias.size(); ++ii )
2704 BOOST_CHECK( vias[ii]->GetParentGroup() == outer );
2713 const std::string src =
2725 const auto copperById = [](
const BOARD& aBoard )
2727 std::map<KIID, const PCB_TRACK*> items;
2729 for(
const PCB_TRACK* item : aBoard.Tracks() )
2730 BOOST_REQUIRE( items.emplace( item->m_Uuid, item ).second );
2734 const auto memberIds = [](
const PCB_GROUP& aGroup )
2738 for(
const EDA_ITEM* member : aGroup.GetItems() )
2743 const auto serializeNative = [](
BOARD* aBoard )
2751 const auto sourceCopper = copperById( *
source );
2753 std::set<KIID> plainVias;
2754 std::set<KIID> generatedVias;
2755 size_t sourceVias = 0;
2756 size_t sourceSegments = 0;
2757 size_t sourceMicrovias = 0;
2759 for(
const auto& [
id, item] : sourceCopper )
2771 if( !
via->GetParentGroup() )
2772 plainVias.insert(
id );
2795 BOOST_REQUIRE(
source->FindNet( viaStitch->GetNetCode() )->GetNetname() == wxT(
"GND" ) );
2821 for(
BOARD_ITEM* member : generator->GetBoardItems() )
2825 BOOST_REQUIRE( sourceCopper.count( member->m_Uuid ) == 1u );
2826 BOOST_REQUIRE( generatedVias.insert( member->m_Uuid ).second );
2835 const auto stitchMembers = memberIds( *stitch );
2838 const wxString outerName = outer->
GetName();
2843 const std::string sourceModel = serializeNative(
source.get() );
2848 const bool preTen = target.m_boardVersion ==
kicad9.m_boardVersion;
2850 for(
bool drop : {
false,
true } )
2859 const std::string dest =
2861 / ( target.m_id.ToStdString() + ( drop ?
"-drop.kicad_pcb" :
"-lower.kicad_pcb" ) ) )
2864 wxString unsupportedToken;
2880 for(
size_t ii = 0; ii < preview.
Entries().size(); ++ii )
2889 BOOST_CHECK( outputBytes.find(
"(generated" ) == std::string::npos );
2893 for(
const char* token : {
"(filling",
"(capping",
"(covering",
"(plugging" } )
2894 BOOST_CHECK( outputBytes.find( token ) == std::string::npos );
2897 std::unique_ptr<BOARD> exported( io.
LoadBoard( dest,
nullptr ) );
2899 BOOST_CHECK_EQUAL( exported->GetFileFormatVersionAtLoad(), target.m_boardVersion );
2904 BOOST_CHECK( exported->GroupsSanityCheck().IsEmpty() );
2906 const auto exportedCopper = copperById( *exported );
2908 PCB_GROUP* exportedOuter = *exported->Groups().begin();
2911 BOOST_CHECK( memberIds( *exportedOuter ) == stitchMembers );
2913 for(
const auto& [
id, original] : sourceCopper )
2915 const auto found = exportedCopper.find(
id );
2924 if(
const PCB_VIA* originalVia =
dynamic_cast<const PCB_VIA*
>( original ) )
2951 const PADSTACK& originalStack = originalVia->Padstack();
2964 if( plainVias.count(
id ) )
2973 if( stitchMembers.count(
id ) )
2983 const auto found = std::find_if( exported->Drawings().begin(), exported->Drawings().end(),
2986 return aItem->m_Uuid == drawing->m_Uuid;
3011 std::unique_ptr<BOARD> lengthFixture( io.
LoadBoard( lengthPath,
nullptr ) );
3012 std::unique_ptr<BOARD> timeFixture( io.
LoadBoard( timePath,
nullptr ) );
3020 if( generator->m_Uuid ==
KIID(
"2acf841f-25ce-450c-b8df-dbbc34cc96ac" ) )
3030 auto length =
dynamic_cast<PCB_TUNING_PATTERN*
>( ( *lengthFixture->Generators().begin() )->DeepClone() );
3034 BOOST_REQUIRE_GT( length->GetItems().size(), 1u );
3036 const auto addCopper = [&](
PCB_TRACK* aTrack )
3042 net =
new NETINFO_ITEM( &board, aTrack->GetNetname() );
3048 board.
Add( aTrack );
3053 for(
BOARD_ITEM* member : pattern->GetBoardItems() )
3060 board.
Add( pattern );
3065 for(
PCB_TRACK* track : timeFixture->Tracks() )
3069 originalControl = track;
3075 auto control =
static_cast<PCB_TRACK*
>( originalControl->
Clone() );
3076 control->SetParentGroup(
nullptr );
3077 addCopper( control );
3079 outer->
SetName( wxT(
"Native tuning ownership" ) );
3085 double patternLength = 0;
3087 for(
BOARD_ITEM* member : length->GetBoardItems() )
3088 patternLength +=
static_cast<PCB_TRACK*
>( member )->GetLength();
3093 for(
const char* key : {
"tuning_mode",
"initial_side",
"last_status" } )
3097 lengthProperties[key] = wxAny( wxString::FromUTF8( value ) );
3100 lengthProperties[
"last_tuning_length"] = wxAny( patternLength /
pcbIUScale.IU_PER_MM );
3101 length->SetProperties( lengthProperties );
3102 const wxString tuningInfo = length->GetRowData().back().second.GetString();
3104 const auto memberIds = [](
const PCB_GROUP& aGroup )
3108 for(
const EDA_ITEM* member : aGroup.GetItems() )
3113 const auto serializeNative = [](
BOARD* aBoard )
3120 std::map<KIID, const PCB_TRACK*> copper;
3123 BOOST_REQUIRE( copper.emplace( track->m_Uuid, track ).second );
3125 const auto lengthMembers = memberIds( *length );
3126 const auto timeMembers = memberIds( *time );
3130 const std::string src = ( tmp.
Path() /
"native-source.kicad_pcb" ).string();
3133 const std::string sourceModel = serializeNative( &board );
3137 const bool preTen = target.m_boardVersion ==
kicad9.m_boardVersion;
3139 for(
bool drop : {
false,
true } )
3148 const std::string dest =
3150 / ( target.m_id.ToStdString() + ( drop ?
"-drop.kicad_pcb" :
"-lower.kicad_pcb" ) ) )
3153 wxString unsupported;
3170 for(
const char* token : {
"(is_time_domain",
"(target_delay",
"(last_tuning_length" } )
3171 BOOST_CHECK( outputBytes.find( token ) == std::string::npos );
3174 BOOST_CHECK( outputBytes.find(
"(last_tuning " + quoting.
Quotew( tuningInfo ) +
")" )
3175 != std::string::npos );
3179 BOOST_CHECK( outputBytes.find(
"(is_time_domain yes)" ) != std::string::npos );
3180 BOOST_CHECK( outputBytes.find(
"(last_tuning_length " ) != std::string::npos );
3181 BOOST_CHECK( outputBytes.find(
"(last_tuning " ) == std::string::npos );
3184 std::unique_ptr<BOARD> exported( io.
LoadBoard( dest,
nullptr ) );
3186 BOOST_CHECK_EQUAL( exported->GetFileFormatVersionAtLoad(), target.m_boardVersion );
3189 BOOST_CHECK( exported->GroupsSanityCheck().IsEmpty() );
3190 PCB_GROUP* exportedOuter = *exported->Groups().begin();
3192 std::set<KIID> expectedOuter{ length->m_Uuid };
3195 expectedOuter.insert( timeMembers.begin(), timeMembers.end() );
3197 expectedOuter.insert( time->m_Uuid );
3199 BOOST_CHECK( memberIds( *exportedOuter ) == expectedOuter );
3202 for(
const PCB_TRACK* track : exported->Tracks() )
3204 const auto found = copper.find( track->m_Uuid );
3206 const PCB_TRACK* original = found->second;
3214 if(
const PCB_ARC* arc =
dynamic_cast<const PCB_ARC*
>( original ) )
3216 const PCB_ARC* exportedArc =
dynamic_cast<const PCB_ARC*
>( track );
3221 if( timeMembers.count( track->m_Uuid ) && preTen )
3223 else if( track->m_Uuid == control->m_Uuid )
3232 BOOST_CHECK( pattern->m_Uuid == length->m_Uuid || ( !preTen && pattern->m_Uuid == time->m_Uuid ) );
3233 const bool isTime = pattern->m_Uuid == time->m_Uuid;
3234 BOOST_CHECK( pattern->GetSettings().m_isTimeDomain == isTime );
3235 BOOST_CHECK( memberIds( *pattern ) == ( isTime ? timeMembers : lengthMembers ) );
3240 for(
const char* key :
3241 {
"target_length",
"target_length_min",
"target_length_max",
"target_skew",
"target_skew_min",
3242 "target_skew_max",
"min_spacing",
"max_amplitude",
"min_amplitude" } )
3245 double originalValue = 0;
3247 BOOST_REQUIRE( originalProperties.get_to( key, originalValue ) );
3253 for(
const char* key :
3254 {
"target_delay",
"target_delay_min",
"target_delay_max",
"last_tuning_length" } )
3257 double originalValue = 0;
3259 BOOST_REQUIRE( originalProperties.get_to( key, originalValue ) );
3285 properties.
set(
"future_tuning_setting",
true );
3291 auto pattern =
new UNREVIEWED_TUNING_PATTERN( &board );
3293 track->SetStart(
VECTOR2I( 1000000, 2000000 ) );
3294 track->SetEnd(
VECTOR2I( 3000000, 2000000 ) );
3296 board.
Add( pattern );
3297 pattern->AddItem( track );
3301 for(
bool drop : {
false,
true } )
3314 const wxString
path = ( tmp.
Path() / ( target.m_id.ToStdString() +
".kicad_pcb" ) ).wstring();
3324 pattern->SetTargetDelay( 100000 );
3326 track->SetStart(
VECTOR2I( 1000000, 2000000 ) );
3327 track->SetEnd(
VECTOR2I( 3000000, 2000000 ) );
3329 board.
Add( pattern );
3330 pattern->AddItem( track );
3334 for(
const char* token :
3335 {
"is_time_domain",
"target_delay",
"target_delay_min",
"target_delay_max",
"last_tuning_length" } )
3337 const wxString value = wxString::FromUTF8(
"(kicad_pcb (generated (" + std::string( token ) +
" 0)))" );
3348 for(
bool stack : {
false,
true } )
3357 const std::string kind = stack ?
"via-stack" :
"via-stitch";
3363 const auto absent = tmp.
Path() / ( kind +
"-" + target.m_id.ToStdString() +
"-absent.kicad_pcb" );
3367 const auto existing = tmp.
Path() / ( kind +
"-" + target.m_id.ToStdString() +
"-existing.kicad_pcb" );
3370 std::ofstream sentinel( existing, std::ios::binary );
3371 sentinel <<
"existing destination";
3386 const std::string src =
3388 wxFileName projectFile( wxString::FromUTF8( src ) );
3389 projectFile.SetExt( wxT(
"kicad_pro" ) );
3400 std::map<KIID, const PCB_TEXT*> sourceNotes;
3405 BOOST_REQUIRE( sourceNotes.emplace( note->m_Uuid, note ).second );
3409 std::map<KIID, const ZONE*> sourceZones;
3410 int placementAreas = 0;
3411 int filledOutlines = 0;
3415 BOOST_REQUIRE( sourceZones.emplace( zone->m_Uuid, zone ).second );
3425 filledOutlines += zone->GetFilledPolysList( layer )->OutlineCount();
3429 BOOST_REQUIRE_GT( filledOutlines, 0 );
3430 const auto memberIds = [](
const PCB_GROUP& aGroup )
3434 for(
const EDA_ITEM* member : aGroup.GetItems() )
3443 for(
int outline = 0; outline < aOriginal.
OutlineCount(); ++outline )
3445 BOOST_CHECK( aExported.COutline( outline ).CompareGeometry( aOriginal.
COutline( outline ) ) );
3448 for(
int hole = 0; hole < aOriginal.
HoleCount( outline ); ++hole )
3449 BOOST_CHECK( aExported.CHole( outline, hole ).CompareGeometry( aOriginal.
CHole( outline, hole ) ) );
3452 const auto serializeNative = [](
BOARD* aBoard )
3459 const std::string sourceModel = serializeNative(
source.get() );
3467 const bool preTen = target.m_boardVersion ==
kicad9.m_boardVersion;
3469 for(
bool drop : {
false,
true } )
3478 const std::string dest =
3480 / ( target.m_id.ToStdString() + ( drop ?
"-drop.kicad_pcb" :
"-lower.kicad_pcb" ) ) )
3483 wxString unsupported;
3497 std::unique_ptr<BOARD> exported( io.
LoadBoard( dest,
nullptr ) );
3499 BOOST_CHECK_EQUAL( exported->GetFileFormatVersionAtLoad(), target.m_boardVersion );
3503 BOOST_CHECK( exported->GroupsSanityCheck().IsEmpty() );
3505 for(
const auto& [
id, original] : sourceNotes )
3507 const auto found = std::find_if( exported->Drawings().begin(), exported->Drawings().end(),
3510 return aItem->m_Uuid == id;
3520 for(
const ZONE* zone : exported->Zones() )
3522 const auto found = sourceZones.find( zone->m_Uuid );
3524 const ZONE* original = found->second;
3535 checkPolygons( original->
GetBoardOutline(), zone->GetBoardOutline() );
3540 const auto exportedFill = zone->GetFilledPolysList( layer );
3541 checkPolygons( *originalFill, *exportedFill );
3543 for(
int outline = 0; outline < originalFill->OutlineCount(); ++outline )
3550 BOOST_CHECK( zone->GetPlacementAreaSource().IsEmpty() );
3563 const auto original = std::find_if(
source->Groups().begin(),
source->Groups().end(),
3566 return aGroup->m_Uuid == group->m_Uuid;
3573 std::map<KIID, const PAD*> sourcePads;
3581 for(
const PAD*
pad : exported->GetPads() )
3583 const auto found = sourcePads.find(
pad->m_Uuid );
3585 const PAD* original = found->second;
3608 for(
bool drop : {
false,
true } )
3611 auto footprint =
new FOOTPRINT( &board );
3612 auto zone =
new ZONE( footprint );
3613 zone->SetIsRuleArea(
true );
3614 zone->SetPlacementAreaEnabled(
true );
3616 zone->SetPlacementAreaSource( wxT(
"Repeated group" ) );
3617 zone->SetDoNotAllowTracks(
true );
3618 footprint->Add( zone );
3619 board.
Add( footprint );
3628 == ( target.m_id ==
kicad10.m_id ? wxT(
"Repeated group" ) : wxEmptyString ) );
3637 == wxT(
"placement/group" ) );
3646 for(
bool drop : {
false,
true } )
3649 auto emptyRuleArea =
new ZONE( &board );
3650 emptyRuleArea->SetIsRuleArea(
true );
3652 board.
Add( emptyRuleArea );
3653 auto ordinaryZone =
new ZONE( &board );
3655 ordinaryZone->SetPlacementAreaEnabled(
true );
3656 ordinaryZone->SetPlacementAreaSource( wxT(
"Unused by ordinary copper zones" ) );
3657 board.
Add( ordinaryZone );
3673 explicit FUTURE_GENERATOR(
BOARD* aBoard ) :
3677 wxString
GetGeneratorType()
const override {
return wxT(
"future_generator" ); }
3681 board.
Add(
new FUTURE_GENERATOR( &board ) );
3683 for(
bool drop : {
false,
true } )
3690 for(
bool drop : {
false,
true } )
3695 std::vector<PCB_SHAPE*> shapes;
3696 double expectedArea = 0;
3707 parent->Add( shape );
3708 shapes.push_back( shape );
3712 expectedArea += ink.
Area();
3734 area +=
static_cast<PCB_SHAPE*
>( item )->GetPolyShape().Area();
3737 area +=
static_cast<PCB_SHAPE*
>( item )->GetPolyShape().Area();
3739 BOOST_CHECK_CLOSE( area, expectedArea, 0.05 );
3765 for(
bool footprintOnly : {
false,
true } )
3771 fp->
Value().
SetText( wxT(
"${PROPERTY.Reference}/${REFERENCE}" ) );
3774 escaped->
SetText( wxT(
"\\${PROPERTY.Serial}" ) );
3777 expression->
SetText( wxT(
"@{${PROPERTY.Reference}+1}/${REFERENCE}" ) );
3778 fp->
Add( expression );
3805 for(
bool drop : {
false,
true } )
3813 const wxString projectPath = ( tmp.
Path() /
"source.kicad_pro" ).string();
3816 std::ofstream
project( projectPath.ToStdString() );
3817 project << R
"({"meta":{"version":4},"text_variables":{"SERIAL":"${PROPERTY.Reference}","ALIAS":"${SERIAL}","UNUSED":"${PROPERTY.Missing}"}})";
3825 std::vector<FOOTPRINT*> footprints;
3827 for(
const wxString& serial : { wxT(
"42" ), wxT(
"73" ) } )
3834 footprints.push_back( fp );
3839 BOOST_CHECK_EQUAL( footprints[0]->Value().GetText(), wxString(
"42/${REFERENCE}" ) );
3840 BOOST_CHECK_EQUAL( footprints[1]->Value().GetText(), wxString(
"73/${REFERENCE}" ) );
3842 footprints[0]->Value().SetText( wxT(
"${UNUSED}" ) );
3851 board.
SetProperties( { { wxT(
"SERIAL" ), wxT(
"${PROPERTY.Reference}" ) },
3852 { wxT(
"UNUSED" ), wxT(
"${PROPERTY.Missing}" ) } } );
3855 fp->
Value().
SetText( wxT(
"${SERIAL}/${REFERENCE}" ) );
3869 fp->
SetKeywords( wxT(
"\\${REFERENCE}/\\@{1+2}" ) );
3870 fp->
Value().
SetText( wxT(
"${PROPERTY.Reference}/\\${U1:PROPERTY.Missing}/${REFERENCE}" ) );
3872 text->SetText( wxT(
"${PROPERTY.Keywords}/${REFERENCE}" ) );
3889 fp->
Value().
SetText( wxT(
"@{1000mils}/${REFERENCE}" ) );
3899 for(
const wxString& raw :
3900 { wxT(
"@{${PROPERTY.Reference}+${MISSING}}" ), wxT(
"@{unknown_function(${PROPERTY.Reference})}" ) } )
3909 for(
bool drop : {
false,
true } )
3917 for(
bool inProperty : {
false,
true } )
3922 const wxString literal = wxT(
"\\${REFERENCE}/\\@{1+2}" );
3924 fp->
Value().
SetText( inProperty ? wxString( wxT(
"${PROPERTY.Keywords}" ) ) : literal );
3928 for(
bool drop : {
false,
true } )
3942 for(
bool drop : {
false,
true } )
3965 for(
bool drop : {
false,
true } )
3973 const wxString projectPath = ( temporary.
Path() /
"source.kicad_pro" ).string();
3976 std::ofstream
project( projectPath.ToStdString() );
3977 project << R
"({"meta":{"version":4},"text_variables":{"TITLE":"${PROPERTY.Reference}"}})";
3991 for(
bool drop : {
false,
true } )
4008 table->SetColCount( 1 );
4009 table->SetColWidth( 0, 10000000 );
4010 table->SetRowHeight( 0, 6000000 );
4012 cell->
SetText( wxT(
"@{${PROPERTY.Reference}+${ROW}}/${COL}/${REFERENCE}" ) );
4013 table->AddCell( cell );
4025 const wxString
source = ( temporary.
Path() /
"source.kicad_mod" ).string();
4028 footprint.
Value().
SetText( wxT(
"${PROPERTY.Reference}/${REFERENCE}" ) );
4037 footprint.
Add( line );
4040 footprint.
Add( constraint );
4046 for(
bool drop : {
false,
true } )
4048 const wxString destination = ( temporary.
Path() /
"out.kicad_mod" ).string();
4057 BOOST_CHECK_EQUAL( converted->Value().GetText(), wxString(
"42/${REFERENCE}" ) );
4060 for(
BOARD_ITEM* item : converted->GraphicalItems() )
4074 for(
bool drop : {
false,
true } )
4099 std::vector<EDA_TEXT*> bold;
4101 text->SetText( wxT(
"board bold" ) );
4103 bold.push_back(
text );
4105 bold.push_back( &fp->
Value() );
4107 fpText->
SetText( wxT(
"graphic bold" ) );
4109 bold.push_back( fpText );
4111 table->SetColCount( 1 );
4112 table->SetColWidth( 0, 10000000 );
4113 table->SetRowHeight( 0, 5000000 );
4115 cell->
SetText( wxT(
"cell bold" ) );
4116 table->AddCell( cell );
4118 bold.push_back( cell );
4124 board.
Add( dimension );
4125 bold.push_back( dimension );
4129 item->SetBold(
true );
4130 item->SetTextThickness( 100000 );
4134 automatic->
SetText( wxT(
"auto bold" ) );
4137 board.
Add( automatic );
4139 outline->
SetText( wxT(
"outline bold" ) );
4143 board.
Add( outline );
4149 const std::string first = ( temporary.
Path() / ( target.m_id.ToStdString() +
"-first.kicad_pcb" ) ).string();
4150 const std::string second = ( temporary.
Path() / ( target.m_id.ToStdString() +
"-second.kicad_pcb" ) ).string();
4154 BOOST_CHECK( content.find(
"(thickness 0.16)" ) != std::string::npos );
4166 reloaded->RunOnChildren(
4171 if( !reloadedText || !reloadedText->
IsBold() )
4174 if( reloadedText->
GetText() == wxT(
"auto bold" ) )
4176 else if( reloadedText->
GetText() != wxT(
"outline bold" ) || outlineAvailable )
4211 const std::string
path = ( temporary.
Path() /
"out.kicad_pcb" ).string();
4215 BOOST_REQUIRE( reloaded && reloaded->Footprints().size() == 1 );
4217 const PAD*
result = reloaded->Footprints()[0]->Pads()[0];
4228 const nlohmann::json exclusion = { {
"marker",
4229 { {
"error_type",
"DRCET_CLEARANCE" },
4230 {
"position", { {
"x_nm",
"123" }, {
"y_nm",
"-456" } } },
4232 { { {
"value",
"11111111-1111-1111-1111-111111111111" } },
4233 { {
"value",
"22222222-2222-2222-2222-222222222222" } } } } } },
4234 {
"comment",
"accepted" } };
4238 nlohmann::json doc = {
4239 {
"meta", { {
"version", 4 } } },
4241 { {
"design_settings", { {
"meta", { {
"version", 3 } } }, {
"drc_exclusions", { exclusion } } } } } }
4246 const auto& settings = doc[
"board"][
"design_settings"];
4250 settings[
"drc_exclusions"][0][0].get<std::string>(),
4251 "clearance|123|-456|11111111-1111-1111-1111-111111111111|22222222-2222-2222-2222-222222222222" );
4252 BOOST_CHECK_EQUAL( settings[
"drc_exclusions"][0][1].get<std::string>(),
"accepted" );
4254 const auto migrated = doc;
4265 nlohmann::json multiple = { {
"marker",
4266 { {
"error_type",
"DRCET_CLEARANCE" },
4267 {
"position", { {
"x_nm",
"123" }, {
"y_nm",
"-456" } } },
4269 { { {
"value",
"11111111-1111-1111-1111-111111111111" } },
4270 { {
"value",
"22222222-2222-2222-2222-222222222222" } },
4271 { {
"value",
"33333333-3333-3333-3333-333333333333" } } } } } },
4272 {
"comment",
"three items" } };
4273 nlohmann::json
unknown = multiple;
4274 unknown[
"marker"][
"error_type"] =
"DRCET_MICROVIA_STACK_DEPTH";
4275 unknown[
"marker"][
"items"].erase( 2 );
4279 nlohmann::json doc = {
4281 { {
"design_settings",
4282 { {
"meta", { {
"version", 3 } } }, {
"drc_exclusions", { multiple,
unknown,
"malformed" } } } } } }
4297 doc[
"net_settings"][
"net_chain_netclasses"] = { { {
"name",
"fast" } } };
4298 doc[
"board"][
"design_settings"][
"via_stack_presets"] = { { {
"name",
"fanout" } } };
4299 doc[
"board"][
"design_settings"][
"teardrop_parameters"] = {
4300 { {
"td_target_name",
"td_track_end" }, {
"td_enabled",
true }, {
"td_max_len", 1.0 } },
4301 { {
"td_enabled",
false } }
4305 BOOST_CHECK( !doc[
"net_settings"].contains(
"net_chain_netclasses" ) );
4306 const auto& settings = doc[
"board"][
"design_settings"];
4307 BOOST_CHECK( !settings.contains(
"via_stack_presets" ) );
4308 BOOST_CHECK( !settings[
"teardrop_parameters"][0].contains(
"td_enabled" ) );
4309 BOOST_CHECK( !settings[
"teardrop_parameters"][1].contains(
"td_enabled" ) );
4310 BOOST_CHECK_EQUAL( settings[
"teardrop_parameters"][0][
"td_max_len"].get<double>(), 1.0 );
4316 nlohmann::json defaults;
4317 defaults[
"net_settings"][
"net_chain_netclasses"] = nlohmann::json::array();
4318 defaults[
"board"][
"design_settings"][
"via_stack_presets"] = nlohmann::json::array();
4319 defaults[
"board"][
"design_settings"][
"teardrop_parameters"] = { { {
"td_enabled",
false } } };
4329 nlohmann::json doc = {
4330 {
"tuning_profiles",
4331 { {
"meta", { {
"version", 2 } } },
4332 {
"tuning_profiles_impedance_geometric",
4333 { { {
"net_chain_bridge_prop_delay", 25 } }, { {
"net_chain_bridge_prop_delay", 0 } } } } } }
4340 for(
const auto& profile : doc[
"tuning_profiles"][
"tuning_profiles_impedance_geometric"] )
4341 BOOST_CHECK( !profile.contains(
"net_chain_bridge_prop_delay" ) );
4350 doc[
"net_settings"][
"net_chain_classes"] = { {
"clock",
"Fast" } };
4353 BOOST_CHECK( !doc[
"net_settings"].contains(
"net_chain_classes" ) );
4358 doc[
"net_settings"][
"net_chain_classes"] = nlohmann::json::object();
4377 const wxString
name = wxString::FromUTF8( vocabulary->
m_functions[i] );
4380 [&](
const char* aBreak )
4382 return name == aBreak;
4386 const wxString rule = wxT(
"(version 1)(rule \"f\" (condition \"A." ) +
name
4387 + wxT(
"('x')\") (constraint clearance (min 0.2mm)))" );
4390 target.m_id +
" dropped a rule calling " +
name );
4396 const wxString rule = wxT(
"(version 1)(rule \"p\" (condition \"A." ) +
name
4397 + wxT(
" == 1\") (constraint clearance (min 0.2mm)))" );
4400 target.m_id +
" dropped a rule reading " +
name );
4412 target.m_name +
" has no entry in include/drc_rules_release_vocabulary.h" );
4423 for(
const wxString& property : { wxT(
"A.Priority > 1" ), wxT(
"A.Hatch_Orientation == 0" ),
4424 wxT(
"A.Line_Color == 'red'" ) } )
4427 + wxT(
"\") (constraint clearance (min 0.2mm)))" ),
4429 BOOST_CHECK_MESSAGE(
result.m_dropped.size() == 1, target.m_id +
" kept " + property );
4432 const auto kept =
FilterDrcRulesForTarget( wxT(
"(version 1)(rule \"enum\" (condition \"A.Pad_Type == 'PTH'\") "
4433 "(constraint clearance (min 0.2mm)))" ),
4446 wxT(
"(version 1)(rule \"spaced\" (constraint clearance (min 0.2 mm) (opt 0.3 mil) (max 1 in)))" ),
4448 BOOST_CHECK_MESSAGE( kept.m_dropped.empty(), target.m_id +
" dropped a rule with a spaced unit" );
4452 wxT(
"(version 1)(rule \"delay\" (constraint skew (max 5 ps)))" ), target );
4453 BOOST_CHECK_EQUAL( dropped.m_dropped.size(), target.m_id == wxT(
"9.0" ) ? 1 : 0 );
4463 const bool old = target.m_id == wxT(
"9.0" );
4466 wxT(
"(version 1)(rule \"a\" (constraint track_angle (max 45deg)))" ), target );
4472 for(
const wxString& rule : { wxT(
"(rule \"v\" (constraint clearance (min ${GAP})))" ),
4473 wxT(
"(rule \"c\" (condition \"A.NetName == '${NET}'\") "
4474 "(constraint clearance (min 0.2mm)))" ) } )
4485 for(
const wxString& expression : { wxT(
"A.hasExactNetclass('x')" ), wxT(
"A.Column_Width == 1" ),
4486 wxT(
"A.Visible == 1" ) } )
4488 const wxString rule = wxT(
"(version 1)(rule \"r\" (condition \"" ) + expression
4489 + wxT(
"\") (constraint clearance (min 0.2mm)))" );
4491 "9.0 kept " + expression +
" which not every 9.0.x release reads" );
4494 for(
const wxString& expression : { wxT(
"A.intersectsKeepout('x')" ), wxT(
"A.Origin_X == 1" ) } )
4496 const wxString rule = wxT(
"(version 1)(rule \"r\" (condition \"" ) + expression
4497 + wxT(
"\") (constraint clearance (min 0.2mm)))" );
4499 "10.0 kept " + expression +
" which not every 10.0.x release reads" );
4509 for(
const wxString& layer : { wxT(
"MyCustomLayer" ), wxT(
"F.Cu" ), wxT(
"\"In1.Cu\"" ), wxT(
"outer" ) } )
4512 + wxT(
") (constraint clearance (min 0.2mm)))" ),
4514 BOOST_CHECK_MESSAGE(
result.m_dropped.empty(), target.m_id +
" dropped a rule on layer " + layer );
4524 unknown.m_name = wxT(
"KiCad 0.0" );
4538 for(
const wxString& keyword : { wxT(
"hole_aspect_ratio" ), wxT(
"microvia_stack_depth" ) } )
4540 const wxString rule =
"(version 1)(rule \"new\" (constraint " + keyword +
" (max 2)))";
4546 for(
const wxString& call :
4547 { wxT(
"A.intersectsKeepout('x')" ), wxT(
"A.intersectsArea('x')" ), wxT(
"A.isStackedVia()" ),
4548 wxT(
"A.ISSTACKEDVIA()" ), wxT(
"A.customProperty('Owner') == 'Team'" ),
4549 wxT(
"A.hasCustomProperty('Owner')" ) } )
4551 for(
const wxString& expression : { wxT(
"condition" ), wxT(
"assertion" ) } )
4553 const wxString rule =
4554 expression == wxT(
"condition" )
4555 ?
"(rule \"new\" (condition \"" + call +
"\") (constraint clearance (min 0.2mm)))"
4556 :
"(rule \"new\" (constraint assertion \"" + call +
"\"))";
4563 const wxString kept = wxT(
"(rule \"customProperty\" (condition \"A.NetName == 'isStackedVia()'\") "
4564 "(constraint clearance (min 0.2mm)))\n"
4565 "(rule \"literal\" (condition \"A.NetName == 'intersectsArea()'\") "
4566 "(constraint clearance (min 0.2mm)))\n"
4567 "(rule \"uppercase literal\" (condition \"A.NetName == 'ISSTACKEDVIA()'\") "
4568 "(constraint clearance (min 0.2mm)))\n"
4569 "(rule \"legacy\" (condition \"A.insideArea('x')\") "
4570 "(constraint clearance (min 0.2mm)))\n"
4571 "(rule \"position\" (condition \"A.Start_X > 1mm && A.Start_Y > 1mm\") "
4572 "(constraint clearance (min 0.2mm)))" );
4585 for(
const wxString& kind : { wxT(
"condition" ), wxT(
"assertion" ) } )
4587 const wxString expression = wxT(
"A.Parent == A.Parent && A.NetName != 'A.parent.Reference'" );
4588 const wxString body =
4589 kind == wxT(
"condition" )
4590 ? wxT(
"(condition \"" ) + expression + wxT(
"\") (constraint clearance (min 0.2mm))" )
4591 : wxT(
"(constraint assertion \"" ) + expression + wxT(
"\")" );
4598 for(
const wxString& property :
4599 { wxT(
"A.Start_Shape" ), wxT(
"A.start_shape" ), wxT(
"B.End_Width" ), wxT(
"AB.Scale_X" ),
4600 wxT(
"A.parent.Reference" ), wxT(
"A . PARENT . Reference" ), wxT(
"A.Major_Radius" ),
4601 wxT(
"A.Exclude_From_Simulation" ), wxT(
"A.Automatically_Update_Net" ), wxT(
"A.Grid_Type" ) } )
4603 for(
const wxString& kind : { wxT(
"condition" ), wxT(
"assertion" ) } )
4605 const wxString expression =
4606 property + (
property.Contains( wxT(
"Reference" ) ) ? wxT(
" == 'U1'" ) : wxT(
" == 1" ) );
4607 const wxString body =
4608 kind == wxT(
"condition" )
4609 ? wxT(
"(condition \"" ) + expression + wxT(
"\") (constraint clearance (min 0.2mm))" )
4610 : wxT(
"(constraint assertion \"" ) + expression + wxT(
"\")" );
4618 for(
const wxString& property :
4619 { wxT(
"A.Corner_Radius" ), wxT(
"A.Auto_Thickness" ), wxT(
"A.Target_Delay" ) } )
4621 for(
const wxString& kind : { wxT(
"condition" ), wxT(
"assertion" ) } )
4623 const wxString expression =
property + wxT(
" == 1" );
4624 const wxString body =
4625 kind == wxT(
"condition" )
4626 ? wxT(
"(condition \"" ) + expression + wxT(
"\") (constraint clearance (min 0.2mm))" )
4627 : wxT(
"(constraint assertion \"" ) + expression + wxT(
"\")" );
4635 const wxString kept = wxT(
"(rule \"literal\" (condition \"A.NetName == 'A.Start_Shape' && A.Start_X > 1mm "
4636 "&& A.End_Y > 1mm && A.Radius > 1mm\") (constraint clearance (min 0.2mm)))" );
constexpr EDA_IU_SCALE pcbIUScale
COMPATIBILITY_REPORT ClassifyBoardForDowngrade(const BOARD *aBoard, const DOWNGRADE_TARGET &aTarget, bool aDropInsteadOfApproximate)
Report what a board would lose if exported to an older KiCad.
void SaveFootprintForTarget(FOOTPRINT *aFootprint, const wxString &aPath, const DOWNGRADE_TARGET &aTarget)
Save a single .kicad_mod footprint file for the target.
int BoardDowngradeCoveredVersion()
The format the denylist was generated against. A format bump forces a review.
void SaveBoardForTarget(BOARD *aBoard, const wxString &aPath, const DOWNGRADE_TARGET &aTarget)
Save a board stamped for the target, using the writer for that version.
void FlattenBoardVariant(BOARD *aBoard, const wxString &aVariantName)
Bake a variant's overrides into the base footprint attributes.
bool ExportBoardToOlderVersion(const wxString &aSrcFile, const wxString &aDestFile, const DOWNGRADE_TARGET &aTarget, COMPATIBILITY_REPORT &aReport, wxString *aUnsupportedToken, const wxString &aVariant, bool aDropInsteadOfApproximate)
Load a board, downgrade the copy, and write it stamped for the target.
DOWNGRADE_FILE_RESULT DowngradeFootprintFileToTemp(const wxString &aSrcFile, const wxString &aTmpFile, const DOWNGRADE_TARGET &aTarget, bool aDropInsteadOfApproximate)
Load one .kicad_mod, classify it against the rule table, and write the downgraded copy to aTmpFile.
void DowngradeBoardInPlace(BOARD *aBoard, const DOWNGRADE_TARGET &aTarget, bool aDropInsteadOfApproximate)
Approximate or remove, in place, what the target cannot represent.
void DowngradeFootprintInPlace(FOOTPRINT *aFootprint, const DOWNGRADE_TARGET &aTarget, bool aDropInsteadOfApproximate)
Footprint-scoped downgrade for standalone .kicad_mod files the board pass never sees.
wxString FindUnsupportedBoardToken(const wxString &aSerialized, const DOWNGRADE_TARGET &aTarget)
Scan serialized board text for tokens the target cannot parse.
@ BS_ITEM_TYPE_DIELECTRIC
int GetLegacyPPI() const
Recompute the PPI the way it was computed before the pixels/cm truncation fix.
wxString GetNetname() const
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
std::map< PCB_LAYER_ID, ZONE_LAYER_PROPERTIES > m_ZoneLayerProperties
DRILL_SYMBOL_PROFILE & GetDrillSymbolProfile()
BOARD_STACKUP & GetStackupDescriptor()
Abstract interface for BOARD_ITEMs capable of storing other items inside.
virtual void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false)=0
Adds an item to the container.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual bool IsKnockout() const
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual void SetIsKnockout(bool aKnockout)
Manage one layer needed to make a physical board.
DIELECTRIC_MODEL GetDielectricModel(int aDielectricSubLayer=0) const
void SetDielectricModel(DIELECTRIC_MODEL aModel, int aDielectricSubLayer=0)
void Add(BOARD_STACKUP_ITEM *aItem)
Add a new item in stackup layer.
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.
const GENERATORS & Generators() const
void SetProperties(const std::map< wxString, wxString > &aProps)
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
TITLE_BLOCK & GetTitleBlock()
const TRACKS & Tracks() const
const CONSTRAINTS & Constraints() const
Geometric constraints (#2329) owned by this board.
void SetCopperLayerCount(int aCount)
void SetProject(PROJECT *aProject, bool aReferenceOnly=false)
Link a board to a given project.
wxString GroupsSanityCheck(bool repair=false)
Consistency check of internal m_groups structure.
void SetEnabledLayers(const LSET &aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
BOARD_DESIGN_SETTINGS & GetDesignSettings()
const DRAWINGS & Drawings() const
What an export to a given target will keep, approximate, drop, or block.
bool IsLossy() const
True if anything is approximated or dropped. This is what triggers the lossy warning.
bool IsBlocked() const
True if some feature makes the target impossible. The user cannot export anyway.
int Count(DOWNGRADE_BUCKET aBucket) const
const std::vector< COMPAT_ENTRY > & Entries() const
Stage related design and library files together, retaining originals until every write is ready.
const wxString & GetRecoveryError() const
Recovery details are nonempty only if restoring an original or removing a new output failed.
wxString Commit()
Replace all destinations, rolling back earlier replacements if a rename fails.
wxString Stage(const wxString &aDestination)
Return an exclusively-created sibling staging file, or empty if it cannot be created.
void Discard(const wxString &aTemporary)
Forget a skipped conversion without exposing its empty staging file as an output.
void Parse(std::vector< std::shared_ptr< DRC_RULE > > &aRules, REPORTER *aReporter)
Grouping rules and symbol assignments, shared by reference so a chart and its map can never disagree ...
void SetName(const wxString &aName)
A set of EDA_ITEMs (i.e., without duplicates).
std::unordered_set< EDA_ITEM * > & GetItems()
void AddItem(EDA_ITEM *aItem)
Add item to group.
void SetName(const wxString &aName)
A base class for most all the KiCad significant classes used in schematics and boards.
virtual EDA_GROUP * GetParentGroup() const
KICAD_T Type() const
Returns the type of object.
bool HasCustomProperties() const
void SetCustomProperty(const wxString &aKey, const wxString &aValue)
void SetEndEnding(const LINE_ENDING &aEnding)
FILL_T GetFillMode() const
void TransformWithLineEndingsToPolygon(SHAPE_POLY_SET &aBuffer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const
Convert the shape body shortened for line endings plus line-ending geometry to polygons.
void SetLineStyle(const LINE_STYLE aStyle)
SHAPE_POLY_SET & GetPolyShape()
void SetEndEndingStyle(LINE_ENDING_STYLE aStyle)
LINE_STYLE GetLineStyle() const
LINE_ENDING_STYLE GetEndEndingStyle() const
int GetCornerRadius() const
void SetFillMode(FILL_T aFill)
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
virtual const wxString & GetText() const
Return the string associated with the text object.
KIFONT::FONT * GetFont() const
void SetBold(bool aBold)
Set the text to be bold - this will also update the font if needed.
virtual int GetTextThickness() const
virtual void SetText(const wxString &aText)
void SetFont(KIFONT::FONT *aFont)
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
virtual bool IsOutline() const
wxString AsString() const
std::string AsStdString() const
const std::filesystem::path & Path() const
Get the path to the temporary directory as a std::filesystem::path.
A logical library item identifier and consists of various portions much like a URI.
Decorative shape (arrowhead, circle, square) at the start or end of a graphic line,...
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Handle the data for a net.
void SetParent(BOARD *aParent)
A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of the word.
MASK_LAYER_PROPS & FrontOuterLayers()
void SetUnconnectedLayerMode(UNCONNECTED_LAYER_MODE aMode)
UNCONNECTED_LAYER_MODE UnconnectedLayerMode() const
@ CUSTOM
Shapes can be defined on arbitrary layers.
MASK_LAYER_PROPS & BackOuterLayers()
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
VECTOR2I GetPosition() const override
double GetRoundRectRadiusRatio(PCB_LAYER_ID aLayer) const
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
VECTOR2I GetSize(PCB_LAYER_ID aLayer) const
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
const VECTOR2I & GetMid() const
wxString GetShownText(RESOLUTION_CONTEXT aContext) const
void SetShowText(bool aShow)
void SetBarcodeText(const wxString &aText)
void SetWidth(int aWidth)
void SetBarcodeKind(BARCODE_T aKind)
void SetHeight(int aHeight)
void SetLayer(PCB_LAYER_ID aLayer) override
Set the drawing layer for the barcode and its text.
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE, bool ignoreLineWidth=false) const override
Convert the barcode (text + symbol shapes) to polygonal geometry suitable for filling/collision tests...
A geometric constraint between board items (issue #2329).
void AddMember(const KIID &aItem, CONSTRAINT_ANCHOR aAnchor=CONSTRAINT_ANCHOR::WHOLE, int aIndex=-1)
virtual void SetEnd(const VECTOR2I &aPoint)
virtual void SetStart(const VECTOR2I &aPoint)
void ChangeOverrideText(const wxString &aValue)
For better understanding of the points that make a dimension:
void SetHeight(int aHeight)
Set the distance from the feature points to the crossbar line.
A drill chart placed on the board, kept in step with the holes.
Turns on drill symbols at the holes, for one layer.
wxString GetShownText(RESOLUTION_CONTEXT aContext, int aDepth=0) const override
Return the string actually shown after processing of the base text.
PCB_GENERATOR * DeepClone() const
A set of BOARD_ITEMs (i.e., without duplicates).
A PCB_IO derivation for saving and loading Pcbnew s-expression formatted files.
std::unique_ptr< FOOTPRINT > ImportFootprint(const wxString &aFootprintPath, wxString &aFootprintNameOut, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Load a single footprint from aFootprintPath and put its name in aFootprintNameOut.
void FootprintSave(const wxString &aLibraryPath, const FOOTPRINT *aFootprint, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Write aFootprint to an existing library located at aLibraryPath.
void SaveBoard(const wxString &aFileName, BOARD &aBoard, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Write aBoard to a storage file in a format that this PCB_IO implementation knows about or it can be u...
void FormatBoardToFormatter(OUTPUTFORMATTER *aOut, BOARD *aBoard, const std::map< std::string, UTF8 > *aProperties=nullptr)
Serialize a BOARD to an OUTPUTFORMATTER without file I/O or Prettify.
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...
Object to handle a bitmap image that can be inserted in a PCB.
REFERENCE_IMAGE & GetReferenceImage()
void SetEllipseCenter(const VECTOR2I &aPt) override
void SetCornerRadius(int aCornerRadius) override
void SetWidth(int aWidth) override
void SetEllipseStartAngle(const EDA_ANGLE &aA) override
void SetEllipseEndAngle(const EDA_ANGLE &aA) override
void SetEnd(const VECTOR2I &aEnd) override
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void SetEllipseMinorRadius(int aR) override
void SetStart(const VECTOR2I &aStart) override
void SetEllipseMajorRadius(int aR) override
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
void AddCell(PCB_TABLECELL *aCell)
void SetColCount(int aCount)
void SetTextThickness(int aWidth) override
The TextThickness is that set by the user.
VECTOR2I GetPosition() const override
int GetTextThickness() const override
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
const VECTOR2I & GetStart() const
const VECTOR2I & GetEnd() const
virtual int GetWidth() const
const STRING_ANY_MAP GetProperties() const override
PCB_TUNING_PATTERN(BOARD_ITEM *aParent=nullptr, PCB_LAYER_ID aLayer=F_Cu, LENGTH_TUNING_MODE aMode=LENGTH_TUNING_MODE::SINGLE)
PNS::MEANDER_SETTINGS & GetSettings()
A microvia stack: several single hop microvias, plus connecting traces for staggered stacks,...
VIA_STACK_STYLE GetStyle() const
PCB_LAYER_ID GetStartLayer() const
PCB_LAYER_ID GetEndLayer() const
wxString GetGeneratorType() const override
PCB_VIA_STITCH(BOARD_ITEM *aParent=nullptr)
int GetGuardedNetCode() const
Net being guarded in GUARD mode.
const PADSTACK & Padstack() const
void SetViaType(VIATYPE aViaType)
VIATYPE GetViaType() const
bool m_isTimeDomain
Calculate tuning in the time domain.
A REFERENCE_IMAGE is a wrapper around a BITMAP_IMAGE that is displayed in an editor as a reference fo...
bool ReadImageFile(const wxString &aFullFilename)
Read and store an image file.
const BITMAP_BASE & GetImage() const
Get the underlying image.
double GetImageScale() const
void SetImageScale(double aScale)
Set the image "zoom" value.
bool LoadProject(const wxString &aFullPath, bool aSetActive=true)
Load a project or sets up a new project with a specified path.
PROJECT * GetProject(const wxString &aFullPath) const
Retrieve a loaded project by name.
double Area(bool aAbsolute=true) const
Return the area of this chain.
Represent a set of closed polygons.
double Area()
Return the area of this poly set.
int HoleCount(int aOutline) const
Returns the number of holes in a given outline.
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)
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
const SHAPE_LINE_CHAIN & CHole(int aOutline, int aHole) const
int OutlineCount() const
Return the number of outlines in the set.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
A name/value tuple with unique names and wxAny values.
bool get_to(const std::string &aKey, T &aVar) const
void set(const std::string &aKey, const T &aVar)
void SetComment(int aIdx, const wxString &aComment)
void SetTitle(const wxString &aTitle)
const wxString & GetTitle() const
A wrapper for reporting to a wxString object.
Handle a list of polygons defining a copper zone.
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
bool GetDoNotAllowVias() const
bool AppendCorner(const VECTOR2I &aPosition, int aHoleIdx, bool aAllowDuplication=false)
Add a new corner to the zone outline (to the main outline or a hole)
ZONE_LAYER_PROPERTIES & LayerProperties(PCB_LAYER_ID aLayer)
wxString GetPlacementAreaSource() const
std::shared_ptr< SHAPE_POLY_SET > GetFilledPolysList(PCB_LAYER_ID aLayer) const
bool GetDoNotAllowPads() const
PLACEMENT_SOURCE_T GetPlacementAreaSourceType() const
bool GetDoNotAllowTracks() const
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
SHAPE_POLY_SET * Outline()
bool IsIsland(PCB_LAYER_ID aLayer, int aPolyIdx) const
Check if a given filled polygon is an insulated island.
bool IsCopperThieving() const
const wxString & GetZoneName() const
SHAPE_POLY_SET GetBoardOutline() const
void SetFillMode(ZONE_FILL_MODE aFillMode)
void SetLayerSet(const LSET &aLayerSet) override
bool GetPlacementAreaEnabled() const
bool GetDoNotAllowFootprints() const
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
bool GetDoNotAllowZoneFills() const
DOWNGRADE_BUCKET
What happens to a feature when we export to an older KiCad.
@ BLOCK
Cannot be represented at all, export to this target is not possible.
@ LOWER
Approximated down to a simpler equivalent.
@ DROP
No equivalent, left out.
static bool empty(const wxTextEntryBase *aCtrl)
wxString DowngradeLibraryFilesInPlace(const wxString &aDir, const wxString &aGlob, int aStampVersion, const std::function< wxString(const wxString &)> &aFindForbidden, const std::function< DOWNGRADE_FILE_RESULT(const wxString &, const wxString &)> &aConvert, DOWNGRADE_FILE_TRANSACTION *aTransaction=nullptr, wxString *aRecoveryError=nullptr)
Downgrade every library file matching aGlob under aDir in place.
bool IsDowngradeDesignFile(const wxString &aPath)
Files the project export carries over.
DOWNGRADE_FILE_RESULT
What a per-file converter did with one library file.
@ REFUSED
The target cannot represent this file.
@ CONVERTED
The temp file holds the downgraded copy.
const std::vector< DOWNGRADE_TARGET > & GetDowngradeTargets()
Supported downgrade targets, newest first.
constexpr const char * DRC_RULE_SEMANTIC_BREAKS[]
A function a release parses but answers differently, which the vocabulary cannot say.
const DRC_RULE_VOCABULARY * FindDrcRuleVocabulary(const DOWNGRADE_TARGET &aTarget)
The vocabulary a target release could parse, generated from its release tags by tools/generate_drc_ru...
DRC_RULES_FILTER_RESULT FilterDrcRulesForTarget(const wxString &aRulesText, const DOWNGRADE_TARGET &aTarget)
Filter a .kicad_dru file for the target.
static constexpr EDA_ANGLE ANGLE_0
static constexpr EDA_ANGLE ANGLE_90
static constexpr EDA_ANGLE ANGLE_360
@ FILLED_SHAPE
Fill with object color.
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
PCB_LAYER_ID
A quick note on layer IDs:
Test utilities for timestamps.
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
std::string ReadGoldenText(const std::string &aPath)
wxMemoryBuffer MakePngWithFractionalPixelsPerCm()
A tiny PNG whose embedded resolution gives a fractional pixels/cm, so the legacy truncating PPI diffe...
double SerializedImageScale(const std::string &aContent, const std::string &aUuid)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ PTH
Plated through hole pad.
@ PRESSFIT
a PTH with a hole diameter with tight tolerances for press fit pin
@ NONE
no special fabrication property
@ REMOVE_EXCEPT_START_AND_END
BARCODE class definition.
@ HORIZONTAL
A segment (or two points) is horizontal.
Class to handle a set of BOARD_ITEMs.
#define SEXPR_BOARD_FILE_VERSION
Current s-expression file format version. 2 was the last legacy format version.
@ STITCH
Fill the outline with vias with a pattern.
@ GUARD
Place vias to guard a net contained within.
void DowngradeProjectFileJson(nlohmann::json &aDoc, const DOWNGRADE_TARGET &aTarget, COMPATIBILITY_REPORT &aReport)
Migrate a .kicad_pro document down to what the target release expects.
One line in the compatibility report.
An older KiCad release we can export a project back to.
wxString m_text
The filtered rules file text.
wxString m_error
Invalid source syntax, do not write m_text.
std::vector< wxString > m_dropped
Names of the rules the target cannot parse.
Everything a rules file could name in one release.
const char *const * m_properties
const char *const * m_functions
std::optional< bool > is_capped
True if the drill hole should be capped.
std::optional< bool > is_filled
True if the drill hole should be filled completely.
std::optional< bool > has_covering
True if the pad on this side should have covering.
std::optional< bool > has_plugging
True if the drill hole should be plugged on this side.
std::optional< VECTOR2I > hatching_offset
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_CASE(EmptyBoardIsClean)
static size_t ParsedDrcRuleCount(const wxString &aText, const wxString &aSource)
static void checkFeature(const COMPATIBILITY_REPORT &aReport, const wxString &aName, DOWNGRADE_BUCKET aBucket, int aCount)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_CHECK(res.column_datatype(0)==SQL_NUMERIC||res.column_datatype(0)==SQL_DECIMAL)
BOOST_REQUIRE_EQUAL(rows.size(), 1)
BOOST_CHECK_EQUAL(std::any_cast< std::string >(rows[0].at("val")), "12345678901234567.89")
BOOST_REQUIRE(res.columns()==1)
BOOST_AUTO_TEST_SUITE_END()
IbisParser parser & reporter
VECTOR3I expected(15, 30, 45)
static const DOWNGRADE_TARGET & kicad10
static const DOWNGRADE_TARGET & kicad9
BOOST_TEST_CONTEXT("Test Clearance")
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
wxString result
Test unit parsing edge cases and error handling.
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
VECTOR2< int32_t > VECTOR2I
Class ZONE_SETTINGS used to handle zones parameters in dialogs.