1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 1992-2019 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 
24 #include <pcb_dimension.h>
25 #include <pcb_track.h>
26 #include <layer_ids.h>
27 #include <kiface_base.h>
28 #include <pad.h>
29 #include <board_design_settings.h>
30 #include <drc/drc_item.h>
31 #include <drc/drc_engine.h>
32 #include <settings/json_settings_internals.h>
33 #include <settings/parameters.h>
34 #include <project/project_file.h>
35 #include <advanced_config.h>
36 #include <board_design_settings.h>
37 #include <pcbnew.h>
38 
39 const int bdsSchemaVersion = 2;
40 
41 
BOARD_DESIGN_SETTINGS(JSON_SETTINGS * aParent,const std::string & aPath)42 BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std::string& aPath ) :
43         NESTED_SETTINGS( "board_design_settings", bdsSchemaVersion, aParent, aPath )
44 {
45     // We want to leave alone parameters that aren't found in the project JSON as they may be
46     // initialized by the board file parser before NESTED_SETTINGS::LoadFromFile is called.
47     m_resetParamsIfMissing = false;
48 
49     // Create a default NETCLASS list so that things don't break horribly if there's no project
50     // loaded.  This also is used during file load for legacy boards that have netclasses stored
51     // in the file.  After load, this information will be moved to the project and the pointer
52     // updated.
53     m_netClasses = &m_internalNetClasses;
54 
55     m_HasStackup = false;                   // no stackup defined by default
56 
57     m_Pad_Master = std::make_unique<PAD>( nullptr );
58 
59     LSET all_set = LSET().set();
60     m_enabledLayers = all_set;              // All layers enabled at first.
61                                             // SetCopperLayerCount() will adjust this.
62 
63     SetCopperLayerCount( 2 );               // Default design is a double sided board
64     m_CurrentViaType = VIATYPE::THROUGH;
65 
66     // if true, when creating a new track starting on an existing track, use this track width
67     m_UseConnectedTrackWidth = false;
68     m_TempOverrideTrackWidth = false;
69 
70     m_BlindBuriedViaAllowed = false;
71     m_MicroViasAllowed  = false;
72 
73     // First is always the reference designator
74     m_DefaultFPTextItems.emplace_back( wxT( "REF**" ), true, F_SilkS );
75     // Second is always the value
76     m_DefaultFPTextItems.emplace_back( wxT( "" ), true, F_Fab );
77     // Any following ones are freebies
78     m_DefaultFPTextItems.emplace_back( wxT( "${REFERENCE}" ), true, F_Fab );
79 
80     m_LineThickness[ LAYER_CLASS_SILK ] = Millimeter2iu( DEFAULT_SILK_LINE_WIDTH );
81     m_TextSize[ LAYER_CLASS_SILK ] = wxSize( Millimeter2iu( DEFAULT_SILK_TEXT_SIZE ),
82                                              Millimeter2iu( DEFAULT_SILK_TEXT_SIZE ) );
83     m_TextThickness[ LAYER_CLASS_SILK ] = Millimeter2iu( DEFAULT_SILK_TEXT_WIDTH );
84     m_TextItalic[ LAYER_CLASS_SILK ] = false;
85     m_TextUpright[ LAYER_CLASS_SILK ] = false;
86 
87     m_LineThickness[ LAYER_CLASS_COPPER ] = Millimeter2iu( DEFAULT_COPPER_LINE_WIDTH );
88     m_TextSize[ LAYER_CLASS_COPPER ] = wxSize( Millimeter2iu( DEFAULT_COPPER_TEXT_SIZE ),
89                                                Millimeter2iu( DEFAULT_COPPER_TEXT_SIZE ) );
90     m_TextThickness[ LAYER_CLASS_COPPER ] = Millimeter2iu( DEFAULT_COPPER_TEXT_WIDTH );
91     m_TextItalic[ LAYER_CLASS_COPPER ] = false;
92     m_TextUpright[ LAYER_CLASS_COPPER ] = false;
93 
94     // Edges & Courtyards; text properties aren't used but better to have them holding
95     // reasonable values than not.
96     m_LineThickness[ LAYER_CLASS_EDGES ] = Millimeter2iu( DEFAULT_EDGE_WIDTH );
97     m_TextSize[ LAYER_CLASS_EDGES ] = wxSize( Millimeter2iu( DEFAULT_TEXT_SIZE ),
98                                               Millimeter2iu( DEFAULT_TEXT_SIZE ) );
99     m_TextThickness[ LAYER_CLASS_EDGES ] = Millimeter2iu( DEFAULT_TEXT_WIDTH );
100     m_TextItalic[ LAYER_CLASS_EDGES ] = false;
101     m_TextUpright[ LAYER_CLASS_EDGES ] = false;
102 
103     m_LineThickness[ LAYER_CLASS_COURTYARD ] = Millimeter2iu( DEFAULT_COURTYARD_WIDTH );
104     m_TextSize[ LAYER_CLASS_COURTYARD ] = wxSize( Millimeter2iu( DEFAULT_TEXT_SIZE ),
105                                                   Millimeter2iu( DEFAULT_TEXT_SIZE ) );
106     m_TextThickness[ LAYER_CLASS_COURTYARD ] = Millimeter2iu( DEFAULT_TEXT_WIDTH );
107     m_TextItalic[ LAYER_CLASS_COURTYARD ] = false;
108     m_TextUpright[ LAYER_CLASS_COURTYARD ] = false;
109 
110     m_LineThickness[ LAYER_CLASS_FAB ] = Millimeter2iu( DEFAULT_LINE_WIDTH );
111     m_TextSize[ LAYER_CLASS_FAB ] = wxSize( Millimeter2iu( DEFAULT_TEXT_SIZE ),
112                                                   Millimeter2iu( DEFAULT_TEXT_SIZE ) );
113     m_TextThickness[ LAYER_CLASS_FAB ] = Millimeter2iu( DEFAULT_TEXT_WIDTH );
114     m_TextItalic[ LAYER_CLASS_FAB ] = false;
115     m_TextUpright[ LAYER_CLASS_FAB ] = false;
116 
117     m_LineThickness[ LAYER_CLASS_OTHERS ] = Millimeter2iu( DEFAULT_LINE_WIDTH );
118     m_TextSize[ LAYER_CLASS_OTHERS ] = wxSize( Millimeter2iu( DEFAULT_TEXT_SIZE ),
119                                                Millimeter2iu( DEFAULT_TEXT_SIZE ) );
120     m_TextThickness[ LAYER_CLASS_OTHERS ] = Millimeter2iu( DEFAULT_TEXT_WIDTH );
121     m_TextItalic[ LAYER_CLASS_OTHERS ] = false;
122     m_TextUpright[ LAYER_CLASS_OTHERS ] = false;
123 
124     m_DimensionPrecision       = 4;
125     m_DimensionUnitsMode       = DIM_UNITS_MODE::AUTOMATIC;
126     m_DimensionUnitsFormat     = DIM_UNITS_FORMAT::BARE_SUFFIX;
127     m_DimensionSuppressZeroes  = false;
128     m_DimensionTextPosition    = DIM_TEXT_POSITION::OUTSIDE;
129     m_DimensionKeepTextAligned = true;
130     m_DimensionArrowLength     = Mils2iu( DEFAULT_DIMENSION_ARROW_LENGTH );
131     m_DimensionExtensionOffset = Millimeter2iu( DEFAULT_DIMENSION_EXTENSION_OFFSET );
132 
133     m_useCustomTrackVia = false;
134     m_customTrackWidth  = Millimeter2iu( DEFAULT_CUSTOMTRACKWIDTH );
135     m_customViaSize.m_Diameter = Millimeter2iu( DEFAULT_VIASMINSIZE );
136     m_customViaSize.m_Drill = Millimeter2iu( DEFAULT_MINTHROUGHDRILL );
137 
138     m_useCustomDiffPair = false;
139     m_customDiffPair.m_Width = Millimeter2iu( DEFAULT_CUSTOMDPAIRWIDTH );
140     m_customDiffPair.m_Gap = Millimeter2iu( DEFAULT_CUSTOMDPAIRGAP );
141     m_customDiffPair.m_ViaGap = Millimeter2iu( DEFAULT_CUSTOMDPAIRVIAGAP );
142 
143     m_MinClearance        = Millimeter2iu( DEFAULT_MINCLEARANCE );
144     m_TrackMinWidth       = Millimeter2iu( DEFAULT_TRACKMINWIDTH );
145     m_ViasMinAnnularWidth = Millimeter2iu( DEFAULT_VIASMINSIZE - DEFAULT_MINTHROUGHDRILL ) / 2;
146     m_ViasMinSize         = Millimeter2iu( DEFAULT_VIASMINSIZE );
147     m_MinThroughDrill     = Millimeter2iu( DEFAULT_MINTHROUGHDRILL );
148     m_MicroViasMinSize    = Millimeter2iu( DEFAULT_MICROVIASMINSIZE );
149     m_MicroViasMinDrill   = Millimeter2iu( DEFAULT_MICROVIASMINDRILL );
150     m_CopperEdgeClearance = Millimeter2iu( DEFAULT_COPPEREDGECLEARANCE );
151     m_HoleClearance       = Millimeter2iu( DEFAULT_HOLECLEARANCE );
152     m_HoleToHoleMin       = Millimeter2iu( DEFAULT_HOLETOHOLEMIN );
153     m_SilkClearance       = Millimeter2iu( DEFAULT_SILKCLEARANCE );
154 
155     for( int errorCode = DRCE_FIRST; errorCode <= DRCE_LAST; ++errorCode )
156         m_DRCSeverities[ errorCode ] = RPT_SEVERITY_ERROR;
157 
158     m_DRCSeverities[ DRCE_DRILLED_HOLES_COLOCATED ] = RPT_SEVERITY_WARNING;
159 
160     m_DRCSeverities[ DRCE_MISSING_COURTYARD ] = RPT_SEVERITY_IGNORE;
161     m_DRCSeverities[ DRCE_PTH_IN_COURTYARD ] = RPT_SEVERITY_IGNORE;
162     m_DRCSeverities[ DRCE_NPTH_IN_COURTYARD ] = RPT_SEVERITY_IGNORE;
163 
164     m_DRCSeverities[ DRCE_DANGLING_TRACK ] = RPT_SEVERITY_WARNING;
165     m_DRCSeverities[ DRCE_DANGLING_VIA ] = RPT_SEVERITY_WARNING;
166 
167     m_DRCSeverities[ DRCE_MISSING_FOOTPRINT ] = RPT_SEVERITY_WARNING;
168     m_DRCSeverities[ DRCE_DUPLICATE_FOOTPRINT ] = RPT_SEVERITY_WARNING;
169     m_DRCSeverities[ DRCE_EXTRA_FOOTPRINT ] = RPT_SEVERITY_WARNING;
170     m_DRCSeverities[ DRCE_NET_CONFLICT ] = RPT_SEVERITY_WARNING;
171 
172     m_DRCSeverities[ DRCE_OVERLAPPING_SILK ] = RPT_SEVERITY_WARNING;
173     m_DRCSeverities[ DRCE_SILK_MASK_CLEARANCE ] = RPT_SEVERITY_WARNING;
174 
175     m_MaxError = ARC_HIGH_DEF;
176     m_ZoneFillVersion = 6;                      // Use new algo by default to fill zones
177     m_ZoneKeepExternalFillets = false;          // Use new algo by default.  Legacy boards might
178                                                 // want to set it to true for old algo....
179     m_UseHeightForLengthCalcs = true;
180 
181     // Global mask margins:
182     m_SolderMaskMargin  = Millimeter2iu( DEFAULT_SOLDERMASK_CLEARANCE );
183     m_SolderMaskMinWidth = Millimeter2iu( DEFAULT_SOLDERMASK_MIN_WIDTH );
184 
185     // Solder paste margin absolute value
186     m_SolderPasteMargin = Millimeter2iu( DEFAULT_SOLDERPASTE_CLEARANCE );
187     // Solder paste margin as a ratio of pad size
188     // The final margin is the sum of these 2 values
189     // Usually < 0 because the mask is smaller than pad
190     m_SolderPasteMarginRatio = DEFAULT_SOLDERPASTE_RATIO;
191 
192     // Layer thickness for 3D viewer
193     m_boardThickness = Millimeter2iu( DEFAULT_BOARD_THICKNESS_MM );
194 
195     m_viaSizeIndex = 0;
196     m_trackWidthIndex = 0;
197     m_diffPairIndex = 0;
198 
199     // Parameters stored in JSON in the project file
200 
201     // NOTE: Previously, BOARD_DESIGN_SETTINGS stored the basic board layer information (layer
202     // names and enable/disable state) in the project file even though this information is also
203     // stored in the board file.  This was implemented for importing these settings from another
204     // project.  Going forward, the import feature will just import from other board files (since
205     // we could have multi-board projects in the future anyway) so this functionality is dropped.
206 
207     m_params.emplace_back( new PARAM<bool>( "rules.allow_microvias", &m_MicroViasAllowed, false ) );
208 
209     m_params.emplace_back( new PARAM<bool>( "rules.allow_blind_buried_vias",
210             &m_BlindBuriedViaAllowed, false ) );
211 
212     m_params.emplace_back( new PARAM<bool>( "rules.use_height_for_length_calcs",
213             &m_UseHeightForLengthCalcs, true ) );
214 
215     m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_clearance", &m_MinClearance,
216             Millimeter2iu( DEFAULT_MINCLEARANCE ), Millimeter2iu( 0.01 ), Millimeter2iu( 25.0 ),
217             MM_PER_IU ) );
218 
219     m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_track_width", &m_TrackMinWidth,
220             Millimeter2iu( DEFAULT_TRACKMINWIDTH ), Millimeter2iu( 0.01 ), Millimeter2iu( 25.0 ),
221             MM_PER_IU ) );
222 
223     m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_via_annular_width",
224             &m_ViasMinAnnularWidth, Millimeter2iu( DEFAULT_VIASMINSIZE ), Millimeter2iu( 0.01 ),
225             Millimeter2iu( 25.0 ), MM_PER_IU ) );
226 
227     m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_via_diameter", &m_ViasMinSize,
228             Millimeter2iu( DEFAULT_VIASMINSIZE ), Millimeter2iu( 0.01 ), Millimeter2iu( 25.0 ),
229             MM_PER_IU ) );
230 
231     m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_through_hole_diameter",
232             &m_MinThroughDrill, Millimeter2iu( DEFAULT_MINTHROUGHDRILL ), Millimeter2iu( 0.01 ),
233             Millimeter2iu( 25.0 ), MM_PER_IU ) );
234 
235     m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_microvia_diameter",
236             &m_MicroViasMinSize, Millimeter2iu( DEFAULT_MICROVIASMINSIZE ), Millimeter2iu( 0.01 ),
237             Millimeter2iu( 10.0 ), MM_PER_IU ) );
238 
239     m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_microvia_drill", &m_MicroViasMinDrill,
240             Millimeter2iu( DEFAULT_MICROVIASMINDRILL ), Millimeter2iu( 0.01 ),
241             Millimeter2iu( 10.0 ), MM_PER_IU ) );
242 
243     m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_hole_to_hole", &m_HoleToHoleMin,
244             Millimeter2iu( DEFAULT_HOLETOHOLEMIN ), Millimeter2iu( 0.00 ), Millimeter2iu( 10.0 ),
245             MM_PER_IU ) );
246 
247     m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_hole_clearance", &m_HoleClearance,
248             Millimeter2iu( DEFAULT_HOLECLEARANCE ), Millimeter2iu( 0.00 ), Millimeter2iu( 100.0 ),
249             MM_PER_IU ) );
250 
251     m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_silk_clearance", &m_SilkClearance,
252             Millimeter2iu( DEFAULT_SILKCLEARANCE ), Millimeter2iu( 0.00 ), Millimeter2iu( 100.0 ),
253             MM_PER_IU ) );
254 
255     // Note: a clearance of -0.01 is a flag indicating we should use the legacy (pre-6.0) method
256     // based on the edge cut thicknesses.
257     m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_copper_edge_clearance",
258             &m_CopperEdgeClearance, Millimeter2iu( LEGACY_COPPEREDGECLEARANCE ),
259             Millimeter2iu( -0.01 ), Millimeter2iu( 25.0 ), MM_PER_IU ) );
260 
261     m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "rule_severities",
262             [&]() -> nlohmann::json
263             {
264                 nlohmann::json ret = {};
265 
266                 for( const RC_ITEM& item : DRC_ITEM::GetItemsWithSeverities() )
267                 {
268                     wxString name = item.GetSettingsKey();
269                     int      code = item.GetErrorCode();
270 
271                     if( name.IsEmpty() || m_DRCSeverities.count( code ) == 0 )
272                         continue;
273 
274                     ret[std::string( name.ToUTF8() )] = SeverityToString( m_DRCSeverities[code] );
275                 }
276 
277                 return ret;
278             },
279             [&]( const nlohmann::json& aJson )
280             {
281                 if( !aJson.is_object() )
282                     return;
283 
284                 for( const RC_ITEM& item : DRC_ITEM::GetItemsWithSeverities() )
285                 {
286                     wxString name = item.GetSettingsKey();
287                     std::string key( name.ToUTF8() );
288 
289                     if( aJson.contains( key ) )
290                         m_DRCSeverities[item.GetErrorCode()] = SeverityFromString( aJson[key] );
291                 }
292             }, {} ) );
293 
294     m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "drc_exclusions",
295             [&]() -> nlohmann::json
296             {
297                 nlohmann::json js = nlohmann::json::array();
298 
299                 for( const auto& entry : m_DrcExclusions )
300                     js.push_back( entry );
301 
302                 return js;
303             },
304             [&]( const nlohmann::json& aObj )
305             {
306                 m_DrcExclusions.clear();
307 
308                 if( !aObj.is_array() )
309                     return;
310 
311                 for( const nlohmann::json& entry : aObj )
312                 {
313                     if( entry.empty() )
314                         continue;
315 
316                     m_DrcExclusions.insert( entry.get<wxString>() );
317                 }
318             },
319             {} ) );
320 
321     m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "track_widths",
322             [&]() -> nlohmann::json
323             {
324                 nlohmann::json js = nlohmann::json::array();
325 
326                 for( const int& width : m_TrackWidthList )
327                     js.push_back( Iu2Millimeter( width ) );
328 
329                 return js;
330             },
331             [&]( const nlohmann::json& aJson )
332             {
333                 if( !aJson.is_array() )
334                     return;
335 
336                 m_TrackWidthList.clear();
337 
338                 for( const nlohmann::json& entry : aJson )
339                 {
340                     if( entry.empty() )
341                         continue;
342 
343                     m_TrackWidthList.emplace_back( Millimeter2iu( entry.get<double>() ) );
344                 }
345             },
346             {} ) );
347 
348     m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "via_dimensions",
349             [&]() -> nlohmann::json
350             {
351                 nlohmann::json js = nlohmann::json::array();
352 
353                 for( const auto& via : m_ViasDimensionsList )
354                 {
355                     nlohmann::json entry = {};
356 
357                     entry["diameter"] = Iu2Millimeter( via.m_Diameter );
358                     entry["drill"]    = Iu2Millimeter( via.m_Drill );
359 
360                     js.push_back( entry );
361                 }
362 
363                 return js;
364             },
365             [&]( const nlohmann::json& aObj )
366             {
367                 if( !aObj.is_array() )
368                     return;
369 
370                 m_ViasDimensionsList.clear();
371 
372                 for( const nlohmann::json& entry : aObj )
373                 {
374                     if( entry.empty() || !entry.is_object() )
375                         continue;
376 
377                     if( !entry.contains( "diameter" ) || !entry.contains( "drill" ) )
378                         continue;
379 
380                     int diameter = Millimeter2iu( entry["diameter"].get<double>() );
381                     int drill    = Millimeter2iu( entry["drill"].get<double>() );
382 
383                     m_ViasDimensionsList.emplace_back( VIA_DIMENSION( diameter, drill ) );
384                 }
385             },
386             {} ) );
387 
388     m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "diff_pair_dimensions",
389             [&]() -> nlohmann::json
390             {
391                 nlohmann::json js = nlohmann::json::array();
392 
393                 for( const auto& pair : m_DiffPairDimensionsList )
394                 {
395                     nlohmann::json entry = {};
396 
397                     entry["width"]   = Iu2Millimeter( pair.m_Width );
398                     entry["gap"]     = Iu2Millimeter( pair.m_Gap );
399                     entry["via_gap"] = Iu2Millimeter( pair.m_ViaGap );
400 
401                     js.push_back( entry );
402                 }
403 
404                 return js;
405             },
406             [&]( const nlohmann::json& aObj )
407             {
408                 if( !aObj.is_array() )
409                     return;
410 
411                 m_DiffPairDimensionsList.clear();
412 
413                 for( const nlohmann::json& entry : aObj )
414                 {
415                     if( entry.empty() || !entry.is_object() )
416                         continue;
417 
418                     if( !entry.contains( "width" ) || !entry.contains( "gap" )
419                             || !entry.contains( "via_gap" ) )
420                         continue;
421 
422                     int width   = Millimeter2iu( entry["width"].get<double>() );
423                     int gap     = Millimeter2iu( entry["gap"].get<double>() );
424                     int via_gap = Millimeter2iu( entry["via_gap"].get<double>() );
425 
426                     m_DiffPairDimensionsList.emplace_back(
427                             DIFF_PAIR_DIMENSION( width, gap, via_gap ) );
428                 }
429             },
430             {} ) );
431 
432     m_params.emplace_back( new PARAM_SCALED<int>( "defaults.silk_line_width",
433             &m_LineThickness[LAYER_CLASS_SILK], Millimeter2iu( DEFAULT_SILK_LINE_WIDTH ),
434             Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) );
435 
436     m_params.emplace_back( new PARAM_SCALED<int>( "defaults.silk_text_size_v",
437             &m_TextSize[LAYER_CLASS_SILK].y, Millimeter2iu( DEFAULT_SILK_TEXT_SIZE ),
438             TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, MM_PER_IU ) );
439 
440     m_params.emplace_back( new PARAM_SCALED<int>( "defaults.silk_text_size_h",
441             &m_TextSize[LAYER_CLASS_SILK].x, Millimeter2iu( DEFAULT_SILK_TEXT_SIZE ),
442             TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, MM_PER_IU ) );
443 
444     m_params.emplace_back( new PARAM_SCALED<int>( "defaults.silk_text_thickness",
445             &m_TextThickness[LAYER_CLASS_SILK], Millimeter2iu( DEFAULT_SILK_TEXT_WIDTH ), 1,
446             TEXTS_MAX_WIDTH, MM_PER_IU ) );
447 
448     m_params.emplace_back( new PARAM<bool>( "defaults.silk_text_italic",
449             &m_TextItalic[LAYER_CLASS_SILK], false ) );
450 
451     m_params.emplace_back( new PARAM<bool>( "defaults.silk_text_upright",
452             &m_TextUpright[ LAYER_CLASS_SILK ], true ) );
453 
454     m_params.emplace_back( new PARAM_SCALED<int>( "defaults.copper_line_width",
455             &m_LineThickness[LAYER_CLASS_COPPER], Millimeter2iu( DEFAULT_SILK_LINE_WIDTH ),
456             Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) );
457 
458     m_params.emplace_back( new PARAM_SCALED<int>( "defaults.copper_text_size_v",
459             &m_TextSize[LAYER_CLASS_COPPER].y, Millimeter2iu( DEFAULT_COPPER_TEXT_SIZE ),
460             TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, MM_PER_IU ) );
461 
462     m_params.emplace_back( new PARAM_SCALED<int>( "defaults.copper_text_size_h",
463             &m_TextSize[LAYER_CLASS_COPPER].x, Millimeter2iu( DEFAULT_COPPER_TEXT_SIZE ),
464             TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, MM_PER_IU ) );
465 
466     m_params.emplace_back( new PARAM_SCALED<int>( "defaults.copper_text_thickness",
467             &m_TextThickness[LAYER_CLASS_COPPER], Millimeter2iu( DEFAULT_COPPER_TEXT_WIDTH ),
468             Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) );
469 
470     m_params.emplace_back( new PARAM<bool>( "defaults.copper_text_italic",
471             &m_TextItalic[LAYER_CLASS_COPPER], false ) );
472 
473     m_params.emplace_back( new PARAM<bool>( "defaults.copper_text_upright",
474             &m_TextUpright[LAYER_CLASS_COPPER], true ) );
475 
476     m_params.emplace_back( new PARAM_SCALED<int>( "defaults.board_outline_line_width",
477             &m_LineThickness[LAYER_CLASS_EDGES], Millimeter2iu( DEFAULT_SILK_LINE_WIDTH ),
478             Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) );
479 
480     m_params.emplace_back( new PARAM_SCALED<int>( "defaults.courtyard_line_width",
481             &m_LineThickness[LAYER_CLASS_COURTYARD], Millimeter2iu( DEFAULT_COURTYARD_WIDTH ),
482             Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) );
483 
484     m_params.emplace_back( new PARAM_SCALED<int>( "defaults.fab_line_width",
485             &m_LineThickness[LAYER_CLASS_FAB], Millimeter2iu( DEFAULT_LINE_WIDTH ),
486             Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) );
487 
488     m_params.emplace_back( new PARAM_SCALED<int>( "defaults.fab_text_size_v",
489             &m_TextSize[LAYER_CLASS_FAB].y, Millimeter2iu( DEFAULT_TEXT_SIZE ),
490             TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, MM_PER_IU ) );
491 
492     m_params.emplace_back( new PARAM_SCALED<int>( "defaults.fab_text_size_h",
493             &m_TextSize[LAYER_CLASS_FAB].x, Millimeter2iu( DEFAULT_TEXT_SIZE ),
494             TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, MM_PER_IU ) );
495 
496     m_params.emplace_back( new PARAM_SCALED<int>( "defaults.fab_text_thickness",
497             &m_TextThickness[LAYER_CLASS_FAB], Millimeter2iu( DEFAULT_TEXT_WIDTH ),
498             Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) );
499 
500     m_params.emplace_back( new PARAM<bool>( "defaults.fab_text_italic",
501             &m_TextItalic[LAYER_CLASS_FAB], false ) );
502 
503     m_params.emplace_back( new PARAM<bool>( "defaults.fab_text_upright",
504             &m_TextUpright[LAYER_CLASS_FAB], true ) );
505 
506     m_params.emplace_back( new PARAM_SCALED<int>( "defaults.other_line_width",
507             &m_LineThickness[LAYER_CLASS_OTHERS], Millimeter2iu( DEFAULT_LINE_WIDTH ),
508             Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) );
509 
510     m_params.emplace_back( new PARAM_SCALED<int>( "defaults.other_text_size_v",
511             &m_TextSize[LAYER_CLASS_OTHERS].y, Millimeter2iu( DEFAULT_TEXT_SIZE ), TEXTS_MIN_SIZE,
512             TEXTS_MAX_SIZE, MM_PER_IU ) );
513 
514     m_params.emplace_back( new PARAM_SCALED<int>( "defaults.other_text_size_h",
515             &m_TextSize[LAYER_CLASS_OTHERS].x, Millimeter2iu( DEFAULT_TEXT_SIZE ), TEXTS_MIN_SIZE,
516             TEXTS_MAX_SIZE, MM_PER_IU ) );
517 
518     m_params.emplace_back( new PARAM_SCALED<int>( "defaults.other_text_thickness",
519             &m_TextThickness[LAYER_CLASS_OTHERS], Millimeter2iu( DEFAULT_TEXT_WIDTH ),
520             Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) );
521 
522     m_params.emplace_back( new PARAM<bool>( "defaults.other_text_italic",
523             &m_TextItalic[LAYER_CLASS_OTHERS], false ) );
524 
525     m_params.emplace_back( new PARAM<bool>( "defaults.other_text_upright",
526             &m_TextUpright[LAYER_CLASS_OTHERS], true ) );
527 
528     m_params.emplace_back( new PARAM_ENUM<DIM_UNITS_MODE>( "defaults.dimension_units",
529             &m_DimensionUnitsMode, DIM_UNITS_MODE::AUTOMATIC, DIM_UNITS_MODE::INCHES,
530             DIM_UNITS_MODE::AUTOMATIC ) );
531 
532     m_params.emplace_back( new PARAM<int>( "defaults.dimension_precision",
533             &m_DimensionPrecision, 4, 0, 5 ) );
534 
535     m_params.emplace_back( new PARAM_ENUM<DIM_UNITS_FORMAT>( "defaults.dimensions.units_format",
536             &m_DimensionUnitsFormat, DIM_UNITS_FORMAT::BARE_SUFFIX, DIM_UNITS_FORMAT::NO_SUFFIX,
537             DIM_UNITS_FORMAT::PAREN_SUFFIX ) );
538 
539     m_params.emplace_back( new PARAM<bool>( "defaults.dimensions.suppress_zeroes",
540             &m_DimensionSuppressZeroes, false ) );
541 
542     // NOTE: excluding DIM_TEXT_POSITION::MANUAL from the valid range here
543     m_params.emplace_back( new PARAM_ENUM<DIM_TEXT_POSITION>( "defaults.dimensions.text_position",
544             &m_DimensionTextPosition, DIM_TEXT_POSITION::OUTSIDE, DIM_TEXT_POSITION::OUTSIDE,
545             DIM_TEXT_POSITION::INLINE ) );
546 
547     m_params.emplace_back( new PARAM<bool>( "defaults.dimensions.keep_text_aligned",
548             &m_DimensionKeepTextAligned, true ) );
549 
550     m_params.emplace_back( new PARAM<int>( "defaults.dimensions.arrow_length",
551             &m_DimensionArrowLength,
552             Mils2iu( DEFAULT_DIMENSION_ARROW_LENGTH ) ) );
553 
554     m_params.emplace_back( new PARAM<int>( "defaults.dimensions.extension_offset",
555             &m_DimensionExtensionOffset,
556             Millimeter2iu( DEFAULT_DIMENSION_EXTENSION_OFFSET ) ) );
557 
558     m_params.emplace_back( new PARAM<bool>( "defaults.zones.45_degree_only",
559             &m_defaultZoneSettings.m_Zone_45_Only, false ) );
560 
561     m_params.emplace_back( new PARAM_SCALED<int>( "defaults.zones.min_clearance",
562             &m_defaultZoneSettings.m_ZoneClearance, Mils2iu( ZONE_CLEARANCE_MIL ),
563             Millimeter2iu( 0.0 ), Millimeter2iu( 25.0 ), MM_PER_IU ) );
564 
565     m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "defaults.pads",
566             [&]() -> nlohmann::json
567             {
568                 nlohmann::json ret =
569                         {
570                             { "width",  Iu2Millimeter( m_Pad_Master->GetSize().x ) },
571                             { "height", Iu2Millimeter( m_Pad_Master->GetSize().y ) },
572                             { "drill",  Iu2Millimeter( m_Pad_Master->GetDrillSize().x ) }
573                         };
574 
575                 return ret;
576             },
577             [&]( const nlohmann::json& aJson )
578             {
579                 if( aJson.contains( "width" ) && aJson.contains( "height" )
580                         && aJson.contains( "drill" ) )
581                 {
582                     wxSize sz;
583                     sz.SetWidth( Millimeter2iu( aJson["width"].get<double>() ) );
584                     sz.SetHeight( Millimeter2iu( aJson["height"].get<double>() ) );
585 
586                     m_Pad_Master->SetSize( sz );
587 
588                     int drill = Millimeter2iu( aJson["drill"].get<double>() );
589 
590                     m_Pad_Master->SetDrillSize( wxSize( drill, drill ) );
591                 }
592             }, {} ) );
593 
594     m_params.emplace_back( new PARAM_SCALED<int>( "rules.max_error", &m_MaxError, ARC_HIGH_DEF,
595             Millimeter2iu( 0.0001 ), Millimeter2iu( 1.0 ), MM_PER_IU ) );
596 
597     // TODO: replace with zones_fill_version parameter and migrate zones_use_no_outline?
598     m_params.emplace_back( new PARAM_LAMBDA<bool>( "zones_use_no_outline",
599             [this]() -> bool
600             {
601                 return m_ZoneFillVersion >= 6;
602             },
603             [this]( bool aVal )
604             {
605                 m_ZoneFillVersion = aVal ? 6 : 5;
606             },
607             true ) );
608 
609     m_params.emplace_back( new PARAM<bool>( "zones_allow_external_fillets",
610             &m_ZoneKeepExternalFillets, false ) );
611 
612     registerMigration( 0, 1, std::bind( &BOARD_DESIGN_SETTINGS::migrateSchema0to1, this ) );
613 
614     registerMigration( 1, 2,
615             [&]() -> bool
616             {
617                 // Schema 1 to 2: move mask and paste margin settings back to board.
618                 // The parameters are removed, so we just have to manually load them here and
619                 // they will get saved with the board
620                 if( OPT<double> optval = Get<double>( "rules.solder_mask_clearance" ) )
621                     m_SolderMaskMargin = static_cast<int>( *optval * IU_PER_MM );
622 
623                 if( OPT<double> optval = Get<double>( "rules.solder_mask_min_width" ) )
624                     m_SolderMaskMinWidth = static_cast<int>( *optval * IU_PER_MM );
625 
626                 if( OPT<double> optval = Get<double>( "rules.solder_paste_clearance" ) )
627                     m_SolderPasteMargin = static_cast<int>( *optval * IU_PER_MM );
628 
629                 if( OPT<double> optval = Get<double>( "rules.solder_paste_margin_ratio" ) )
630                     m_SolderPasteMarginRatio = *optval;
631 
632                 try
633                 {
634                     At( "rules" ).erase( "solder_mask_clearance" );
635                     At( "rules" ).erase( "solder_mask_min_width" );
636                     At( "rules" ).erase( "solder_paste_clearance" );
637                     At( "rules" ).erase( "solder_paste_margin_ratio" );
638                 }
639                 catch( ... )
640                 {}
641 
642                 return true;
643             } );
644 }
645 
646 
~BOARD_DESIGN_SETTINGS()647 BOARD_DESIGN_SETTINGS::~BOARD_DESIGN_SETTINGS()
648 {
649     if( m_parent )
650     {
651         m_parent->ReleaseNestedSettings( this );
652         m_parent = nullptr;
653     }
654 }
655 
656 
BOARD_DESIGN_SETTINGS(const BOARD_DESIGN_SETTINGS & aOther)657 BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( const BOARD_DESIGN_SETTINGS& aOther ) :
658         NESTED_SETTINGS( "board_design_settings", bdsSchemaVersion, aOther.m_parent,
659                          aOther.m_path ),
660         m_Pad_Master( nullptr )
661 {
662     initFromOther( aOther );
663 }
664 
665 
operator =(const BOARD_DESIGN_SETTINGS & aOther)666 BOARD_DESIGN_SETTINGS& BOARD_DESIGN_SETTINGS::operator=( const BOARD_DESIGN_SETTINGS& aOther )
667 {
668     initFromOther( aOther );
669     return *this;
670 }
671 
672 
initFromOther(const BOARD_DESIGN_SETTINGS & aOther)673 void BOARD_DESIGN_SETTINGS::initFromOther( const BOARD_DESIGN_SETTINGS& aOther )
674 {
675     // Copy of NESTED_SETTINGS around is not allowed, so let's just update the params.
676     m_TrackWidthList         = aOther.m_TrackWidthList;
677     m_ViasDimensionsList     = aOther.m_ViasDimensionsList;
678     m_DiffPairDimensionsList = aOther.m_DiffPairDimensionsList;
679     m_MicroViasAllowed       = aOther.m_MicroViasAllowed;
680     m_BlindBuriedViaAllowed  = aOther.m_BlindBuriedViaAllowed;
681     m_CurrentViaType         = aOther.m_CurrentViaType;
682     m_UseConnectedTrackWidth = aOther.m_UseConnectedTrackWidth;
683     m_MinClearance           = aOther.m_MinClearance;
684     m_TrackMinWidth          = aOther.m_TrackMinWidth;
685     m_ViasMinAnnularWidth    = aOther.m_ViasMinAnnularWidth;
686     m_ViasMinSize            = aOther.m_ViasMinSize;
687     m_MinThroughDrill        = aOther.m_MinThroughDrill;
688     m_MicroViasMinSize       = aOther.m_MicroViasMinSize;
689     m_MicroViasMinDrill      = aOther.m_MicroViasMinDrill;
690     m_CopperEdgeClearance    = aOther.m_CopperEdgeClearance;
691     m_HoleClearance          = aOther.m_HoleClearance;
692     m_HoleToHoleMin          = aOther.m_HoleToHoleMin;
693     m_SilkClearance          = aOther.m_SilkClearance;
694     m_DRCSeverities          = aOther.m_DRCSeverities;
695     m_DrcExclusions          = aOther.m_DrcExclusions;
696     m_ZoneFillVersion        = aOther.m_ZoneFillVersion;
697     m_ZoneKeepExternalFillets= aOther.m_ZoneKeepExternalFillets;
698     m_MaxError               = aOther.m_MaxError;
699     m_SolderMaskMargin       = aOther.m_SolderMaskMargin;
700     m_SolderMaskMinWidth     = aOther.m_SolderMaskMinWidth;
701     m_SolderPasteMargin      = aOther.m_SolderPasteMargin;
702     m_SolderPasteMarginRatio = aOther.m_SolderPasteMarginRatio;
703     m_DefaultFPTextItems     = aOther.m_DefaultFPTextItems;
704 
705     std::copy( std::begin( aOther.m_LineThickness ), std::end( aOther.m_LineThickness ),
706                std::begin( m_LineThickness ) );
707 
708     std::copy( std::begin( aOther.m_TextSize ), std::end( aOther.m_TextSize ),
709                std::begin( m_TextSize ) );
710 
711     std::copy( std::begin( aOther.m_TextThickness ), std::end( aOther.m_TextThickness ),
712                std::begin( m_TextThickness ) );
713 
714     std::copy( std::begin( aOther.m_TextItalic ), std::end( aOther.m_TextItalic ),
715                std::begin( m_TextItalic ) );
716 
717     std::copy( std::begin( aOther.m_TextUpright ), std::end( aOther.m_TextUpright ),
718                std::begin( m_TextUpright ) );
719 
720     m_DimensionUnitsMode       = aOther.m_DimensionUnitsMode;
721     m_DimensionPrecision       = aOther.m_DimensionPrecision;
722     m_DimensionUnitsFormat     = aOther.m_DimensionUnitsFormat;
723     m_DimensionSuppressZeroes  = aOther.m_DimensionSuppressZeroes;
724     m_DimensionTextPosition    = aOther.m_DimensionTextPosition;
725     m_DimensionKeepTextAligned = aOther.m_DimensionKeepTextAligned;
726     m_DimensionArrowLength     = aOther.m_DimensionArrowLength;
727     m_DimensionExtensionOffset = aOther.m_DimensionExtensionOffset;
728 
729     m_auxOrigin              = aOther.m_auxOrigin;
730     m_gridOrigin             = aOther.m_gridOrigin;
731     m_HasStackup             = aOther.m_HasStackup;
732     m_UseHeightForLengthCalcs= aOther.m_UseHeightForLengthCalcs;
733 
734     m_trackWidthIndex        = aOther.m_trackWidthIndex;
735     m_viaSizeIndex           = aOther.m_viaSizeIndex;
736     m_diffPairIndex          = aOther.m_diffPairIndex;
737     m_useCustomTrackVia      = aOther.m_useCustomTrackVia;
738     m_customTrackWidth       = aOther.m_customTrackWidth;
739     m_customViaSize          = aOther.m_customViaSize;
740     m_useCustomDiffPair      = aOther.m_useCustomDiffPair;
741     m_customDiffPair         = aOther.m_customDiffPair;
742     m_copperLayerCount       = aOther.m_copperLayerCount;
743     m_enabledLayers          = aOther.m_enabledLayers;
744     m_boardThickness         = aOther.m_boardThickness;
745     m_currentNetClassName    = aOther.m_currentNetClassName;
746     m_stackup                = aOther.m_stackup;
747 
748     // Only take the pointer from the other if it isn't the default
749     if( aOther.m_netClasses == &aOther.m_internalNetClasses )
750         m_netClasses = &m_internalNetClasses;
751     else
752         m_netClasses = aOther.m_netClasses;
753 
754     m_defaultZoneSettings    = aOther.m_defaultZoneSettings;
755 }
756 
757 
migrateSchema0to1()758 bool BOARD_DESIGN_SETTINGS::migrateSchema0to1()
759 {
760     /**
761      * Schema 0 to 1: default dimension precision changed in meaning.
762      * Previously it was an enum with the following meaning:
763      *
764      * 0: 0.01mm / 1 mil / 0.001 in
765      * 1: 0.001mm / 0.1 mil / 0.0001 in
766      * 2: 0.0001mm / 0.01 mil / 0.00001 in
767      *
768      * Now it is independent of display units and is an integer meaning the number of digits
769      * displayed after the decimal point, so we have to migrate based on the default units.
770      *
771      * The units is an integer with the following mapping:
772      *
773      * 0: Inches
774      * 1: Mils
775      * 2: Millimeters
776      */
777     std::string units_ptr( "defaults.dimension_units" );
778     std::string precision_ptr( "defaults.dimension_precision" );
779 
780     if( !( Contains( units_ptr ) && Contains( precision_ptr ) &&
781            At( units_ptr ).is_number_integer() &&
782            At( precision_ptr ).is_number_integer() ) )
783     {
784         // if either is missing or invalid, migration doesn't make sense
785         return true;
786     }
787 
788     int units     = Get<int>( units_ptr ).value();
789     int precision = Get<int>( precision_ptr ).value();
790 
791     // The enum maps directly to precision if the units is mils
792     int extraDigits = 0;
793 
794     switch( units )
795     {
796     case 0: extraDigits = 3; break;
797     case 2: extraDigits = 2; break;
798     default: break;
799     }
800 
801     precision += extraDigits;
802 
803     Set( precision_ptr, precision );
804 
805     return true;
806 }
807 
808 
LoadFromFile(const wxString & aDirectory)809 bool BOARD_DESIGN_SETTINGS::LoadFromFile( const wxString& aDirectory )
810 {
811     bool ret = NESTED_SETTINGS::LoadFromFile( aDirectory );
812 
813     // A number of things won't have been translated by the PROJECT_FILE migration because of
814     // descoped objects required to decode this data.  So, it will be in the legacy.pcbnew
815     // section and needs to be pulled out here
816 
817     PROJECT_FILE* project = dynamic_cast<PROJECT_FILE*>( GetParent() );
818 
819     if( !project )
820         return ret;
821 
822     bool migrated = false;
823 
824     auto drcName =
825             []( int aCode ) -> std::string
826             {
827                 std::shared_ptr<DRC_ITEM> item = DRC_ITEM::Create( aCode );
828                 wxString name = item->GetSettingsKey();
829                 return std::string( name.ToUTF8() );
830             };
831 
832     std::string bp = "board.design_settings.rule_severities.";
833     std::string rs = "rule_severities.";
834 
835     if( OPT<bool> v = project->Get<bool>( bp + "legacy_no_courtyard_defined" ) )
836     {
837         if( *v )
838             Set( rs + drcName( DRCE_MISSING_COURTYARD ), "error" );
839         else
840             Set( rs + drcName( DRCE_MISSING_COURTYARD ), "ignore" );
841 
842         project->Internals()->erase( m_internals->PointerFromString( bp + "legacy_no_courtyard_defined" ) );
843         migrated = true;
844     }
845 
846     if( OPT<bool> v = project->Get<bool>( bp + "legacy_courtyards_overlap" ) )
847     {
848         if( *v )
849             Set( rs + drcName( DRCE_OVERLAPPING_FOOTPRINTS ), "error" );
850         else
851             Set( rs + drcName( DRCE_OVERLAPPING_FOOTPRINTS ), "ignore" );
852 
853         project->Internals()->erase( JSON_SETTINGS_INTERNALS::PointerFromString( bp + "legacy_courtyards_overlap" ) );
854         migrated = true;
855     }
856 
857     if( Contains( "legacy" ) )
858     {
859         // This defaults to false for new boards, but version 5.1.x and prior kept the fillets
860         // so we do the same for legacy boards.
861         m_ZoneKeepExternalFillets = true;
862 
863         project->At( "legacy" ).erase( "pcbnew" );
864     }
865 
866     // Now that we have everything, we need to load again
867     if( migrated )
868         Load();
869 
870     return ret;
871 }
872 
873 
GetSeverity(int aDRCErrorCode)874 SEVERITY BOARD_DESIGN_SETTINGS::GetSeverity( int aDRCErrorCode )
875 {
876     return m_DRCSeverities[ aDRCErrorCode ];
877 }
878 
879 
Ignore(int aDRCErrorCode)880 bool BOARD_DESIGN_SETTINGS::Ignore( int aDRCErrorCode )
881 {
882     return m_DRCSeverities[ aDRCErrorCode ] == RPT_SEVERITY_IGNORE;
883 }
884 
885 
GetBiggestClearanceValue() const886 int BOARD_DESIGN_SETTINGS::GetBiggestClearanceValue() const
887 {
888     int            biggest = 0;
889     DRC_CONSTRAINT constraint;
890 
891     if( m_DRCEngine )
892     {
893         m_DRCEngine->QueryWorstConstraint( CLEARANCE_CONSTRAINT, constraint );
894         biggest = std::max( biggest, constraint.Value().Min() );
895 
896         m_DRCEngine->QueryWorstConstraint( HOLE_CLEARANCE_CONSTRAINT, constraint );
897         biggest = std::max( biggest, constraint.Value().Min() );
898 
899         m_DRCEngine->QueryWorstConstraint( EDGE_CLEARANCE_CONSTRAINT, constraint );
900         biggest = std::max( biggest, constraint.Value().Min() );
901     }
902 
903     return biggest;
904 }
905 
906 
GetSmallestClearanceValue() const907 int BOARD_DESIGN_SETTINGS::GetSmallestClearanceValue() const
908 {
909     int clearance = GetDefault()->GetClearance();
910 
911     for( const std::pair<const wxString, NETCLASSPTR>& netclass : GetNetClasses().NetClasses() )
912         clearance = std::min( clearance, netclass.second->GetClearance() );
913 
914     return clearance;
915 }
916 
917 
GetCurrentMicroViaSize()918 int BOARD_DESIGN_SETTINGS::GetCurrentMicroViaSize()
919 {
920     NETCLASSPTR netclass = GetNetClasses().Find( m_currentNetClassName );
921 
922     return netclass->GetuViaDiameter();
923 }
924 
925 
GetCurrentMicroViaDrill()926 int BOARD_DESIGN_SETTINGS::GetCurrentMicroViaDrill()
927 {
928     NETCLASSPTR netclass = GetNetClasses().Find( m_currentNetClassName );
929 
930     return netclass->GetuViaDrill();
931 }
932 
933 
SetViaSizeIndex(unsigned aIndex)934 void BOARD_DESIGN_SETTINGS::SetViaSizeIndex( unsigned aIndex )
935 {
936     m_viaSizeIndex = std::min( aIndex, (unsigned) m_ViasDimensionsList.size() );
937     m_useCustomTrackVia = false;
938 }
939 
940 
GetCurrentViaSize() const941 int BOARD_DESIGN_SETTINGS::GetCurrentViaSize() const
942 {
943     if( m_useCustomTrackVia )
944         return m_customViaSize.m_Diameter;
945     else if( m_viaSizeIndex == 0 )
946         return GetNetClasses().GetDefaultPtr()->GetViaDiameter();
947     else
948         return m_ViasDimensionsList[ m_viaSizeIndex ].m_Diameter;
949 }
950 
951 
GetCurrentViaDrill() const952 int BOARD_DESIGN_SETTINGS::GetCurrentViaDrill() const
953 {
954     int drill;
955 
956     if( m_useCustomTrackVia )
957         drill = m_customViaSize.m_Drill;
958     else if( m_viaSizeIndex == 0 )
959         drill = GetNetClasses().GetDefaultPtr()->GetViaDrill();
960     else
961         drill = m_ViasDimensionsList[ m_viaSizeIndex ].m_Drill;
962 
963     return drill > 0 ? drill : -1;
964 }
965 
966 
SetTrackWidthIndex(unsigned aIndex)967 void BOARD_DESIGN_SETTINGS::SetTrackWidthIndex( unsigned aIndex )
968 {
969     m_trackWidthIndex = std::min( aIndex, (unsigned) m_TrackWidthList.size() );
970     m_useCustomTrackVia = false;
971 }
972 
973 
GetCurrentTrackWidth() const974 int BOARD_DESIGN_SETTINGS::GetCurrentTrackWidth() const
975 {
976     if( m_useCustomTrackVia )
977         return m_customTrackWidth;
978     else if( m_trackWidthIndex == 0 )
979         return GetNetClasses().GetDefaultPtr()->GetTrackWidth();
980     else
981         return m_TrackWidthList[ m_trackWidthIndex ];
982 }
983 
984 
SetDiffPairIndex(unsigned aIndex)985 void BOARD_DESIGN_SETTINGS::SetDiffPairIndex( unsigned aIndex )
986 {
987     if( !m_DiffPairDimensionsList.empty() )
988     {
989         m_diffPairIndex = std::min( aIndex,
990                 static_cast<unsigned>( m_DiffPairDimensionsList.size() ) - 1 );
991     }
992 
993     m_useCustomDiffPair = false;
994 }
995 
996 
GetCurrentDiffPairWidth() const997 int BOARD_DESIGN_SETTINGS::GetCurrentDiffPairWidth() const
998 {
999     if( m_useCustomDiffPair )
1000     {
1001         return m_customDiffPair.m_Width;
1002     }
1003     else if( m_diffPairIndex == 0 )
1004     {
1005         if( GetNetClasses().GetDefaultPtr()->HasDiffPairWidth() )
1006             return GetNetClasses().GetDefaultPtr()->GetDiffPairWidth();
1007         else
1008             return GetNetClasses().GetDefaultPtr()->GetTrackWidth();
1009     }
1010     else
1011     {
1012         return m_DiffPairDimensionsList[m_diffPairIndex].m_Width;
1013     }
1014 }
1015 
1016 
GetCurrentDiffPairGap() const1017 int BOARD_DESIGN_SETTINGS::GetCurrentDiffPairGap() const
1018 {
1019     if( m_useCustomDiffPair )
1020     {
1021         return m_customDiffPair.m_Gap;
1022     }
1023     else if( m_diffPairIndex == 0 )
1024     {
1025         if( GetNetClasses().GetDefaultPtr()->HasDiffPairGap() )
1026             return GetNetClasses().GetDefaultPtr()->GetDiffPairGap();
1027         else
1028             return GetNetClasses().GetDefaultPtr()->GetClearance();
1029     }
1030     else
1031     {
1032         return m_DiffPairDimensionsList[m_diffPairIndex].m_Gap;
1033     }
1034 }
1035 
1036 
GetCurrentDiffPairViaGap() const1037 int BOARD_DESIGN_SETTINGS::GetCurrentDiffPairViaGap() const
1038 {
1039     if( m_useCustomDiffPair )
1040     {
1041         return m_customDiffPair.m_ViaGap;
1042     }
1043     else if( m_diffPairIndex == 0 )
1044     {
1045         if( GetNetClasses().GetDefaultPtr()->HasDiffPairViaGap() )
1046             return GetNetClasses().GetDefaultPtr()->GetDiffPairViaGap();
1047         else
1048             return GetCurrentDiffPairGap();
1049     }
1050     else
1051     {
1052         return m_DiffPairDimensionsList[m_diffPairIndex].m_ViaGap;
1053     }
1054 }
1055 
1056 
SetMinHoleSeparation(int aDistance)1057 void BOARD_DESIGN_SETTINGS::SetMinHoleSeparation( int aDistance )
1058 {
1059     m_HoleToHoleMin = aDistance;
1060 }
1061 
1062 
SetCopperEdgeClearance(int aDistance)1063 void BOARD_DESIGN_SETTINGS::SetCopperEdgeClearance( int aDistance )
1064 {
1065     m_CopperEdgeClearance = aDistance;
1066 }
1067 
1068 
SetSilkClearance(int aDistance)1069 void BOARD_DESIGN_SETTINGS::SetSilkClearance( int aDistance )
1070 {
1071     m_SilkClearance = aDistance;
1072 }
1073 
1074 
SetCopperLayerCount(int aNewLayerCount)1075 void BOARD_DESIGN_SETTINGS::SetCopperLayerCount( int aNewLayerCount )
1076 {
1077     m_copperLayerCount = aNewLayerCount;
1078 
1079     // Update only enabled copper layers mask
1080     m_enabledLayers &= ~LSET::AllCuMask();
1081 
1082     if( aNewLayerCount > 0 )
1083         m_enabledLayers |= LSET::AllCuMask( aNewLayerCount );
1084 }
1085 
1086 
SetEnabledLayers(LSET aMask)1087 void BOARD_DESIGN_SETTINGS::SetEnabledLayers( LSET aMask )
1088 {
1089     // Back and front layers are always enabled.
1090     aMask.set( B_Cu ).set( F_Cu );
1091 
1092     m_enabledLayers = aMask;
1093 
1094     // update m_CopperLayerCount to ensure its consistency with m_EnabledLayers
1095     m_copperLayerCount = ( aMask & LSET::AllCuMask() ).count();
1096 }
1097 
1098 
1099 // Return the layer class index { silk, copper, edges & courtyards, fab, others } of the
1100 // given layer.
GetLayerClass(PCB_LAYER_ID aLayer) const1101 int BOARD_DESIGN_SETTINGS::GetLayerClass( PCB_LAYER_ID aLayer ) const
1102 {
1103     if( aLayer == F_SilkS || aLayer == B_SilkS )
1104         return LAYER_CLASS_SILK;
1105     else if( IsCopperLayer( aLayer ) )
1106         return LAYER_CLASS_COPPER;
1107     else if( aLayer == Edge_Cuts )
1108         return LAYER_CLASS_EDGES;
1109     else if( aLayer == F_CrtYd || aLayer == B_CrtYd )
1110         return LAYER_CLASS_COURTYARD;
1111     else if( aLayer == F_Fab || aLayer == B_Fab )
1112         return LAYER_CLASS_FAB;
1113     else
1114         return LAYER_CLASS_OTHERS;
1115 }
1116 
1117 
GetDRCEpsilon() const1118 int BOARD_DESIGN_SETTINGS::GetDRCEpsilon() const
1119 {
1120     return Millimeter2iu( ADVANCED_CFG::GetCfg().m_DRCEpsilon );
1121 }
1122 
1123 
GetHolePlatingThickness() const1124 int BOARD_DESIGN_SETTINGS::GetHolePlatingThickness() const
1125 {
1126     return Millimeter2iu( ADVANCED_CFG::GetCfg().m_HoleWallThickness );
1127 }
1128 
1129 
GetLineThickness(PCB_LAYER_ID aLayer) const1130 int BOARD_DESIGN_SETTINGS::GetLineThickness( PCB_LAYER_ID aLayer ) const
1131 {
1132     return m_LineThickness[ GetLayerClass( aLayer ) ];
1133 }
1134 
1135 
GetTextSize(PCB_LAYER_ID aLayer) const1136 wxSize BOARD_DESIGN_SETTINGS::GetTextSize( PCB_LAYER_ID aLayer ) const
1137 {
1138     return m_TextSize[ GetLayerClass( aLayer ) ];
1139 }
1140 
1141 
GetTextThickness(PCB_LAYER_ID aLayer) const1142 int BOARD_DESIGN_SETTINGS::GetTextThickness( PCB_LAYER_ID aLayer ) const
1143 {
1144     return m_TextThickness[ GetLayerClass( aLayer ) ];
1145 }
1146 
1147 
GetTextItalic(PCB_LAYER_ID aLayer) const1148 bool BOARD_DESIGN_SETTINGS::GetTextItalic( PCB_LAYER_ID aLayer ) const
1149 {
1150     return m_TextItalic[ GetLayerClass( aLayer ) ];
1151 }
1152 
1153 
GetTextUpright(PCB_LAYER_ID aLayer) const1154 bool BOARD_DESIGN_SETTINGS::GetTextUpright( PCB_LAYER_ID aLayer ) const
1155 {
1156     return m_TextUpright[ GetLayerClass( aLayer ) ];
1157 }
1158 
1159 
1160