Cherry-pick some 7.0 Clearance Resolution improvements.

6.0 will be in the field for a long time, and the better the debugging
tools we have available the less costly it will be to maintain.

Fixes https://gitlab.com/kicad/code/kicad/issues/8961
This commit is contained in:
Jeff Young 2021-08-15 18:23:54 +01:00
parent c6ce367f1e
commit 1ec70d30af
14 changed files with 406 additions and 367 deletions

View File

@ -340,8 +340,8 @@ void AR_AUTOPLACER::buildFpAreas( FOOTPRINT* aFootprint, int aFpClearance )
m_fpAreaBottom.RemoveAllContours(); m_fpAreaBottom.RemoveAllContours();
aFootprint->BuildPolyCourtyards(); aFootprint->BuildPolyCourtyards();
m_fpAreaTop = aFootprint->GetPolyCourtyardFront(); m_fpAreaTop = aFootprint->GetPolyCourtyard( F_CrtYd );
m_fpAreaBottom = aFootprint->GetPolyCourtyardBack(); m_fpAreaBottom = aFootprint->GetPolyCourtyard( B_CrtYd );
LSET layerMask; LSET layerMask;

View File

@ -17,7 +17,7 @@ DIALOG_CONSTRAINTS_REPORTER_BASE::DIALOG_CONSTRAINTS_REPORTER_BASE( wxWindow* pa
bMainSizer = new wxBoxSizer( wxVERTICAL ); bMainSizer = new wxBoxSizer( wxVERTICAL );
m_notebook = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxSize( -1,-1 ), 0 ); m_notebook = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxSize( -1,-1 ), 0 );
m_notebook->SetMinSize( wxSize( 480,360 ) ); m_notebook->SetMinSize( wxSize( 550,480 ) );
bMainSizer->Add( m_notebook, 1, wxEXPAND|wxRIGHT|wxLEFT, 10 ); bMainSizer->Add( m_notebook, 1, wxEXPAND|wxRIGHT|wxLEFT, 10 );

View File

@ -96,7 +96,7 @@
<property name="maximum_size"></property> <property name="maximum_size"></property>
<property name="min_size"></property> <property name="min_size"></property>
<property name="minimize_button">0</property> <property name="minimize_button">0</property>
<property name="minimum_size">480,360</property> <property name="minimum_size">550,480</property>
<property name="moveable">1</property> <property name="moveable">1</property>
<property name="name">m_notebook</property> <property name="name">m_notebook</property>
<property name="pane_border">1</property> <property name="pane_border">1</property>

View File

@ -452,7 +452,7 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
} }
if( rcItem->GetErrorCode() == DRCE_CLEARANCE if( rcItem->GetErrorCode() == DRCE_CLEARANCE
|| rcItem->GetErrorCode() == DRCE_COPPER_EDGE_CLEARANCE ) || rcItem->GetErrorCode() == DRCE_EDGE_CLEARANCE )
{ {
menu.Append( 3, _( "Run clearance resolution tool..." ) ); menu.Append( 3, _( "Run clearance resolution tool..." ) );
} }

View File

@ -969,10 +969,10 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
{ {
const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( a ); const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( a );
if( !footprint->GetPolyCourtyardFront().IsEmpty() ) if( !footprint->GetPolyCourtyard( F_CrtYd ).IsEmpty() )
itemLayers |= LSET::FrontMask(); itemLayers |= LSET::FrontMask();
if( !footprint->GetPolyCourtyardBack().IsEmpty() ) if( !footprint->GetPolyCourtyard( B_CrtYd ).IsEmpty() )
itemLayers |= LSET::BackMask(); itemLayers |= LSET::BackMask();
} }

View File

@ -69,7 +69,7 @@ DRC_ITEM DRC_ITEM::tracksCrossing( DRCE_TRACKS_CROSSING,
_( "Tracks crossing" ), _( "Tracks crossing" ),
wxT( "tracks_crossing" ) ); wxT( "tracks_crossing" ) );
DRC_ITEM DRC_ITEM::copperEdgeClearance( DRCE_COPPER_EDGE_CLEARANCE, DRC_ITEM DRC_ITEM::edgeClearance( DRCE_EDGE_CLEARANCE,
_( "Board edge clearance violation" ), _( "Board edge clearance violation" ),
wxT( "copper_edge_clearance" ) ); wxT( "copper_edge_clearance" ) );
@ -210,7 +210,7 @@ std::vector<std::reference_wrapper<RC_ITEM>> DRC_ITEM::allItemTypes( {
DRC_ITEM::trackDangling, DRC_ITEM::trackDangling,
DRC_ITEM::heading_DFM, DRC_ITEM::heading_DFM,
DRC_ITEM::copperEdgeClearance, DRC_ITEM::edgeClearance,
DRC_ITEM::holeClearance, DRC_ITEM::holeClearance,
DRC_ITEM::holeNearHole, DRC_ITEM::holeNearHole,
DRC_ITEM::trackWidth, DRC_ITEM::trackWidth,
@ -260,7 +260,7 @@ std::shared_ptr<DRC_ITEM> DRC_ITEM::Create( int aErrorCode )
case DRCE_TEXT_ON_EDGECUTS: return std::make_shared<DRC_ITEM>( textOnEdgeCuts ); case DRCE_TEXT_ON_EDGECUTS: return std::make_shared<DRC_ITEM>( textOnEdgeCuts );
case DRCE_CLEARANCE: return std::make_shared<DRC_ITEM>( clearance ); case DRCE_CLEARANCE: return std::make_shared<DRC_ITEM>( clearance );
case DRCE_TRACKS_CROSSING: return std::make_shared<DRC_ITEM>( tracksCrossing ); case DRCE_TRACKS_CROSSING: return std::make_shared<DRC_ITEM>( tracksCrossing );
case DRCE_COPPER_EDGE_CLEARANCE: return std::make_shared<DRC_ITEM>( copperEdgeClearance ); case DRCE_EDGE_CLEARANCE: return std::make_shared<DRC_ITEM>( edgeClearance );
case DRCE_ZONES_INTERSECT: return std::make_shared<DRC_ITEM>( zonesIntersect ); case DRCE_ZONES_INTERSECT: return std::make_shared<DRC_ITEM>( zonesIntersect );
case DRCE_ZONE_HAS_EMPTY_NET: return std::make_shared<DRC_ITEM>( zoneHasEmptyNet ); case DRCE_ZONE_HAS_EMPTY_NET: return std::make_shared<DRC_ITEM>( zoneHasEmptyNet );
case DRCE_DANGLING_VIA: return std::make_shared<DRC_ITEM>( viaDangling ); case DRCE_DANGLING_VIA: return std::make_shared<DRC_ITEM>( viaDangling );

View File

@ -39,7 +39,7 @@ enum PCB_DRC_CODE {
DRCE_TEXT_ON_EDGECUTS, // text or dimension on Edge.Cuts layer DRCE_TEXT_ON_EDGECUTS, // text or dimension on Edge.Cuts layer
DRCE_CLEARANCE, // items are too close together DRCE_CLEARANCE, // items are too close together
DRCE_TRACKS_CROSSING, // tracks are crossing DRCE_TRACKS_CROSSING, // tracks are crossing
DRCE_COPPER_EDGE_CLEARANCE, // a copper item is too close to the board edge DRCE_EDGE_CLEARANCE, // a copper item is too close to the board edge
DRCE_ZONES_INTERSECT, // copper area outlines intersect DRCE_ZONES_INTERSECT, // copper area outlines intersect
DRCE_ZONE_HAS_EMPTY_NET, // copper area has a net but no pads in nets, which is suspicious DRCE_ZONE_HAS_EMPTY_NET, // copper area has a net but no pads in nets, which is suspicious
DRCE_DANGLING_VIA, // via which isn't connected to anything DRCE_DANGLING_VIA, // via which isn't connected to anything
@ -134,7 +134,7 @@ private:
static DRC_ITEM textOnEdgeCuts; static DRC_ITEM textOnEdgeCuts;
static DRC_ITEM clearance; static DRC_ITEM clearance;
static DRC_ITEM tracksCrossing; static DRC_ITEM tracksCrossing;
static DRC_ITEM copperEdgeClearance; static DRC_ITEM edgeClearance;
static DRC_ITEM zonesIntersect; static DRC_ITEM zonesIntersect;
static DRC_ITEM zoneHasEmptyNet; static DRC_ITEM zoneHasEmptyNet;
static DRC_ITEM viaDangling; static DRC_ITEM viaDangling;

View File

@ -120,8 +120,8 @@ bool DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefinitions()
// Re-run courtyard tests to generate DRC_ITEMs // Re-run courtyard tests to generate DRC_ITEMs
footprint->BuildPolyCourtyards( &errorHandler ); footprint->BuildPolyCourtyards( &errorHandler );
} }
else if( footprint->GetPolyCourtyardFront().OutlineCount() == 0 else if( footprint->GetPolyCourtyard( F_CrtYd ).OutlineCount() == 0
&& footprint->GetPolyCourtyardBack().OutlineCount() == 0 ) && footprint->GetPolyCourtyard( B_CrtYd ).OutlineCount() == 0 )
{ {
if( m_drcEngine->IsErrorLimitExceeded( DRCE_MISSING_COURTYARD ) ) if( m_drcEngine->IsErrorLimitExceeded( DRCE_MISSING_COURTYARD ) )
continue; continue;
@ -132,8 +132,8 @@ bool DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefinitions()
} }
else else
{ {
footprint->GetPolyCourtyardFront().BuildBBoxCaches(); footprint->GetPolyCourtyard( F_CrtYd ).BuildBBoxCaches();
footprint->GetPolyCourtyardBack().BuildBBoxCaches(); footprint->GetPolyCourtyard( B_CrtYd ).BuildBBoxCaches();
} }
} }
@ -153,7 +153,7 @@ bool DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testCourtyardClearances()
int ii = 0; int ii = 0;
for( auto it1 = m_board->Footprints().begin(); it1 != m_board->Footprints().end(); it1++ ) for( auto itA = m_board->Footprints().begin(); itA != m_board->Footprints().end(); itA++ )
{ {
if( !reportProgress( ii++, m_board->Footprints().size(), delta ) ) if( !reportProgress( ii++, m_board->Footprints().size(), delta ) )
return false; // DRC cancelled return false; // DRC cancelled
@ -161,39 +161,39 @@ bool DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testCourtyardClearances()
if( m_drcEngine->IsErrorLimitExceeded( DRCE_OVERLAPPING_FOOTPRINTS) ) if( m_drcEngine->IsErrorLimitExceeded( DRCE_OVERLAPPING_FOOTPRINTS) )
break; break;
FOOTPRINT* footprint = *it1; FOOTPRINT* fpA = *itA;
const SHAPE_POLY_SET& footprintFront = footprint->GetPolyCourtyardFront(); const SHAPE_POLY_SET& frontA = fpA->GetPolyCourtyard( F_CrtYd );
const SHAPE_POLY_SET& footprintBack = footprint->GetPolyCourtyardBack(); const SHAPE_POLY_SET& backA = fpA->GetPolyCourtyard( B_CrtYd );
if( footprintFront.OutlineCount() == 0 && footprintBack.OutlineCount() == 0 ) if( frontA.OutlineCount() == 0 && backA.OutlineCount() == 0 )
continue; // No courtyards defined continue; // No courtyards defined
BOX2I frontBBox = footprintFront.BBoxFromCaches(); BOX2I frontBBox = frontA.BBoxFromCaches();
BOX2I backBBox = footprintBack.BBoxFromCaches(); BOX2I backBBox = backA.BBoxFromCaches();
frontBBox.Inflate( m_largestClearance ); frontBBox.Inflate( m_largestClearance );
backBBox.Inflate( m_largestClearance ); backBBox.Inflate( m_largestClearance );
for( auto it2 = it1 + 1; it2 != m_board->Footprints().end(); it2++ ) for( auto itB = itA + 1; itB != m_board->Footprints().end(); itB++ )
{ {
FOOTPRINT* test = *it2; FOOTPRINT* fpB = *itB;
const SHAPE_POLY_SET& testFront = test->GetPolyCourtyardFront(); const SHAPE_POLY_SET& frontB = fpB->GetPolyCourtyard( F_CrtYd );
const SHAPE_POLY_SET& testBack = test->GetPolyCourtyardBack(); const SHAPE_POLY_SET& backB = fpB->GetPolyCourtyard( B_CrtYd );
DRC_CONSTRAINT constraint; DRC_CONSTRAINT constraint;
int clearance; int clearance;
int actual; int actual;
VECTOR2I pos; VECTOR2I pos;
if( footprintFront.OutlineCount() > 0 && testFront.OutlineCount() > 0 if( frontA.OutlineCount() > 0 && frontB.OutlineCount() > 0
&& frontBBox.Intersects( testFront.BBoxFromCaches() ) ) && frontBBox.Intersects( frontB.BBoxFromCaches() ) )
{ {
constraint = m_drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, footprint, constraint = m_drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, fpA, fpB,
test, F_Cu ); F_Cu );
clearance = constraint.GetValue().Min(); clearance = constraint.GetValue().Min();
if( clearance >= 0 && footprintFront.Collide( &testFront, clearance, &actual, &pos ) ) if( clearance >= 0 && frontA.Collide( &frontB, clearance, &actual, &pos ) )
{ {
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_OVERLAPPING_FOOTPRINTS ); auto drce = DRC_ITEM::Create( DRCE_OVERLAPPING_FOOTPRINTS );
if( clearance > 0 ) if( clearance > 0 )
{ {
@ -206,21 +206,21 @@ bool DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testCourtyardClearances()
drce->SetViolatingRule( constraint.GetParentRule() ); drce->SetViolatingRule( constraint.GetParentRule() );
} }
drce->SetItems( footprint, test ); drce->SetItems( fpA, fpB );
reportViolation( drce, (wxPoint) pos ); reportViolation( drce, (wxPoint) pos );
} }
} }
if( footprintBack.OutlineCount() > 0 && testBack.OutlineCount() > 0 if( backA.OutlineCount() > 0 && backB.OutlineCount() > 0
&& backBBox.Intersects( testBack.BBoxFromCaches() ) ) && backBBox.Intersects( backB.BBoxFromCaches() ) )
{ {
constraint = m_drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, footprint, constraint = m_drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, fpA, fpB,
test, B_Cu ); B_Cu );
clearance = constraint.GetValue().Min(); clearance = constraint.GetValue().Min();
if( clearance >= 0 && footprintBack.Collide( &testBack, clearance, &actual, &pos ) ) if( clearance >= 0 && backA.Collide( &backB, clearance, &actual, &pos ) )
{ {
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_OVERLAPPING_FOOTPRINTS ); auto drce = DRC_ITEM::Create( DRCE_OVERLAPPING_FOOTPRINTS );
if( clearance > 0 ) if( clearance > 0 )
{ {
@ -233,7 +233,7 @@ bool DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testCourtyardClearances()
drce->SetViolatingRule( constraint.GetParentRule() ); drce->SetViolatingRule( constraint.GetParentRule() );
} }
drce->SetItems( footprint, test ); drce->SetItems( fpA, fpB );
reportViolation( drce, (wxPoint) pos ); reportViolation( drce, (wxPoint) pos );
} }
} }

View File

@ -35,7 +35,7 @@
Board edge clearance test. Checks all items for their mechanical clearances against the board Board edge clearance test. Checks all items for their mechanical clearances against the board
edge. edge.
Errors generated: Errors generated:
- DRCE_COPPER_EDGE_CLEARANCE - DRCE_EDGE_CLEARANCE
TODO: TODO:
- separate holes to edge check - separate holes to edge check
@ -118,7 +118,7 @@ bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::testAgainstEdge( BOARD_ITEM* item, SHAPE*
bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run() bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run()
{ {
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_COPPER_EDGE_CLEARANCE ) ) if( !m_drcEngine->IsErrorLimitExceeded( DRCE_EDGE_CLEARANCE ) )
{ {
if( !reportPhase( _( "Checking copper to board edge clearances..." ) ) ) if( !reportPhase( _( "Checking copper to board edge clearances..." ) ) )
return false; // DRC cancelled return false; // DRC cancelled
@ -230,7 +230,7 @@ bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run()
for( BOARD_ITEM* item : boardItems ) for( BOARD_ITEM* item : boardItems )
{ {
bool testCopper = !m_drcEngine->IsErrorLimitExceeded( DRCE_COPPER_EDGE_CLEARANCE ); bool testCopper = !m_drcEngine->IsErrorLimitExceeded( DRCE_EDGE_CLEARANCE );
bool testSilk = !m_drcEngine->IsErrorLimitExceeded( DRCE_SILK_MASK_CLEARANCE ); bool testSilk = !m_drcEngine->IsErrorLimitExceeded( DRCE_SILK_MASK_CLEARANCE );
if( !testCopper && !testSilk ) if( !testCopper && !testSilk )
@ -250,7 +250,7 @@ bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run()
{ {
return testAgainstEdge( item, itemShape.get(), edge, return testAgainstEdge( item, itemShape.get(), edge,
EDGE_CLEARANCE_CONSTRAINT, EDGE_CLEARANCE_CONSTRAINT,
DRCE_COPPER_EDGE_CLEARANCE ); DRCE_EDGE_CLEARANCE );
}, },
m_largestClearance ); m_largestClearance );
} }

View File

@ -185,8 +185,7 @@ int PLACEFILE_GERBER_WRITER::CreatePlaceFile( wxString& aFullFilename, PCB_LAYER
{ {
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CMP_COURTYARD ); gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CMP_COURTYARD );
const SHAPE_POLY_SET& courtyard = onBack ? footprint->GetPolyCourtyardBack() const SHAPE_POLY_SET& courtyard = footprint->GetPolyCourtyard( aLayer );
: footprint->GetPolyCourtyardFront();
for( int ii = 0; ii < courtyard.OutlineCount(); ii++ ) for( int ii = 0; ii < courtyard.OutlineCount(); ii++ )
{ {

View File

@ -652,8 +652,13 @@ public:
* *
* @return the courtyard polygon. * @return the courtyard polygon.
*/ */
const SHAPE_POLY_SET& GetPolyCourtyardFront() const { return m_poly_courtyard_front; } const SHAPE_POLY_SET& GetPolyCourtyard( PCB_LAYER_ID aLayer ) const
const SHAPE_POLY_SET& GetPolyCourtyardBack() const { return m_poly_courtyard_back; } {
if( IsBackLayer( aLayer ) )
return m_poly_courtyard_back;
else
return m_poly_courtyard_front;
}
/** /**
* Build complex polygons of the courtyard areas from graphic items on the courtyard layers. * Build complex polygons of the courtyard areas from graphic items on the courtyard layers.

View File

@ -149,14 +149,7 @@ static bool insideFootprintCourtyard( BOARD_ITEM* aItem, const EDA_RECT& aItemBB
{ {
SHAPE_POLY_SET footprintCourtyard; SHAPE_POLY_SET footprintCourtyard;
if( aSide == F_Cu ) footprintCourtyard = aFootprint->GetPolyCourtyard( aSide );
footprintCourtyard = aFootprint->GetPolyCourtyardFront();
else if( aSide == B_Cu )
footprintCourtyard = aFootprint->GetPolyCourtyardBack();
else if( aFootprint->IsFlipped() )
footprintCourtyard = aFootprint->GetPolyCourtyardBack();
else
footprintCourtyard = aFootprint->GetPolyCourtyardFront();
if( aItem->Type() == PCB_ZONE_T || aItem->Type() == PCB_FP_ZONE_T ) if( aItem->Type() == PCB_ZONE_T || aItem->Type() == PCB_FP_ZONE_T )
{ {
@ -503,7 +496,7 @@ static void insideArea( LIBEVAL::CONTEXT* aCtx, void* self )
if( ( area->GetLayerSet() & LSET::FrontMask() ).any() ) if( ( area->GetLayerSet() & LSET::FrontMask() ).any() )
{ {
SHAPE_POLY_SET courtyard = footprint->GetPolyCourtyardFront(); SHAPE_POLY_SET courtyard = footprint->GetPolyCourtyard( F_CrtYd );
if( courtyard.OutlineCount() == 0 ) if( courtyard.OutlineCount() == 0 )
{ {
@ -520,7 +513,7 @@ static void insideArea( LIBEVAL::CONTEXT* aCtx, void* self )
if( ( area->GetLayerSet() & LSET::BackMask() ).any() ) if( ( area->GetLayerSet() & LSET::BackMask() ).any() )
{ {
SHAPE_POLY_SET courtyard = footprint->GetPolyCourtyardBack(); SHAPE_POLY_SET courtyard = footprint->GetPolyCourtyard( B_CrtYd );
if( courtyard.OutlineCount() == 0 ) if( courtyard.OutlineCount() == 0 )
{ {

View File

@ -40,14 +40,6 @@
#include <drc/drc_item.h> #include <drc/drc_item.h>
#include <pad.h> #include <pad.h>
void DIALOG_INSPECTION_REPORTER::OnErrorLinkClicked( wxHtmlLinkEvent& event )
{
if( event.GetLinkInfo().GetHref() == "boardsetup" )
m_frame->ShowBoardSetupDialog( _( "Rules" ) );
else if( event.GetLinkInfo().GetHref() == "drc" )
m_frame->GetToolManager()->RunAction( PCB_ACTIONS::runDRC, true );
}
BOARD_INSPECTION_TOOL::BOARD_INSPECTION_TOOL() : BOARD_INSPECTION_TOOL::BOARD_INSPECTION_TOOL() :
PCB_TOOL_BASE( "pcbnew.InspectionTool" ), PCB_TOOL_BASE( "pcbnew.InspectionTool" ),
@ -87,8 +79,8 @@ bool BOARD_INSPECTION_TOOL::Init()
auto netSubMenu = std::make_shared<NET_CONTEXT_MENU>(); auto netSubMenu = std::make_shared<NET_CONTEXT_MENU>();
netSubMenu->SetTool( this ); netSubMenu->SetTool( this );
static KICAD_T connectedTypes[] = { PCB_TRACE_T, PCB_VIA_T, PCB_ARC_T, PCB_PAD_T, static KICAD_T connectedTypes[] = { PCB_TRACE_T, PCB_VIA_T, PCB_ARC_T, PCB_PAD_T, PCB_ZONE_T,
PCB_ZONE_T, EOT }; EOT };
CONDITIONAL_MENU& menu = selectionTool->GetToolMenu().GetMenu(); CONDITIONAL_MENU& menu = selectionTool->GetToolMenu().GetMenu();
@ -134,83 +126,11 @@ wxString BOARD_INSPECTION_TOOL::getItemDescription( BOARD_ITEM* aItem )
}; };
void BOARD_INSPECTION_TOOL::reportZoneConnection( ZONE* aZone, PAD* aPad, REPORTER* r ) void reportCompileError( REPORTER* r )
{ {
ENUM_MAP<ZONE_CONNECTION> connectionEnum = ENUM_MAP<ZONE_CONNECTION>::Instance();
wxString source;
ZONE_CONNECTION connection = aZone->GetPadConnection( aPad, &source );
r->Report( "" ); r->Report( "" );
r->Report( _( "Report incomplete: could not compile custom design rules. " )
r->Report( wxString::Format( _( "Zone connection type: %s." ), + "<a href='boardsetup'>" + _( "Show design rules." ) + "</a>" );
connectionEnum.ToString( aZone->GetPadConnection() ) ) );
if( source != _( "zone" ) )
{
r->Report( wxString::Format( _( "Overridden by %s; connection type: %s." ),
source,
connectionEnum.ToString( connection ) ) );
}
// Resolve complex connection types into simple types
if( connection == ZONE_CONNECTION::THT_THERMAL )
{
if( aPad->GetAttribute() == PAD_ATTRIB::PTH )
{
connection = ZONE_CONNECTION::THERMAL;
}
else
{
connection = ZONE_CONNECTION::FULL;
r->Report( wxString::Format( _( "Pad is not a PTH pad; connection will be: %s." ),
connectionEnum.ToString( ZONE_CONNECTION::FULL ) ) );
}
}
r->Report( "" );
// Process simple connection types
if( connection == ZONE_CONNECTION::THERMAL )
{
int gap = aZone->GetThermalReliefGap();
r->Report( wxString::Format( _( "Zone thermal relief: %s." ),
StringFromValue( r->GetUnits(), gap, true ) ) );
gap = aZone->GetThermalReliefGap( aPad, &source );
if( source != _( "zone" ) )
{
r->Report( wxString::Format( _( "Overridden by %s; thermal relief: %s." ),
source,
StringFromValue( r->GetUnits(), gap, true ) ) );
}
}
else if( connection == ZONE_CONNECTION::NONE )
{
int clearance = aZone->GetLocalClearance();
r->Report( wxString::Format( _( "Zone clearance: %s." ),
StringFromValue( r->GetUnits(), clearance, true ) ) );
if( aZone->GetThermalReliefGap( aPad ) > clearance )
{
clearance = aZone->GetThermalReliefGap( aPad, &source );
if( source != _( "zone" ) )
{
r->Report( wxString::Format( _( "Overridden by larger thermal relief from %s;"
"clearance: %s." ),
source,
StringFromValue( r->GetUnits(), clearance, true ) ) );
}
}
}
else
{
r->Report( wxString::Format( _( "Clearance: %s." ),
StringFromValue( r->GetUnits(), 0, true ) ) );
}
} }
@ -227,9 +147,7 @@ void BOARD_INSPECTION_TOOL::reportClearance( DRC_CONSTRAINT_T aClearanceType, PC
} }
catch( PARSE_ERROR& ) catch( PARSE_ERROR& )
{ {
r->Report( "" ); reportCompileError( r );
r->Report( _( "Report incomplete: could not compile custom design rules. " )
+ "<a href='boardsetup'>" + _( "Show design rules." ) + "</a>" );
return; return;
} }
@ -244,9 +162,8 @@ void BOARD_INSPECTION_TOOL::reportClearance( DRC_CONSTRAINT_T aClearanceType, PC
footprint->BuildPolyCourtyards(); footprint->BuildPolyCourtyards();
} }
auto constraint = drcEngine.EvalRules( aClearanceType, aA, aB, aLayer, r ); DRC_CONSTRAINT constraint = drcEngine.EvalRules( aClearanceType, aA, aB, aLayer, r );
int clearance = constraint.m_Value.Min(); int clearance = constraint.m_Value.Min();
wxString clearanceStr = StringFromValue( r->GetUnits(), clearance, true ); wxString clearanceStr = StringFromValue( r->GetUnits(), clearance, true );
r->Report( "" ); r->Report( "" );
@ -265,7 +182,7 @@ void BOARD_INSPECTION_TOOL::InspectDRCError( const std::shared_ptr<RC_ITEM>& aDR
if( m_inspectClearanceDialog == nullptr ) if( m_inspectClearanceDialog == nullptr )
{ {
m_inspectClearanceDialog = std::make_unique<DIALOG_INSPECTION_REPORTER>( m_frame ); m_inspectClearanceDialog = std::make_unique<DIALOG_CONSTRAINTS_REPORTER>( m_frame );
m_inspectClearanceDialog->SetTitle( _( "Clearance Report" ) ); m_inspectClearanceDialog->SetTitle( _( "Clearance Report" ) );
m_inspectClearanceDialog->Connect( wxEVT_CLOSE_WINDOW, m_inspectClearanceDialog->Connect( wxEVT_CLOSE_WINDOW,
@ -273,13 +190,11 @@ void BOARD_INSPECTION_TOOL::InspectDRCError( const std::shared_ptr<RC_ITEM>& aDR
nullptr, this ); nullptr, this );
} }
WX_HTML_REPORT_BOX* r = m_inspectClearanceDialog->m_Reporter; WX_HTML_REPORT_BOX* r = m_inspectClearanceDialog->AddPage( _( "Clearance" ) );
r->SetUnits( m_frame->GetUserUnits() );
r->Clear();
switch( aDRCItem->GetErrorCode() ) switch( aDRCItem->GetErrorCode() )
{ {
case DRCE_COPPER_EDGE_CLEARANCE: case DRCE_EDGE_CLEARANCE:
r->Report( "<h7>" + _( "Edge clearance resolution for:" ) + "</h7>" ); r->Report( "<h7>" + _( "Edge clearance resolution for:" ) + "</h7>" );
r->Report( wxString::Format( "<ul><li>%s</li><li>%s</li></ul>", r->Report( wxString::Format( "<ul><li>%s</li><li>%s</li></ul>",
@ -350,30 +265,9 @@ int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent )
return 0; return 0;
} }
if( m_inspectClearanceDialog == nullptr )
{
m_inspectClearanceDialog = std::make_unique<DIALOG_INSPECTION_REPORTER>( m_frame );
m_inspectClearanceDialog->SetTitle( _( "Clearance Report" ) );
m_inspectClearanceDialog->Connect( wxEVT_CLOSE_WINDOW,
wxCommandEventHandler( BOARD_INSPECTION_TOOL::onInspectClearanceDialogClosed ),
nullptr, this );
}
WX_HTML_REPORT_BOX* r = m_inspectClearanceDialog->m_Reporter;
r->SetUnits( m_frame->GetUserUnits() );
r->Clear();
BOARD_ITEM* a = static_cast<BOARD_ITEM*>( selection.GetItem( 0 ) ); BOARD_ITEM* a = static_cast<BOARD_ITEM*>( selection.GetItem( 0 ) );
BOARD_ITEM* b = static_cast<BOARD_ITEM*>( selection.GetItem( 1 ) ); BOARD_ITEM* b = static_cast<BOARD_ITEM*>( selection.GetItem( 1 ) );
auto hasHole =
[]( BOARD_ITEM* aItem )
{
PAD* pad = dynamic_cast<PAD*>( aItem );
return pad && pad->GetDrillSizeX() > 0 && pad->GetDrillSizeY() > 0;
};
wxCHECK( a && b, 0 ); wxCHECK( a && b, 0 );
if( a->Type() == PCB_GROUP_T ) if( a->Type() == PCB_GROUP_T )
@ -405,121 +299,325 @@ int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent )
// a and b could be null after group tests above. // a and b could be null after group tests above.
wxCHECK( a && b, 0 ); wxCHECK( a && b, 0 );
PCB_LAYER_ID layer; if( m_inspectClearanceDialog == nullptr )
LSET intersection = a->GetLayerSet() & b->GetLayerSet(); {
m_inspectClearanceDialog = std::make_unique<DIALOG_CONSTRAINTS_REPORTER>( m_frame );
m_inspectClearanceDialog->SetTitle( _( "Clearance Report" ) );
if( intersection.any() && !intersection.Contains( m_frame->GetActiveLayer() ) ) m_inspectClearanceDialog->Connect( wxEVT_CLOSE_WINDOW,
layer = intersection.Seq().front(); wxCommandEventHandler( BOARD_INSPECTION_TOOL::onInspectClearanceDialogClosed ),
else nullptr, this );
layer = m_frame->GetActiveLayer(); }
WX_HTML_REPORT_BOX* r = nullptr;
EDA_UNITS units = m_frame->GetUserUnits();
m_inspectClearanceDialog->DeleteAllPages();
if( a->Type() != PCB_ZONE_T && b->Type() == PCB_ZONE_T ) if( a->Type() != PCB_ZONE_T && b->Type() == PCB_ZONE_T )
std::swap( a, b ); std::swap( a, b );
else if( !a->IsConnected() && b->IsConnected() ) else if( !a->IsConnected() && b->IsConnected() )
std::swap( a, b ); std::swap( a, b );
if( layer == F_SilkS || layer == B_SilkS ) PCB_LAYER_ID active = m_frame->GetActiveLayer();
{ LSET layerIntersection = a->GetLayerSet() & b->GetLayerSet();
r->Report( "<h7>" + _( "Silkscreen clearance resolution for:" ) + "</h7>" ); LSET copperIntersection = layerIntersection & LSET::AllCuMask();
BOARD_CONNECTED_ITEM* ac = dynamic_cast<BOARD_CONNECTED_ITEM*>( a );
BOARD_CONNECTED_ITEM* bc = dynamic_cast<BOARD_CONNECTED_ITEM*>( b );
ZONE* zone = dynamic_cast<ZONE*>( a );
PAD* pad = dynamic_cast<PAD*>( b );
FOOTPRINT* aFP = dynamic_cast<FOOTPRINT*>( a );
FOOTPRINT* bFP = dynamic_cast<FOOTPRINT*>( b );
DRC_ENGINE drcEngine( m_frame->GetBoard(), &m_frame->GetBoard()->GetDesignSettings() );
bool compileError = false;
DRC_CONSTRAINT constraint;
int clearance = 0;
try
{
drcEngine.InitEngine( m_frame->GetDesignRulesPath() );
}
catch( PARSE_ERROR& )
{
compileError = true;
}
for( ZONE* z : m_frame->GetBoard()->Zones() )
z->CacheBoundingBox();
for( FOOTPRINT* f : m_frame->GetBoard()->Footprints() )
{
for( ZONE* z : f->Zones() )
z->CacheBoundingBox();
f->BuildPolyCourtyards();
}
auto hasHole =
[]( BOARD_ITEM* aItem )
{
PAD* pad = dynamic_cast<PAD*>( aItem );
if( pad && pad->GetDrillSizeX() > 0 && pad->GetDrillSizeY() > 0 )
return true;
PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem );
if( via )
return true;
return false;
};
if( copperIntersection.any() && zone && pad && zone->GetNetCode() == pad->GetNetCode() )
{
PCB_LAYER_ID layer = active;
wxString source;
if( !zone->IsOnLayer( active ) )
layer = zone->GetLayerSet().Seq().front();
r = m_inspectClearanceDialog->AddPage( _( "Zone" ) );
r->Report( "<h7>" + _( "Zone connection resolution for:" ) + "</h7>" );
r->Report( wxString::Format( "<ul><li>%s %s</li><li>%s</li><li>%s</li></ul>", r->Report( wxString::Format( "<ul><li>%s %s</li><li>%s</li><li>%s</li></ul>",
_( "Layer" ), _( "Layer" ),
EscapeHTML( m_frame->GetBoard()->GetLayerName( layer ) ), EscapeHTML( m_frame->GetBoard()->GetLayerName( layer ) ),
EscapeHTML( getItemDescription( a ) ), EscapeHTML( getItemDescription( a ) ),
EscapeHTML( getItemDescription( b ) ) ) ); EscapeHTML( getItemDescription( b ) ) ) );
reportClearance( SILK_CLEARANCE_CONSTRAINT, layer, a, b, r ); ZONE_CONNECTION zoneConnection = zone->GetPadConnection( pad );
if( zoneConnection == ZONE_CONNECTION::THERMAL )
{
int gap = zone->GetThermalReliefGap();
r->Report( "" );
r->Report( wxString::Format( _( "Zone thermal relief: %s." ),
StringFromValue( r->GetUnits(), gap, true ) ) );
gap = zone->GetThermalReliefGap( pad, &source );
if( source != _( "zone" ) )
{
r->Report( wxString::Format( _( "Overridden by %s; thermal relief: %s." ),
source,
StringFromValue( r->GetUnits(), gap, true ) ) );
} }
else if( !( a->GetLayerSet() & LSET( 3, layer, Edge_Cuts, Margin ) ).any() ) }
else if( zoneConnection == ZONE_CONNECTION::NONE )
{ {
if( hasHole( a ) ) clearance = zone->GetLocalClearance();
r->Report( "" );
r->Report( wxString::Format( _( "Zone clearance: %s." ),
StringFromValue( r->GetUnits(), clearance, true ) ) );
if( zone->GetThermalReliefGap( pad ) > clearance )
{ {
r->Report( "<h7>" + _( "Hole clearance resolution for:" ) + "</h7>" ); clearance = zone->GetThermalReliefGap( pad, &source );
r->Report( wxString::Format( "<ul><li>%s %s</li><li>%s</li><li>%s</li></ul>", if( source != _( "zone" ) )
_( "Layer" ), {
EscapeHTML( m_frame->GetBoard()->GetLayerName( layer ) ), r->Report( wxString::Format( _( "Overridden by larger thermal relief from %s;"
EscapeHTML( getItemDescription( a ) ), "clearance: %s." ),
EscapeHTML( getItemDescription( b ) ) ) ); source,
StringFromValue( r->GetUnits(), clearance, true ) ) );
}
}
reportClearance( HOLE_CLEARANCE_CONSTRAINT, layer, a, b, r ); if( compileError )
reportCompileError( r );
r->Report( "" );
r->Report( wxString::Format( _( "Clearance: %s." ),
StringFromValue( units, 0, true ) ) );
} }
else else
{ {
r->Report( wxString::Format( _( "%s not present on layer %s. No clearance defined." ), if( compileError )
a->GetSelectMenuText( r->GetUnits() ), reportCompileError( r );
m_frame->GetBoard()->GetLayerName( layer ) ) );
}
}
else if( !( b->GetLayerSet() & LSET( 3, layer, Edge_Cuts, Margin ) ).any() )
{
if( hasHole( b ) )
{
r->Report( "<h7>" + _( "Hole clearance resolution for:" ) + "</h7>" );
r->Report( wxString::Format( "<ul><li>%s %s</li><li>%s</li><li>%s</li></ul>", // Report a 0 clearance for solid connections
_( "Layer" ), r->Report( "" );
EscapeHTML( m_frame->GetBoard()->GetLayerName( layer ) ), r->Report( wxString::Format( _( "Clearance: %s." ),
EscapeHTML( getItemDescription( b ) ), StringFromValue( units, 0, true ) ) );
EscapeHTML( getItemDescription( a ) ) ) ); }
reportClearance( HOLE_CLEARANCE_CONSTRAINT, layer, b, a, r ); r->Flush();
} }
else else if( copperIntersection.any() && !aFP && !bFP )
{ {
r->Report( wxString::Format( _( "%s not present on layer %s. No clearance defined." ), PCB_LAYER_ID layer = active;
b->GetSelectMenuText( r->GetUnits() ),
m_frame->GetBoard()->GetLayerName( layer ) ) );
}
}
else if( a->GetLayer() == Edge_Cuts || a->GetLayer() == Margin
|| b->GetLayer() == Edge_Cuts || b->GetLayer() == Margin )
{
r->Report( "<h7>" + _( "Edge clearance resolution for:" ) + "</h7>" );
r->Report( wxString::Format( "<ul><li>%s</li><li>%s</li></ul>", if( !copperIntersection.test( layer ) )
EscapeHTML( getItemDescription( a ) ), layer = copperIntersection.Seq().front();
EscapeHTML( getItemDescription( b ) ) ) );
r = m_inspectClearanceDialog->AddPage( m_frame->GetBoard()->GetLayerName( layer ) );
reportClearance( EDGE_CLEARANCE_CONSTRAINT, layer, a, b, r );
}
else
{
r->Report( "<h7>" + _( "Clearance resolution for:" ) + "</h7>" ); r->Report( "<h7>" + _( "Clearance resolution for:" ) + "</h7>" );
r->Report( wxString::Format( "<ul><li>%s %s</li><li>%s</li><li>%s</li></ul>", r->Report( wxString::Format( "<ul><li>%s %s</li><li>%s</li><li>%s</li></ul>",
_( "Layer" ), _( "Layer" ),
EscapeHTML( m_frame->GetBoard()->GetLayerName( layer ) ), EscapeHTML( m_frame->GetBoard()->GetLayerName( layer ) ),
EscapeHTML( getItemDescription( a ) ), EscapeHTML( getItemDescription( a ) ),
EscapeHTML( getItemDescription( b ) ) ) ); EscapeHTML( getItemDescription( b ) ) ) );
BOARD_CONNECTED_ITEM* ac = a->IsConnected() ?
static_cast<BOARD_CONNECTED_ITEM*>( a ) : nullptr;
BOARD_CONNECTED_ITEM* bc = b->IsConnected() ?
static_cast<BOARD_CONNECTED_ITEM*>( b ) : nullptr;
if( ac && bc && ac->GetNetCode() > 0 && ac->GetNetCode() == bc->GetNetCode() ) if( ac && bc && ac->GetNetCode() > 0 && ac->GetNetCode() == bc->GetNetCode() )
{ {
// Same nets.... // Same nets....
if( ac->Type() == PCB_ZONE_T && bc->Type() == PCB_PAD_T )
{
reportZoneConnection( static_cast<ZONE*>( ac ), static_cast<PAD*>( bc ), r );
}
else
{
r->Report( "" );
r->Report( _( "Items belong to the same net. Clearance is 0." ) ); r->Report( _( "Items belong to the same net. Clearance is 0." ) );
} }
}
else else
{ {
// Different nets (or one or both unconnected).... // Different nets (or one or both unconnected)....
reportClearance( CLEARANCE_CONSTRAINT, layer, a, b, r ); constraint = drcEngine.EvalRules( CLEARANCE_CONSTRAINT, a, b, layer, r );
} clearance = constraint.m_Value.Min();
if( compileError )
reportCompileError( r );
r->Report( "" );
r->Report( wxString::Format( _( "Resolved clearance: %s." ),
StringFromValue( units, clearance, true ) ) );
} }
r->Flush(); r->Flush();
}
for( PCB_LAYER_ID layer : { F_SilkS, B_SilkS } )
{
if( layerIntersection.test( layer ) )
{
r = m_inspectClearanceDialog->AddPage( m_frame->GetBoard()->GetLayerName( layer ) );
r->Report( "<h7>" + _( "Silkscreen clearance resolution for:" ) + "</h7>" );
r->Report( wxString::Format( "<ul><li>%s %s</li><li>%s</li><li>%s</li></ul>",
_( "Layer" ),
EscapeHTML( m_frame->GetBoard()->GetLayerName( layer ) ),
EscapeHTML( getItemDescription( a ) ),
EscapeHTML( getItemDescription( b ) ) ) );
constraint = drcEngine.EvalRules( SILK_CLEARANCE_CONSTRAINT, a, b, layer, r );
clearance = constraint.m_Value.Min();
if( compileError )
reportCompileError( r );
r->Report( "" );
r->Report( wxString::Format( _( "Resolved clearance: %s." ),
StringFromValue( units, clearance, true ) ) );
r->Flush();
}
}
for( PCB_LAYER_ID layer : { F_CrtYd, B_CrtYd } )
{
bool aCourtyard = aFP && !aFP->GetPolyCourtyard( layer ).IsEmpty();
bool bCourtyard = bFP && !bFP->GetPolyCourtyard( layer ).IsEmpty();
if( aCourtyard && bCourtyard )
{
r = m_inspectClearanceDialog->AddPage( m_frame->GetBoard()->GetLayerName( layer ) );
r->Report( "<h7>" + _( "Courtyard clearance resolution for:" ) + "</h7>" );
r->Report( wxString::Format( "<ul><li>%s %s</li><li>%s</li><li>%s</li></ul>",
_( "Layer" ),
EscapeHTML( m_frame->GetBoard()->GetLayerName( layer ) ),
EscapeHTML( getItemDescription( a ) ),
EscapeHTML( getItemDescription( b ) ) ) );
constraint = drcEngine.EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, a, b, layer, r );
clearance = constraint.m_Value.Min();
if( compileError )
reportCompileError( r );
r->Report( "" );
r->Report( wxString::Format( _( "Resolved clearance: %s." ),
StringFromValue( units, clearance, true ) ) );
r->Flush();
}
}
if( hasHole( a ) || hasHole( b ) )
{
PCB_LAYER_ID layer = UNDEFINED_LAYER;
if( hasHole( a ) && b->IsOnLayer( active ) && IsCopperLayer( active ) )
layer = active;
else if( hasHole( b ) && a->IsOnLayer( active ) && IsCopperLayer( active ) )
layer = active;
else if( hasHole( a ) && IsCopperLayer( b->GetLayer() ) )
layer = b->GetLayer();
else if( hasHole( b ) && IsCopperLayer( a->GetLayer() ) )
layer = a->GetLayer();
if( layer >= 0 )
{
r = m_inspectClearanceDialog->AddPage( _( "Hole" ) );
r->Report( "<h7>" + _( "Hole clearance resolution for:" ) + "</h7>" );
r->Report( wxString::Format( "<ul><li>%s %s</li><li>%s</li><li>%s</li></ul>",
_( "Layer" ),
EscapeHTML( m_frame->GetBoard()->GetLayerName( layer ) ),
EscapeHTML( getItemDescription( a ) ),
EscapeHTML( getItemDescription( b ) ) ) );
constraint = drcEngine.EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer, r );
clearance = constraint.m_Value.Min();
if( compileError )
reportCompileError( r );
r->Report( "" );
r->Report( wxString::Format( _( "Resolved clearance: %s." ),
StringFromValue( units, clearance, true ) ) );
r->Flush();
}
}
for( PCB_LAYER_ID edgeLayer : { Edge_Cuts, Margin } )
{
PCB_LAYER_ID layer = UNDEFINED_LAYER;
if( a->IsOnLayer( edgeLayer ) && b->IsOnLayer( active ) && IsCopperLayer( active ) )
layer = active;
else if( b->IsOnLayer( edgeLayer ) && a->IsOnLayer( active ) && IsCopperLayer( active ) )
layer = active;
else if( a->IsOnLayer( edgeLayer ) && IsCopperLayer( b->GetLayer() ) )
layer = b->GetLayer();
else if( b->IsOnLayer( edgeLayer ) && IsCopperLayer( a->GetLayer() ) )
layer = a->GetLayer();
if( layer >= 0 )
{
wxString layerName = m_frame->GetBoard()->GetLayerName( edgeLayer );
r = m_inspectClearanceDialog->AddPage( layerName + wxS( " " ) + _( "Clearance" ) );
r->Report( "<h7>" + _( "Edge clearance resolution for:" ) + "</h7>" );
r->Report( wxString::Format( "<ul><li>%s %s</li><li>%s</li><li>%s</li></ul>",
_( "Layer" ),
EscapeHTML( m_frame->GetBoard()->GetLayerName( layer ) ),
EscapeHTML( getItemDescription( a ) ),
EscapeHTML( getItemDescription( b ) ) ) );
constraint = drcEngine.EvalRules( EDGE_CLEARANCE_CONSTRAINT, a, b, layer, r );
clearance = constraint.m_Value.Min();
if( compileError )
reportCompileError( r );
r->Report( "" );
r->Report( wxString::Format( _( "Resolved clearance: %s." ),
StringFromValue( units, clearance, true ) ) );
r->Flush();
}
}
m_inspectClearanceDialog->Raise(); m_inspectClearanceDialog->Raise();
m_inspectClearanceDialog->Show( true ); m_inspectClearanceDialog->Show( true );
@ -556,6 +654,8 @@ wxString reportMax( EDA_UNITS aUnits, DRC_CONSTRAINT& aConstraint )
int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent ) int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
{ {
#define EVAL_RULES( constraint, a, b, layer, r ) drcEngine.EvalRules( constraint, a, b, layer, r )
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>(); PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
const PCB_SELECTION& selection = selTool->GetSelection(); const PCB_SELECTION& selection = selTool->GetSelection();
@ -570,8 +670,7 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
m_inspectConstraintsDialog = std::make_unique<DIALOG_CONSTRAINTS_REPORTER>( m_frame ); m_inspectConstraintsDialog = std::make_unique<DIALOG_CONSTRAINTS_REPORTER>( m_frame );
m_inspectConstraintsDialog->SetTitle( _( "Constraints Report" ) ); m_inspectConstraintsDialog->SetTitle( _( "Constraints Report" ) );
m_inspectConstraintsDialog->Connect( m_inspectConstraintsDialog->Connect( wxEVT_CLOSE_WINDOW,
wxEVT_CLOSE_WINDOW,
wxCommandEventHandler( BOARD_INSPECTION_TOOL::onInspectConstraintsDialogClosed ), wxCommandEventHandler( BOARD_INSPECTION_TOOL::onInspectConstraintsDialogClosed ),
nullptr, this ); nullptr, this );
} }
@ -580,6 +679,7 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selection.GetItem( 0 ) ); BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selection.GetItem( 0 ) );
DRC_ENGINE drcEngine( m_frame->GetBoard(), &m_frame->GetBoard()->GetDesignSettings() ); DRC_ENGINE drcEngine( m_frame->GetBoard(), &m_frame->GetBoard()->GetDesignSettings() );
DRC_CONSTRAINT constraint;
bool courtyardError = false; bool courtyardError = false;
bool compileError = false; bool compileError = false;
@ -616,23 +716,16 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
r->Report( "<ul><li>" + EscapeHTML( getItemDescription( item ) ) + "</li></ul>" ); r->Report( "<ul><li>" + EscapeHTML( getItemDescription( item ) ) + "</li></ul>" );
r->Report( "" ); r->Report( "" );
constraint = EVAL_RULES( TRACK_WIDTH_CONSTRAINT, item, nullptr, item->GetLayer(), r );
if( compileError ) if( compileError )
{ reportCompileError( r );
r->Report( "" );
r->Report( _( "Report incomplete: could not compile custom design rules. " )
+ "<a href='boardsetup'>" + _( "Show design rules." ) + "</a>" );
}
else
{
auto constraint = drcEngine.EvalRules( TRACK_WIDTH_CONSTRAINT, item, nullptr,
item->GetLayer(), r );
r->Report( "" ); r->Report( "" );
r->Report( wxString::Format( _( "Width constraints: min %s; opt %s; max %s." ), r->Report( wxString::Format( _( "Width constraints: min %s; opt %s; max %s." ),
reportMin( r->GetUnits(), constraint ), reportMin( r->GetUnits(), constraint ),
reportOpt( r->GetUnits(), constraint ), reportOpt( r->GetUnits(), constraint ),
reportMax( r->GetUnits(), constraint ) ) ); reportMax( r->GetUnits(), constraint ) ) );
}
r->Flush(); r->Flush();
} }
@ -645,24 +738,17 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
r->Report( "<ul><li>" + EscapeHTML( getItemDescription( item ) ) + "</li></ul>" ); r->Report( "<ul><li>" + EscapeHTML( getItemDescription( item ) ) + "</li></ul>" );
r->Report( "" ); r->Report( "" );
if( compileError )
{
r->Report( "" );
r->Report( _( "Report incomplete: could not compile custom design rules. " )
+ "<a href='boardsetup'>" + _( "Show design rules." ) + "</a>" );
}
else
{
// PADSTACKS TODO: once we have padstacks we'll need to run this per-layer.... // PADSTACKS TODO: once we have padstacks we'll need to run this per-layer....
auto constraint = drcEngine.EvalRules( VIA_DIAMETER_CONSTRAINT, item, nullptr, constraint = EVAL_RULES( VIA_DIAMETER_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
UNDEFINED_LAYER, r );
if( compileError )
reportCompileError( r );
r->Report( "" ); r->Report( "" );
r->Report( wxString::Format( _( "Diameter constraints: min %s; opt %s; max %s." ), r->Report( wxString::Format( _( "Diameter constraints: min %s; opt %s; max %s." ),
reportMin( r->GetUnits(), constraint ), reportMin( r->GetUnits(), constraint ),
reportOpt( r->GetUnits(), constraint ), reportOpt( r->GetUnits(), constraint ),
reportMax( r->GetUnits(), constraint ) ) ); reportMax( r->GetUnits(), constraint ) ) );
}
r->Flush(); r->Flush();
@ -672,24 +758,17 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
r->Report( "<ul><li>" + EscapeHTML( getItemDescription( item ) ) + "</li></ul>" ); r->Report( "<ul><li>" + EscapeHTML( getItemDescription( item ) ) + "</li></ul>" );
r->Report( "" ); r->Report( "" );
if( compileError )
{
r->Report( "" );
r->Report( _( "Report incomplete: could not compile custom design rules. " )
+ "<a href='boardsetup'>" + _( "Show design rules." ) + "</a>" );
}
else
{
// PADSTACKS TODO: once we have padstacks we'll need to run this per-layer.... // PADSTACKS TODO: once we have padstacks we'll need to run this per-layer....
auto constraint = drcEngine.EvalRules( ANNULAR_WIDTH_CONSTRAINT, item, nullptr, constraint = EVAL_RULES( ANNULAR_WIDTH_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
UNDEFINED_LAYER, r );
if( compileError )
reportCompileError( r );
r->Report( "" ); r->Report( "" );
r->Report( wxString::Format( _( "Annular width constraints: min %s; opt %s; max %s." ), r->Report( wxString::Format( _( "Annular width constraints: min %s; opt %s; max %s." ),
reportMin( r->GetUnits(), constraint ), reportMin( r->GetUnits(), constraint ),
reportOpt( r->GetUnits(), constraint ), reportOpt( r->GetUnits(), constraint ),
reportMax( r->GetUnits(), constraint ) ) ); reportMax( r->GetUnits(), constraint ) ) );
}
r->Flush(); r->Flush();
} }
@ -703,17 +782,11 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
r->Report( "<ul><li>" + EscapeHTML( getItemDescription( item ) ) + "</li></ul>" ); r->Report( "<ul><li>" + EscapeHTML( getItemDescription( item ) ) + "</li></ul>" );
r->Report( "" ); r->Report( "" );
if( compileError )
{
r->Report( "" );
r->Report( _( "Report incomplete: could not compile custom design rules. " )
+ "<a href='boardsetup'>" + _( "Show design rules." ) + "</a>" );
}
else
{
// PADSTACKS TODO: once we have padstacks we'll need to run this per-layer.... // PADSTACKS TODO: once we have padstacks we'll need to run this per-layer....
auto constraint = drcEngine.EvalRules( HOLE_SIZE_CONSTRAINT, item, nullptr, constraint = EVAL_RULES( HOLE_SIZE_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
UNDEFINED_LAYER, r );
if( compileError )
reportCompileError( r );
wxString min = _( "undefined" ); wxString min = _( "undefined" );
@ -722,7 +795,6 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
r->Report( "" ); r->Report( "" );
r->Report( wxString::Format( _( "Hole constraint: min %s." ), min ) ); r->Report( wxString::Format( _( "Hole constraint: min %s." ), min ) );
}
r->Flush(); r->Flush();
} }
@ -733,14 +805,11 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
r->Report( "<ul><li>" + EscapeHTML( getItemDescription( item ) ) + "</li></ul>" ); r->Report( "<ul><li>" + EscapeHTML( getItemDescription( item ) ) + "</li></ul>" );
r->Report( "" ); r->Report( "" );
constraint = EVAL_RULES( DISALLOW_CONSTRAINT, item, nullptr, item->GetLayer(), r );
if( compileError ) if( compileError )
{ reportCompileError( r );
r->Report( "" );
r->Report( _( "Report incomplete: could not compile custom design rules. " )
+ "<a href='boardsetup'>" + _( "Show design rules." ) + "</a>" );
}
else
{
if( courtyardError ) if( courtyardError )
{ {
r->Report( "" ); r->Report( "" );
@ -748,16 +817,12 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
+ " <a href='drc'>" + _( "Run DRC for a full analysis." ) + "</a>" ); + " <a href='drc'>" + _( "Run DRC for a full analysis." ) + "</a>" );
} }
auto constraint = drcEngine.EvalRules( DISALLOW_CONSTRAINT, item, nullptr, item->GetLayer(),
r );
r->Report( "" ); r->Report( "" );
if( constraint.m_DisallowFlags ) if( constraint.m_DisallowFlags )
r->Report( _( "Item <b>disallowed</b> at current location." ) ); r->Report( _( "Item <b>disallowed</b> at current location." ) );
else else
r->Report( _( "Item allowed at current location." ) ); r->Report( _( "Item allowed at current location." ) );
}
r->Flush(); r->Flush();

View File

@ -37,29 +37,6 @@
class CONNECTIVITY_DATA; class CONNECTIVITY_DATA;
class DIALOG_INSPECTION_REPORTER : public DIALOG_HTML_REPORTER
{
public:
DIALOG_INSPECTION_REPORTER( PCB_EDIT_FRAME* aFrame ) :
DIALOG_HTML_REPORTER( aFrame ),
m_frame( aFrame )
{
m_sdbSizerOK->SetDefault();
SetInitialFocus( m_sdbSizerOK );
}
void OnErrorLinkClicked( wxHtmlLinkEvent& event ) override;
void OnOK( wxCommandEvent& event ) override
{
Close();
}
protected:
PCB_EDIT_FRAME* m_frame;
};
/** /**
* Tool for pcb inspection. * Tool for pcb inspection.
*/ */
@ -172,7 +149,7 @@ private:
std::unique_ptr<DIALOG_NET_INSPECTOR> m_listNetsDialog; std::unique_ptr<DIALOG_NET_INSPECTOR> m_listNetsDialog;
DIALOG_NET_INSPECTOR::SETTINGS m_listNetsDialogSettings; DIALOG_NET_INSPECTOR::SETTINGS m_listNetsDialogSettings;
std::unique_ptr<DIALOG_INSPECTION_REPORTER> m_inspectClearanceDialog; std::unique_ptr<DIALOG_CONSTRAINTS_REPORTER> m_inspectClearanceDialog;
std::unique_ptr<DIALOG_CONSTRAINTS_REPORTER> m_inspectConstraintsDialog; std::unique_ptr<DIALOG_CONSTRAINTS_REPORTER> m_inspectConstraintsDialog;
}; };