You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1271 lines
52 KiB

8 years ago
14 years ago
4 years ago
5 years ago
14 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you may find one here:
  18. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  19. * or you may search the http://www.gnu.org website for the version 2 license,
  20. * or you may write to the Free Software Foundation, Inc.,
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. #include <pcb_dimension.h>
  24. #include <pcb_track.h>
  25. #include <layer_ids.h>
  26. #include <kiface_base.h>
  27. #include <pad.h>
  28. #include <board_design_settings.h>
  29. #include <drc/drc_item.h>
  30. #include <drc/drc_engine.h>
  31. #include <settings/json_settings_internals.h>
  32. #include <settings/parameters.h>
  33. #include <project/project_file.h>
  34. #include <advanced_config.h>
  35. #include <pcbnew.h>
  36. const int bdsSchemaVersion = 2;
  37. BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std::string& aPath ) :
  38. NESTED_SETTINGS( "board_design_settings", bdsSchemaVersion, aParent, aPath )
  39. {
  40. // We want to leave alone parameters that aren't found in the project JSON as they may be
  41. // initialized by the board file parser before NESTED_SETTINGS::LoadFromFile is called.
  42. m_resetParamsIfMissing = false;
  43. // Create a default NET_SETTINGS so that things don't break horribly if there's no project
  44. // loaded. This also is used during file load for legacy boards that have netclasses stored
  45. // in the file. After load, this information will be moved to the project and the pointer
  46. // updated.
  47. m_NetSettings = std::make_shared<NET_SETTINGS>( nullptr, "" );
  48. m_HasStackup = false; // no stackup defined by default
  49. m_Pad_Master = std::make_unique<PAD>( nullptr );
  50. LSET all_set = LSET().set();
  51. m_enabledLayers = all_set; // All layers enabled at first.
  52. // SetCopperLayerCount() will adjust this.
  53. SetCopperLayerCount( 2 ); // Default design is a double sided board
  54. m_CurrentViaType = VIATYPE::THROUGH;
  55. // if true, when creating a new track starting on an existing track, use this track width
  56. m_UseConnectedTrackWidth = false;
  57. m_TempOverrideTrackWidth = false;
  58. // First is always the reference designator
  59. m_DefaultFPTextItems.emplace_back( wxT( "REF**" ), true, F_SilkS );
  60. // Second is always the value
  61. m_DefaultFPTextItems.emplace_back( wxT( "" ), true, F_Fab );
  62. // Any following ones are freebies
  63. m_DefaultFPTextItems.emplace_back( wxT( "${REFERENCE}" ), true, F_Fab );
  64. m_LineThickness[ LAYER_CLASS_SILK ] = pcbIUScale.mmToIU( DEFAULT_SILK_LINE_WIDTH );
  65. m_TextSize[ LAYER_CLASS_SILK ] = VECTOR2I( pcbIUScale.mmToIU( DEFAULT_SILK_TEXT_SIZE ),
  66. pcbIUScale.mmToIU( DEFAULT_SILK_TEXT_SIZE ) );
  67. m_TextThickness[ LAYER_CLASS_SILK ] = pcbIUScale.mmToIU( DEFAULT_SILK_TEXT_WIDTH );
  68. m_TextItalic[ LAYER_CLASS_SILK ] = false;
  69. m_TextUpright[ LAYER_CLASS_SILK ] = false;
  70. m_LineThickness[ LAYER_CLASS_COPPER ] = pcbIUScale.mmToIU( DEFAULT_COPPER_LINE_WIDTH );
  71. m_TextSize[ LAYER_CLASS_COPPER ] = VECTOR2I( pcbIUScale.mmToIU( DEFAULT_COPPER_TEXT_SIZE ),
  72. pcbIUScale.mmToIU( DEFAULT_COPPER_TEXT_SIZE ) );
  73. m_TextThickness[ LAYER_CLASS_COPPER ] = pcbIUScale.mmToIU( DEFAULT_COPPER_TEXT_WIDTH );
  74. m_TextItalic[ LAYER_CLASS_COPPER ] = false;
  75. m_TextUpright[ LAYER_CLASS_COPPER ] = false;
  76. // Edges & Courtyards; text properties aren't used but better to have them holding
  77. // reasonable values than not.
  78. m_LineThickness[ LAYER_CLASS_EDGES ] = pcbIUScale.mmToIU( DEFAULT_EDGE_WIDTH );
  79. m_TextSize[ LAYER_CLASS_EDGES ] = VECTOR2I( pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE ),
  80. pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE ) );
  81. m_TextThickness[ LAYER_CLASS_EDGES ] = pcbIUScale.mmToIU( DEFAULT_TEXT_WIDTH );
  82. m_TextItalic[ LAYER_CLASS_EDGES ] = false;
  83. m_TextUpright[ LAYER_CLASS_EDGES ] = false;
  84. m_LineThickness[ LAYER_CLASS_COURTYARD ] = pcbIUScale.mmToIU( DEFAULT_COURTYARD_WIDTH );
  85. m_TextSize[ LAYER_CLASS_COURTYARD ] = VECTOR2I( pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE ),
  86. pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE ) );
  87. m_TextThickness[ LAYER_CLASS_COURTYARD ] = pcbIUScale.mmToIU( DEFAULT_TEXT_WIDTH );
  88. m_TextItalic[ LAYER_CLASS_COURTYARD ] = false;
  89. m_TextUpright[ LAYER_CLASS_COURTYARD ] = false;
  90. m_LineThickness[ LAYER_CLASS_FAB ] = pcbIUScale.mmToIU( DEFAULT_LINE_WIDTH );
  91. m_TextSize[LAYER_CLASS_FAB] = VECTOR2I( pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE ),
  92. pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE ) );
  93. m_TextThickness[ LAYER_CLASS_FAB ] = pcbIUScale.mmToIU( DEFAULT_TEXT_WIDTH );
  94. m_TextItalic[ LAYER_CLASS_FAB ] = false;
  95. m_TextUpright[ LAYER_CLASS_FAB ] = false;
  96. m_LineThickness[ LAYER_CLASS_OTHERS ] = pcbIUScale.mmToIU( DEFAULT_LINE_WIDTH );
  97. m_TextSize[ LAYER_CLASS_OTHERS ] = VECTOR2I( pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE ),
  98. pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE ) );
  99. m_TextThickness[ LAYER_CLASS_OTHERS ] = pcbIUScale.mmToIU( DEFAULT_TEXT_WIDTH );
  100. m_TextItalic[ LAYER_CLASS_OTHERS ] = false;
  101. m_TextUpright[ LAYER_CLASS_OTHERS ] = false;
  102. m_DimensionPrecision = 4;
  103. m_DimensionUnitsMode = DIM_UNITS_MODE::AUTOMATIC;
  104. m_DimensionUnitsFormat = DIM_UNITS_FORMAT::BARE_SUFFIX;
  105. m_DimensionSuppressZeroes = false;
  106. m_DimensionTextPosition = DIM_TEXT_POSITION::OUTSIDE;
  107. m_DimensionKeepTextAligned = true;
  108. m_DimensionArrowLength = pcbIUScale.MilsToIU( DEFAULT_DIMENSION_ARROW_LENGTH );
  109. m_DimensionExtensionOffset = pcbIUScale.mmToIU( DEFAULT_DIMENSION_EXTENSION_OFFSET );
  110. m_useCustomTrackVia = false;
  111. m_customTrackWidth = pcbIUScale.mmToIU( DEFAULT_CUSTOMTRACKWIDTH );
  112. m_customViaSize.m_Diameter = pcbIUScale.mmToIU( DEFAULT_VIASMINSIZE );
  113. m_customViaSize.m_Drill = pcbIUScale.mmToIU( DEFAULT_MINTHROUGHDRILL );
  114. m_useCustomDiffPair = false;
  115. m_customDiffPair.m_Width = pcbIUScale.mmToIU( DEFAULT_CUSTOMDPAIRWIDTH );
  116. m_customDiffPair.m_Gap = pcbIUScale.mmToIU( DEFAULT_CUSTOMDPAIRGAP );
  117. m_customDiffPair.m_ViaGap = pcbIUScale.mmToIU( DEFAULT_CUSTOMDPAIRVIAGAP );
  118. m_MinClearance = pcbIUScale.mmToIU( DEFAULT_MINCLEARANCE );
  119. m_MinConn = pcbIUScale.mmToIU( DEFAULT_MINCONNECTION );
  120. m_TrackMinWidth = pcbIUScale.mmToIU( DEFAULT_TRACKMINWIDTH );
  121. m_ViasMinAnnularWidth = pcbIUScale.mmToIU( DEFAULT_VIASMINSIZE - DEFAULT_MINTHROUGHDRILL ) / 2;
  122. m_ViasMinSize = pcbIUScale.mmToIU( DEFAULT_VIASMINSIZE );
  123. m_MinThroughDrill = pcbIUScale.mmToIU( DEFAULT_MINTHROUGHDRILL );
  124. m_MicroViasMinSize = pcbIUScale.mmToIU( DEFAULT_MICROVIASMINSIZE );
  125. m_MicroViasMinDrill = pcbIUScale.mmToIU( DEFAULT_MICROVIASMINDRILL );
  126. m_CopperEdgeClearance = pcbIUScale.mmToIU( DEFAULT_COPPEREDGECLEARANCE );
  127. m_HoleClearance = pcbIUScale.mmToIU( DEFAULT_HOLECLEARANCE );
  128. m_HoleToHoleMin = pcbIUScale.mmToIU( DEFAULT_HOLETOHOLEMIN );
  129. m_SilkClearance = pcbIUScale.mmToIU( DEFAULT_SILKCLEARANCE );
  130. m_MinResolvedSpokes = DEFAULT_MINRESOLVEDSPOKES;
  131. m_MinSilkTextHeight = pcbIUScale.mmToIU( DEFAULT_SILK_TEXT_SIZE * 0.8 );
  132. m_MinSilkTextThickness= pcbIUScale.mmToIU( DEFAULT_SILK_TEXT_WIDTH * 0.8 );
  133. for( int errorCode = DRCE_FIRST; errorCode <= DRCE_LAST; ++errorCode )
  134. m_DRCSeverities[ errorCode ] = RPT_SEVERITY_ERROR;
  135. m_DRCSeverities[ DRCE_DRILLED_HOLES_COLOCATED ] = RPT_SEVERITY_WARNING;
  136. m_DRCSeverities[ DRCE_MISSING_COURTYARD ] = RPT_SEVERITY_IGNORE;
  137. m_DRCSeverities[ DRCE_PTH_IN_COURTYARD ] = RPT_SEVERITY_IGNORE;
  138. m_DRCSeverities[ DRCE_NPTH_IN_COURTYARD ] = RPT_SEVERITY_IGNORE;
  139. m_DRCSeverities[ DRCE_DANGLING_TRACK ] = RPT_SEVERITY_WARNING;
  140. m_DRCSeverities[ DRCE_DANGLING_VIA ] = RPT_SEVERITY_WARNING;
  141. m_DRCSeverities[ DRCE_COPPER_SLIVER ] = RPT_SEVERITY_WARNING;
  142. m_DRCSeverities[ DRCE_ISOLATED_COPPER ] = RPT_SEVERITY_WARNING;
  143. m_DRCSeverities[ DRCE_PADSTACK ] = RPT_SEVERITY_WARNING;
  144. m_DRCSeverities[ DRCE_MISSING_FOOTPRINT ] = RPT_SEVERITY_WARNING;
  145. m_DRCSeverities[ DRCE_DUPLICATE_FOOTPRINT ] = RPT_SEVERITY_WARNING;
  146. m_DRCSeverities[ DRCE_EXTRA_FOOTPRINT ] = RPT_SEVERITY_WARNING;
  147. m_DRCSeverities[ DRCE_NET_CONFLICT ] = RPT_SEVERITY_WARNING;
  148. m_DRCSeverities[ DRCE_OVERLAPPING_SILK ] = RPT_SEVERITY_WARNING;
  149. m_DRCSeverities[ DRCE_SILK_CLEARANCE ] = RPT_SEVERITY_WARNING;
  150. m_DRCSeverities[ DRCE_SILK_EDGE_CLEARANCE ] = RPT_SEVERITY_WARNING;
  151. m_DRCSeverities[ DRCE_TEXT_HEIGHT ] = RPT_SEVERITY_WARNING;
  152. m_DRCSeverities[ DRCE_TEXT_THICKNESS ] = RPT_SEVERITY_WARNING;
  153. m_DRCSeverities[ DRCE_FOOTPRINT_TYPE_MISMATCH ] = RPT_SEVERITY_IGNORE;
  154. m_DRCSeverities[ DRCE_LIB_FOOTPRINT_ISSUES ] = RPT_SEVERITY_WARNING;
  155. m_DRCSeverities[ DRCE_LIB_FOOTPRINT_MISMATCH ] = RPT_SEVERITY_WARNING;
  156. m_DRCSeverities[ DRCE_CONNECTION_WIDTH ] = RPT_SEVERITY_WARNING;
  157. m_MaxError = ARC_HIGH_DEF;
  158. m_ZoneKeepExternalFillets = false;
  159. m_UseHeightForLengthCalcs = true;
  160. // Global mask margins:
  161. m_SolderMaskExpansion = pcbIUScale.mmToIU( DEFAULT_SOLDERMASK_EXPANSION );
  162. m_SolderMaskMinWidth = pcbIUScale.mmToIU( DEFAULT_SOLDERMASK_MIN_WIDTH );
  163. m_SolderMaskToCopperClearance = pcbIUScale.mmToIU( DEFAULT_SOLDERMASK_TO_COPPER_CLEARANCE );
  164. // Solder paste margin absolute value
  165. m_SolderPasteMargin = pcbIUScale.mmToIU( DEFAULT_SOLDERPASTE_CLEARANCE );
  166. // Solder paste margin as a ratio of pad size
  167. // The final margin is the sum of these 2 values
  168. // Usually < 0 because the mask is smaller than pad
  169. m_SolderPasteMarginRatio = DEFAULT_SOLDERPASTE_RATIO;
  170. m_AllowSoldermaskBridgesInFPs = false;
  171. // Layer thickness for 3D viewer
  172. m_boardThickness = pcbIUScale.mmToIU( DEFAULT_BOARD_THICKNESS_MM );
  173. m_viaSizeIndex = 0;
  174. m_trackWidthIndex = 0;
  175. m_diffPairIndex = 0;
  176. // Parameters stored in JSON in the project file
  177. // NOTE: Previously, BOARD_DESIGN_SETTINGS stored the basic board layer information (layer
  178. // names and enable/disable state) in the project file even though this information is also
  179. // stored in the board file. This was implemented for importing these settings from another
  180. // project. Going forward, the import feature will just import from other board files (since
  181. // we could have multi-board projects in the future anyway) so this functionality is dropped.
  182. m_params.emplace_back( new PARAM<bool>( "rules.use_height_for_length_calcs",
  183. &m_UseHeightForLengthCalcs, true ) );
  184. m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_clearance",
  185. &m_MinClearance, pcbIUScale.mmToIU( DEFAULT_MINCLEARANCE ),
  186. pcbIUScale.mmToIU( 0.01 ), pcbIUScale.mmToIU( 25.0 ), pcbIUScale.MM_PER_IU ) );
  187. m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_connection",
  188. &m_MinConn, pcbIUScale.mmToIU( DEFAULT_MINCONNECTION ),
  189. pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 100.0 ), pcbIUScale.MM_PER_IU ) );
  190. m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_track_width",
  191. &m_TrackMinWidth, pcbIUScale.mmToIU( DEFAULT_TRACKMINWIDTH ),
  192. pcbIUScale.mmToIU( 0.01 ), pcbIUScale.mmToIU( 25.0 ), pcbIUScale.MM_PER_IU ) );
  193. m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_via_annular_width",
  194. &m_ViasMinAnnularWidth, pcbIUScale.mmToIU( DEFAULT_VIASMINSIZE ), pcbIUScale.mmToIU( 0.01 ),
  195. pcbIUScale.mmToIU( 25.0 ), pcbIUScale.MM_PER_IU ) );
  196. m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_via_diameter",
  197. &m_ViasMinSize, pcbIUScale.mmToIU( DEFAULT_VIASMINSIZE ),
  198. pcbIUScale.mmToIU( 0.01 ), pcbIUScale.mmToIU( 25.0 ), pcbIUScale.MM_PER_IU ) );
  199. m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_through_hole_diameter",
  200. &m_MinThroughDrill, pcbIUScale.mmToIU( DEFAULT_MINTHROUGHDRILL ),
  201. pcbIUScale.mmToIU( 0.01 ), pcbIUScale.mmToIU( 25.0 ), pcbIUScale.MM_PER_IU ) );
  202. m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_microvia_diameter",
  203. &m_MicroViasMinSize, pcbIUScale.mmToIU( DEFAULT_MICROVIASMINSIZE ),
  204. pcbIUScale.mmToIU( 0.01 ), pcbIUScale.mmToIU( 10.0 ), pcbIUScale.MM_PER_IU ) );
  205. m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_microvia_drill",
  206. &m_MicroViasMinDrill, pcbIUScale.mmToIU( DEFAULT_MICROVIASMINDRILL ),
  207. pcbIUScale.mmToIU( 0.01 ), pcbIUScale.mmToIU( 10.0 ), pcbIUScale.MM_PER_IU ) );
  208. m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_hole_to_hole",
  209. &m_HoleToHoleMin, pcbIUScale.mmToIU( DEFAULT_HOLETOHOLEMIN ),
  210. pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 10.0 ), pcbIUScale.MM_PER_IU ) );
  211. m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_hole_clearance",
  212. &m_HoleClearance, pcbIUScale.mmToIU( DEFAULT_HOLECLEARANCE ),
  213. pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 100.0 ), pcbIUScale.MM_PER_IU ) );
  214. m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_silk_clearance",
  215. &m_SilkClearance, pcbIUScale.mmToIU( DEFAULT_SILKCLEARANCE ),
  216. pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 100.0 ), pcbIUScale.MM_PER_IU ) );
  217. // While the maximum *effective* value is 4, we've had users interpret this as the count on
  218. // all layers, and enter something like 10. They'll figure it out soon enough *unless* we
  219. // enforce a max of 4 (and therefore reset it back to the default of 2), at which point it
  220. // just looks buggy.
  221. m_params.emplace_back( new PARAM<int>( "rules.min_resolved_spokes",
  222. &m_MinResolvedSpokes, DEFAULT_MINRESOLVEDSPOKES, 0, 99 ) );
  223. m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_text_height",
  224. &m_MinSilkTextHeight, pcbIUScale.mmToIU( DEFAULT_SILK_TEXT_SIZE * 0.8 ),
  225. pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 100.0 ), pcbIUScale.MM_PER_IU ) );
  226. m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_text_thickness",
  227. &m_MinSilkTextThickness, pcbIUScale.mmToIU( DEFAULT_SILK_TEXT_WIDTH * 0.8 ),
  228. pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 25.0 ), pcbIUScale.MM_PER_IU ) );
  229. // Note: a clearance of -0.01 is a flag indicating we should use the legacy (pre-6.0) method
  230. // based on the edge cut thicknesses.
  231. m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_copper_edge_clearance",
  232. &m_CopperEdgeClearance, pcbIUScale.mmToIU( LEGACY_COPPEREDGECLEARANCE ),
  233. pcbIUScale.mmToIU( -0.01 ), pcbIUScale.mmToIU( 25.0 ), pcbIUScale.MM_PER_IU ) );
  234. m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "rule_severities",
  235. [&]() -> nlohmann::json
  236. {
  237. nlohmann::json ret = {};
  238. for( const RC_ITEM& item : DRC_ITEM::GetItemsWithSeverities() )
  239. {
  240. wxString name = item.GetSettingsKey();
  241. int code = item.GetErrorCode();
  242. if( name.IsEmpty() || m_DRCSeverities.count( code ) == 0 )
  243. continue;
  244. ret[std::string( name.ToUTF8() )] = SeverityToString( m_DRCSeverities[code] );
  245. }
  246. return ret;
  247. },
  248. [&]( const nlohmann::json& aJson )
  249. {
  250. if( !aJson.is_object() )
  251. return;
  252. for( const RC_ITEM& item : DRC_ITEM::GetItemsWithSeverities() )
  253. {
  254. wxString name = item.GetSettingsKey();
  255. std::string key( name.ToUTF8() );
  256. if( aJson.contains( key ) )
  257. m_DRCSeverities[item.GetErrorCode()] = SeverityFromString( aJson[key] );
  258. }
  259. }, {} ) );
  260. m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "drc_exclusions",
  261. [&]() -> nlohmann::json
  262. {
  263. nlohmann::json js = nlohmann::json::array();
  264. for( const auto& entry : m_DrcExclusions )
  265. js.push_back( entry );
  266. return js;
  267. },
  268. [&]( const nlohmann::json& aObj )
  269. {
  270. m_DrcExclusions.clear();
  271. if( !aObj.is_array() )
  272. return;
  273. for( const nlohmann::json& entry : aObj )
  274. {
  275. if( entry.empty() )
  276. continue;
  277. m_DrcExclusions.insert( entry.get<wxString>() );
  278. }
  279. },
  280. {} ) );
  281. m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "track_widths",
  282. [&]() -> nlohmann::json
  283. {
  284. nlohmann::json js = nlohmann::json::array();
  285. for( const int& width : m_TrackWidthList )
  286. js.push_back( pcbIUScale.IUTomm( width ) );
  287. return js;
  288. },
  289. [&]( const nlohmann::json& aJson )
  290. {
  291. if( !aJson.is_array() )
  292. return;
  293. m_TrackWidthList.clear();
  294. for( const nlohmann::json& entry : aJson )
  295. {
  296. if( entry.empty() )
  297. continue;
  298. m_TrackWidthList.emplace_back( pcbIUScale.mmToIU( entry.get<double>() ) );
  299. }
  300. },
  301. {} ) );
  302. m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "via_dimensions",
  303. [&]() -> nlohmann::json
  304. {
  305. nlohmann::json js = nlohmann::json::array();
  306. for( const auto& via : m_ViasDimensionsList )
  307. {
  308. nlohmann::json entry = {};
  309. entry["diameter"] = pcbIUScale.IUTomm( via.m_Diameter );
  310. entry["drill"] = pcbIUScale.IUTomm( via.m_Drill );
  311. js.push_back( entry );
  312. }
  313. return js;
  314. },
  315. [&]( const nlohmann::json& aObj )
  316. {
  317. if( !aObj.is_array() )
  318. return;
  319. m_ViasDimensionsList.clear();
  320. for( const nlohmann::json& entry : aObj )
  321. {
  322. if( entry.empty() || !entry.is_object() )
  323. continue;
  324. if( !entry.contains( "diameter" ) || !entry.contains( "drill" ) )
  325. continue;
  326. int diameter = pcbIUScale.mmToIU( entry["diameter"].get<double>() );
  327. int drill = pcbIUScale.mmToIU( entry["drill"].get<double>() );
  328. m_ViasDimensionsList.emplace_back( VIA_DIMENSION( diameter, drill ) );
  329. }
  330. },
  331. {} ) );
  332. m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "diff_pair_dimensions",
  333. [&]() -> nlohmann::json
  334. {
  335. nlohmann::json js = nlohmann::json::array();
  336. for( const auto& pair : m_DiffPairDimensionsList )
  337. {
  338. nlohmann::json entry = {};
  339. entry["width"] = pcbIUScale.IUTomm( pair.m_Width );
  340. entry["gap"] = pcbIUScale.IUTomm( pair.m_Gap );
  341. entry["via_gap"] = pcbIUScale.IUTomm( pair.m_ViaGap );
  342. js.push_back( entry );
  343. }
  344. return js;
  345. },
  346. [&]( const nlohmann::json& aObj )
  347. {
  348. if( !aObj.is_array() )
  349. return;
  350. m_DiffPairDimensionsList.clear();
  351. for( const nlohmann::json& entry : aObj )
  352. {
  353. if( entry.empty() || !entry.is_object() )
  354. continue;
  355. if( !entry.contains( "width" ) || !entry.contains( "gap" )
  356. || !entry.contains( "via_gap" ) )
  357. continue;
  358. int width = pcbIUScale.mmToIU( entry["width"].get<double>() );
  359. int gap = pcbIUScale.mmToIU( entry["gap"].get<double>() );
  360. int via_gap = pcbIUScale.mmToIU( entry["via_gap"].get<double>() );
  361. m_DiffPairDimensionsList.emplace_back(
  362. DIFF_PAIR_DIMENSION( width, gap, via_gap ) );
  363. }
  364. },
  365. {} ) );
  366. // Handle options for teardrops (targets and some others):
  367. m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "teardrop_options",
  368. [&]() -> nlohmann::json
  369. {
  370. nlohmann::json js = nlohmann::json::array();
  371. nlohmann::json entry = {};
  372. entry["td_onviapad"] = m_TeardropParamsList.m_TargetViasPads;
  373. entry["td_onpadsmd"] = m_TeardropParamsList.m_TargetPadsWithNoHole;
  374. entry["td_ontrackend"] = m_TeardropParamsList.m_TargetTrack2Track;
  375. entry["td_onroundshapesonly"] = m_TeardropParamsList.m_UseRoundShapesOnly;
  376. entry["td_allow_use_two_tracks"] = m_TeardropParamsList.m_AllowUseTwoTracks;
  377. entry["td_curve_segcount"] = m_TeardropParamsList.m_CurveSegCount;
  378. entry["td_on_pad_in_zone"] = m_TeardropParamsList.m_TdOnPadsInZones;
  379. js.push_back( entry );
  380. return js;
  381. },
  382. [&]( const nlohmann::json& aObj )
  383. {
  384. if( !aObj.is_array() )
  385. return;
  386. for( const nlohmann::json& entry : aObj )
  387. {
  388. if( entry.empty() || !entry.is_object() )
  389. continue;
  390. if( entry.contains( "td_onviapad" ) )
  391. m_TeardropParamsList.m_TargetViasPads = entry["td_onviapad"].get<bool>();
  392. if( entry.contains( "td_onpadsmd" ) )
  393. m_TeardropParamsList.m_TargetPadsWithNoHole = entry["td_onpadsmd"].get<bool>();
  394. if( entry.contains( "td_ontrackend" ) )
  395. m_TeardropParamsList.m_TargetTrack2Track = entry["td_ontrackend"].get<bool>();
  396. if( entry.contains( "td_onroundshapesonly" ) )
  397. m_TeardropParamsList.m_UseRoundShapesOnly = entry["td_onroundshapesonly"].get<bool>();
  398. if( entry.contains( "td_allow_use_two_tracks" ) )
  399. m_TeardropParamsList.m_AllowUseTwoTracks = entry["td_allow_use_two_tracks"].get<bool>();
  400. if( entry.contains( "td_curve_segcount" ) )
  401. m_TeardropParamsList.m_CurveSegCount = entry["td_curve_segcount"].get<int>();
  402. if( entry.contains( "td_on_pad_in_zone" ) )
  403. m_TeardropParamsList.m_TdOnPadsInZones = entry["td_on_pad_in_zone"].get<bool>();
  404. }
  405. },
  406. {} ) );
  407. // Handle parameters (sizes, shape) for each type of teardrop:
  408. m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "teardrop_parameters",
  409. [&]() -> nlohmann::json
  410. {
  411. nlohmann::json js = nlohmann::json::array();
  412. for( size_t ii = 0; ii < m_TeardropParamsList.GetParametersCount(); ii++ )
  413. {
  414. nlohmann::json entry = {};
  415. TEARDROP_PARAMETERS* td_prm = m_TeardropParamsList.GetParameters( (TARGET_TD)ii );
  416. entry["td_target_name"] = GetTeardropTargetCanonicalName( (TARGET_TD)ii );
  417. entry["td_maxlen"] = pcbIUScale.IUTomm( td_prm->m_TdMaxLen );
  418. entry["td_maxheight"] = pcbIUScale.IUTomm( td_prm->m_TdMaxHeight );
  419. entry["td_length_ratio"] = td_prm->m_LengthRatio;
  420. entry["td_height_ratio"] = td_prm->m_HeightRatio;
  421. entry["td_curve_segcount"] = td_prm->m_CurveSegCount;
  422. entry["td_width_to_size_filter_ratio"] = td_prm->m_WidthtoSizeFilterRatio;
  423. js.push_back( entry );
  424. }
  425. return js;
  426. },
  427. [&]( const nlohmann::json& aObj )
  428. {
  429. if( !aObj.is_array() )
  430. return;
  431. for( const nlohmann::json& entry : aObj )
  432. {
  433. if( entry.empty() || !entry.is_object() )
  434. continue;
  435. if( !entry.contains( "td_target_name" ) )
  436. continue;
  437. int idx = GetTeardropTargetTypeFromCanonicalName( entry["td_target_name"].get<std::string>() );
  438. if( idx >= 0 && idx < 3 )
  439. {
  440. TEARDROP_PARAMETERS* td_prm = m_TeardropParamsList.GetParameters( (TARGET_TD)idx );
  441. if( entry.contains( "td_maxlen" ) )
  442. td_prm->m_TdMaxLen = pcbIUScale.mmToIU( entry["td_maxlen"].get<double>() );
  443. if( entry.contains( "td_maxheight" ) )
  444. td_prm->m_TdMaxHeight = pcbIUScale.mmToIU( entry["td_maxheight"].get<double>() );
  445. if( entry.contains( "td_length_ratio" ) )
  446. td_prm->m_LengthRatio = entry["td_length_ratio"].get<double>();
  447. if( entry.contains( "td_height_ratio" ) )
  448. td_prm->m_HeightRatio = entry["td_height_ratio"].get<double>();
  449. if( entry.contains( "td_curve_segcount" ) )
  450. td_prm->m_CurveSegCount = entry["td_curve_segcount"].get<int>();
  451. if( entry.contains( "td_width_to_size_filter_ratio" ) )
  452. td_prm->m_WidthtoSizeFilterRatio = entry["td_width_to_size_filter_ratio"].get<double>();
  453. }
  454. }
  455. },
  456. {} ) );
  457. m_params.emplace_back( new PARAM_SCALED<int>( "defaults.silk_line_width",
  458. &m_LineThickness[LAYER_CLASS_SILK], pcbIUScale.mmToIU( DEFAULT_SILK_LINE_WIDTH ),
  459. pcbIUScale.mmToIU( 0.01 ), pcbIUScale.mmToIU( 5.0 ), pcbIUScale.MM_PER_IU ) );
  460. m_params.emplace_back( new PARAM_SCALED<int>( "defaults.silk_text_size_v",
  461. &m_TextSize[LAYER_CLASS_SILK].y, pcbIUScale.mmToIU( DEFAULT_SILK_TEXT_SIZE ),
  462. TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, pcbIUScale.MM_PER_IU ) );
  463. m_params.emplace_back( new PARAM_SCALED<int>( "defaults.silk_text_size_h",
  464. &m_TextSize[LAYER_CLASS_SILK].x, pcbIUScale.mmToIU( DEFAULT_SILK_TEXT_SIZE ),
  465. TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, pcbIUScale.MM_PER_IU ) );
  466. m_params.emplace_back( new PARAM_SCALED<int>( "defaults.silk_text_thickness",
  467. &m_TextThickness[LAYER_CLASS_SILK], pcbIUScale.mmToIU( DEFAULT_SILK_TEXT_WIDTH ), 1,
  468. TEXTS_MAX_WIDTH, pcbIUScale.MM_PER_IU ) );
  469. m_params.emplace_back( new PARAM<bool>( "defaults.silk_text_italic",
  470. &m_TextItalic[LAYER_CLASS_SILK], false ) );
  471. m_params.emplace_back( new PARAM<bool>( "defaults.silk_text_upright",
  472. &m_TextUpright[ LAYER_CLASS_SILK ], true ) );
  473. m_params.emplace_back( new PARAM_SCALED<int>( "defaults.copper_line_width",
  474. &m_LineThickness[LAYER_CLASS_COPPER], pcbIUScale.mmToIU( DEFAULT_COPPER_LINE_WIDTH ),
  475. pcbIUScale.mmToIU( 0.01 ), pcbIUScale.mmToIU( 5.0 ), pcbIUScale.MM_PER_IU ) );
  476. m_params.emplace_back( new PARAM_SCALED<int>( "defaults.copper_text_size_v",
  477. &m_TextSize[LAYER_CLASS_COPPER].y, pcbIUScale.mmToIU( DEFAULT_COPPER_TEXT_SIZE ),
  478. TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, pcbIUScale.MM_PER_IU ) );
  479. m_params.emplace_back( new PARAM_SCALED<int>( "defaults.copper_text_size_h",
  480. &m_TextSize[LAYER_CLASS_COPPER].x, pcbIUScale.mmToIU( DEFAULT_COPPER_TEXT_SIZE ),
  481. TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, pcbIUScale.MM_PER_IU ) );
  482. m_params.emplace_back( new PARAM_SCALED<int>( "defaults.copper_text_thickness",
  483. &m_TextThickness[LAYER_CLASS_COPPER], pcbIUScale.mmToIU( DEFAULT_COPPER_TEXT_WIDTH ),
  484. pcbIUScale.mmToIU( 0.01 ), pcbIUScale.mmToIU( 5.0 ), pcbIUScale.MM_PER_IU ) );
  485. m_params.emplace_back( new PARAM<bool>( "defaults.copper_text_italic",
  486. &m_TextItalic[LAYER_CLASS_COPPER], false ) );
  487. m_params.emplace_back( new PARAM<bool>( "defaults.copper_text_upright",
  488. &m_TextUpright[LAYER_CLASS_COPPER], true ) );
  489. m_params.emplace_back( new PARAM_SCALED<int>( "defaults.board_outline_line_width",
  490. &m_LineThickness[LAYER_CLASS_EDGES], pcbIUScale.mmToIU( DEFAULT_EDGE_WIDTH ),
  491. pcbIUScale.mmToIU( 0.01 ), pcbIUScale.mmToIU( 5.0 ), pcbIUScale.MM_PER_IU ) );
  492. m_params.emplace_back( new PARAM_SCALED<int>( "defaults.courtyard_line_width",
  493. &m_LineThickness[LAYER_CLASS_COURTYARD], pcbIUScale.mmToIU( DEFAULT_COURTYARD_WIDTH ),
  494. pcbIUScale.mmToIU( 0.01 ), pcbIUScale.mmToIU( 5.0 ), pcbIUScale.MM_PER_IU ) );
  495. m_params.emplace_back( new PARAM_SCALED<int>( "defaults.fab_line_width",
  496. &m_LineThickness[LAYER_CLASS_FAB], pcbIUScale.mmToIU( DEFAULT_LINE_WIDTH ),
  497. pcbIUScale.mmToIU( 0.01 ), pcbIUScale.mmToIU( 5.0 ), pcbIUScale.MM_PER_IU ) );
  498. m_params.emplace_back( new PARAM_SCALED<int>( "defaults.fab_text_size_v",
  499. &m_TextSize[LAYER_CLASS_FAB].y, pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE ),
  500. TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, pcbIUScale.MM_PER_IU ) );
  501. m_params.emplace_back( new PARAM_SCALED<int>( "defaults.fab_text_size_h",
  502. &m_TextSize[LAYER_CLASS_FAB].x, pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE ),
  503. TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, pcbIUScale.MM_PER_IU ) );
  504. m_params.emplace_back( new PARAM_SCALED<int>( "defaults.fab_text_thickness",
  505. &m_TextThickness[LAYER_CLASS_FAB], pcbIUScale.mmToIU( DEFAULT_TEXT_WIDTH ),
  506. pcbIUScale.mmToIU( 0.01 ), pcbIUScale.mmToIU( 5.0 ), pcbIUScale.MM_PER_IU ) );
  507. m_params.emplace_back( new PARAM<bool>( "defaults.fab_text_italic",
  508. &m_TextItalic[LAYER_CLASS_FAB], false ) );
  509. m_params.emplace_back( new PARAM<bool>( "defaults.fab_text_upright",
  510. &m_TextUpright[LAYER_CLASS_FAB], true ) );
  511. m_params.emplace_back( new PARAM_SCALED<int>( "defaults.other_line_width",
  512. &m_LineThickness[LAYER_CLASS_OTHERS], pcbIUScale.mmToIU( DEFAULT_LINE_WIDTH ),
  513. pcbIUScale.mmToIU( 0.01 ), pcbIUScale.mmToIU( 5.0 ), pcbIUScale.MM_PER_IU ) );
  514. m_params.emplace_back( new PARAM_SCALED<int>( "defaults.other_text_size_v",
  515. &m_TextSize[LAYER_CLASS_OTHERS].y, pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE ), TEXTS_MIN_SIZE,
  516. TEXTS_MAX_SIZE, pcbIUScale.MM_PER_IU ) );
  517. m_params.emplace_back( new PARAM_SCALED<int>( "defaults.other_text_size_h",
  518. &m_TextSize[LAYER_CLASS_OTHERS].x, pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE ), TEXTS_MIN_SIZE,
  519. TEXTS_MAX_SIZE, pcbIUScale.MM_PER_IU ) );
  520. m_params.emplace_back( new PARAM_SCALED<int>( "defaults.other_text_thickness",
  521. &m_TextThickness[LAYER_CLASS_OTHERS], pcbIUScale.mmToIU( DEFAULT_TEXT_WIDTH ),
  522. pcbIUScale.mmToIU( 0.01 ), pcbIUScale.mmToIU( 5.0 ), pcbIUScale.MM_PER_IU ) );
  523. m_params.emplace_back( new PARAM<bool>( "defaults.other_text_italic",
  524. &m_TextItalic[LAYER_CLASS_OTHERS], false ) );
  525. m_params.emplace_back( new PARAM<bool>( "defaults.other_text_upright",
  526. &m_TextUpright[LAYER_CLASS_OTHERS], true ) );
  527. m_params.emplace_back( new PARAM_ENUM<DIM_UNITS_MODE>( "defaults.dimension_units",
  528. &m_DimensionUnitsMode, DIM_UNITS_MODE::AUTOMATIC, DIM_UNITS_MODE::INCHES,
  529. DIM_UNITS_MODE::AUTOMATIC ) );
  530. m_params.emplace_back( new PARAM<int>( "defaults.dimension_precision",
  531. &m_DimensionPrecision, 4, 0, 5 ) );
  532. m_params.emplace_back( new PARAM_ENUM<DIM_UNITS_FORMAT>( "defaults.dimensions.units_format",
  533. &m_DimensionUnitsFormat, DIM_UNITS_FORMAT::BARE_SUFFIX, DIM_UNITS_FORMAT::NO_SUFFIX,
  534. DIM_UNITS_FORMAT::PAREN_SUFFIX ) );
  535. m_params.emplace_back( new PARAM<bool>( "defaults.dimensions.suppress_zeroes",
  536. &m_DimensionSuppressZeroes, false ) );
  537. // NOTE: excluding DIM_TEXT_POSITION::MANUAL from the valid range here
  538. m_params.emplace_back( new PARAM_ENUM<DIM_TEXT_POSITION>( "defaults.dimensions.text_position",
  539. &m_DimensionTextPosition, DIM_TEXT_POSITION::OUTSIDE, DIM_TEXT_POSITION::OUTSIDE,
  540. DIM_TEXT_POSITION::INLINE ) );
  541. m_params.emplace_back( new PARAM<bool>( "defaults.dimensions.keep_text_aligned",
  542. &m_DimensionKeepTextAligned, true ) );
  543. m_params.emplace_back( new PARAM<int>( "defaults.dimensions.arrow_length",
  544. &m_DimensionArrowLength,
  545. pcbIUScale.MilsToIU( DEFAULT_DIMENSION_ARROW_LENGTH ) ) );
  546. m_params.emplace_back( new PARAM<int>( "defaults.dimensions.extension_offset",
  547. &m_DimensionExtensionOffset,
  548. pcbIUScale.mmToIU( DEFAULT_DIMENSION_EXTENSION_OFFSET ) ) );
  549. m_params.emplace_back( new PARAM_SCALED<int>( "defaults.zones.min_clearance",
  550. &m_defaultZoneSettings.m_ZoneClearance, pcbIUScale.mmToIU( ZONE_CLEARANCE_MM ),
  551. pcbIUScale.mmToIU( 0.0 ), pcbIUScale.mmToIU( 25.0 ), pcbIUScale.MM_PER_IU ) );
  552. m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "defaults.pads",
  553. [&]() -> nlohmann::json
  554. {
  555. nlohmann::json ret =
  556. {
  557. { "width", pcbIUScale.IUTomm( m_Pad_Master->GetSize().x ) },
  558. { "height", pcbIUScale.IUTomm( m_Pad_Master->GetSize().y ) },
  559. { "drill", pcbIUScale.IUTomm( m_Pad_Master->GetDrillSize().x ) }
  560. };
  561. return ret;
  562. },
  563. [&]( const nlohmann::json& aJson )
  564. {
  565. if( aJson.contains( "width" ) && aJson.contains( "height" )
  566. && aJson.contains( "drill" ) )
  567. {
  568. VECTOR2I sz;
  569. sz.x = pcbIUScale.mmToIU( aJson["width"].get<double>() );
  570. sz.y = pcbIUScale.mmToIU( aJson["height"].get<double>() );
  571. m_Pad_Master->SetSize( sz );
  572. int drill = pcbIUScale.mmToIU( aJson["drill"].get<double>() );
  573. m_Pad_Master->SetDrillSize( VECTOR2I( drill, drill ) );
  574. }
  575. }, {} ) );
  576. m_params.emplace_back( new PARAM_SCALED<int>( "rules.max_error",
  577. &m_MaxError, ARC_HIGH_DEF, pcbIUScale.mmToIU( 0.0001 ), pcbIUScale.mmToIU( 1.0 ), pcbIUScale.MM_PER_IU ) );
  578. m_params.emplace_back( new PARAM_SCALED<int>( "rules.solder_mask_to_copper_clearance",
  579. &m_SolderMaskToCopperClearance, pcbIUScale.mmToIU( DEFAULT_SOLDERMASK_TO_COPPER_CLEARANCE ),
  580. pcbIUScale.mmToIU( 0.0 ), pcbIUScale.mmToIU( 25.0 ), pcbIUScale.MM_PER_IU ) );
  581. m_params.emplace_back( new PARAM<bool>( "zones_allow_external_fillets",
  582. &m_ZoneKeepExternalFillets, false ) );
  583. registerMigration( 0, 1, std::bind( &BOARD_DESIGN_SETTINGS::migrateSchema0to1, this ) );
  584. registerMigration( 1, 2,
  585. [&]() -> bool
  586. {
  587. // Schema 1 to 2: move mask and paste margin settings back to board.
  588. // The parameters are removed, so we just have to manually load them here and
  589. // they will get saved with the board
  590. if( std::optional<double> optval = Get<double>( "rules.solder_mask_clearance" ) )
  591. m_SolderMaskExpansion = static_cast<int>( *optval * pcbIUScale.IU_PER_MM );
  592. if( std::optional<double> optval = Get<double>( "rules.solder_mask_min_width" ) )
  593. m_SolderMaskMinWidth = static_cast<int>( *optval * pcbIUScale.IU_PER_MM );
  594. if( std::optional<double> optval = Get<double>( "rules.solder_paste_clearance" ) )
  595. m_SolderPasteMargin = static_cast<int>( *optval * pcbIUScale.IU_PER_MM );
  596. if( std::optional<double> optval = Get<double>( "rules.solder_paste_margin_ratio" ) )
  597. m_SolderPasteMarginRatio = *optval;
  598. try
  599. {
  600. At( "rules" ).erase( "solder_mask_clearance" );
  601. At( "rules" ).erase( "solder_mask_min_width" );
  602. At( "rules" ).erase( "solder_paste_clearance" );
  603. At( "rules" ).erase( "solder_paste_margin_ratio" );
  604. }
  605. catch( ... )
  606. {}
  607. return true;
  608. } );
  609. }
  610. BOARD_DESIGN_SETTINGS::~BOARD_DESIGN_SETTINGS()
  611. {
  612. if( m_parent )
  613. {
  614. m_parent->ReleaseNestedSettings( this );
  615. m_parent = nullptr;
  616. }
  617. }
  618. BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( const BOARD_DESIGN_SETTINGS& aOther ) :
  619. NESTED_SETTINGS( "board_design_settings", bdsSchemaVersion, aOther.m_parent,
  620. aOther.m_path ),
  621. m_Pad_Master( nullptr )
  622. {
  623. initFromOther( aOther );
  624. }
  625. BOARD_DESIGN_SETTINGS& BOARD_DESIGN_SETTINGS::operator=( const BOARD_DESIGN_SETTINGS& aOther )
  626. {
  627. initFromOther( aOther );
  628. return *this;
  629. }
  630. void BOARD_DESIGN_SETTINGS::initFromOther( const BOARD_DESIGN_SETTINGS& aOther )
  631. {
  632. // Copy of NESTED_SETTINGS around is not allowed, so let's just update the params.
  633. m_TrackWidthList = aOther.m_TrackWidthList;
  634. m_ViasDimensionsList = aOther.m_ViasDimensionsList;
  635. m_DiffPairDimensionsList = aOther.m_DiffPairDimensionsList;
  636. m_CurrentViaType = aOther.m_CurrentViaType;
  637. m_UseConnectedTrackWidth = aOther.m_UseConnectedTrackWidth;
  638. m_MinClearance = aOther.m_MinClearance;
  639. m_MinConn = aOther.m_MinConn;
  640. m_TrackMinWidth = aOther.m_TrackMinWidth;
  641. m_ViasMinAnnularWidth = aOther.m_ViasMinAnnularWidth;
  642. m_ViasMinSize = aOther.m_ViasMinSize;
  643. m_MinThroughDrill = aOther.m_MinThroughDrill;
  644. m_MicroViasMinSize = aOther.m_MicroViasMinSize;
  645. m_MicroViasMinDrill = aOther.m_MicroViasMinDrill;
  646. m_CopperEdgeClearance = aOther.m_CopperEdgeClearance;
  647. m_HoleClearance = aOther.m_HoleClearance;
  648. m_HoleToHoleMin = aOther.m_HoleToHoleMin;
  649. m_SilkClearance = aOther.m_SilkClearance;
  650. m_MinSilkTextHeight = aOther.m_MinSilkTextHeight;
  651. m_MinSilkTextThickness = aOther.m_MinSilkTextThickness;
  652. m_DRCSeverities = aOther.m_DRCSeverities;
  653. m_DrcExclusions = aOther.m_DrcExclusions;
  654. m_ZoneKeepExternalFillets = aOther.m_ZoneKeepExternalFillets;
  655. m_MaxError = aOther.m_MaxError;
  656. m_SolderMaskExpansion = aOther.m_SolderMaskExpansion;
  657. m_SolderMaskMinWidth = aOther.m_SolderMaskMinWidth;
  658. m_SolderMaskToCopperClearance = aOther.m_SolderMaskToCopperClearance;
  659. m_SolderPasteMargin = aOther.m_SolderPasteMargin;
  660. m_SolderPasteMarginRatio = aOther.m_SolderPasteMarginRatio;
  661. m_DefaultFPTextItems = aOther.m_DefaultFPTextItems;
  662. std::copy( std::begin( aOther.m_LineThickness ), std::end( aOther.m_LineThickness ),
  663. std::begin( m_LineThickness ) );
  664. std::copy( std::begin( aOther.m_TextSize ), std::end( aOther.m_TextSize ),
  665. std::begin( m_TextSize ) );
  666. std::copy( std::begin( aOther.m_TextThickness ), std::end( aOther.m_TextThickness ),
  667. std::begin( m_TextThickness ) );
  668. std::copy( std::begin( aOther.m_TextItalic ), std::end( aOther.m_TextItalic ),
  669. std::begin( m_TextItalic ) );
  670. std::copy( std::begin( aOther.m_TextUpright ), std::end( aOther.m_TextUpright ),
  671. std::begin( m_TextUpright ) );
  672. m_DimensionUnitsMode = aOther.m_DimensionUnitsMode;
  673. m_DimensionPrecision = aOther.m_DimensionPrecision;
  674. m_DimensionUnitsFormat = aOther.m_DimensionUnitsFormat;
  675. m_DimensionSuppressZeroes = aOther.m_DimensionSuppressZeroes;
  676. m_DimensionTextPosition = aOther.m_DimensionTextPosition;
  677. m_DimensionKeepTextAligned = aOther.m_DimensionKeepTextAligned;
  678. m_DimensionArrowLength = aOther.m_DimensionArrowLength;
  679. m_DimensionExtensionOffset = aOther.m_DimensionExtensionOffset;
  680. m_auxOrigin = aOther.m_auxOrigin;
  681. m_gridOrigin = aOther.m_gridOrigin;
  682. m_HasStackup = aOther.m_HasStackup;
  683. m_UseHeightForLengthCalcs= aOther.m_UseHeightForLengthCalcs;
  684. m_trackWidthIndex = aOther.m_trackWidthIndex;
  685. m_viaSizeIndex = aOther.m_viaSizeIndex;
  686. m_diffPairIndex = aOther.m_diffPairIndex;
  687. m_useCustomTrackVia = aOther.m_useCustomTrackVia;
  688. m_customTrackWidth = aOther.m_customTrackWidth;
  689. m_customViaSize = aOther.m_customViaSize;
  690. m_useCustomDiffPair = aOther.m_useCustomDiffPair;
  691. m_customDiffPair = aOther.m_customDiffPair;
  692. m_copperLayerCount = aOther.m_copperLayerCount;
  693. m_enabledLayers = aOther.m_enabledLayers;
  694. m_boardThickness = aOther.m_boardThickness;
  695. m_currentNetClassName = aOther.m_currentNetClassName;
  696. m_stackup = aOther.m_stackup;
  697. m_NetSettings = aOther.m_NetSettings;
  698. m_Pad_Master = std::make_unique<PAD>( *aOther.m_Pad_Master );
  699. m_defaultZoneSettings = aOther.m_defaultZoneSettings;
  700. }
  701. bool BOARD_DESIGN_SETTINGS::migrateSchema0to1()
  702. {
  703. /**
  704. * Schema 0 to 1: default dimension precision changed in meaning.
  705. * Previously it was an enum with the following meaning:
  706. *
  707. * 0: 0.01mm / 1 mil / 0.001 in
  708. * 1: 0.001mm / 0.1 mil / 0.0001 in
  709. * 2: 0.0001mm / 0.01 mil / 0.00001 in
  710. *
  711. * Now it is independent of display units and is an integer meaning the number of digits
  712. * displayed after the decimal point, so we have to migrate based on the default units.
  713. *
  714. * The units is an integer with the following mapping:
  715. *
  716. * 0: Inches
  717. * 1: Mils
  718. * 2: Millimeters
  719. */
  720. std::string units_ptr( "defaults.dimension_units" );
  721. std::string precision_ptr( "defaults.dimension_precision" );
  722. if( !( Contains( units_ptr ) && Contains( precision_ptr ) &&
  723. At( units_ptr ).is_number_integer() &&
  724. At( precision_ptr ).is_number_integer() ) )
  725. {
  726. // if either is missing or invalid, migration doesn't make sense
  727. return true;
  728. }
  729. int units = *Get<int>( units_ptr );
  730. int precision = *Get<int>( precision_ptr );
  731. // The enum maps directly to precision if the units is mils
  732. int extraDigits = 0;
  733. switch( units )
  734. {
  735. case 0: extraDigits = 3; break;
  736. case 2: extraDigits = 2; break;
  737. default: break;
  738. }
  739. precision += extraDigits;
  740. Set( precision_ptr, precision );
  741. return true;
  742. }
  743. bool BOARD_DESIGN_SETTINGS::LoadFromFile( const wxString& aDirectory )
  744. {
  745. bool ret = NESTED_SETTINGS::LoadFromFile( aDirectory );
  746. // A number of things won't have been translated by the PROJECT_FILE migration because of
  747. // descoped objects required to decode this data. So, it will be in the legacy.pcbnew
  748. // section and needs to be pulled out here
  749. PROJECT_FILE* project = dynamic_cast<PROJECT_FILE*>( GetParent() );
  750. if( !project )
  751. return ret;
  752. bool migrated = false;
  753. auto drcName =
  754. []( int aCode ) -> std::string
  755. {
  756. std::shared_ptr<DRC_ITEM> item = DRC_ITEM::Create( aCode );
  757. wxString name = item->GetSettingsKey();
  758. return std::string( name.ToUTF8() );
  759. };
  760. const std::string rs = "rule_severities.";
  761. const std::string no_courtyard_key = "legacy_no_courtyard_defined";
  762. const std::string courtyard_overlap_key = "legacy_courtyards_overlap";
  763. try
  764. {
  765. nlohmann::json& severities =
  766. project->Internals()->at( "/board/design_settings/rule_severities"_json_pointer );
  767. if( severities.contains( no_courtyard_key ) )
  768. {
  769. if( severities[no_courtyard_key].get<bool>() )
  770. Set( rs + drcName( DRCE_MISSING_COURTYARD ), "error" );
  771. else
  772. Set( rs + drcName( DRCE_MISSING_COURTYARD ), "ignore" );
  773. severities.erase( no_courtyard_key );
  774. migrated = true;
  775. }
  776. if( severities.contains( courtyard_overlap_key ) )
  777. {
  778. if( severities[courtyard_overlap_key].get<bool>() )
  779. Set( rs + drcName( DRCE_OVERLAPPING_FOOTPRINTS ), "error" );
  780. else
  781. Set( rs + drcName( DRCE_OVERLAPPING_FOOTPRINTS ), "ignore" );
  782. severities.erase( courtyard_overlap_key );
  783. migrated = true;
  784. }
  785. }
  786. catch( ... )
  787. {
  788. }
  789. if( Contains( "legacy" ) )
  790. {
  791. // This defaults to false for new boards, but version 5.1.x and prior kept the fillets
  792. // so we do the same for legacy boards.
  793. m_ZoneKeepExternalFillets = true;
  794. project->At( "legacy" ).erase( "pcbnew" );
  795. }
  796. // Now that we have everything, we need to load again
  797. if( migrated )
  798. Load();
  799. return ret;
  800. }
  801. SEVERITY BOARD_DESIGN_SETTINGS::GetSeverity( int aDRCErrorCode )
  802. {
  803. return m_DRCSeverities[ aDRCErrorCode ];
  804. }
  805. bool BOARD_DESIGN_SETTINGS::Ignore( int aDRCErrorCode )
  806. {
  807. return m_DRCSeverities[ aDRCErrorCode ] == RPT_SEVERITY_IGNORE;
  808. }
  809. int BOARD_DESIGN_SETTINGS::GetBiggestClearanceValue() const
  810. {
  811. int biggest = 0;
  812. DRC_CONSTRAINT constraint;
  813. if( m_DRCEngine )
  814. {
  815. m_DRCEngine->QueryWorstConstraint( CLEARANCE_CONSTRAINT, constraint );
  816. biggest = std::max( biggest, constraint.Value().Min() );
  817. m_DRCEngine->QueryWorstConstraint( HOLE_CLEARANCE_CONSTRAINT, constraint );
  818. biggest = std::max( biggest, constraint.Value().Min() );
  819. m_DRCEngine->QueryWorstConstraint( EDGE_CLEARANCE_CONSTRAINT, constraint );
  820. biggest = std::max( biggest, constraint.Value().Min() );
  821. m_DRCEngine->QueryWorstConstraint( HOLE_TO_HOLE_CONSTRAINT, constraint );
  822. biggest = std::max( biggest, constraint.Value().Min() );
  823. }
  824. return biggest;
  825. }
  826. int BOARD_DESIGN_SETTINGS::GetSmallestClearanceValue() const
  827. {
  828. int clearance = m_NetSettings->m_DefaultNetClass->GetClearance();
  829. for( const auto& [ name, netclass ] : m_NetSettings->m_NetClasses )
  830. clearance = std::min( clearance, netclass->GetClearance() );
  831. return clearance;
  832. }
  833. void BOARD_DESIGN_SETTINGS::SetViaSizeIndex( unsigned aIndex )
  834. {
  835. m_viaSizeIndex = std::min( aIndex, (unsigned) m_ViasDimensionsList.size() );
  836. m_useCustomTrackVia = false;
  837. }
  838. int BOARD_DESIGN_SETTINGS::GetCurrentViaSize() const
  839. {
  840. if( m_useCustomTrackVia )
  841. return m_customViaSize.m_Diameter;
  842. else if( m_viaSizeIndex == 0 )
  843. return m_NetSettings->m_DefaultNetClass->GetViaDiameter();
  844. else
  845. return m_ViasDimensionsList[ m_viaSizeIndex ].m_Diameter;
  846. }
  847. int BOARD_DESIGN_SETTINGS::GetCurrentViaDrill() const
  848. {
  849. int drill;
  850. if( m_useCustomTrackVia )
  851. drill = m_customViaSize.m_Drill;
  852. else if( m_viaSizeIndex == 0 )
  853. drill = m_NetSettings->m_DefaultNetClass->GetViaDrill();
  854. else
  855. drill = m_ViasDimensionsList[ m_viaSizeIndex ].m_Drill;
  856. return drill > 0 ? drill : -1;
  857. }
  858. void BOARD_DESIGN_SETTINGS::SetTrackWidthIndex( unsigned aIndex )
  859. {
  860. m_trackWidthIndex = std::min( aIndex, (unsigned) m_TrackWidthList.size() );
  861. m_useCustomTrackVia = false;
  862. }
  863. int BOARD_DESIGN_SETTINGS::GetCurrentTrackWidth() const
  864. {
  865. if( m_useCustomTrackVia )
  866. return m_customTrackWidth;
  867. else if( m_trackWidthIndex == 0 )
  868. return m_NetSettings->m_DefaultNetClass->GetTrackWidth();
  869. else
  870. return m_TrackWidthList[ m_trackWidthIndex ];
  871. }
  872. void BOARD_DESIGN_SETTINGS::SetDiffPairIndex( unsigned aIndex )
  873. {
  874. if( !m_DiffPairDimensionsList.empty() )
  875. {
  876. m_diffPairIndex = std::min( aIndex,
  877. static_cast<unsigned>( m_DiffPairDimensionsList.size() ) - 1 );
  878. }
  879. m_useCustomDiffPair = false;
  880. }
  881. int BOARD_DESIGN_SETTINGS::GetCurrentDiffPairWidth() const
  882. {
  883. if( m_useCustomDiffPair )
  884. {
  885. return m_customDiffPair.m_Width;
  886. }
  887. else if( m_diffPairIndex == 0 )
  888. {
  889. if( m_NetSettings->m_DefaultNetClass->HasDiffPairWidth() )
  890. return m_NetSettings->m_DefaultNetClass->GetDiffPairWidth();
  891. else
  892. return m_NetSettings->m_DefaultNetClass->GetTrackWidth();
  893. }
  894. else
  895. {
  896. return m_DiffPairDimensionsList[m_diffPairIndex].m_Width;
  897. }
  898. }
  899. int BOARD_DESIGN_SETTINGS::GetCurrentDiffPairGap() const
  900. {
  901. if( m_useCustomDiffPair )
  902. {
  903. return m_customDiffPair.m_Gap;
  904. }
  905. else if( m_diffPairIndex == 0 )
  906. {
  907. if( m_NetSettings->m_DefaultNetClass->HasDiffPairGap() )
  908. return m_NetSettings->m_DefaultNetClass->GetDiffPairGap();
  909. else
  910. return m_NetSettings->m_DefaultNetClass->GetClearance();
  911. }
  912. else
  913. {
  914. return m_DiffPairDimensionsList[m_diffPairIndex].m_Gap;
  915. }
  916. }
  917. int BOARD_DESIGN_SETTINGS::GetCurrentDiffPairViaGap() const
  918. {
  919. if( m_useCustomDiffPair )
  920. {
  921. return m_customDiffPair.m_ViaGap;
  922. }
  923. else if( m_diffPairIndex == 0 )
  924. {
  925. if( m_NetSettings->m_DefaultNetClass->HasDiffPairViaGap() )
  926. return m_NetSettings->m_DefaultNetClass->GetDiffPairViaGap();
  927. else
  928. return GetCurrentDiffPairGap();
  929. }
  930. else
  931. {
  932. return m_DiffPairDimensionsList[m_diffPairIndex].m_ViaGap;
  933. }
  934. }
  935. void BOARD_DESIGN_SETTINGS::SetCopperLayerCount( int aNewLayerCount )
  936. {
  937. m_copperLayerCount = aNewLayerCount;
  938. // Update only enabled copper layers mask
  939. m_enabledLayers &= ~LSET::AllCuMask();
  940. if( aNewLayerCount > 0 )
  941. m_enabledLayers |= LSET::AllCuMask( aNewLayerCount );
  942. }
  943. void BOARD_DESIGN_SETTINGS::SetEnabledLayers( LSET aMask )
  944. {
  945. // Back and front layers are always enabled.
  946. aMask.set( B_Cu ).set( F_Cu );
  947. m_enabledLayers = aMask;
  948. // update m_CopperLayerCount to ensure its consistency with m_EnabledLayers
  949. m_copperLayerCount = ( aMask & LSET::AllCuMask() ).count();
  950. }
  951. // Return the layer class index { silk, copper, edges & courtyards, fab, others } of the
  952. // given layer.
  953. int BOARD_DESIGN_SETTINGS::GetLayerClass( PCB_LAYER_ID aLayer ) const
  954. {
  955. if( aLayer == F_SilkS || aLayer == B_SilkS )
  956. return LAYER_CLASS_SILK;
  957. else if( IsCopperLayer( aLayer ) )
  958. return LAYER_CLASS_COPPER;
  959. else if( aLayer == Edge_Cuts )
  960. return LAYER_CLASS_EDGES;
  961. else if( aLayer == F_CrtYd || aLayer == B_CrtYd )
  962. return LAYER_CLASS_COURTYARD;
  963. else if( aLayer == F_Fab || aLayer == B_Fab )
  964. return LAYER_CLASS_FAB;
  965. else
  966. return LAYER_CLASS_OTHERS;
  967. }
  968. int BOARD_DESIGN_SETTINGS::GetDRCEpsilon() const
  969. {
  970. return pcbIUScale.mmToIU( ADVANCED_CFG::GetCfg().m_DRCEpsilon );
  971. }
  972. int BOARD_DESIGN_SETTINGS::GetHolePlatingThickness() const
  973. {
  974. return pcbIUScale.mmToIU( ADVANCED_CFG::GetCfg().m_HoleWallThickness );
  975. }
  976. int BOARD_DESIGN_SETTINGS::GetLineThickness( PCB_LAYER_ID aLayer ) const
  977. {
  978. return m_LineThickness[ GetLayerClass( aLayer ) ];
  979. }
  980. VECTOR2I BOARD_DESIGN_SETTINGS::GetTextSize( PCB_LAYER_ID aLayer ) const
  981. {
  982. return m_TextSize[ GetLayerClass( aLayer ) ];
  983. }
  984. int BOARD_DESIGN_SETTINGS::GetTextThickness( PCB_LAYER_ID aLayer ) const
  985. {
  986. return m_TextThickness[ GetLayerClass( aLayer ) ];
  987. }
  988. bool BOARD_DESIGN_SETTINGS::GetTextItalic( PCB_LAYER_ID aLayer ) const
  989. {
  990. return m_TextItalic[ GetLayerClass( aLayer ) ];
  991. }
  992. bool BOARD_DESIGN_SETTINGS::GetTextUpright( PCB_LAYER_ID aLayer ) const
  993. {
  994. return m_TextUpright[ GetLayerClass( aLayer ) ];
  995. }