7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-18 22:41:41 +00:00

Consolidate Maximum clearance calculation

We were calculating the same thing in three locations and we missed
adding the clearance from the footprints in, resulting in bad fills and
missed drc errors (see QA addition)
This commit is contained in:
Seth Hillbrand 2023-07-26 12:36:13 -07:00
parent 5ea170baab
commit 96a34e5b57
12 changed files with 819 additions and 40 deletions

View File

@ -742,6 +742,27 @@ void BOARD::SetZoneSettings( const ZONE_SETTINGS& aSettings )
GetDesignSettings().SetDefaultZoneSettings( aSettings );
}
int BOARD::GetMaxClearanceValue() const
{
int worstClearance = m_designSettings->GetBiggestClearanceValue();
for( ZONE* zone : m_zones )
worstClearance = std::max( worstClearance, zone->GetLocalClearance() );
for( FOOTPRINT* footprint : m_footprints )
{
worstClearance = std::max( worstClearance, footprint->GetLocalClearance() );
for( PAD* pad : footprint->Pads() )
worstClearance = std::max( worstClearance, pad->GetLocalClearance() );
for( ZONE* zone : footprint->Zones() )
worstClearance = std::max( worstClearance, zone->GetLocalClearance() );
}
return worstClearance;
}
void BOARD::CacheTriangulation( PROGRESS_REPORTER* aReporter, const std::vector<ZONE*>& aZones )
{

View File

@ -1086,6 +1086,13 @@ public:
FOOTPRINT* GetFootprint( const VECTOR2I& aPosition, PCB_LAYER_ID aActiveLayer,
bool aVisibleOnly, bool aIgnoreLocked = false ) const;
/**
* Returns the maximum clearance value for any object on the board. This considers
* the clearances from board design settings as well as embedded clearances in footprints,
* pads and zones. Includes electrical, physical, hole and edge clearances.
*/
int GetMaxClearanceValue() const;
/**
* Map all nets in the given board to nets with the same name (if any) in the destination
* board. This allows us to share layouts which came from the same hierarchical sheet in

View File

@ -35,22 +35,18 @@ bool DRC_CACHE_GENERATOR::Run()
{
m_board = m_drcEngine->GetBoard();
int& m_largestClearance = m_board->m_DRCMaxClearance;
int& m_largestPhysicalClearance = m_board->m_DRCMaxPhysicalClearance;
int& largestClearance = m_board->m_DRCMaxClearance;
int& largestPhysicalClearance = m_board->m_DRCMaxPhysicalClearance;
DRC_CONSTRAINT worstConstraint;
LSET boardCopperLayers = LSET::AllCuMask( m_board->GetCopperLayerCount() );
if( m_drcEngine->QueryWorstConstraint( CLEARANCE_CONSTRAINT, worstConstraint ) )
m_largestClearance = worstConstraint.GetValue().Min();
if( m_drcEngine->QueryWorstConstraint( HOLE_CLEARANCE_CONSTRAINT, worstConstraint ) )
m_largestClearance = std::max( m_largestClearance, worstConstraint.GetValue().Min() );
largestClearance = std::max( largestClearance, m_board->GetMaxClearanceValue() );
if( m_drcEngine->QueryWorstConstraint( PHYSICAL_CLEARANCE_CONSTRAINT, worstConstraint ) )
m_largestPhysicalClearance = worstConstraint.GetValue().Min();
largestPhysicalClearance = worstConstraint.GetValue().Min();
if( m_drcEngine->QueryWorstConstraint( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT, worstConstraint ) )
m_largestPhysicalClearance = std::max( m_largestPhysicalClearance, worstConstraint.GetValue().Min() );
largestPhysicalClearance = std::max( largestPhysicalClearance, worstConstraint.GetValue().Min() );
std::set<ZONE*> allZones;
@ -65,16 +61,12 @@ bool DRC_CACHE_GENERATOR::Run()
if( ( zone->GetLayerSet() & boardCopperLayers ).any() )
{
m_board->m_DRCCopperZones.push_back( zone );
m_largestClearance = std::max( m_largestClearance, zone->GetLocalClearance() );
}
}
}
for( FOOTPRINT* footprint : m_board->Footprints() )
{
for( PAD* pad : footprint->Pads() )
m_largestClearance = std::max( m_largestClearance, pad->GetLocalClearance() );
for( ZONE* zone : footprint->Zones() )
{
allZones.insert( zone );
@ -84,10 +76,7 @@ bool DRC_CACHE_GENERATOR::Run()
m_board->m_DRCZones.push_back( zone );
if( ( zone->GetLayerSet() & boardCopperLayers ).any() )
{
m_board->m_DRCCopperZones.push_back( zone );
m_largestClearance = std::max( m_largestClearance, zone->GetLocalClearance() );
}
}
}
}
@ -124,7 +113,7 @@ bool DRC_CACHE_GENERATOR::Run()
for( PCB_LAYER_ID layer : copperLayers.Seq() )
{
if( IsCopperLayer( layer ) )
m_board->m_CopperItemRTreeCache->Insert( item, layer, m_largestClearance );
m_board->m_CopperItemRTreeCache->Insert( item, layer, largestClearance );
}
return true;

View File

@ -1684,7 +1684,7 @@ const BOX2I FOOTPRINT::ViewBBox() const
// Inflate in case clearance lines are drawn around pads, etc.
if( const BOARD* board = GetBoard() )
{
int biggest_clearance = board->GetDesignSettings().GetBiggestClearanceValue();
int biggest_clearance = board->GetMaxClearanceValue();
area.Inflate( biggest_clearance );
}

View File

@ -1449,7 +1449,7 @@ const BOX2I PAD::ViewBBox() const
if( PCBNEW_SETTINGS* cfg = dynamic_cast<PCBNEW_SETTINGS*>( Kiface().KifaceSettings() ) )
{
if( cfg && cfg->m_Display.m_PadClearance && GetBoard() )
clearance = GetBoard()->GetDesignSettings().GetBiggestClearanceValue();
clearance = GetBoard()->GetMaxClearanceValue();
}
// Look for the biggest possible bounding box

View File

@ -1519,7 +1519,7 @@ void PNS_KICAD_IFACE_BASE::SyncWorld( PNS::NODE *aWorld )
return;
}
int worstClearance = m_board->GetDesignSettings().GetBiggestClearanceValue();
int worstClearance = m_board->GetMaxClearanceValue();
m_world = aWorld;

View File

@ -100,7 +100,7 @@ bool ZONE_FILLER::Fill( std::vector<ZONE*>& aZones, bool aCheck, wxWindow* aPare
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
m_worstClearance = bds.GetBiggestClearanceValue();
m_worstClearance = m_board->GetMaxClearanceValue();
if( m_progressReporter )
{
@ -118,10 +118,7 @@ bool ZONE_FILLER::Fill( std::vector<ZONE*>& aZones, bool aCheck, wxWindow* aPare
// make them thread-safe.
//
for( ZONE* zone : m_board->Zones() )
{
zone->CacheBoundingBox();
m_worstClearance = std::max( m_worstClearance, zone->GetLocalClearance() );
}
for( FOOTPRINT* footprint : m_board->Footprints() )
{
@ -132,15 +129,10 @@ bool ZONE_FILLER::Fill( std::vector<ZONE*>& aZones, bool aCheck, wxWindow* aPare
pad->BuildEffectiveShapes( UNDEFINED_LAYER );
pad->BuildEffectivePolygon();
}
m_worstClearance = std::max( m_worstClearance, pad->GetLocalClearance() );
}
for( ZONE* zone : footprint->Zones() )
{
zone->CacheBoundingBox();
m_worstClearance = std::max( m_worstClearance, zone->GetLocalClearance() );
}
// Rules may depend on insideCourtyard() or other expressions
footprint->BuildCourtyardCaches();

View File

LOADING design file

View File

@ -0,0 +1,528 @@
{
"board": {
"3dviewports": [],
"design_settings": {
"defaults": {
"board_outline_line_width": 0.15,
"copper_line_width": 0.19999999999999998,
"copper_text_italic": false,
"copper_text_size_h": 1.5,
"copper_text_size_v": 1.5,
"copper_text_thickness": 0.3,
"copper_text_upright": false,
"courtyard_line_width": 0.049999999999999996,
"dimension_precision": 4,
"dimension_units": 3,
"dimensions": {
"arrow_length": 1270000,
"extension_offset": 500000,
"keep_text_aligned": true,
"suppress_zeroes": false,
"text_position": 0,
"units_format": 1
},
"fab_line_width": 0.09999999999999999,
"fab_text_italic": false,
"fab_text_size_h": 1.0,
"fab_text_size_v": 1.0,
"fab_text_thickness": 0.15,
"fab_text_upright": false,
"other_line_width": 0.09999999999999999,
"other_text_italic": false,
"other_text_size_h": 1.0,
"other_text_size_v": 1.0,
"other_text_thickness": 0.15,
"other_text_upright": false,
"pads": {
"drill": 0.762,
"height": 1.524,
"width": 1.524
},
"silk_line_width": 0.15,
"silk_text_italic": false,
"silk_text_size_h": 0.5,
"silk_text_size_v": 0.5,
"silk_text_thickness": 0.125,
"silk_text_upright": false,
"zones": {
"45_degree_only": false,
"min_clearance": 0.127
}
},
"diff_pair_dimensions": [
{
"gap": 0.0,
"via_gap": 0.0,
"width": 0.0
}
],
"drc_exclusions": [],
"meta": {
"filename": "board_design_settings.json",
"version": 2
},
"rule_severities": {
"annular_width": "error",
"clearance": "error",
"connection_width": "warning",
"copper_edge_clearance": "error",
"copper_sliver": "warning",
"courtyards_overlap": "error",
"diff_pair_gap_out_of_range": "error",
"diff_pair_uncoupled_length_too_long": "error",
"drill_out_of_range": "error",
"duplicate_footprints": "warning",
"extra_footprint": "warning",
"footprint": "error",
"footprint_type_mismatch": "error",
"hole_clearance": "error",
"hole_near_hole": "error",
"invalid_outline": "error",
"isolated_copper": "warning",
"item_on_disabled_layer": "error",
"items_not_allowed": "error",
"length_out_of_range": "error",
"lib_footprint_issues": "ignore",
"lib_footprint_mismatch": "warning",
"malformed_courtyard": "error",
"microvia_drill_out_of_range": "error",
"missing_courtyard": "error",
"missing_footprint": "warning",
"net_conflict": "warning",
"npth_inside_courtyard": "warning",
"padstack": "error",
"pth_inside_courtyard": "warning",
"shorting_items": "error",
"silk_edge_clearance": "warning",
"silk_over_copper": "warning",
"silk_overlap": "warning",
"skew_out_of_range": "error",
"solder_mask_bridge": "error",
"starved_thermal": "error",
"text_height": "warning",
"text_thickness": "warning",
"through_hole_pad_without_hole": "error",
"too_many_vias": "error",
"track_dangling": "warning",
"track_width": "error",
"tracks_crossing": "error",
"unconnected_items": "error",
"unresolved_variable": "error",
"via_dangling": "warning",
"zones_intersect": "error"
},
"rule_severitieslegacy_courtyards_overlap": true,
"rule_severitieslegacy_no_courtyard_defined": false,
"rules": {
"allow_blind_buried_vias": false,
"allow_microvias": false,
"max_error": 0.005,
"min_clearance": 0.127,
"min_connection": 0.0,
"min_copper_edge_clearance": 0.254,
"min_hole_clearance": 0.254,
"min_hole_to_hole": 0.25,
"min_microvia_diameter": 0.19999999999999998,
"min_microvia_drill": 0.09999999999999999,
"min_resolved_spokes": 2,
"min_silk_clearance": 0.0,
"min_text_height": 0.7999999999999999,
"min_text_thickness": 0.08,
"min_through_hole_diameter": 0.19999999999999998,
"min_track_width": 0.127,
"min_via_annular_width": 0.127,
"min_via_diameter": 0.45399999999999996,
"solder_mask_to_copper_clearance": 0.0,
"use_height_for_length_calcs": true
},
"teardrop_options": [
{
"td_onpadsmd": true,
"td_onroundshapesonly": false,
"td_ontrackend": false,
"td_onviapad": true
}
],
"teardrop_parameters": [
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_round_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_rect_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_track_end",
"td_width_to_size_filter_ratio": 0.9
}
],
"track_widths": [
0.0,
0.25,
0.32,
0.5,
0.75,
1.0,
1.5,
2.0,
2.5
],
"via_dimensions": [
{
"diameter": 0.0,
"drill": 0.0
},
{
"diameter": 0.454,
"drill": 0.2
}
],
"zones_allow_external_fillets": true,
"zones_use_no_outline": true
},
"layer_presets": [],
"viewports": []
},
"boards": [],
"cvpcb": {
"equivalence_files": []
},
"erc": {
"erc_exclusions": [],
"meta": {
"version": 0
},
"pin_map": [
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
1,
2
],
[
0,
1,
0,
0,
0,
0,
1,
1,
2,
1,
1,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2
],
[
1,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
2
],
[
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
1,
2,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
0,
2,
1,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2
]
],
"rule_severities": {
"bus_definition_conflict": "error",
"bus_entry_needed": "error",
"bus_to_bus_conflict": "error",
"bus_to_net_conflict": "error",
"conflicting_netclasses": "error",
"different_unit_footprint": "error",
"different_unit_net": "error",
"duplicate_reference": "error",
"duplicate_sheet_names": "error",
"endpoint_off_grid": "warning",
"extra_units": "error",
"global_label_dangling": "warning",
"hier_label_mismatch": "error",
"label_dangling": "error",
"lib_symbol_issues": "warning",
"missing_bidi_pin": "warning",
"missing_input_pin": "warning",
"missing_power_pin": "error",
"missing_unit": "warning",
"multiple_net_names": "warning",
"net_not_bus_member": "warning",
"no_connect_connected": "warning",
"no_connect_dangling": "warning",
"pin_not_connected": "error",
"pin_not_driven": "error",
"pin_to_pin": "error",
"power_pin_not_driven": "error",
"similar_labels": "warning",
"simulation_model_issue": "ignore",
"unannotated": "error",
"unit_value_mismatch": "error",
"unresolved_variable": "error",
"wire_dangling": "error"
}
},
"libraries": {
"pinned_footprint_libs": [],
"pinned_symbol_libs": []
},
"meta": {
"filename": "fill_bad.kicad_pro",
"version": 1
},
"net_settings": {
"classes": [
{
"bus_width": 12,
"clearance": 0.127,
"diff_pair_gap": 0.127,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.21,
"line_style": 0,
"microvia_diameter": 0.2,
"microvia_drill": 0.1,
"name": "Default",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.127,
"via_diameter": 0.454,
"via_drill": 0.2,
"wire_width": 6
}
],
"meta": {
"version": 3
},
"net_colors": null,
"netclass_assignments": null,
"netclass_patterns": []
},
"pcbnew": {
"last_paths": {
"gencad": "",
"idf": "",
"netlist": "",
"plot": "",
"pos_files": "",
"specctra_dsn": "",
"step": "p-1743-sbm-swappable-battery-module.step",
"svg": "",
"vrml": ""
},
"page_layout_descr_file": ""
},
"schematic": {
"annotate_start_num": 0,
"drawing": {
"dashed_lines_dash_length_ratio": 12.0,
"dashed_lines_gap_length_ratio": 3.0,
"default_line_thickness": 6.0,
"default_text_size": 60.0,
"field_names": [],
"intersheets_ref_own_page": false,
"intersheets_ref_prefix": "",
"intersheets_ref_short": false,
"intersheets_ref_show": false,
"intersheets_ref_suffix": "",
"junction_size_choice": 3,
"label_size_ratio": 0.25,
"pin_symbol_size": 0.0,
"text_offset_ratio": 0.08
},
"legacy_lib_dir": "",
"legacy_lib_list": [],
"meta": {
"version": 1
},
"net_format_name": "",
"ngspice": {
"fix_include_paths": true,
"fix_passive_vals": false,
"meta": {
"version": 0
},
"model_mode": 0,
"workbook_filename": ""
},
"page_layout_descr_file": "${KICAD_USER_TEMPLATE_DIR}/UXV_Technologies.kicad_wks",
"plot_directory": "",
"spice_adjust_passive_values": false,
"spice_current_sheet_as_root": false,
"spice_external_command": "spice \"%I\"",
"spice_model_current_sheet_as_root": true,
"spice_save_all_currents": false,
"spice_save_all_voltages": false,
"subpart_first_id": 65,
"subpart_id_separator": 0
},
"sheets": [
[
"e67d5971-86c9-4966-a671-2c2aab2d5789",
""
]
],
"text_variables": {
"PROJECT_ID": "726",
"PROJECT_NAME": "sbm-swappable-battery-module",
"PROJECT_NUMBER": "1743",
"PROJECT_VERSION": "V1.0.0"
}
}

View File

@ -56,15 +56,7 @@
"width": 0.0
}
],
"drc_exclusions": [
"clearance|87150000|140800000|713a642e-4662-4581-a311-4a183ae3a0a4|0e2e2e70-712c-4a91-9883-5badae873369",
"courtyards_overlap|102580000|139229999|00000000-0000-0000-0000-00005db27222|00000000-0000-0000-0000-00005e4ffe1e",
"courtyards_overlap|102580000|142700000|00000000-0000-0000-0000-00005db270f4|00000000-0000-0000-0000-00005e4ffe1e",
"courtyards_overlap|116660000|142900000|00000000-0000-0000-0000-00005db26ea8|00000000-0000-0000-0000-00005db2741b",
"courtyards_overlap|126820000|142900000|00000000-0000-0000-0000-00005db272bc|00000000-0000-0000-0000-00005db2741b",
"courtyards_overlap|144725000|118017468|00000000-0000-0000-0000-00005d888938|00000000-0000-0000-0000-00005e2b4dc2",
"courtyards_overlap|86925000|140617468|00000000-0000-0000-0000-00005db273cf|00000000-0000-0000-0000-00005e2b4dc5"
],
"drc_exclusions": [],
"meta": {
"version": 2
},

View File

@ -137,7 +137,8 @@ BOOST_FIXTURE_TEST_CASE( DRCFalseNegativeRegressions, DRC_REGRESSION_TEST_FIXTUR
{ "issue12109", 8 }, // Pads fail annular width test
{ "issue14334", 2 }, // Thermal spoke to otherwise unconnected island
{ "reverse_via", 3 }, // Via/track ordering
{ "intersectingzones", 1 } // zones are too close to each other
{ "intersectingzones", 1 }, // zones are too close to each other
{ "fill_bad", 1 } // zone max BBox was too small
};
for( const std::pair<wxString, int>& entry : tests )

View File

@ -176,7 +176,8 @@ BOOST_FIXTURE_TEST_CASE( RegressionZoneFillTests, ZONE_FILL_TEST_FIXTURE )
"issue6260",
"issue6284",
"issue7086",
"issue14294" // Bad Clipper2 fill
"issue14294", // Bad Clipper2 fill
"fill_bad" // Missing zone clearance expansion
};
for( const wxString& relPath : tests )