KiCad PCB EDA Suite
board_design_settings.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (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 <dimension.h>
25 #include <track.h>
27 #include <kiface_i.h>
28 #include <board_design_settings.h>
29 #include <drc/drc_item.h>
30 #include <drc/drc_engine.h>
31 #include <settings/parameters.h>
32 #include <project/project_file.h>
33 #include <advanced_config.h>
34 
35 const int bdsSchemaVersion = 2;
36 
37 
38 BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std::string& aPath ) :
39  NESTED_SETTINGS( "board_design_settings", bdsSchemaVersion, aParent, aPath ),
40  m_Pad_Master( NULL )
41 {
42  // We want to leave alone parameters that aren't found in the project JSON as they may be
43  // initialized by the board file parser before NESTED_SETTINGS::LoadFromFile is called.
44  m_resetParamsIfMissing = false;
45 
46  // Create a default NETCLASS list so that things don't break horribly if there's no project
47  // loaded. This also is used during file load for legacy boards that have netclasses stored
48  // in the file. After load, this information will be moved to the project and the pointer
49  // updated.
51 
52  m_HasStackup = false; // no stackup defined by default
53 
54  LSET all_set = LSET().set();
55  m_enabledLayers = all_set; // All layers enabled at first.
56  // SetCopperLayerCount() will adjust this.
57 
58  SetCopperLayerCount( 2 ); // Default design is a double sided board
60 
61  // if true, when creating a new track starting on an existing track, use this track width
63 
65  m_MicroViasAllowed = false;
66 
67  // First is always the reference designator
68  m_DefaultFPTextItems.emplace_back( wxT( "REF**" ), true, F_SilkS );
69  // Second is always the value
70  m_DefaultFPTextItems.emplace_back( wxT( "" ), true, F_Fab );
71  // Any following ones are freebies
72  m_DefaultFPTextItems.emplace_back( wxT( "${REF}" ), true, F_Fab );
73 
78  m_TextItalic[ LAYER_CLASS_SILK ] = false;
80 
87 
88  // Edges & Courtyards; text properties aren't used but better to have them holding
89  // reasonable values than not.
96 
103 
108  m_TextItalic[ LAYER_CLASS_FAB ] = false;
109  m_TextUpright[ LAYER_CLASS_FAB ] = false;
110 
115  m_TextItalic[ LAYER_CLASS_OTHERS ] = false;
117 
126 
127  m_useCustomTrackVia = false;
131 
132  m_useCustomDiffPair = false;
136 
148 
149  for( int errorCode = DRCE_FIRST; errorCode <= DRCE_LAST; ++errorCode )
150  m_DRCSeverities[ errorCode ] = RPT_SEVERITY_ERROR;
151 
155 
158 
163 
164  m_MaxError = ARC_HIGH_DEF;
165  m_ZoneFillVersion = 6; // Use new algo by default to fill zones
166  m_ZoneKeepExternalFillets = false; // Use new algo by default. Legacy boards might
167  // want to set it to true for old algo....
169 
170  // Global mask margins:
173 
174  // Solder paste margin absolute value
176  // Solder paste margin as a ratio of pad size
177  // The final margin is the sum of these 2 values
178  // Usually < 0 because the mask is smaller than pad
180 
181  // Layer thickness for 3D viewer
183 
184  m_viaSizeIndex = 0;
185  m_trackWidthIndex = 0;
186  m_diffPairIndex = 0;
187 
188  // Parameters stored in JSON in the project file
189 
190  // NOTE: Previously, BOARD_DESIGN_SETTINGS stored the basic board layer information (layer
191  // names and enable/disable state) in the project file even though this information is also
192  // stored in the board file. This was implemented for importing these settings from another
193  // project. Going forward, the import feature will just import from other board files (since
194  // we could have multi-board projects in the future anyway) so this functionality is dropped.
195 
196  m_params.emplace_back( new PARAM<bool>( "rules.allow_microvias", &m_MicroViasAllowed, false ) );
197 
198  m_params.emplace_back( new PARAM<bool>( "rules.allow_blind_buried_vias",
199  &m_BlindBuriedViaAllowed, false ) );
200 
201  m_params.emplace_back( new PARAM<bool>( "rules.use_height_for_length_calcs",
202  &m_UseHeightForLengthCalcs, true ) );
203 
204  m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_clearance", &m_MinClearance,
206  MM_PER_IU ) );
207 
208  m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_track_width", &m_TrackMinWidth,
210  MM_PER_IU ) );
211 
212  m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_via_annular_width", &m_ViasMinAnnulus,
214  MM_PER_IU ) );
215 
216  m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_via_diameter", &m_ViasMinSize,
218  MM_PER_IU ) );
219 
220  m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_through_hole_diameter",
222  Millimeter2iu( 25.0 ), MM_PER_IU ) );
223 
224  m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_microvia_diameter",
226  Millimeter2iu( 10.0 ), MM_PER_IU ) );
227 
228  m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_microvia_drill", &m_MicroViasMinDrill,
230  Millimeter2iu( 10.0 ), MM_PER_IU ) );
231 
232  m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_hole_to_hole", &m_HoleToHoleMin,
234  MM_PER_IU ) );
235 
236  m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_hole_clearance", &m_HoleClearance,
238  MM_PER_IU ) );
239 
240  m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_silk_clearance", &m_SilkClearance,
242  MM_PER_IU ) );
243 
244  // Note: a clearance of -0.01 is a flag indicating we should use the legacy (pre-6.0) method
245  // based on the edge cut thicknesses.
246  m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_copper_edge_clearance",
248  Millimeter2iu( -0.01 ), Millimeter2iu( 25.0 ), MM_PER_IU ) );
249 
250  m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "rule_severities",
251  [&]() -> nlohmann::json
252  {
253  nlohmann::json ret = {};
254 
255  for( const RC_ITEM& item : DRC_ITEM::GetItemsWithSeverities() )
256  {
257  wxString name = item.GetSettingsKey();
258  int code = item.GetErrorCode();
259 
260  if( name.IsEmpty() || m_DRCSeverities.count( code ) == 0 )
261  continue;
262 
263  ret[std::string( name.ToUTF8() )] = SeverityToString( m_DRCSeverities[code] );
264  }
265 
266  return ret;
267  },
268  [&]( const nlohmann::json& aJson )
269  {
270  if( !aJson.is_object() )
271  return;
272 
273  for( const RC_ITEM& item : DRC_ITEM::GetItemsWithSeverities() )
274  {
275  wxString name = item.GetSettingsKey();
276  std::string key( name.ToUTF8() );
277 
278  if( aJson.contains( key ) )
279  m_DRCSeverities[item.GetErrorCode()] = SeverityFromString( aJson[key] );
280  }
281  }, {} ) );
282 
283  m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "drc_exclusions",
284  [&]() -> nlohmann::json
285  {
286  nlohmann::json js = nlohmann::json::array();
287 
288  for( const auto& entry : m_DrcExclusions )
289  js.push_back( entry );
290 
291  return js;
292  },
293  [&]( const nlohmann::json& aObj )
294  {
295  m_DrcExclusions.clear();
296 
297  if( !aObj.is_array() )
298  return;
299 
300  for( const nlohmann::json& entry : aObj )
301  {
302  if( entry.empty() )
303  continue;
304 
305  m_DrcExclusions.insert( entry.get<wxString>() );
306  }
307  },
308  {} ) );
309 
310  m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "track_widths",
311  [&]() -> nlohmann::json
312  {
313  nlohmann::json js = nlohmann::json::array();
314 
315  for( const int& width : m_TrackWidthList )
316  js.push_back( Iu2Millimeter( width ) );
317 
318  return js;
319  },
320  [&]( const nlohmann::json& aJson )
321  {
322  if( !aJson.is_array() )
323  return;
324 
325  m_TrackWidthList.clear();
326 
327  for( const nlohmann::json& entry : aJson )
328  {
329  if( entry.empty() )
330  continue;
331 
332  m_TrackWidthList.emplace_back( Millimeter2iu( entry.get<double>() ) );
333  }
334  },
335  {} ) );
336 
337  m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "via_dimensions",
338  [&]() -> nlohmann::json
339  {
340  nlohmann::json js = nlohmann::json::array();
341 
342  for( const auto& via : m_ViasDimensionsList )
343  {
344  nlohmann::json entry = {};
345 
346  entry["diameter"] = Iu2Millimeter( via.m_Diameter );
347  entry["drill"] = Iu2Millimeter( via.m_Drill );
348 
349  js.push_back( entry );
350  }
351 
352  return js;
353  },
354  [&]( const nlohmann::json& aObj )
355  {
356  if( !aObj.is_array() )
357  return;
358 
359  m_ViasDimensionsList.clear();
360 
361  for( const nlohmann::json& entry : aObj )
362  {
363  if( entry.empty() || !entry.is_object() )
364  continue;
365 
366  if( !entry.contains( "diameter" ) || !entry.contains( "drill" ) )
367  continue;
368 
369  int diameter = Millimeter2iu( entry["diameter"].get<double>() );
370  int drill = Millimeter2iu( entry["drill"].get<double>() );
371 
372  m_ViasDimensionsList.emplace_back( VIA_DIMENSION( diameter, drill ) );
373  }
374  },
375  {} ) );
376 
377  m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "diff_pair_dimensions",
378  [&]() -> nlohmann::json
379  {
380  nlohmann::json js = nlohmann::json::array();
381 
382  for( const auto& pair : m_DiffPairDimensionsList )
383  {
384  nlohmann::json entry = {};
385 
386  entry["width"] = Iu2Millimeter( pair.m_Width );
387  entry["gap"] = Iu2Millimeter( pair.m_Gap );
388  entry["via_gap"] = Iu2Millimeter( pair.m_ViaGap );
389 
390  js.push_back( entry );
391  }
392 
393  return js;
394  },
395  [&]( const nlohmann::json& aObj )
396  {
397  if( !aObj.is_array() )
398  return;
399 
400  m_DiffPairDimensionsList.clear();
401 
402  for( const nlohmann::json& entry : aObj )
403  {
404  if( entry.empty() || !entry.is_object() )
405  continue;
406 
407  if( !entry.contains( "width" ) || !entry.contains( "gap" )
408  || !entry.contains( "via_gap" ) )
409  continue;
410 
411  int width = Millimeter2iu( entry["width"].get<double>() );
412  int gap = Millimeter2iu( entry["gap"].get<double>() );
413  int via_gap = Millimeter2iu( entry["via_gap"].get<double>() );
414 
415  m_DiffPairDimensionsList.emplace_back(
416  DIFF_PAIR_DIMENSION( width, gap, via_gap ) );
417  }
418  },
419  {} ) );
420 
421  m_params.emplace_back( new PARAM_SCALED<int>( "defaults.silk_line_width",
423  Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) );
424 
425  m_params.emplace_back( new PARAM_SCALED<int>( "defaults.silk_text_size_v",
427  TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, MM_PER_IU ) );
428 
429  m_params.emplace_back( new PARAM_SCALED<int>( "defaults.silk_text_size_h",
431  TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, MM_PER_IU ) );
432 
433  m_params.emplace_back( new PARAM_SCALED<int>( "defaults.silk_text_thickness",
435  TEXTS_MAX_WIDTH, MM_PER_IU ) );
436 
437  m_params.emplace_back( new PARAM<bool>( "defaults.silk_text_italic",
438  &m_TextItalic[LAYER_CLASS_SILK], false ) );
439 
440  m_params.emplace_back( new PARAM<bool>( "defaults.silk_text_upright",
441  &m_TextUpright[ LAYER_CLASS_SILK ], true ) );
442 
443  m_params.emplace_back( new PARAM_SCALED<int>( "defaults.copper_line_width",
445  Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) );
446 
447  m_params.emplace_back( new PARAM_SCALED<int>( "defaults.copper_text_size_v",
449  TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, MM_PER_IU ) );
450 
451  m_params.emplace_back( new PARAM_SCALED<int>( "defaults.copper_text_size_h",
453  TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, MM_PER_IU ) );
454 
455  m_params.emplace_back( new PARAM_SCALED<int>( "defaults.copper_text_thickness",
457  Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) );
458 
459  m_params.emplace_back( new PARAM<bool>( "defaults.copper_text_italic",
460  &m_TextItalic[LAYER_CLASS_COPPER], false ) );
461 
462  m_params.emplace_back( new PARAM<bool>( "defaults.copper_text_upright",
463  &m_TextUpright[LAYER_CLASS_COPPER], true ) );
464 
465  m_params.emplace_back( new PARAM_SCALED<int>( "defaults.board_outline_line_width",
467  Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) );
468 
469  m_params.emplace_back( new PARAM_SCALED<int>( "defaults.courtyard_line_width",
471  Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) );
472 
473  m_params.emplace_back( new PARAM_SCALED<int>( "defaults.fab_line_width",
475  Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) );
476 
477  m_params.emplace_back( new PARAM_SCALED<int>( "defaults.fab_text_size_v",
479  TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, MM_PER_IU ) );
480 
481  m_params.emplace_back( new PARAM_SCALED<int>( "defaults.fab_text_size_h",
483  TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, MM_PER_IU ) );
484 
485  m_params.emplace_back( new PARAM_SCALED<int>( "defaults.fab_text_thickness",
487  Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) );
488 
489  m_params.emplace_back( new PARAM<bool>( "defaults.fab_text_italic",
490  &m_TextItalic[LAYER_CLASS_FAB], false ) );
491 
492  m_params.emplace_back( new PARAM<bool>( "defaults.fab_text_upright",
493  &m_TextUpright[LAYER_CLASS_FAB], true ) );
494 
495  m_params.emplace_back( new PARAM_SCALED<int>( "defaults.other_line_width",
497  Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) );
498 
499  m_params.emplace_back( new PARAM_SCALED<int>( "defaults.other_text_size_v",
501  TEXTS_MAX_SIZE, MM_PER_IU ) );
502 
503  m_params.emplace_back( new PARAM_SCALED<int>( "defaults.other_text_size_h",
505  TEXTS_MAX_SIZE, MM_PER_IU ) );
506 
507  m_params.emplace_back( new PARAM_SCALED<int>( "defaults.other_text_thickness",
509  Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) );
510 
511  m_params.emplace_back( new PARAM<bool>( "defaults.other_text_italic",
512  &m_TextItalic[LAYER_CLASS_OTHERS], false ) );
513 
514  m_params.emplace_back( new PARAM<bool>( "defaults.other_text_upright",
515  &m_TextUpright[LAYER_CLASS_OTHERS], true ) );
516 
517  m_params.emplace_back( new PARAM_ENUM<DIM_UNITS_MODE>( "defaults.dimension_units",
520 
521  m_params.emplace_back( new PARAM<int>( "defaults.dimension_precision",
522  &m_DimensionPrecision, 4, 0, 5 ) );
523 
524  m_params.emplace_back( new PARAM_ENUM<DIM_UNITS_FORMAT>( "defaults.dimensions.units_format",
527 
528  m_params.emplace_back( new PARAM<bool>( "defaults.dimensions.suppress_zeroes",
529  &m_DimensionSuppressZeroes, false ) );
530 
531  // NOTE: excluding DIM_TEXT_POSITION::MANUAL from the valid range here
532  m_params.emplace_back( new PARAM_ENUM<DIM_TEXT_POSITION>( "defaults.dimensions.text_position",
535 
536  m_params.emplace_back( new PARAM<bool>( "defaults.dimensions.keep_text_aligned",
537  &m_DimensionKeepTextAligned, true ) );
538 
539  m_params.emplace_back( new PARAM<int>( "defaults.dimensions.arrow_length",
541  Mils2iu( DEFAULT_DIMENSION_ARROW_LENGTH ) ) );
542 
543  m_params.emplace_back( new PARAM<int>( "defaults.dimensions.extension_offset",
546 
547  m_params.emplace_back( new PARAM<bool>( "defaults.zones.45_degree_only",
549 
550  m_params.emplace_back( new PARAM_SCALED<int>( "defaults.zones.min_clearance",
552  Millimeter2iu( 0.0 ), Millimeter2iu( 25.0 ), MM_PER_IU ) );
553 
554  m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "defaults.pads",
555  [&]() -> nlohmann::json
556  {
557  nlohmann::json ret =
558  {
559  { "width", Iu2Millimeter( m_Pad_Master.GetSize().x ) },
560  { "height", Iu2Millimeter( m_Pad_Master.GetSize().y ) },
561  { "drill", Iu2Millimeter( m_Pad_Master.GetDrillSize().x ) }
562  };
563 
564  return ret;
565  },
566  [&]( const nlohmann::json& aJson )
567  {
568  if( aJson.contains( "width" ) && aJson.contains( "height" )
569  && aJson.contains( "drill" ) )
570  {
571  wxSize sz;
572  sz.SetWidth( Millimeter2iu( aJson["width"].get<double>() ) );
573  sz.SetHeight( Millimeter2iu( aJson["height"].get<double>() ) );
574 
575  m_Pad_Master.SetSize( sz );
576 
577  int drill = Millimeter2iu( aJson["drill"].get<double>() );
578 
579  m_Pad_Master.SetDrillSize( wxSize( drill, drill ) );
580  }
581  }, {} ) );
582 
583  m_params.emplace_back( new PARAM_SCALED<int>( "rules.max_error", &m_MaxError, ARC_HIGH_DEF,
584  Millimeter2iu( 0.0001 ), Millimeter2iu( 1.0 ), MM_PER_IU ) );
585 
586  // TODO: replace with zones_fill_version parameter and migrate zones_use_no_outline?
587  m_params.emplace_back( new PARAM_LAMBDA<bool>( "zones_use_no_outline",
588  [this]() -> bool
589  {
590  return m_ZoneFillVersion >= 6;
591  },
592  [this]( bool aVal )
593  {
594  m_ZoneFillVersion = aVal ? 6 : 5;
595  },
596  true ) );
597 
598  m_params.emplace_back( new PARAM<bool>( "zones_allow_external_fillets",
599  &m_ZoneKeepExternalFillets, false ) );
600 
601  registerMigration( 0, 1, std::bind( &BOARD_DESIGN_SETTINGS::migrateSchema0to1, this ) );
602 
603  registerMigration( 1, 2,
604  [&]() -> bool
605  {
606  // Schema 1 to 2: move mask and paste margin settings back to board.
607  // The parameters are removed, so we just have to manually load them here and
608  // they will get saved with the board
609  if( OPT<double> optval = Get<double>( "rules.solder_mask_clearance" ) )
610  m_SolderMaskMargin = static_cast<int>( *optval * IU_PER_MM );
611 
612  if( OPT<double> optval = Get<double>( "rules.solder_mask_min_width" ) )
613  m_SolderMaskMinWidth = static_cast<int>( *optval * IU_PER_MM );
614 
615  if( OPT<double> optval = Get<double>( "rules.solder_paste_clearance" ) )
616  m_SolderPasteMargin = static_cast<int>( *optval * IU_PER_MM );
617 
618  if( OPT<double> optval = Get<double>( "rules.solder_paste_margin_ratio" ) )
619  m_SolderPasteMarginRatio = *optval;
620 
621  try
622  {
623  at( "rules" ).erase( "solder_mask_clearance" );
624  at( "rules" ).erase( "solder_mask_min_width" );
625  at( "rules" ).erase( "solder_paste_clearance" );
626  at( "rules" ).erase( "solder_paste_margin_ratio" );
627  }
628  catch( ... )
629  {}
630 
631  return true;
632  } );
633 }
634 
635 
637 {
638  if( m_parent )
639  {
641  m_parent = nullptr;
642  }
643 }
644 
645 
647  NESTED_SETTINGS( "board_design_settings", bdsSchemaVersion, aOther.m_parent,
648  aOther.m_path ),
649  m_Pad_Master( nullptr )
650 {
651  initFromOther( aOther );
652 }
653 
654 
656 {
657  initFromOther( aOther );
658  return *this;
659 }
660 
661 
663 {
664  // Copy of NESTED_SETTINGS around is not allowed, so let's just update the params.
675  m_ViasMinSize = aOther.m_ViasMinSize;
687  m_MaxError = aOther.m_MaxError;
693 
694  std::copy( std::begin( aOther.m_LineThickness ), std::end( aOther.m_LineThickness ),
695  std::begin( m_LineThickness ) );
696 
697  std::copy( std::begin( aOther.m_TextSize ), std::end( aOther.m_TextSize ),
698  std::begin( m_TextSize ) );
699 
700  std::copy( std::begin( aOther.m_TextThickness ), std::end( aOther.m_TextThickness ),
701  std::begin( m_TextThickness ) );
702 
703  std::copy( std::begin( aOther.m_TextItalic ), std::end( aOther.m_TextItalic ),
704  std::begin( m_TextItalic ) );
705 
706  std::copy( std::begin( aOther.m_TextUpright ), std::end( aOther.m_TextUpright ),
707  std::begin( m_TextUpright ) );
708 
717 
718  m_AuxOrigin = aOther.m_AuxOrigin;
719  m_GridOrigin = aOther.m_GridOrigin;
720  m_HasStackup = aOther.m_HasStackup;
721 
734  m_stackup = aOther.m_stackup;
735 
736  // Only take the pointer from the other if it isn't the default
737  if( aOther.m_netClasses == &aOther.m_internalNetClasses )
739  else
740  m_netClasses = aOther.m_netClasses;
741 
743 }
744 
745 
747 {
765  nlohmann::json::json_pointer units_ptr( "/defaults/dimension_units" );
766  nlohmann::json::json_pointer precision_ptr( "/defaults/dimension_precision" );
767 
768  if( !( contains( units_ptr ) && contains( precision_ptr ) &&
769  at( units_ptr ).is_number_integer() &&
770  at( precision_ptr ).is_number_integer() ) )
771  {
772  // if either is missing or invalid, migration doesn't make sense
773  return true;
774  }
775 
776  int units = at( units_ptr ).get<int>();
777  int precision = at( precision_ptr ).get<int>();
778 
779  // The enum maps directly to precision if the units is mils
780  int extraDigits = 0;
781 
782  switch( units )
783  {
784  case 0: extraDigits = 3; break;
785  case 2: extraDigits = 2; break;
786  default: break;
787  }
788 
789  precision += extraDigits;
790 
791  ( *this )[precision_ptr] = precision;
792 
793  return true;
794 }
795 
796 
797 bool BOARD_DESIGN_SETTINGS::LoadFromFile( const wxString& aDirectory )
798 {
799  bool ret = NESTED_SETTINGS::LoadFromFile( aDirectory );
800 
801  // A number of things won't have been translated by the PROJECT_FILE migration because of
802  // descoped objects required to decode this data. So, it will be in the legacy.pcbnew
803  // section and needs to be pulled out here
804 
805  PROJECT_FILE* project = dynamic_cast<PROJECT_FILE*>( GetParent() );
806 
807  if( !project )
808  return ret;
809 
810  bool migrated = false;
811 
812  auto drcName =
813  []( int aCode ) -> std::string
814  {
815  std::shared_ptr<DRC_ITEM> item = DRC_ITEM::Create( aCode );
816  wxString name = item->GetSettingsKey();
817  return std::string( name.ToUTF8() );
818  };
819 
820  std::string bp = "board.design_settings.rule_severities.";
821  std::string rs = "rule_severities.";
822 
823  if( OPT<bool> v =
824  project->Get<bool>( PointerFromString( bp + "legacy_no_courtyard_defined" ) ) )
825  {
826  if( *v )
827  ( *this )[PointerFromString( rs + drcName( DRCE_MISSING_COURTYARD ) )] = "error";
828  else
829  ( *this )[PointerFromString( rs + drcName( DRCE_MISSING_COURTYARD ) )] = "ignore";
830 
831  project->erase( PointerFromString( bp + "legacy_no_courtyard_defined" ) );
832  migrated = true;
833  }
834 
835  if( OPT<bool> v = project->Get<bool>( PointerFromString( bp + "legacy_courtyards_overlap" ) ) )
836  {
837  if( *v )
838  ( *this )[PointerFromString( rs + drcName( DRCE_OVERLAPPING_FOOTPRINTS ) )] = "error";
839  else
840  ( *this )[PointerFromString( rs + drcName( DRCE_OVERLAPPING_FOOTPRINTS ) )] = "ignore";
841 
842  project->erase( PointerFromString( bp + "legacy_courtyards_overlap" ) );
843  migrated = true;
844  }
845 
846  if( project->contains( "legacy" ) )
847  {
848  // This defaults to false for new boards, but version 5.1.x and prior kept the fillets
849  // so we do the same for legacy boards.
851 
852  project->at( "legacy" ).erase( "pcbnew" );
853  }
854 
855  // Now that we have everything, we need to load again
856  if( migrated )
857  Load();
858 
859  return ret;
860 }
861 
862 
864 {
865  return m_DRCSeverities[ aDRCErrorCode ];
866 }
867 
868 
869 bool BOARD_DESIGN_SETTINGS::Ignore( int aDRCErrorCode )
870 {
871  return m_DRCSeverities[ aDRCErrorCode ] == RPT_SEVERITY_IGNORE;
872 }
873 
874 
876 {
877  int biggest = 0;
878  DRC_CONSTRAINT constraint;
879 
880  if( m_DRCEngine )
881  {
882  m_DRCEngine->QueryWorstConstraint( CLEARANCE_CONSTRAINT, constraint );
883  biggest = std::max( biggest, constraint.Value().Min() );
884 
885  m_DRCEngine->QueryWorstConstraint( HOLE_CLEARANCE_CONSTRAINT, constraint );
886  biggest = std::max( biggest, constraint.Value().Min() );
887 
888  m_DRCEngine->QueryWorstConstraint( EDGE_CLEARANCE_CONSTRAINT, constraint );
889  biggest = std::max( biggest, constraint.Value().Min() );
890  }
891 
892  return biggest;
893 }
894 
895 
897 {
898  int clearance = GetDefault()->GetClearance();
899 
900  for( const std::pair<const wxString, NETCLASSPTR>& netclass : GetNetClasses().NetClasses() )
901  clearance = std::min( clearance, netclass.second->GetClearance() );
902 
903  return clearance;
904 }
905 
906 
908 {
909  NETCLASSPTR netclass = GetNetClasses().Find( m_currentNetClassName );
910 
911  return netclass->GetuViaDiameter();
912 }
913 
914 
916 {
917  NETCLASSPTR netclass = GetNetClasses().Find( m_currentNetClassName );
918 
919  return netclass->GetuViaDrill();
920 }
921 
922 
924 {
925  m_viaSizeIndex = std::min( aIndex, (unsigned) m_ViasDimensionsList.size() );
926  m_useCustomTrackVia = false;
927 }
928 
929 
931 {
932  if( m_useCustomTrackVia )
934  else if( m_viaSizeIndex == 0 )
936  else
937  return m_ViasDimensionsList[ m_viaSizeIndex ].m_Diameter;
938 }
939 
940 
942 {
943  int drill;
944 
945  if( m_useCustomTrackVia )
946  drill = m_customViaSize.m_Drill;
947  else if( m_viaSizeIndex == 0 )
948  drill = GetNetClasses().GetDefaultPtr()->GetViaDrill();
949  else
950  drill = m_ViasDimensionsList[ m_viaSizeIndex ].m_Drill;
951 
952  return drill > 0 ? drill : -1;
953 }
954 
955 
957 {
958  m_trackWidthIndex = std::min( aIndex, (unsigned) m_TrackWidthList.size() );
959  m_useCustomTrackVia = false;
960 }
961 
962 
964 {
965  if( m_useCustomTrackVia )
966  return m_customTrackWidth;
967  else if( m_trackWidthIndex == 0 )
969  else
971 }
972 
973 
975 {
976  m_diffPairIndex = std::min( aIndex, (unsigned) 8 );
977  m_useCustomDiffPair = false;
978 }
979 
980 
982 {
983  if( m_useCustomDiffPair )
984  {
985  return m_customDiffPair.m_Width;
986  }
987  else if( m_diffPairIndex == 0 )
988  {
989  if( GetNetClasses().GetDefaultPtr()->HasDiffPairWidth() )
991  else
993  }
994  else
995  {
997  }
998 }
999 
1000 
1002 {
1003  if( m_useCustomDiffPair )
1004  {
1005  return m_customDiffPair.m_Gap;
1006  }
1007  else if( m_diffPairIndex == 0 )
1008  {
1009  if( GetNetClasses().GetDefaultPtr()->HasDiffPairGap() )
1011  else
1013  }
1014  else
1015  {
1017  }
1018 }
1019 
1020 
1022 {
1023  if( m_useCustomDiffPair )
1024  {
1025  return m_customDiffPair.m_ViaGap;
1026  }
1027  else if( m_diffPairIndex == 0 )
1028  {
1029  if( GetNetClasses().GetDefaultPtr()->HasDiffPairViaGap() )
1031  else
1032  return GetCurrentDiffPairGap();
1033  }
1034  else
1035  {
1036  return m_DiffPairDimensionsList[m_diffPairIndex].m_ViaGap;
1037  }
1038 }
1039 
1040 
1042 {
1043  m_HoleToHoleMin = aDistance;
1044 }
1045 
1046 
1048 {
1049  m_CopperEdgeClearance = aDistance;
1050 }
1051 
1052 
1054 {
1055  m_SilkClearance = aDistance;
1056 }
1057 
1058 
1060 {
1061  m_copperLayerCount = aNewLayerCount;
1062 
1063  // Update only enabled copper layers mask
1064  m_enabledLayers &= ~LSET::AllCuMask();
1065 
1066  if( aNewLayerCount > 0 )
1067  m_enabledLayers |= LSET::AllCuMask( aNewLayerCount );
1068 }
1069 
1070 
1072 {
1073  // Back and front layers are always enabled.
1074  aMask.set( B_Cu ).set( F_Cu );
1075 
1076  m_enabledLayers = aMask;
1077 
1078  // update m_CopperLayerCount to ensure its consistency with m_EnabledLayers
1079  m_copperLayerCount = ( aMask & LSET::AllCuMask() ).count();
1080 }
1081 
1082 
1083 // Return the layer class index { silk, copper, edges & courtyards, fab, others } of the
1084 // given layer.
1086 {
1087  if( aLayer == F_SilkS || aLayer == B_SilkS )
1088  return LAYER_CLASS_SILK;
1089  else if( IsCopperLayer( aLayer ) )
1090  return LAYER_CLASS_COPPER;
1091  else if( aLayer == Edge_Cuts )
1092  return LAYER_CLASS_EDGES;
1093  else if( aLayer == F_CrtYd || aLayer == B_CrtYd )
1094  return LAYER_CLASS_COURTYARD;
1095  else if( aLayer == F_Fab || aLayer == B_Fab )
1096  return LAYER_CLASS_FAB;
1097  else
1098  return LAYER_CLASS_OTHERS;
1099 }
1100 
1101 
1103 {
1104  return Millimeter2iu( ADVANCED_CFG::GetCfg().m_DRCEpsilon );
1105 }
1106 
1107 
1109 {
1110  return Millimeter2iu( ADVANCED_CFG::GetCfg().m_HoleWallThickness );
1111 }
1112 
1113 
1115 {
1116  return m_LineThickness[ GetLayerClass( aLayer ) ];
1117 }
1118 
1119 
1121 {
1122  return m_TextSize[ GetLayerClass( aLayer ) ];
1123 }
1124 
1125 
1127 {
1128  return m_TextThickness[ GetLayerClass( aLayer ) ];
1129 }
1130 
1131 
1133 {
1134  return m_TextItalic[ GetLayerClass( aLayer ) ];
1135 }
1136 
1137 
1139 {
1140  return m_TextUpright[ GetLayerClass( aLayer ) ];
1141 }
1142 
1143 
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:750
#define DEFAULT_EDGE_WIDTH
#define DEFAULT_SILK_TEXT_WIDTH
void SetCopperLayerCount(int aNewLayerCount)
Set the copper layer count to aNewLayerCount.
#define DEFAULT_TRACKMINWIDTH
Container to handle a stock of specific vias each with unique diameter and drill sizes in the BOARD c...
int m_ZoneFillVersion
Option to select different fill algorithms.
void SetEnabledLayers(LSET aMask)
Change the bit-mask of enabled layers to aMask.
void SetCopperEdgeClearance(int aDistance)
#define DEFAULT_COURTYARD_WIDTH
void SetTrackWidthIndex(unsigned aIndex)
Set the current track width list index to aIndex.
wxString m_currentNetClassName
Current net class name used to display netclass info.
std::vector< TEXT_ITEM_INFO > m_DefaultFPTextItems
std::vector< PARAM_BASE * > m_params
The list of parameters (owned by this object)
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition: drc_item.cpp:245
#define DEFAULT_SOLDERPASTE_RATIO
wxPoint m_GridOrigin
origin for grid offsets
NETCLASSPTR Find(const wxString &aName) const
Search this container for a NETCLASS given by aName.
Definition: netclass.cpp:132
int GetDiffPairGap() const
Definition: netclass.h:152
JSON_SETTINGS * GetParent()
#define DEFAULT_VIASMINSIZE
#define TEXTS_MAX_WIDTH
Maximum text width in internal units (10 inches)
Definition: pcbnew.h:33
BOARD_DESIGN_SETTINGS(JSON_SETTINGS *aParent, const std::string &aPath)
MINOPTMAX< int > & Value()
Definition: drc_rule.h:122
std::vector< int > m_TrackWidthList
BOARD_STACKUP m_stackup
the description of layers stackup, for board fabrication only physical layers are in layers stackup.
SEVERITY
Definition: ui_common.h:83
static constexpr double IU_PER_MM
Mock up a conversion function.
std::vector< DIFF_PAIR_DIMENSION > m_DiffPairDimensionsList
int GetHolePlatingThickness() const
Pad & via drills are finish size.
A holder for a rule check item, DRC in Pcbnew or ERC in Eeschema.
Definition: rc_item.h:72
NETCLASSES m_internalNetClasses
Net classes that are loaded from the board file before these were stored in the project.
bool Ignore(int aDRCErrorCode)
Return true if the DRC error code's severity is SEVERITY_IGNORE.
#define LEGACY_COPPEREDGECLEARANCE
#define DEFAULT_BOARD_THICKNESS_MM
int m_DimensionPrecision
Number of digits after the decimal.
ZONE_SETTINGS m_defaultZoneSettings
The default settings that will be used for new zones.
#define DEFAULT_LINE_WIDTH
#define DEFAULT_DIMENSION_ARROW_LENGTH
#define DEFAULT_COPPER_LINE_WIDTH
#define DEFAULT_HOLETOHOLEMIN
Stores an enum as an integer.
Definition: parameters.h:226
void SetSize(const wxSize &aSize)
Definition: pad.h:231
T Min() const
Definition: minoptmax.h:33
DIFF_PAIR_DIMENSION m_customDiffPair
#define DEFAULT_CUSTOMDPAIRGAP
int GetTextThickness(PCB_LAYER_ID aLayer) const
Return the default text thickness from the layer class for the given layer.
VIATYPE m_CurrentViaType
(VIA_BLIND_BURIED, VIA_THROUGH, VIA_MICROVIA)
bool LoadFromFile(const wxString &aDirectory="") override
Loads the JSON document from the parent and then calls Load()
nlohmann::json json
Definition: gerbview.cpp:41
The backing store for a PROJECT, in JSON format.
Definition: project_file.h:64
Container to handle a stock of specific differential pairs each with unique track width,...
#define DEFAULT_MINCLEARANCE
#define DEFAULT_MINTHROUGHDRILL
DIM_TEXT_POSITION m_DimensionTextPosition
DIM_UNITS_MODE m_DimensionUnitsMode
#define DEFAULT_CUSTOMDPAIRVIAGAP
int GetLayerClass(PCB_LAYER_ID aLayer) const
#define DEFAULT_DIMENSION_EXTENSION_OFFSET
bool GetTextUpright(PCB_LAYER_ID aLayer) const
#define DEFAULT_SOLDERPASTE_CLEARANCE
bool GetTextItalic(PCB_LAYER_ID aLayer) const
int GetLineThickness(PCB_LAYER_ID aLayer) const
Return the default graphic segment thickness from the layer class for the given layer.
#define DEFAULT_TEXT_WIDTH
wxSize m_TextSize[LAYER_CLASS_COUNT]
void SetViaSizeIndex(unsigned aIndex)
Set the current via size list index to aIndex.
NESTED_SETTINGS is a JSON_SETTINGS that lives inside a JSON_SETTINGS.
#define DEFAULT_CUSTOMDPAIRWIDTH
const wxSize & GetDrillSize() const
Definition: pad.h:242
PCB_LAYER_ID
A quick note on layer IDs:
int GetTrackWidth() const
Definition: netclass.h:128
#define DEFAULT_SILK_TEXT_SIZE
int m_TextThickness[LAYER_CLASS_COUNT]
LSET is a set of PCB_LAYER_IDs.
#define DEFAULT_SILK_LINE_WIDTH
int GetDiffPairViaGap() const
Definition: netclass.h:156
#define NULL
void SetMinHoleSeparation(int aDistance)
bool LoadFromFile(const wxString &aDirectory="") override
Loads the backing file from disk and then calls Load()
void SetDrillSize(const wxSize &aSize)
Definition: pad.h:241
const wxSize & GetSize() const
Definition: pad.h:232
JSON_SETTINGS * m_parent
A pointer to the parent object to load and store from.
int GetViaDrill() const
Definition: netclass.h:136
bool m_TextItalic[LAYER_CLASS_COUNT]
Represents a parameter that has a scaling factor between the value in the file and the value used int...
Definition: parameters.h:388
#define ZONE_CLEARANCE_MIL
Definition: zones.h:33
BOARD_DESIGN_SETTINGS & operator=(const BOARD_DESIGN_SETTINGS &aOther)
NETCLASSES & GetNetClasses() const
Text appears outside the dimension line (default)
bool m_BlindBuriedViaAllowed
true to allow blind/buried vias
SEVERITY GetSeverity(int aDRCErrorCode)
const int bdsSchemaVersion
#define TEXTS_MAX_SIZE
Maximum text size in internal units (10 inches)
Definition: pcbnew.h:32
void SetDiffPairIndex(unsigned aIndex)
#define DEFAULT_MICROVIASMINSIZE
int GetDiffPairWidth() const
Definition: netclass.h:148
NETCLASS * GetDefaultPtr() const
Definition: netclass.h:258
#define DEFAULT_MICROVIASMINDRILL
#define DEFAULT_SOLDERMASK_MIN_WIDTH
int m_LineThickness[LAYER_CLASS_COUNT]
Text appears in line with the dimension line.
#define DEFAULT_HOLECLEARANCE
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition: kicad_algo.h:81
#define TEXTS_MIN_SIZE
Minimum text size in internal units (1 mil)
Definition: pcbnew.h:31
#define DEFAULT_COPPEREDGECLEARANCE
bool m_UseHeightForLengthCalcs
Enable inclusion of stackup height in track length measurements and length tuning.
bool m_resetParamsIfMissing
Whether or not to set parameters to their default value if missing from JSON on Load()
wxString SeverityToString(const SEVERITY &aSeverity)
Definition: ui_common.cpp:47
Board layer functions and definitions.
const char * name
Definition: DXF_plotter.cpp:59
void registerMigration(int aOldSchemaVersion, int aNewSchemaVersion, std::function< bool(void)> aMigrator)
Registers a migration from one schema version to another.
#define DEFAULT_SILKCLEARANCE
int GetClearance() const
Definition: netclass.h:124
std::map< int, SEVERITY > m_DRCSeverities
SEVERITY SeverityFromString(const wxString &aSeverity)
Definition: ui_common.cpp:36
static std::vector< std::reference_wrapper< RC_ITEM > > GetItemsWithSeverities()
Definition: drc_item.h:100
NETCLASS * GetDefault() const
int GetViaDiameter() const
Definition: netclass.h:132
void SetSilkClearance(int aDistance)
Set the minimum distance between silk items to aValue.
void initFromOther(const BOARD_DESIGN_SETTINGS &aOther)
#define DEFAULT_COPPER_TEXT_WIDTH
std::vector< VIA_DIMENSION > m_ViasDimensionsList
boost::optional< T > OPT
Definition: optional.h:7
#define DEFAULT_CUSTOMTRACKWIDTH
bool IsCopperLayer(LAYER_NUM aLayerId)
Tests whether a layer is a copper layer.
DIM_UNITS_FORMAT m_DimensionUnitsFormat
#define DEFAULT_TEXT_SIZE
Ratio of the font height to the baseline of the text above the wire.
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
NETCLASSES * m_netClasses
This will point to m_internalNetClasses until it is repointed to the project after load.
#define DEFAULT_SOLDERMASK_CLEARANCE
int m_copperLayerCount
Number of copper layers for this design.
#define DEFAULT_COPPER_TEXT_SIZE
bool m_MicroViasAllowed
true to allow micro vias
void ReleaseNestedSettings(NESTED_SETTINGS *aSettings)
Saves and frees a nested settings object, if it exists within this one.
std::set< wxString > m_DrcExclusions
static constexpr int Millimeter2iu(double mm)
static nlohmann::json::json_pointer PointerFromString(std::string aPath)
Builds a JSON pointer based on a given string.
LSET m_enabledLayers
Bit-mask for layer enabling.
wxPoint m_AuxOrigin
origin for plot exports
wxSize GetTextSize(PCB_LAYER_ID aLayer) const
Return the default text size from the layer class for the given layer.
int m_boardThickness
Board thickness for 3D viewer.
std::shared_ptr< DRC_ENGINE > m_DRCEngine
virtual void Load()
Updates the parameters of this object based on the current JSON document contents.
bool m_TextUpright[LAYER_CLASS_COUNT]
Container for design settings for a BOARD object.