KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 The 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 <lset.h>
28#include <kiface_base.h>
29#include <pad.h>
31#include <drc/drc_item.h>
32#include <drc/drc_engine.h>
34#include <settings/parameters.h>
36#include <advanced_config.h>
37
38const int bdsSchemaVersion = 2;
39
40
41BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std::string& aPath ) :
42 NESTED_SETTINGS( "board_design_settings", bdsSchemaVersion, aParent, aPath )
43{
44 // We want to leave alone parameters that aren't found in the project JSON as they may be
45 // initialized by the board file parser before NESTED_SETTINGS::LoadFromFile is called.
47
48 // Create a default NET_SETTINGS so that things don't break horribly if there's no project
49 // loaded. This also is used during file load for legacy boards that have netclasses stored
50 // in the file. After load, this information will be moved to the project and the pointer
51 // updated.
52 m_NetSettings = std::make_shared<NET_SETTINGS>( nullptr, "" );
53
54 m_HasStackup = false; // no stackup defined by default
55
56 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 // Default design is a double layer board with 4 user defined layers
66
68
69 // if true, when creating a new track starting on an existing track, use this track width
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
86
93
94 // Edges & Courtyards; text properties aren't used but better to have them holding
95 // reasonable values than not.
98 pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE ) );
102
105 pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE ) );
109
112 pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE ) );
114 m_TextItalic[ LAYER_CLASS_FAB ] = false;
116
119 pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE ) );
123
124 m_StyleFPFields = false;
125 m_StyleFPText = false;
126 m_StyleFPShapes = false;
127 m_StyleFPDimensions = false;
128 m_StyleFPBarcodes = false;
129
138
139 m_useCustomTrackVia = false;
141 m_customViaSize.m_Diameter = pcbIUScale.mmToIU( DEFAULT_VIASMINSIZE );
143
144 m_useCustomDiffPair = false;
148
165
166 for( int errorCode = DRCE_FIRST; errorCode <= DRCE_LAST; ++errorCode )
167 m_DRCSeverities[ errorCode ] = RPT_SEVERITY_ERROR;
168
171
175
178
181
183
191
197
199
202
204
207
210
214
215 // Global mask margins:
219
220 // Solder paste margin absolute value
222 // Solder paste margin as a ratio of pad size
223 // The final margin is the sum of these 2 values
224 // Usually < 0 because the mask is smaller than pad
226
228 m_TentViasFront = true;
229 m_TentViasBack = true;
230
231 m_CoverViasFront = false;
232 m_CoverViasBack = false;
233
234 m_PlugViasFront = false;
235 m_PlugViasBack = false;
236
237 m_CapVias = false;
238
239 m_FillVias = false;
240
241 // Layer thickness for 3D viewer
243
244 // Default spacing for meanders
248
249 m_viaSizeIndex = 0;
251 m_diffPairIndex = 0;
252
253 // Parameters stored in JSON in the project file
254
255 // NOTE: Previously, BOARD_DESIGN_SETTINGS stored the basic board layer information (layer
256 // names and enable/disable state) in the project file even though this information is also
257 // stored in the board file. This was implemented for importing these settings from another
258 // project. Going forward, the import feature will just import from other board files (since
259 // we could have multi-board projects in the future anyway) so this functionality is dropped.
260
261
262 m_params.emplace_back( new PARAM<bool>( "rules.use_height_for_length_calcs",
263 &m_UseHeightForLengthCalcs, true ) );
264
265 m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_clearance",
267 pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 25.0 ), pcbIUScale.MM_PER_IU ) );
268
269 m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_connection",
271 pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 100.0 ), pcbIUScale.MM_PER_IU ) );
272
273 m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_track_width",
275 pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 25.0 ), pcbIUScale.MM_PER_IU ) );
276
277 m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_via_annular_width",
279 pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 25.0 ), pcbIUScale.MM_PER_IU ) );
280
281 m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_via_diameter",
283 pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 25.0 ), pcbIUScale.MM_PER_IU ) );
284
285 m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_through_hole_diameter",
287 pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 25.0 ), pcbIUScale.MM_PER_IU ) );
288
289 m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_microvia_diameter",
291 pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 10.0 ), pcbIUScale.MM_PER_IU ) );
292
293 m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_microvia_drill",
295 pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 10.0 ), pcbIUScale.MM_PER_IU ) );
296
297 m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_hole_to_hole",
299 pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 10.0 ), pcbIUScale.MM_PER_IU ) );
300
301 m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_hole_clearance",
303 pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 100.0 ), pcbIUScale.MM_PER_IU ) );
304
305 m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_silk_clearance",
307 pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 100.0 ), pcbIUScale.MM_PER_IU ) );
308
309 m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_groove_width",
311 pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 25.0 ), pcbIUScale.MM_PER_IU ) );
312
313 // While the maximum *effective* value is 4, we've had users interpret this as the count on
314 // all layers, and enter something like 10. They'll figure it out soon enough *unless* we
315 // enforce a max of 4 (and therefore reset it back to the default of 2), at which point it
316 // just looks buggy.
317 m_params.emplace_back( new PARAM<int>( "rules.min_resolved_spokes",
319
320 m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_text_height",
322 pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 100.0 ), pcbIUScale.MM_PER_IU ) );
323
324 m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_text_thickness",
326 pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 25.0 ), pcbIUScale.MM_PER_IU ) );
327
328 // Note: a clearance of -0.01 is a flag indicating we should use the legacy (pre-6.0) method
329 // based on the edge cut thicknesses.
330 m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_copper_edge_clearance",
332 pcbIUScale.mmToIU( -0.01 ), pcbIUScale.mmToIU( 25.0 ), pcbIUScale.MM_PER_IU ) );
333
334 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "rule_severities",
335 [&]() -> nlohmann::json
336 {
337 nlohmann::json ret = {};
338
339 for( const RC_ITEM& item : DRC_ITEM::GetItemsWithSeverities() )
340 {
341 wxString name = item.GetSettingsKey();
342 int code = item.GetErrorCode();
343
344 if( name.IsEmpty() || m_DRCSeverities.count( code ) == 0 )
345 continue;
346
347 ret[std::string( name.ToUTF8() )] = SeverityToString( m_DRCSeverities[code] );
348 }
349
350 return ret;
351 },
352 [&]( const nlohmann::json& aJson )
353 {
354 if( !aJson.is_object() )
355 return;
356
357 // Load V8 'hole_near_hole' token first (if present). Any current 'hole_to_hole' token
358 // found will then overwrite it.
359 // We can't use the migration architecture because we forgot to bump the version number
360 // when the change was made. But this is a one-off as any future deprecations should
361 // bump the version number and use registerMigration().
362 if( aJson.contains( "hole_near_hole" ) )
364
365 for( const RC_ITEM& item : DRC_ITEM::GetItemsWithSeverities() )
366 {
367 wxString name = item.GetSettingsKey();
368 std::string key( name.ToUTF8() );
369
370 if( aJson.contains( key ) )
371 m_DRCSeverities[item.GetErrorCode()] = SeverityFromString( aJson[key] );
372 }
373 }, {} ) );
374
375 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "drc_exclusions",
376 [&]() -> nlohmann::json
377 {
378 nlohmann::json js = nlohmann::json::array();
379
380 for( const wxString& entry : m_DrcExclusions )
381 js.push_back( { entry, m_DrcExclusionComments[ entry ] } );
382
383 return js;
384 },
385 [&]( const nlohmann::json& aObj )
386 {
387 m_DrcExclusions.clear();
388
389 if( !aObj.is_array() )
390 return;
391
392 for( const nlohmann::json& entry : aObj )
393 {
394 if( entry.is_array() )
395 {
396 wxString serialized = entry[0].get<wxString>();
397 m_DrcExclusions.insert( serialized );
398 m_DrcExclusionComments[ serialized ] = entry[1].get<wxString>();
399 }
400 else if( entry.is_string() )
401 {
402 m_DrcExclusions.insert( entry.get<wxString>() );
403 }
404 }
405 },
406 {} ) );
407
408 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "track_widths",
409 [&]() -> nlohmann::json
410 {
411 nlohmann::json js = nlohmann::json::array();
412
413 for( const int& width : m_TrackWidthList )
414 js.push_back( pcbIUScale.IUTomm( width ) );
415
416 return js;
417 },
418 [&]( const nlohmann::json& aJson )
419 {
420 if( !aJson.is_array() )
421 return;
422
423 m_TrackWidthList.clear();
424
425 for( const nlohmann::json& entry : aJson )
426 {
427 if( entry.empty() )
428 continue;
429
430 m_TrackWidthList.emplace_back( pcbIUScale.mmToIU( entry.get<double>() ) );
431 }
432 },
433 {} ) );
434
435 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "via_dimensions",
436 [&]() -> nlohmann::json
437 {
438 nlohmann::json js = nlohmann::json::array();
439
440 for( const auto& via : m_ViasDimensionsList )
441 {
442 nlohmann::json entry = {};
443
444 entry["diameter"] = pcbIUScale.IUTomm( via.m_Diameter );
445 entry["drill"] = pcbIUScale.IUTomm( via.m_Drill );
446
447 js.push_back( entry );
448 }
449
450 return js;
451 },
452 [&]( const nlohmann::json& aObj )
453 {
454 if( !aObj.is_array() )
455 return;
456
457 m_ViasDimensionsList.clear();
458
459 for( const nlohmann::json& entry : aObj )
460 {
461 if( entry.empty() || !entry.is_object() )
462 continue;
463
464 if( !entry.contains( "diameter" ) || !entry.contains( "drill" ) )
465 continue;
466
467 int diameter = pcbIUScale.mmToIU( entry["diameter"].get<double>() );
468 int drill = pcbIUScale.mmToIU( entry["drill"].get<double>() );
469
470 m_ViasDimensionsList.emplace_back( VIA_DIMENSION( diameter, drill ) );
471 }
472 },
473 {} ) );
474
475 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "diff_pair_dimensions",
476 [&]() -> nlohmann::json
477 {
478 nlohmann::json js = nlohmann::json::array();
479
480 for( const auto& pair : m_DiffPairDimensionsList )
481 {
482 nlohmann::json entry = {};
483
484 entry["width"] = pcbIUScale.IUTomm( pair.m_Width );
485 entry["gap"] = pcbIUScale.IUTomm( pair.m_Gap );
486 entry["via_gap"] = pcbIUScale.IUTomm( pair.m_ViaGap );
487
488 js.push_back( entry );
489 }
490
491 return js;
492 },
493 [&]( const nlohmann::json& aObj )
494 {
495 if( !aObj.is_array() )
496 return;
497
499
500 for( const nlohmann::json& entry : aObj )
501 {
502 if( entry.empty() || !entry.is_object() )
503 continue;
504
505 if( !entry.contains( "width" )
506 || !entry.contains( "gap" )
507 || !entry.contains( "via_gap" ) )
508 {
509 continue;
510 }
511
512 int width = pcbIUScale.mmToIU( entry["width"].get<double>() );
513 int gap = pcbIUScale.mmToIU( entry["gap"].get<double>() );
514 int via_gap = pcbIUScale.mmToIU( entry["via_gap"].get<double>() );
515
516 m_DiffPairDimensionsList.emplace_back( DIFF_PAIR_DIMENSION( width, gap, via_gap ) );
517 }
518 },
519 {} ) );
520
521 // Handle options for teardrops (targets and some others):
522 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "teardrop_options",
523 [&]() -> nlohmann::json
524 {
525 nlohmann::json js = nlohmann::json::array();
526 nlohmann::json entry = {};
527
528 entry["td_onvia"] = m_TeardropParamsList.m_TargetVias;
529 entry["td_onpthpad"] = m_TeardropParamsList.m_TargetPTHPads;
530 entry["td_onsmdpad"] = m_TeardropParamsList.m_TargetSMDPads;
531 entry["td_ontrackend"] = m_TeardropParamsList.m_TargetTrack2Track;
532 entry["td_onroundshapesonly"] = m_TeardropParamsList.m_UseRoundShapesOnly;
533
534 js.push_back( entry );
535
536 return js;
537 },
538 [&]( const nlohmann::json& aObj )
539 {
540 if( !aObj.is_array() )
541 return;
542
543 for( const nlohmann::json& entry : aObj )
544 {
545 if( entry.empty() || !entry.is_object() )
546 continue;
547
548 if( entry.contains( "td_onvia" ) )
549 m_TeardropParamsList.m_TargetVias = entry["td_onvia"].get<bool>();
550
551 if( entry.contains( "td_onpthpad" ) )
552 m_TeardropParamsList.m_TargetPTHPads = entry["td_onpthpad"].get<bool>();
553
554 if( entry.contains( "td_onsmdpad" ) )
555 m_TeardropParamsList.m_TargetSMDPads = entry["td_onsmdpad"].get<bool>();
556
557 if( entry.contains( "td_ontrackend" ) )
558 m_TeardropParamsList.m_TargetTrack2Track = entry["td_ontrackend"].get<bool>();
559
560 if( entry.contains( "td_onroundshapesonly" ) )
561 m_TeardropParamsList.m_UseRoundShapesOnly = entry["td_onroundshapesonly"].get<bool>();
562
563 // Legacy settings
564 for( int ii = 0; ii < 3; ++ii )
565 {
566 TEARDROP_PARAMETERS* td_prm = m_TeardropParamsList.GetParameters( (TARGET_TD)ii );
567
568 if( entry.contains( "td_allow_use_two_tracks" ) )
569 td_prm->m_AllowUseTwoTracks = entry["td_allow_use_two_tracks"].get<bool>();
570
571 if( entry.contains( "td_curve_segcount" ) )
572 {
573 if( entry["td_curve_segcount"].get<int>() > 0 )
574 td_prm->m_CurvedEdges = true;
575 }
576
577 if( entry.contains( "td_on_pad_in_zone" ) )
578 td_prm->m_TdOnPadsInZones = entry["td_on_pad_in_zone"].get<bool>();
579 }
580 }
581 },
582 {} ) );
583
584 // Handle parameters (sizes, shape) for each type of teardrop:
585 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "teardrop_parameters",
586 [&]() -> nlohmann::json
587 {
588 nlohmann::json js = nlohmann::json::array();
589
590 for( size_t ii = 0; ii < m_TeardropParamsList.GetParametersCount(); ii++ )
591 {
592 nlohmann::json entry = {};
593 TEARDROP_PARAMETERS* td_prm = m_TeardropParamsList.GetParameters( (TARGET_TD)ii );
594
595 entry["td_target_name"] = GetTeardropTargetCanonicalName( (TARGET_TD)ii );
596 entry["td_maxlen"] = pcbIUScale.IUTomm( td_prm->m_TdMaxLen );
597 entry["td_maxheight"] = pcbIUScale.IUTomm( td_prm->m_TdMaxWidth );
598 entry["td_length_ratio"] = td_prm->m_BestLengthRatio;
599 entry["td_height_ratio"] = td_prm->m_BestWidthRatio;
600 entry["td_curve_segcount"] = td_prm->m_CurvedEdges ? 1 : 0;
601 entry["td_width_to_size_filter_ratio"] = td_prm->m_WidthtoSizeFilterRatio;
602 entry["td_allow_use_two_tracks"] = td_prm->m_AllowUseTwoTracks;
603 entry["td_on_pad_in_zone"] = td_prm->m_TdOnPadsInZones;
604
605 js.push_back( entry );
606 }
607
608 return js;
609 },
610 [&]( const nlohmann::json& aObj )
611 {
612 if( !aObj.is_array() )
613 return;
614
615 for( const nlohmann::json& entry : aObj )
616 {
617 if( entry.empty() || !entry.is_object() )
618 continue;
619
620 if( !entry.contains( "td_target_name" ) )
621 continue;
622
623 int idx = GetTeardropTargetTypeFromCanonicalName( entry["td_target_name"].get<std::string>() );
624
625 if( idx >= 0 && idx < 3 )
626 {
627 TEARDROP_PARAMETERS* td_prm = m_TeardropParamsList.GetParameters( (TARGET_TD)idx );
628
629 if( entry.contains( "td_maxlen" ) )
630 td_prm->m_TdMaxLen = pcbIUScale.mmToIU( entry["td_maxlen"].get<double>() );
631
632 if( entry.contains( "td_maxheight" ) )
633 td_prm->m_TdMaxWidth = pcbIUScale.mmToIU( entry["td_maxheight"].get<double>() );
634
635 if( entry.contains( "td_length_ratio" ) )
636 td_prm->m_BestLengthRatio = entry["td_length_ratio"].get<double>();
637
638 if( entry.contains( "td_height_ratio" ) )
639 td_prm->m_BestWidthRatio = entry["td_height_ratio"].get<double>();
640
641 if( entry.contains( "td_curve_segcount" ) )
642 {
643 if( entry["td_curve_segcount"].get<int>() > 0 )
644 td_prm->m_CurvedEdges = true;
645 }
646
647 if( entry.contains( "td_width_to_size_filter_ratio" ) )
648 td_prm->m_WidthtoSizeFilterRatio = entry["td_width_to_size_filter_ratio"].get<double>();
649
650 if( entry.contains( "td_allow_use_two_tracks" ) )
651 td_prm->m_AllowUseTwoTracks = entry["td_allow_use_two_tracks"].get<bool>();
652
653 if( entry.contains( "td_on_pad_in_zone" ) )
654 td_prm->m_TdOnPadsInZones = entry["td_on_pad_in_zone"].get<bool>();
655 }
656 }
657 },
658 {} ) );
659
660 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "tuning_pattern_settings",
661 [&]() -> nlohmann::json
662 {
663 nlohmann::json js = {};
664
665 auto make_settings =
666 []( const PNS::MEANDER_SETTINGS& aSettings )
667 {
668 nlohmann::json entry = {};
669
670 entry["min_amplitude"] = pcbIUScale.IUTomm( aSettings.m_minAmplitude );
671 entry["max_amplitude"] = pcbIUScale.IUTomm( aSettings.m_maxAmplitude );
672 entry["spacing"] = pcbIUScale.IUTomm( aSettings.m_spacing );
673 entry["corner_style"] = aSettings.m_cornerStyle == PNS::MEANDER_STYLE_CHAMFER ? 0 : 1;
674 entry["corner_radius_percentage"] = aSettings.m_cornerRadiusPercentage;
675 entry["single_sided"] = aSettings.m_singleSided;
676
677 return entry;
678 };
679
680 js["single_track_defaults"] = make_settings( m_SingleTrackMeanderSettings );
681 js["diff_pair_defaults"] = make_settings( m_DiffPairMeanderSettings );
682 js["diff_pair_skew_defaults"] = make_settings( m_SkewMeanderSettings );
683
684 return js;
685 },
686 [&]( const nlohmann::json& aObj )
687 {
688 auto read_settings =
689 []( const nlohmann::json& entry ) -> PNS::MEANDER_SETTINGS
690 {
691 PNS::MEANDER_SETTINGS settings;
692
693 if( entry.contains( "min_amplitude" ) )
694 settings.m_minAmplitude = pcbIUScale.mmToIU( entry["min_amplitude"].get<double>() );
695
696 if( entry.contains( "max_amplitude" ) )
697 settings.m_maxAmplitude = pcbIUScale.mmToIU( entry["max_amplitude"].get<double>() );
698
699 if( entry.contains( "spacing" ) )
700 settings.m_spacing = pcbIUScale.mmToIU( entry["spacing"].get<double>() );
701
702 if( entry.contains( "corner_style" ) )
703 {
704 settings.m_cornerStyle = entry["corner_style"] == 0 ? PNS::MEANDER_STYLE_CHAMFER
706 }
707
708 if( entry.contains( "corner_radius_percentage" ) )
709 settings.m_cornerRadiusPercentage = entry["corner_radius_percentage"].get<int>();
710
711 if( entry.contains( "single_sided" ) )
712 settings.m_singleSided = entry["single_sided"].get<bool>();
713
714 return settings;
715 };
716
717 if( aObj.contains( "single_track_defaults" ) )
718 m_SingleTrackMeanderSettings = read_settings( aObj["single_track_defaults"] );
719
720 if( aObj.contains( "diff_pair_defaults" ) )
721 m_DiffPairMeanderSettings = read_settings( aObj["diff_pair_defaults"] );
722
723 if( aObj.contains( "diff_pair_skew_defaults" ) )
724 m_SkewMeanderSettings = read_settings( aObj["diff_pair_skew_defaults"] );
725 },
726 {} ) );
727
728 int minTextSize = pcbIUScale.mmToIU( TEXT_MIN_SIZE_MM );
729 int maxTextSize = pcbIUScale.mmToIU( TEXT_MAX_SIZE_MM );
730 int minStroke = 1;
731 int maxStroke = pcbIUScale.mmToIU( 100 );
732
733 m_params.emplace_back( new PARAM_SCALED<int>( "defaults.silk_line_width",
735 minStroke, maxStroke, pcbIUScale.MM_PER_IU ) );
736
737 m_params.emplace_back( new PARAM_SCALED<int>( "defaults.silk_text_size_v",
739 minTextSize, maxTextSize, pcbIUScale.MM_PER_IU ) );
740
741 m_params.emplace_back( new PARAM_SCALED<int>( "defaults.silk_text_size_h",
743 minTextSize, maxTextSize, pcbIUScale.MM_PER_IU ) );
744
745 m_params.emplace_back( new PARAM_SCALED<int>( "defaults.silk_text_thickness",
747 minStroke, maxStroke, pcbIUScale.MM_PER_IU ) );
748
749 m_params.emplace_back( new PARAM<bool>( "defaults.silk_text_italic",
750 &m_TextItalic[LAYER_CLASS_SILK], false ) );
751
752 m_params.emplace_back( new PARAM<bool>( "defaults.silk_text_upright",
753 &m_TextUpright[ LAYER_CLASS_SILK ], true ) );
754
755 m_params.emplace_back( new PARAM_SCALED<int>( "defaults.copper_line_width",
757 minStroke, maxStroke, pcbIUScale.MM_PER_IU ) );
758
759 m_params.emplace_back( new PARAM_SCALED<int>( "defaults.copper_text_size_v",
761 minTextSize, maxTextSize, pcbIUScale.MM_PER_IU ) );
762
763 m_params.emplace_back( new PARAM_SCALED<int>( "defaults.copper_text_size_h",
765 minTextSize, maxTextSize, pcbIUScale.MM_PER_IU ) );
766
767 m_params.emplace_back( new PARAM_SCALED<int>( "defaults.copper_text_thickness",
769 minStroke, maxStroke, pcbIUScale.MM_PER_IU ) );
770
771 m_params.emplace_back( new PARAM<bool>( "defaults.copper_text_italic",
772 &m_TextItalic[LAYER_CLASS_COPPER], false ) );
773
774 m_params.emplace_back( new PARAM<bool>( "defaults.copper_text_upright",
776
777 m_params.emplace_back( new PARAM_SCALED<int>( "defaults.board_outline_line_width",
779 minStroke, maxStroke, pcbIUScale.MM_PER_IU ) );
780
781 m_params.emplace_back( new PARAM_SCALED<int>( "defaults.courtyard_line_width",
783 minStroke, maxStroke, pcbIUScale.MM_PER_IU ) );
784
785 m_params.emplace_back( new PARAM_SCALED<int>( "defaults.fab_line_width",
787 minStroke, maxStroke, pcbIUScale.MM_PER_IU ) );
788
789 m_params.emplace_back( new PARAM_SCALED<int>( "defaults.fab_text_size_v",
791 minTextSize, maxTextSize, pcbIUScale.MM_PER_IU ) );
792
793 m_params.emplace_back( new PARAM_SCALED<int>( "defaults.fab_text_size_h",
795 minTextSize, maxTextSize, pcbIUScale.MM_PER_IU ) );
796
797 m_params.emplace_back( new PARAM_SCALED<int>( "defaults.fab_text_thickness",
799 minStroke, maxStroke, pcbIUScale.MM_PER_IU ) );
800
801 m_params.emplace_back( new PARAM<bool>( "defaults.fab_text_italic",
802 &m_TextItalic[LAYER_CLASS_FAB], false ) );
803
804 m_params.emplace_back( new PARAM<bool>( "defaults.fab_text_upright",
805 &m_TextUpright[LAYER_CLASS_FAB], true ) );
806
807 m_params.emplace_back( new PARAM_SCALED<int>( "defaults.other_line_width",
809 minStroke, maxStroke, pcbIUScale.MM_PER_IU ) );
810
811 m_params.emplace_back( new PARAM_SCALED<int>( "defaults.other_text_size_v",
813 minTextSize, maxTextSize, pcbIUScale.MM_PER_IU ) );
814
815 m_params.emplace_back( new PARAM_SCALED<int>( "defaults.other_text_size_h",
817 minTextSize, maxTextSize, pcbIUScale.MM_PER_IU ) );
818
819 m_params.emplace_back( new PARAM_SCALED<int>( "defaults.other_text_thickness",
821 minStroke, maxStroke, pcbIUScale.MM_PER_IU ) );
822
823 m_params.emplace_back( new PARAM<bool>( "defaults.other_text_italic",
824 &m_TextItalic[LAYER_CLASS_OTHERS], false ) );
825
826 m_params.emplace_back( new PARAM<bool>( "defaults.other_text_upright",
828
829 m_params.emplace_back( new PARAM_ENUM<DIM_UNITS_MODE>( "defaults.dimension_units",
832
833 m_params.emplace_back( new PARAM_ENUM<DIM_PRECISION>( "defaults.dimension_precision",
835
836 m_params.emplace_back( new PARAM_ENUM<DIM_UNITS_FORMAT>( "defaults.dimensions.units_format",
839
840 m_params.emplace_back( new PARAM<bool>( "defaults.dimensions.suppress_zeroes",
841 &m_DimensionSuppressZeroes, true ) );
842
843 // NOTE: excluding DIM_TEXT_POSITION::MANUAL from the valid range here
844 m_params.emplace_back( new PARAM_ENUM<DIM_TEXT_POSITION>( "defaults.dimensions.text_position",
847
848 m_params.emplace_back( new PARAM<bool>( "defaults.dimensions.keep_text_aligned",
850
851 m_params.emplace_back( new PARAM<int>( "defaults.dimensions.arrow_length",
854
855 m_params.emplace_back( new PARAM<int>( "defaults.dimensions.extension_offset",
858
859 m_params.emplace_back( new PARAM<bool>( "defaults.apply_defaults_to_fp_fields",
860 &m_StyleFPFields, false ) );
861 m_params.emplace_back( new PARAM<bool>( "defaults.apply_defaults_to_fp_text",
862 &m_StyleFPText, false ) );
863 m_params.emplace_back( new PARAM<bool>( "defaults.apply_defaults_to_fp_shapes",
864 &m_StyleFPShapes, false ) );
865 m_params.emplace_back( new PARAM<bool>( "defaults.apply_defaults_to_fp_dimensions",
866 &m_StyleFPDimensions, false ) );
867 m_params.emplace_back( new PARAM<bool>( "defaults.apply_defaults_to_fp_barcodes",
868 &m_StyleFPBarcodes, false ) );
869
870 m_params.emplace_back( new PARAM_SCALED<int>( "defaults.zones.min_clearance",
871 &m_defaultZoneSettings.m_ZoneClearance, pcbIUScale.mmToIU( ZONE_CLEARANCE_MM ),
872 pcbIUScale.mmToIU( 0.0 ), pcbIUScale.mmToIU( 25.0 ), pcbIUScale.MM_PER_IU ) );
873
874 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "defaults.pads",
875 [&]() -> nlohmann::json
876 {
877 nlohmann::json ret =
878 {
879 { "width", pcbIUScale.IUTomm( m_Pad_Master->GetSize( PADSTACK::ALL_LAYERS ).x ) },
880 { "height", pcbIUScale.IUTomm( m_Pad_Master->GetSize( PADSTACK::ALL_LAYERS ).y ) },
881 { "drill", pcbIUScale.IUTomm( m_Pad_Master->GetDrillSize().x ) }
882 };
883
884 return ret;
885 },
886 [&]( const nlohmann::json& aJson )
887 {
888 if( aJson.contains( "width" ) && aJson.contains( "height" )
889 && aJson.contains( "drill" ) )
890 {
891 VECTOR2I sz;
892 sz.x = pcbIUScale.mmToIU( aJson["width"].get<double>() );
893 sz.y = pcbIUScale.mmToIU( aJson["height"].get<double>() );
894
895 m_Pad_Master->SetSize( PADSTACK::ALL_LAYERS, sz );
896
897 int drill = pcbIUScale.mmToIU( aJson["drill"].get<double>() );
898
899 m_Pad_Master->SetDrillSize( VECTOR2I( drill, drill ) );
900 }
901 }, {} ) );
902
903 m_params.emplace_back( new PARAM_SCALED<int>( "rules.max_error",
905 pcbIUScale.mmToIU( 0.0001 ), pcbIUScale.mmToIU( 1.0 ), pcbIUScale.MM_PER_IU ) );
906
907 m_params.emplace_back( new PARAM_SCALED<int>( "rules.solder_mask_to_copper_clearance",
909 pcbIUScale.mmToIU( 0.0 ), pcbIUScale.mmToIU( 25.0 ), pcbIUScale.MM_PER_IU ) );
910
911 m_params.emplace_back( new PARAM<bool>( "zones_allow_external_fillets",
912 &m_ZoneKeepExternalFillets, false ) );
913
915
916 registerMigration( 1, 2,
917 [&]() -> bool
918 {
919 // Schema 1 to 2: move mask and paste margin settings back to board.
920 // The parameters are removed, so we just have to manually load them here and
921 // they will get saved with the board
922 if( std::optional<double> optval = Get<double>( "rules.solder_mask_clearance" ) )
923 m_SolderMaskExpansion = static_cast<int>( *optval * pcbIUScale.IU_PER_MM );
924
925 if( std::optional<double> optval = Get<double>( "rules.solder_mask_min_width" ) )
926 m_SolderMaskMinWidth = static_cast<int>( *optval * pcbIUScale.IU_PER_MM );
927
928 if( std::optional<double> optval = Get<double>( "rules.solder_paste_clearance" ) )
929 m_SolderPasteMargin = static_cast<int>( *optval * pcbIUScale.IU_PER_MM );
930
931 if( std::optional<double> optval = Get<double>( "rules.solder_paste_margin_ratio" ) )
932 m_SolderPasteMarginRatio = *optval;
933
934 try
935 {
936 At( "rules" ).erase( "solder_mask_clearance" );
937 At( "rules" ).erase( "solder_mask_min_width" );
938 At( "rules" ).erase( "solder_paste_clearance" );
939 At( "rules" ).erase( "solder_paste_margin_ratio" );
940 }
941 catch( ... )
942 {}
943
944 return true;
945 } );
946}
947
948
950{
951 if( m_parent )
952 {
953 m_parent->ReleaseNestedSettings( this );
954 m_parent = nullptr;
955 }
956}
957
958
960 NESTED_SETTINGS( "board_design_settings", bdsSchemaVersion, aOther.m_parent,
961 aOther.m_path ),
962 m_Pad_Master( nullptr )
963{
964 initFromOther( aOther );
965}
966
967
969{
970 initFromOther( aOther );
971 return *this;
972}
973
974
976{
977 // Copy of NESTED_SETTINGS around is not allowed, so let's just update the params.
986 m_MinConn = aOther.m_MinConn;
1004 m_MaxError = aOther.m_MaxError;
1017 m_CapVias = aOther.m_CapVias;
1018 m_FillVias = aOther.m_FillVias;
1021
1022 std::copy( std::begin( aOther.m_LineThickness ), std::end( aOther.m_LineThickness ),
1023 std::begin( m_LineThickness ) );
1024
1025 std::copy( std::begin( aOther.m_TextSize ), std::end( aOther.m_TextSize ),
1026 std::begin( m_TextSize ) );
1027
1028 std::copy( std::begin( aOther.m_TextThickness ), std::end( aOther.m_TextThickness ),
1029 std::begin( m_TextThickness ) );
1030
1031 std::copy( std::begin( aOther.m_TextItalic ), std::end( aOther.m_TextItalic ),
1032 std::begin( m_TextItalic ) );
1033
1034 std::copy( std::begin( aOther.m_TextUpright ), std::end( aOther.m_TextUpright ),
1035 std::begin( m_TextUpright ) );
1036
1045
1046 m_auxOrigin = aOther.m_auxOrigin;
1047 m_gridOrigin = aOther.m_gridOrigin;
1048 m_HasStackup = aOther.m_HasStackup;
1050
1064 m_stackup = aOther.m_stackup;
1066 m_Pad_Master = std::make_unique<PAD>( *aOther.m_Pad_Master );
1068
1074}
1075
1076
1078{
1079 if( m_TrackWidthList != aOther.m_TrackWidthList ) return false;
1080 if( m_ViasDimensionsList != aOther.m_ViasDimensionsList ) return false;
1081 if( m_DiffPairDimensionsList != aOther.m_DiffPairDimensionsList ) return false;
1082 if( m_CurrentViaType != aOther.m_CurrentViaType ) return false;
1083 if( m_UseConnectedTrackWidth != aOther.m_UseConnectedTrackWidth ) return false;
1084 if( m_TempOverrideTrackWidth != aOther.m_TempOverrideTrackWidth ) return false;
1085 if( m_MinClearance != aOther.m_MinClearance ) return false;
1086 if( m_MinGrooveWidth != aOther.m_MinGrooveWidth ) return false;
1087 if( m_MinConn != aOther.m_MinConn ) return false;
1088 if( m_TrackMinWidth != aOther.m_TrackMinWidth ) return false;
1089 if( m_ViasMinAnnularWidth != aOther.m_ViasMinAnnularWidth ) return false;
1090 if( m_ViasMinSize != aOther.m_ViasMinSize ) return false;
1091 if( m_MinThroughDrill != aOther.m_MinThroughDrill ) return false;
1092 if( m_MicroViasMinSize != aOther.m_MicroViasMinSize ) return false;
1093 if( m_MicroViasMinDrill != aOther.m_MicroViasMinDrill ) return false;
1094 if( m_CopperEdgeClearance != aOther.m_CopperEdgeClearance ) return false;
1095 if( m_HoleClearance != aOther.m_HoleClearance ) return false;
1096 if( m_HoleToHoleMin != aOther.m_HoleToHoleMin ) return false;
1097 if( m_SilkClearance != aOther.m_SilkClearance ) return false;
1098 if( m_MinResolvedSpokes != aOther.m_MinResolvedSpokes ) return false;
1099 if( m_MinSilkTextHeight != aOther.m_MinSilkTextHeight ) return false;
1100 if( m_MinSilkTextThickness != aOther.m_MinSilkTextThickness ) return false;
1101 if( m_DRCSeverities != aOther.m_DRCSeverities ) return false;
1102 if( m_DrcExclusions != aOther.m_DrcExclusions ) return false;
1103 if( m_DrcExclusionComments != aOther.m_DrcExclusionComments ) return false;
1104 if( m_ZoneKeepExternalFillets != aOther.m_ZoneKeepExternalFillets ) return false;
1105 if( m_MaxError != aOther.m_MaxError ) return false;
1106 if( m_SolderMaskExpansion != aOther.m_SolderMaskExpansion ) return false;
1107 if( m_SolderMaskMinWidth != aOther.m_SolderMaskMinWidth ) return false;
1109 if( m_SolderPasteMargin != aOther.m_SolderPasteMargin ) return false;
1110 if( m_SolderPasteMarginRatio != aOther.m_SolderPasteMarginRatio ) return false;
1112 if( m_TentViasFront != aOther.m_TentViasFront ) return false;
1113 if( m_TentViasBack != aOther.m_TentViasBack ) return false;
1114 if( m_CoverViasFront != aOther.m_CoverViasFront ) return false;
1115 if( m_CoverViasBack != aOther.m_CoverViasBack ) return false;
1116 if( m_PlugViasFront != aOther.m_PlugViasFront ) return false;
1117 if( m_PlugViasBack != aOther.m_PlugViasBack ) return false;
1118 if( m_CapVias != aOther.m_CapVias ) return false;
1119 if( m_FillVias != aOther.m_FillVias ) return false;
1120 if( m_DefaultFPTextItems != aOther.m_DefaultFPTextItems ) return false;
1121 if( m_UserLayerNames != aOther.m_UserLayerNames ) return false;
1122
1123 if( !std::equal( std::begin( m_LineThickness ), std::end( m_LineThickness ),
1124 std::begin( aOther.m_LineThickness ) ) )
1125 return false;
1126
1127 if( !std::equal( std::begin( m_TextSize ), std::end( m_TextSize ),
1128 std::begin( aOther.m_TextSize ) ) )
1129 return false;
1130
1131 if( !std::equal( std::begin( m_TextThickness ), std::end( m_TextThickness ),
1132 std::begin( aOther.m_TextThickness ) ) )
1133 return false;
1134
1135 if( !std::equal( std::begin( m_TextItalic ), std::end( m_TextItalic ),
1136 std::begin( aOther.m_TextItalic ) ) )
1137 return false;
1138
1139 if( !std::equal( std::begin( m_TextUpright ), std::end( m_TextUpright ),
1140 std::begin( aOther.m_TextUpright ) ) )
1141 return false;
1142
1143 if( m_DimensionUnitsMode != aOther.m_DimensionUnitsMode ) return false;
1144 if( m_DimensionPrecision != aOther.m_DimensionPrecision ) return false;
1145 if( m_DimensionUnitsFormat != aOther.m_DimensionUnitsFormat ) return false;
1146 if( m_DimensionSuppressZeroes != aOther.m_DimensionSuppressZeroes ) return false;
1147 if( m_DimensionTextPosition != aOther.m_DimensionTextPosition ) return false;
1148 if( m_DimensionKeepTextAligned != aOther.m_DimensionKeepTextAligned ) return false;
1149 if( m_DimensionArrowLength != aOther.m_DimensionArrowLength ) return false;
1150 if( m_DimensionExtensionOffset != aOther.m_DimensionExtensionOffset ) return false;
1151 if( m_auxOrigin != aOther.m_auxOrigin ) return false;
1152 if( m_gridOrigin != aOther.m_gridOrigin ) return false;
1153 if( m_HasStackup != aOther.m_HasStackup ) return false;
1154 if( m_UseHeightForLengthCalcs != aOther.m_UseHeightForLengthCalcs ) return false;
1155 if( m_trackWidthIndex != aOther.m_trackWidthIndex ) return false;
1156 if( m_viaSizeIndex != aOther.m_viaSizeIndex ) return false;
1157 if( m_diffPairIndex != aOther.m_diffPairIndex ) return false;
1158 if( m_useCustomTrackVia != aOther.m_useCustomTrackVia ) return false;
1159 if( m_customTrackWidth != aOther.m_customTrackWidth ) return false;
1160 if( m_customViaSize != aOther.m_customViaSize ) return false;
1161 if( m_useCustomDiffPair != aOther.m_useCustomDiffPair ) return false;
1162 if( m_customDiffPair != aOther.m_customDiffPair ) return false;
1163 if( m_copperLayerCount != aOther.m_copperLayerCount ) return false;
1164 if( m_userDefinedLayerCount != aOther.m_userDefinedLayerCount ) return false;
1165 if( m_enabledLayers != aOther.m_enabledLayers ) return false;
1166 if( m_boardThickness != aOther.m_boardThickness ) return false;
1167 if( m_currentNetClassName != aOther.m_currentNetClassName ) return false;
1168 if( m_stackup != aOther.m_stackup ) return false;
1169 if( *m_NetSettings != *aOther.m_NetSettings ) return false;
1170 if( *m_Pad_Master != *aOther.m_Pad_Master ) return false;
1171 if( m_defaultZoneSettings != aOther.m_defaultZoneSettings ) return false;
1172
1173 if( m_StyleFPFields != aOther.m_StyleFPFields ) return false;
1174 if( m_StyleFPText != aOther.m_StyleFPText ) return false;
1175 if( m_StyleFPShapes != aOther.m_StyleFPShapes ) return false;
1176 if( m_StyleFPDimensions != aOther.m_StyleFPDimensions ) return false;
1177 if( m_StyleFPBarcodes != aOther.m_StyleFPBarcodes ) return false;
1178
1179 return true;
1180}
1181
1182
1184{
1202 std::string units_ptr( "defaults.dimension_units" );
1203 std::string precision_ptr( "defaults.dimension_precision" );
1204
1205 if( !( Contains( units_ptr )
1206 && Contains( precision_ptr )
1207 && At( units_ptr ).is_number_integer()
1208 && At( precision_ptr ).is_number_integer() ) )
1209 {
1210 // if either is missing or invalid, migration doesn't make sense
1211 return true;
1212 }
1213
1214 int units = *Get<int>( units_ptr );
1215 int precision = *Get<int>( precision_ptr );
1216
1217 // The enum maps directly to precision if the units is mils
1218 int extraDigits = 0;
1219
1220 switch( units )
1221 {
1222 case 0: extraDigits = 3; break;
1223 case 2: extraDigits = 2; break;
1224 default: break;
1225 }
1226
1227 precision += extraDigits;
1228
1229 Set( precision_ptr, precision );
1230
1231 return true;
1232}
1233
1234
1235bool BOARD_DESIGN_SETTINGS::LoadFromFile( const wxString& aDirectory )
1236{
1237 bool ret = NESTED_SETTINGS::LoadFromFile( aDirectory );
1238
1239 // A number of things won't have been translated by the PROJECT_FILE migration because of
1240 // descoped objects required to decode this data. So, it will be in the legacy.pcbnew
1241 // section and needs to be pulled out here
1242
1243 PROJECT_FILE* project = dynamic_cast<PROJECT_FILE*>( GetParent() );
1244
1245 if( !project )
1246 return ret;
1247
1248 bool migrated = false;
1249
1250 auto drcName =
1251 []( int aCode ) -> std::string
1252 {
1253 return std::string( DRC_ITEM::Create( aCode )->GetSettingsKey().ToUTF8() );
1254 };
1255
1256 const std::string rs = "rule_severities.";
1257 const std::string no_courtyard_key = "legacy_no_courtyard_defined";
1258 const std::string courtyard_overlap_key = "legacy_courtyards_overlap";
1259
1260 try
1261 {
1262 nlohmann::json& severities =
1263 project->Internals()->at( "/board/design_settings/rule_severities"_json_pointer );
1264
1265 if( severities.contains( no_courtyard_key ) )
1266 {
1267 if( severities[no_courtyard_key].get<bool>() )
1268 Set( rs + drcName( DRCE_MISSING_COURTYARD ), "error" );
1269 else
1270 Set( rs + drcName( DRCE_MISSING_COURTYARD ), "ignore" );
1271
1272 severities.erase( no_courtyard_key );
1273 migrated = true;
1274 }
1275
1276 if( severities.contains( courtyard_overlap_key ) )
1277 {
1278 if( severities[courtyard_overlap_key].get<bool>() )
1279 Set( rs + drcName( DRCE_OVERLAPPING_FOOTPRINTS ), "error" );
1280 else
1281 Set( rs + drcName( DRCE_OVERLAPPING_FOOTPRINTS ), "ignore" );
1282
1283 severities.erase( courtyard_overlap_key );
1284 migrated = true;
1285 }
1286 }
1287 catch( ... )
1288 {
1289 }
1290
1291 if( Contains( "legacy" ) )
1292 {
1293 // This defaults to false for new boards, but version 5.1.x and prior kept the fillets
1294 // so we do the same for legacy boards.
1296
1297 project->At( "legacy" ).erase( "pcbnew" );
1298 }
1299
1300 // Now that we have everything, we need to load again
1301 if( migrated )
1302 Load();
1303
1304 return ret;
1305}
1306
1307
1309{
1310 return m_DRCSeverities[ aDRCErrorCode ];
1311}
1312
1313
1314bool BOARD_DESIGN_SETTINGS::Ignore( int aDRCErrorCode )
1315{
1316 return m_DRCSeverities[ aDRCErrorCode ] == RPT_SEVERITY_IGNORE;
1317}
1318
1319
1321{
1322 int biggest = std::max( m_MinClearance, m_HoleClearance );
1323 DRC_CONSTRAINT constraint;
1324
1325 biggest = std::max( biggest, m_HoleToHoleMin );
1326 biggest = std::max( biggest, m_CopperEdgeClearance );
1327
1328 if( m_DRCEngine )
1329 {
1330 m_DRCEngine->QueryWorstConstraint( CLEARANCE_CONSTRAINT, constraint );
1331 biggest = std::max( biggest, constraint.Value().Min() );
1332
1333 m_DRCEngine->QueryWorstConstraint( PHYSICAL_CLEARANCE_CONSTRAINT, constraint );
1334 biggest = std::max( biggest, constraint.Value().Min() );
1335
1336 m_DRCEngine->QueryWorstConstraint( HOLE_CLEARANCE_CONSTRAINT, constraint );
1337 biggest = std::max( biggest, constraint.Value().Min() );
1338
1339 m_DRCEngine->QueryWorstConstraint( EDGE_CLEARANCE_CONSTRAINT, constraint );
1340 biggest = std::max( biggest, constraint.Value().Min() );
1341
1342 m_DRCEngine->QueryWorstConstraint( HOLE_TO_HOLE_CONSTRAINT, constraint );
1343 biggest = std::max( biggest, constraint.Value().Min() );
1344 }
1345
1346 // Clip to avoid integer overflows in subsequent calculations
1347 return std::min( biggest, MAXIMUM_CLEARANCE );
1348}
1349
1350
1352{
1353 int clearance = m_NetSettings->GetDefaultNetclass()->GetClearance();
1354
1355 for( const auto& [name, netclass] : m_NetSettings->GetNetclasses() )
1356 clearance = std::min( clearance, netclass->GetClearance() );
1357
1358 return clearance;
1359}
1360
1361
1363{
1364 m_viaSizeIndex = std::min( aIndex, (int) m_ViasDimensionsList.size() - 1 );
1365 m_useCustomTrackVia = false;
1366}
1367
1368
1370{
1372 return m_customViaSize.m_Diameter;
1374 return m_NetSettings->GetDefaultNetclass()->GetViaDiameter();
1375 else
1376 return m_ViasDimensionsList[ m_viaSizeIndex ].m_Diameter;
1377}
1378
1379
1381{
1382 int drill;
1383
1385 drill = m_customViaSize.m_Drill;
1387 drill = m_NetSettings->GetDefaultNetclass()->GetViaDrill();
1388 else
1389 drill = m_ViasDimensionsList[ m_viaSizeIndex ].m_Drill;
1390
1391 return drill > 0 ? drill : -1;
1392}
1393
1394
1396{
1397 m_trackWidthIndex = std::min( aIndex, (int) m_TrackWidthList.size() - 1 );
1398 m_useCustomTrackVia = false;
1399}
1400
1401
1403{
1405 return m_customTrackWidth;
1407 return m_NetSettings->GetDefaultNetclass()->GetTrackWidth();
1408 else
1410}
1411
1412
1414{
1415 if( !m_DiffPairDimensionsList.empty() )
1416 m_diffPairIndex = std::min( aIndex, (int) m_DiffPairDimensionsList.size() - 1 );
1417
1418 m_useCustomDiffPair = false;
1419}
1420
1421
1423{
1425 {
1426 return m_customDiffPair.m_Width;
1427 }
1429 {
1430 if( m_NetSettings->GetDefaultNetclass()->HasDiffPairWidth() )
1431 return m_NetSettings->GetDefaultNetclass()->GetDiffPairWidth();
1432 else
1433 return m_NetSettings->GetDefaultNetclass()->GetTrackWidth();
1434 }
1435 else
1436 {
1438 }
1439}
1440
1441
1443{
1445 {
1446 return m_customDiffPair.m_Gap;
1447 }
1448 else if( m_diffPairIndex == 0 )
1449 {
1450 if( m_NetSettings->GetDefaultNetclass()->HasDiffPairGap() )
1451 return m_NetSettings->GetDefaultNetclass()->GetDiffPairGap();
1452 else
1453 return m_NetSettings->GetDefaultNetclass()->GetClearance();
1454 }
1455 else
1456 {
1458 }
1459}
1460
1461
1463{
1465 {
1466 return m_customDiffPair.m_ViaGap;
1467 }
1468 else if( m_diffPairIndex == 0 )
1469 {
1470 if( m_NetSettings->GetDefaultNetclass()->HasDiffPairViaGap() )
1471 return m_NetSettings->GetDefaultNetclass()->GetDiffPairViaGap();
1472 else
1473 return GetCurrentDiffPairGap();
1474 }
1475 else
1476 {
1478 }
1479}
1480
1481
1483{
1484 m_copperLayerCount = aNewLayerCount;
1485
1486 // Update only enabled copper layers mask
1487 m_enabledLayers.ClearCopperLayers();
1488
1489 if( aNewLayerCount > 0 )
1490 m_enabledLayers |= LSET::AllCuMask( aNewLayerCount );
1491}
1492
1493
1495{
1496 m_userDefinedLayerCount = aNewLayerCount;
1497
1498 m_enabledLayers.ClearUserDefinedLayers();
1499
1500 if( aNewLayerCount > 0 )
1501 m_enabledLayers |= LSET::UserDefinedLayersMask( aNewLayerCount );
1502}
1503
1504
1506{
1507 m_enabledLayers = aMask;
1508
1509 // Ensures mandatory back and front layers are always enabled regardless of board file
1510 // configuration.
1511 m_enabledLayers.set( B_Cu ).set( F_Cu )
1512 .set( B_CrtYd ).set( F_CrtYd )
1513 .set( Edge_Cuts )
1514 .set( Margin );
1515
1516 // update layer counts to ensure their consistency with m_EnabledLayers
1517 LSET copperLayers = aMask;
1518 copperLayers.ClearNonCopperLayers();
1519
1520 LSET userLayers = aMask & LSET::UserDefinedLayersMask();
1521
1522 m_copperLayerCount = (int) copperLayers.count();
1523 m_userDefinedLayerCount = (int) userLayers.count();
1524}
1525
1526
1527// Return the layer class index { silk, copper, edges & courtyards, fab, others } of the
1528// given layer.
1530{
1531 if( aLayer == F_SilkS || aLayer == B_SilkS )
1532 return LAYER_CLASS_SILK;
1533 else if( IsCopperLayer( aLayer ) )
1534 return LAYER_CLASS_COPPER;
1535 else if( aLayer == Edge_Cuts )
1536 return LAYER_CLASS_EDGES;
1537 else if( aLayer == F_CrtYd || aLayer == B_CrtYd )
1538 return LAYER_CLASS_COURTYARD;
1539 else if( aLayer == F_Fab || aLayer == B_Fab )
1540 return LAYER_CLASS_FAB;
1541 else
1542 return LAYER_CLASS_OTHERS;
1543}
1544
1545
1547{
1548 return pcbIUScale.mmToIU( ADVANCED_CFG::GetCfg().m_DRCEpsilon );
1549}
1550
1551
1553{
1554 return pcbIUScale.mmToIU( ADVANCED_CFG::GetCfg().m_HoleWallThickness );
1555}
1556
1557
1559{
1560 return m_LineThickness[ GetLayerClass( aLayer ) ];
1561}
1562
1563
1565{
1566 return m_TextSize[ GetLayerClass( aLayer ) ];
1567}
1568
1569
1571{
1572 return m_TextThickness[ GetLayerClass( aLayer ) ];
1573}
1574
1575
1577{
1578 return m_TextItalic[ GetLayerClass( aLayer ) ];
1579}
1580
1581
1583{
1584 return m_TextUpright[ GetLayerClass( aLayer ) ];
1585}
1586
1588{
1589 m_Pad_Master->SetSizeX( pcbIUScale.mmToIU( DEFAULT_PAD_WIDTH_MM ) );
1590 m_Pad_Master->SetSizeY( pcbIUScale.mmToIU( DEFAULT_PAD_HEIGTH_MM ) );
1591 m_Pad_Master->SetDrillShape( PAD_DRILL_SHAPE::CIRCLE );
1592 m_Pad_Master->SetDrillSize( VECTOR2I( pcbIUScale.mmToIU( DEFAULT_PAD_DRILL_DIAMETER_MM ), 0 ) );
1594
1595 constexpr double RR_RADIUS = DEFAULT_PAD_HEIGTH_MM * DEFAULT_PAD_RR_RADIUS_RATIO;
1596 m_Pad_Master->SetRoundRectCornerRadius( PADSTACK::ALL_LAYERS, pcbIUScale.mmToIU( RR_RADIUS ) );
1597
1598 if( m_Pad_Master->GetFrontShape() == PAD_SHAPE::CIRCLE )
1599 m_Pad_Master->SetThermalSpokeAngle( ANGLE_45 );
1600 else
1601 m_Pad_Master->SetThermalSpokeAngle( ANGLE_90 );
1602}
const char * name
constexpr int ARC_HIGH_DEF
Definition base_units.h:129
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
const int bdsSchemaVersion
#define DEFAULT_MICROVIASMINDRILL
#define DEFAULT_SOLDERPASTE_CLEARANCE
#define DEFAULT_SOLDERPASTE_RATIO
#define DEFAULT_CUSTOMDPAIRWIDTH
#define DEFAULT_DP_MEANDER_SPACING
@ LAYER_CLASS_OTHERS
@ LAYER_CLASS_FAB
@ LAYER_CLASS_COURTYARD
@ LAYER_CLASS_SILK
@ LAYER_CLASS_COPPER
@ LAYER_CLASS_EDGES
#define DEFAULT_PAD_WIDTH_MM
#define DEFAULT_VIASMINSIZE
#define DEFAULT_PAD_DRILL_DIAMETER_MM
#define DEFAULT_TEXT_WIDTH
#define DEFAULT_COPPER_TEXT_WIDTH
#define DEFAULT_CUSTOMDPAIRGAP
#define DEFAULT_MINCLEARANCE
#define DEFAULT_HOLECLEARANCE
#define DEFAULT_SOLDERMASK_EXPANSION
#define DEFAULT_SOLDERMASK_MIN_WIDTH
#define DEFAULT_DIMENSION_EXTENSION_OFFSET
#define DEFAULT_COPPEREDGECLEARANCE
#define DEFAULT_PAD_HEIGTH_MM
#define DEFAULT_DIMENSION_ARROW_LENGTH
#define DEFAULT_TRACKMINWIDTH
#define DEFAULT_MINTHROUGHDRILL
#define DEFAULT_PAD_RR_RADIUS_RATIO
#define DEFAULT_SILK_TEXT_SIZE
#define MAXIMUM_CLEARANCE
#define DEFAULT_HOLETOHOLEMIN
#define DEFAULT_MINCONNECTION
#define DEFAULT_COPPER_LINE_WIDTH
#define DEFAULT_SILK_LINE_WIDTH
#define DEFAULT_SILKCLEARANCE
#define DEFAULT_MICROVIASMINSIZE
#define DEFAULT_SILK_TEXT_WIDTH
#define DEFAULT_MINGROOVEWIDTH
#define DEFAULT_TEXT_SIZE
#define DEFAULT_EDGE_WIDTH
#define DEFAULT_CUSTOMTRACKWIDTH
#define DEFAULT_CUSTOMDPAIRVIAGAP
#define DEFAULT_COPPER_TEXT_SIZE
#define DEFAULT_SOLDERMASK_TO_COPPER_CLEARANCE
#define DEFAULT_LINE_WIDTH
#define DEFAULT_MEANDER_SPACING
#define DEFAULT_COURTYARD_WIDTH
#define DEFAULT_BOARD_THICKNESS_MM
#define DEFAULT_MINRESOLVEDSPOKES
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
BASE_SET & set(size_t pos)
Definition base_set.h:116
DIM_PRECISION m_DimensionPrecision
Number of digits after the decimal.
std::vector< TEXT_ITEM_INFO > m_DefaultFPTextItems
int GetHolePlatingThickness() const
Pad & via drills are finish size.
VIATYPE m_CurrentViaType
(VIA_BLIND_BURIED, VIA_THROUGH, VIA_MICROVIA)
void SetEnabledLayers(const LSET &aMask)
Change the bit-mask of enabled layers to aMask.
std::shared_ptr< NET_SETTINGS > m_NetSettings
bool operator==(const BOARD_DESIGN_SETTINGS &aOther) const
std::map< wxString, wxString > m_DrcExclusionComments
DIM_UNITS_FORMAT m_DimensionUnitsFormat
void initFromOther(const BOARD_DESIGN_SETTINGS &aOther)
bool GetTextUpright(PCB_LAYER_ID aLayer) const
std::map< int, SEVERITY > m_DRCSeverities
VECTOR2I m_gridOrigin
origin for grid offsets
int GetTextThickness(PCB_LAYER_ID aLayer) const
Return the default text thickness from the layer class for the given layer.
VECTOR2I m_auxOrigin
origin for plot exports
bool m_TextUpright[LAYER_CLASS_COUNT]
BOARD_DESIGN_SETTINGS(JSON_SETTINGS *aParent, const std::string &aPath)
bool GetTextItalic(PCB_LAYER_ID aLayer) const
wxString m_currentNetClassName
Current net class name used to display netclass info.
void SetViaSizeIndex(int aIndex)
Set the current via size list index to aIndex.
std::shared_ptr< DRC_ENGINE > m_DRCEngine
std::vector< DIFF_PAIR_DIMENSION > m_DiffPairDimensionsList
std::set< wxString > m_DrcExclusions
bool Ignore(int aDRCErrorCode)
Return true if the DRC error code's severity is SEVERITY_IGNORE.
std::map< std::string, wxString > m_UserLayerNames
std::unique_ptr< PAD > m_Pad_Master
TEARDROP_PARAMETERS_LIST m_TeardropParamsList
The parameters of teardrops for the different teardrop targets (via/pad, track end).
void SetUserDefinedLayerCount(int aNewLayerCount)
Set the number of user defined layers to aNewLayerCount.
int GetDRCEpsilon() const
Return an epsilon which accounts for rounding errors, etc.
int GetLayerClass(PCB_LAYER_ID aLayer) const
PNS::MEANDER_SETTINGS m_DiffPairMeanderSettings
int m_boardThickness
Board thickness for 3D viewer.
int m_copperLayerCount
Number of copper layers for this design.
int m_userDefinedLayerCount
Number of user defined layers for this design.
bool LoadFromFile(const wxString &aDirectory="") override
Loads the backing file from disk and then calls Load()
PNS::MEANDER_SETTINGS m_SingleTrackMeanderSettings
void SetTrackWidthIndex(int aIndex)
Set the current track width list index to aIndex.
int m_TextThickness[LAYER_CLASS_COUNT]
ZONE_SETTINGS m_defaultZoneSettings
The default settings that will be used for new zones.
SEVERITY GetSeverity(int aDRCErrorCode)
std::vector< int > m_TrackWidthList
DIFF_PAIR_DIMENSION m_customDiffPair
int m_LineThickness[LAYER_CLASS_COUNT]
VECTOR2I GetTextSize(PCB_LAYER_ID aLayer) const
Return the default text size from the layer class for the given layer.
int GetLineThickness(PCB_LAYER_ID aLayer) const
Return the default graphic segment thickness from the layer class for the given layer.
bool m_UseHeightForLengthCalcs
Enable inclusion of stackup height in track length measurements and length tuning.
VECTOR2I m_TextSize[LAYER_CLASS_COUNT]
PNS::MEANDER_SETTINGS m_SkewMeanderSettings
LSET m_enabledLayers
Bit-mask for layer enabling.
bool m_TextItalic[LAYER_CLASS_COUNT]
void SetCopperLayerCount(int aNewLayerCount)
Set the copper layer count to aNewLayerCount.
DIM_TEXT_POSITION m_DimensionTextPosition
BOARD_STACKUP m_stackup
The description of layers stackup, for board fabrication only physical layers are in layers stackup.
std::vector< VIA_DIMENSION > m_ViasDimensionsList
BOARD_DESIGN_SETTINGS & operator=(const BOARD_DESIGN_SETTINGS &aOther)
MINOPTMAX< int > & Value()
Definition drc_rule.h:187
static std::vector< std::reference_wrapper< RC_ITEM > > GetItemsWithSeverities()
Definition drc_item.h:141
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition drc_item.cpp:400
void Set(const std::string &aPath, ValueType aVal)
Stores a value into the JSON document Will throw an exception if ValueType isn't something that the l...
bool Contains(const std::string &aPath) const
virtual void Load()
Updates the parameters of this object based on the current JSON document contents.
std::optional< ValueType > Get(const std::string &aPath) const
Fetches a value from within the JSON document.
std::vector< PARAM_BASE * > m_params
The list of parameters (owned by this object)
void registerMigration(int aOldSchemaVersion, int aNewSchemaVersion, std::function< bool(void)> aMigrator)
Registers a migration from one schema version to another.
nlohmann::json & At(const std::string &aPath)
Wrappers for the underlying JSON API so that most consumers don't need json.hpp All of these function...
JSON_SETTINGS(const wxString &aFilename, SETTINGS_LOC aLocation, int aSchemaVersion)
bool m_resetParamsIfMissing
Whether or not to set parameters to their default value if missing from JSON on Load()
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
LSET & ClearNonCopperLayers()
Clear the non-copper layers in this set.
Definition lset.cpp:934
static LSET UserDefinedLayersMask(int aUserDefinedLayerCount=MAX_USER_DEFINED_LAYERS)
Return a mask with the requested number of user defined layers.
Definition lset.cpp:687
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:591
T Min() const
Definition minoptmax.h:33
std::string m_path
The path (in pointer format) of where to store this document in the parent.
JSON_SETTINGS * GetParent()
JSON_SETTINGS * m_parent
A pointer to the parent object to load and store from.
NESTED_SETTINGS(const std::string &aName, int aSchemaVersion, JSON_SETTINGS *aParent, const std::string &aPath, bool aLoadFromFile=true)
bool LoadFromFile(const wxString &aDirectory="") override
Loads the JSON document from the parent and then calls Load()
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:177
Stores an enum as an integer.
Definition parameters.h:229
Like a normal param, but with custom getter and setter functions.
Definition parameters.h:296
Represents a parameter that has a scaling factor between the value in the file and the value used int...
Definition parameters.h:393
Dimensions for the meandering algorithm.
Definition pns_meander.h:68
int m_minAmplitude
Maximum meandering amplitude.
Definition pns_meander.h:93
int m_cornerRadiusPercentage
Place meanders on one side.
bool m_singleSided
Initial side when placing meanders at segment.
MEANDER_STYLE m_cornerStyle
Rounding percentage (0 - 100).
int m_maxAmplitude
Meandering period/spacing (see dialog picture for explanation).
Definition pns_meander.h:96
int m_spacing
Amplitude/spacing adjustment step.
Definition pns_meander.h:99
The backing store for a PROJECT, in JSON format.
A holder for a rule check item, DRC in Pcbnew or ERC in Eeschema.
Definition rc_item.h:81
TEARDROP_PARAMETARS is a helper class to handle parameters needed to build teardrops for a board thes...
double m_BestWidthRatio
The height of a teardrop as ratio between height and size of pad/via.
int m_TdMaxLen
max allowed length for teardrops in IU. <= 0 to disable
bool m_AllowUseTwoTracks
True to create teardrops using 2 track segments if the first in too small.
int m_TdMaxWidth
max allowed height for teardrops in IU. <= 0 to disable
double m_BestLengthRatio
The length of a teardrop as ratio between length and size of pad/via.
double m_WidthtoSizeFilterRatio
The ratio (H/D) between the via/pad size and the track width max value to create a teardrop 1....
bool m_TdOnPadsInZones
A filter to exclude pads inside zone fills.
bool m_CurvedEdges
True if the teardrop should be curved.
@ DRCE_TUNING_PROFILE_IMPLICIT_RULES
Definition drc_item.h:114
@ DRCE_SILK_EDGE_CLEARANCE
Definition drc_item.h:99
@ DRCE_FOOTPRINT_FILTERS
Definition drc_item.h:80
@ DRCE_SILK_MASK_CLEARANCE
Definition drc_item.h:97
@ DRCE_PADSTACK
Definition drc_item.h:63
@ DRCE_MIRRORED_TEXT_ON_FRONT_LAYER
Definition drc_item.h:110
@ DRCE_LIB_FOOTPRINT_ISSUES
Definition drc_item.h:83
@ DRCE_OVERLAPPING_FOOTPRINTS
Definition drc_item.h:66
@ DRCE_SCHEMATIC_FIELDS_PARITY
Definition drc_item.h:118
@ DRCE_MISSING_COURTYARD
Definition drc_item.h:67
@ DRCE_ISOLATED_COPPER
Definition drc_item.h:49
@ DRCE_MISSING_TUNING_PROFILE
Definition drc_item.h:113
@ DRCE_DRILLED_HOLES_TOO_CLOSE
Definition drc_item.h:53
@ DRCE_COPPER_SLIVER
Definition drc_item.h:93
@ DRCE_PTH_IN_COURTYARD
Definition drc_item.h:70
@ DRCE_FIRST
Definition drc_item.h:39
@ DRCE_DANGLING_VIA
Definition drc_item.h:51
@ DRCE_FOOTPRINT_TYPE_MISMATCH
Definition drc_item.h:82
@ DRCE_NONMIRRORED_TEXT_ON_BACK_LAYER
Definition drc_item.h:111
@ DRCE_DUPLICATE_FOOTPRINT
Definition drc_item.h:76
@ DRCE_DANGLING_TRACK
Definition drc_item.h:52
@ DRCE_TEXT_HEIGHT
Definition drc_item.h:101
@ DRCE_DRILLED_HOLES_COLOCATED
Definition drc_item.h:54
@ DRCE_EXTRA_FOOTPRINT
Definition drc_item.h:77
@ DRCE_SILK_CLEARANCE
Definition drc_item.h:100
@ DRCE_LAST
Definition drc_item.h:120
@ DRCE_LIB_FOOTPRINT_MISMATCH
Definition drc_item.h:84
@ DRCE_NET_CONFLICT
Definition drc_item.h:78
@ DRCE_MISSING_FOOTPRINT
Definition drc_item.h:75
@ DRCE_TEXT_THICKNESS
Definition drc_item.h:102
@ DRCE_NPTH_IN_COURTYARD
Definition drc_item.h:71
@ DRCE_CONNECTION_WIDTH
Definition drc_item.h:60
@ DRCE_SCHEMATIC_PARITY
Definition drc_item.h:79
@ EDGE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:53
@ CLEARANCE_CONSTRAINT
Definition drc_rule.h:49
@ HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:51
@ PHYSICAL_CLEARANCE_CONSTRAINT
Definition drc_rule.h:77
@ HOLE_TO_HOLE_CONSTRAINT
Definition drc_rule.h:52
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:413
static constexpr EDA_ANGLE ANGLE_45
Definition eda_angle.h:412
#define TEXT_MIN_SIZE_MM
Minimum text size (1 micron).
Definition eda_text.h:47
#define TEXT_MAX_SIZE_MM
Maximum text size in mm (~10 inches)
Definition eda_text.h:48
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:677
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ F_CrtYd
Definition layer_ids.h:116
@ Edge_Cuts
Definition layer_ids.h:112
@ B_Cu
Definition layer_ids.h:65
@ F_Fab
Definition layer_ids.h:119
@ Margin
Definition layer_ids.h:113
@ F_SilkS
Definition layer_ids.h:100
@ B_CrtYd
Definition layer_ids.h:115
@ B_SilkS
Definition layer_ids.h:101
@ F_Cu
Definition layer_ids.h:64
@ B_Fab
Definition layer_ids.h:118
@ MEANDER_STYLE_ROUND
Definition pns_meander.h:52
@ MEANDER_STYLE_CHAMFER
Definition pns_meander.h:53
@ ROUNDRECT
Definition padstack.h:57
@ OUTSIDE
Text appears outside the dimension line (default)
@ INLINE
Text appears in line with the dimension line.
@ THROUGH
Definition pcb_track.h:68
SEVERITY
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_IGNORE
Container to handle a stock of specific differential pairs each with unique track width,...
Container to handle a stock of specific vias each with unique diameter and drill sizes in the BOARD c...
std::string GetTeardropTargetCanonicalName(TARGET_TD aTdType)
TARGET_TD GetTeardropTargetTypeFromCanonicalName(const std::string &aTargetName)
int clearance
SEVERITY SeverityFromString(const wxString &aSeverity)
Definition ui_common.cpp:56
wxString SeverityToString(const SEVERITY &aSeverity)
Definition ui_common.cpp:67
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
#define ZONE_CLEARANCE_MM
Definition zones.h:36