2020-06-13 23:28:08 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2004-2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
|
|
|
* Copyright (C) 2014 Dick Hollenbeck, dick@softplc.com
|
|
|
|
* Copyright (C) 2017-2020 KiCad Developers, see change_log.txt for contributors.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, you may find one here:
|
|
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <fctsys.h>
|
2020-06-18 16:55:22 +00:00
|
|
|
#include <reporter.h>
|
|
|
|
#include <widgets/progress_reporter.h>
|
2020-09-11 15:04:11 +00:00
|
|
|
#include <drc/drc_engine.h>
|
|
|
|
#include <drc/drc_rule_parser.h>
|
|
|
|
#include <drc/drc_rule.h>
|
2020-09-12 23:05:32 +00:00
|
|
|
#include <drc/drc_rule_condition.h>
|
2020-09-11 15:04:11 +00:00
|
|
|
#include <drc/drc_test_provider.h>
|
2020-06-13 23:28:08 +00:00
|
|
|
|
2020-09-15 11:06:15 +00:00
|
|
|
void drcPrintDebugMessage( int level, const wxString& msg, const char *function, int line )
|
2020-08-12 22:19:34 +00:00
|
|
|
{
|
|
|
|
wxString valueStr;
|
2020-09-11 15:04:11 +00:00
|
|
|
|
2020-08-12 22:19:34 +00:00
|
|
|
if( wxGetEnv( "DRC_DEBUG", &valueStr ) )
|
|
|
|
{
|
|
|
|
int setLevel = wxAtoi( valueStr );
|
2020-09-11 16:24:27 +00:00
|
|
|
|
2020-08-25 17:42:52 +00:00
|
|
|
if( level <= setLevel )
|
|
|
|
{
|
|
|
|
printf("%-30s:%d | %s\n", function, line, (const char *) msg.c_str() );
|
|
|
|
}
|
2020-08-12 22:19:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-18 14:17:16 +00:00
|
|
|
|
2020-09-11 15:04:11 +00:00
|
|
|
DRC_ENGINE::DRC_ENGINE( BOARD* aBoard, BOARD_DESIGN_SETTINGS *aSettings ) :
|
2020-06-19 21:34:19 +00:00
|
|
|
m_designSettings ( aSettings ),
|
2020-09-11 15:04:11 +00:00
|
|
|
m_board( aBoard ),
|
2020-08-25 17:42:52 +00:00
|
|
|
m_worksheet( nullptr ),
|
|
|
|
m_schematicNetlist( nullptr ),
|
2020-09-15 11:06:15 +00:00
|
|
|
m_userUnits( EDA_UNITS::MILLIMETRES ),
|
|
|
|
m_testTracksAgainstZones( false ),
|
|
|
|
m_reportAllTrackErrors( false ),
|
|
|
|
m_testFootprints( false ),
|
2020-06-19 21:34:19 +00:00
|
|
|
m_reporter( nullptr ),
|
|
|
|
m_progressReporter( nullptr )
|
2020-08-18 14:17:16 +00:00
|
|
|
{
|
2020-09-16 11:45:12 +00:00
|
|
|
m_errorLimits.resize( DRCE_LAST + 1 );
|
2020-09-15 11:06:15 +00:00
|
|
|
|
2020-09-16 11:45:12 +00:00
|
|
|
for( int ii = DRCE_FIRST; ii <= DRCE_LAST; ++ii )
|
2020-09-15 11:06:15 +00:00
|
|
|
m_errorLimits[ ii ] = INT_MAX;
|
2020-08-18 14:17:16 +00:00
|
|
|
}
|
2020-06-13 23:28:08 +00:00
|
|
|
|
|
|
|
|
2020-09-11 15:04:11 +00:00
|
|
|
DRC_ENGINE::~DRC_ENGINE()
|
2020-06-13 23:28:08 +00:00
|
|
|
{
|
2020-08-11 22:15:50 +00:00
|
|
|
}
|
|
|
|
|
2020-08-18 14:17:16 +00:00
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
DRC_RULE* DRC_ENGINE::createImplicitRule( const wxString& name )
|
2020-08-26 22:07:31 +00:00
|
|
|
{
|
|
|
|
DRC_RULE *rule = new DRC_RULE;
|
|
|
|
|
2020-09-11 15:04:11 +00:00
|
|
|
rule->m_Name = name;
|
2020-09-13 10:37:20 +00:00
|
|
|
rule->m_Implicit = true;
|
2020-08-26 22:07:31 +00:00
|
|
|
|
|
|
|
addRule( rule );
|
|
|
|
|
|
|
|
return rule;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
void DRC_ENGINE::loadImplicitRules()
|
2020-06-13 23:28:08 +00:00
|
|
|
{
|
2020-09-13 10:37:20 +00:00
|
|
|
ReportAux( wxString::Format( "Building implicit rules (per-item/class overrides, etc...)" ) );
|
2020-08-26 22:07:31 +00:00
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
2020-08-26 22:07:31 +00:00
|
|
|
|
|
|
|
// 1) global defaults
|
|
|
|
|
2020-09-14 17:54:14 +00:00
|
|
|
DRC_RULE* rule = createImplicitRule( _( "board setup constraints" ));
|
2020-08-26 22:07:31 +00:00
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
DRC_CONSTRAINT clearanceConstraint( DRC_CONSTRAINT_TYPE_CLEARANCE );
|
2020-08-26 22:07:31 +00:00
|
|
|
clearanceConstraint.Value().SetMin( bds.m_MinClearance );
|
|
|
|
rule->AddConstraint( clearanceConstraint );
|
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
DRC_CONSTRAINT widthConstraint( DRC_CONSTRAINT_TYPE_TRACK_WIDTH );
|
2020-08-26 22:07:31 +00:00
|
|
|
widthConstraint.Value().SetMin( bds.m_TrackMinWidth );
|
|
|
|
rule->AddConstraint( widthConstraint );
|
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
DRC_CONSTRAINT drillConstraint( DRC_CONSTRAINT_TYPE_HOLE_SIZE );
|
2020-08-26 22:07:31 +00:00
|
|
|
drillConstraint.Value().SetMin( bds.m_MinThroughDrill );
|
|
|
|
rule->AddConstraint( drillConstraint );
|
|
|
|
|
2020-09-23 10:46:41 +00:00
|
|
|
DRC_CONSTRAINT annulusConstraint( DRC_CONSTRAINT_TYPE_ANNULAR_WIDTH );
|
2020-08-26 22:07:31 +00:00
|
|
|
annulusConstraint.Value().SetMin( bds.m_ViasMinAnnulus );
|
|
|
|
rule->AddConstraint( annulusConstraint );
|
2020-09-14 08:02:07 +00:00
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
DRC_CONSTRAINT diameterConstraint( DRC_CONSTRAINT_TYPE_VIA_DIAMETER );
|
2020-08-26 22:07:31 +00:00
|
|
|
diameterConstraint.Value().SetMin( bds.m_ViasMinSize );
|
|
|
|
rule->AddConstraint( diameterConstraint );
|
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
DRC_CONSTRAINT edgeClearanceConstraint( DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE );
|
2020-08-26 22:07:31 +00:00
|
|
|
edgeClearanceConstraint.Value().SetMin( bds.m_CopperEdgeClearance );
|
|
|
|
rule->AddConstraint( edgeClearanceConstraint );
|
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
DRC_CONSTRAINT holeClearanceConstraint( DRC_CONSTRAINT_TYPE_HOLE_CLEARANCE );
|
2020-08-26 22:07:31 +00:00
|
|
|
holeClearanceConstraint.Value().SetMin( bds.m_HoleToHoleMin );
|
|
|
|
rule->AddConstraint( holeClearanceConstraint );
|
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
DRC_CONSTRAINT courtyardClearanceConstraint( DRC_CONSTRAINT_TYPE_COURTYARD_CLEARANCE );
|
2020-09-07 12:30:51 +00:00
|
|
|
holeClearanceConstraint.Value().SetMin( 0 );
|
|
|
|
rule->AddConstraint( courtyardClearanceConstraint );
|
|
|
|
|
2020-09-18 14:24:09 +00:00
|
|
|
DRC_CONSTRAINT silkToPadClearanceConstraint( DRC_CONSTRAINT_TYPE_SILK_TO_PAD );
|
|
|
|
silkToPadClearanceConstraint.Value().SetMin( 0 );
|
|
|
|
rule->AddConstraint( silkToPadClearanceConstraint );
|
|
|
|
|
2020-09-23 21:48:11 +00:00
|
|
|
DRC_CONSTRAINT silkToSilkClearanceConstraint( DRC_CONSTRAINT_TYPE_SILK_TO_SILK );
|
|
|
|
silkToSilkClearanceConstraint.Value().SetMin( 0 );
|
|
|
|
rule->AddConstraint( silkToSilkClearanceConstraint );
|
|
|
|
|
2020-08-26 22:07:31 +00:00
|
|
|
// 2) micro-via specific defaults (new DRC doesn't treat microvias in any special way)
|
|
|
|
|
2020-09-22 23:16:02 +00:00
|
|
|
DRC_RULE* uViaRule = createImplicitRule( _( "board setup micro-via constraints" ));
|
2020-08-26 22:07:31 +00:00
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
uViaRule->m_Condition = new DRC_RULE_CONDITION ( "A.Via_Type == 'micro_via'" );
|
2020-08-26 22:07:31 +00:00
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
DRC_CONSTRAINT uViaDrillConstraint( DRC_CONSTRAINT_TYPE_HOLE_SIZE );
|
2020-08-26 22:07:31 +00:00
|
|
|
uViaDrillConstraint.Value().SetMin( bds.m_MicroViasMinDrill );
|
|
|
|
uViaRule->AddConstraint( uViaDrillConstraint );
|
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
DRC_CONSTRAINT uViaDiameterConstraint( DRC_CONSTRAINT_TYPE_VIA_DIAMETER );
|
2020-08-26 22:07:31 +00:00
|
|
|
uViaDiameterConstraint.Value().SetMin( bds.m_MicroViasMinSize );
|
|
|
|
uViaRule->AddConstraint( uViaDiameterConstraint );
|
|
|
|
|
|
|
|
if( !bds.m_MicroViasAllowed )
|
|
|
|
{
|
2020-09-13 10:37:20 +00:00
|
|
|
DRC_CONSTRAINT disallowConstraint( DRC_CONSTRAINT_TYPE_DISALLOW );
|
|
|
|
disallowConstraint.m_DisallowFlags = DRC_DISALLOW_MICRO_VIAS;
|
2020-08-26 22:07:31 +00:00
|
|
|
uViaRule->AddConstraint( disallowConstraint );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !bds.m_BlindBuriedViaAllowed )
|
|
|
|
{
|
2020-09-14 17:54:14 +00:00
|
|
|
DRC_RULE* bbViaRule = createImplicitRule( _( "board setup constraints" ));
|
2020-08-26 22:07:31 +00:00
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
bbViaRule->m_Condition = new DRC_RULE_CONDITION ( "A.Via_Type == 'buried_via'" );
|
2020-08-26 22:07:31 +00:00
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
DRC_CONSTRAINT disallowConstraint( DRC_CONSTRAINT_TYPE_DISALLOW );
|
|
|
|
disallowConstraint.m_DisallowFlags = DRC_DISALLOW_BB_VIAS;
|
|
|
|
bbViaRule->AddConstraint( disallowConstraint );
|
|
|
|
}
|
2020-09-04 23:19:01 +00:00
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
// 3) per-netclass rules
|
2020-09-04 23:19:01 +00:00
|
|
|
|
2020-09-15 19:13:45 +00:00
|
|
|
int ruleCount = 0;
|
2020-09-04 23:19:01 +00:00
|
|
|
|
2020-09-15 19:13:45 +00:00
|
|
|
auto makeNetclassRule =
|
|
|
|
[&]( const NETCLASSPTR& nc, bool isDefault )
|
|
|
|
{
|
|
|
|
wxString className = nc->GetName();
|
|
|
|
wxString expr;
|
2020-09-14 08:02:07 +00:00
|
|
|
|
2020-09-15 19:13:45 +00:00
|
|
|
if( !isDefault )
|
|
|
|
{
|
|
|
|
expr = wxString::Format( "A.NetClass == '%s' || B.NetClass == '%s'",
|
2020-09-22 14:50:15 +00:00
|
|
|
className, className );
|
2020-09-15 19:13:45 +00:00
|
|
|
}
|
2020-09-04 23:19:01 +00:00
|
|
|
|
2020-09-15 19:13:45 +00:00
|
|
|
DRC_RULE_CONDITION* inNetclassCondition = new DRC_RULE_CONDITION ( expr );
|
2020-09-22 14:50:15 +00:00
|
|
|
DRC_RULE* nc_rule = createImplicitRule( wxString::Format( _( "netclass '%s'" ),
|
2020-09-15 19:13:45 +00:00
|
|
|
className ));
|
2020-09-07 12:30:51 +00:00
|
|
|
|
2020-09-22 14:50:15 +00:00
|
|
|
nc_rule->m_Condition = inNetclassCondition;
|
2020-08-26 22:07:31 +00:00
|
|
|
|
2020-09-15 19:13:45 +00:00
|
|
|
// Only add netclass clearances if they're larger than board minimums. That way
|
|
|
|
// board minimums will still enforce a global minimum.
|
2020-09-14 08:02:07 +00:00
|
|
|
|
2020-09-15 19:13:45 +00:00
|
|
|
if( nc->GetClearance() > bds.m_MinClearance )
|
|
|
|
{
|
|
|
|
DRC_CONSTRAINT ncClearanceConstraint( DRC_CONSTRAINT_TYPE_CLEARANCE );
|
|
|
|
ncClearanceConstraint.Value().SetMin( nc->GetClearance() );
|
2020-09-22 14:50:15 +00:00
|
|
|
nc_rule->AddConstraint( ncClearanceConstraint );
|
2020-09-15 19:13:45 +00:00
|
|
|
}
|
2020-08-26 22:07:31 +00:00
|
|
|
|
2020-09-15 19:13:45 +00:00
|
|
|
ruleCount++;
|
|
|
|
};
|
2020-08-26 22:07:31 +00:00
|
|
|
|
2020-09-15 19:13:45 +00:00
|
|
|
m_board->SynchronizeNetsAndNetClasses();
|
|
|
|
makeNetclassRule( bds.GetNetClasses().GetDefault(), true );
|
2020-08-26 22:07:31 +00:00
|
|
|
|
2020-09-15 19:13:45 +00:00
|
|
|
for( const std::pair<const wxString, NETCLASSPTR>& netclass : bds.GetNetClasses() )
|
|
|
|
makeNetclassRule( netclass.second, false );
|
|
|
|
|
|
|
|
ReportAux( wxString::Format( "Building %d implicit netclass rules", ruleCount ) );
|
2020-08-26 22:07:31 +00:00
|
|
|
}
|
|
|
|
|
2020-09-11 15:04:11 +00:00
|
|
|
static wxString formatConstraint( const DRC_CONSTRAINT& constraint )
|
2020-08-26 22:07:31 +00:00
|
|
|
{
|
|
|
|
struct Formatter
|
|
|
|
{
|
2020-09-11 15:04:11 +00:00
|
|
|
DRC_CONSTRAINT_TYPE_T type;
|
2020-08-26 22:07:31 +00:00
|
|
|
wxString name;
|
2020-09-11 15:04:11 +00:00
|
|
|
std::function<wxString(const DRC_CONSTRAINT&)> formatter;
|
2020-08-26 22:07:31 +00:00
|
|
|
};
|
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
auto formatMinMax =
|
|
|
|
[]( const DRC_CONSTRAINT& c ) -> wxString
|
|
|
|
{
|
|
|
|
wxString str;
|
|
|
|
const auto value = c.GetValue();
|
2020-08-26 22:07:31 +00:00
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
if ( value.HasMin() )
|
|
|
|
str += wxString::Format(" min: %d", value.Min() );
|
|
|
|
if ( value.HasOpt() )
|
|
|
|
str += wxString::Format(" opt: %d", value.Opt() );
|
|
|
|
if ( value.HasMax() )
|
|
|
|
str += wxString::Format(" max: %d", value.Max() );
|
2020-08-26 22:07:31 +00:00
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
return str;
|
|
|
|
};
|
2020-08-26 22:07:31 +00:00
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
std::vector<Formatter> formats =
|
|
|
|
{
|
2020-09-23 21:48:11 +00:00
|
|
|
{ DRC_CONSTRAINT_TYPE_UNKNOWN, "unknown", nullptr },
|
|
|
|
{ DRC_CONSTRAINT_TYPE_CLEARANCE, "clearance", formatMinMax },
|
|
|
|
{ DRC_CONSTRAINT_TYPE_HOLE_CLEARANCE, "hole_clearance", formatMinMax },
|
|
|
|
{ DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE, "edge_clearance", formatMinMax },
|
|
|
|
{ DRC_CONSTRAINT_TYPE_HOLE_SIZE, "hole_size", formatMinMax },
|
2020-09-11 15:04:11 +00:00
|
|
|
{ DRC_CONSTRAINT_TYPE_COURTYARD_CLEARANCE, "courtyard_clearance", formatMinMax },
|
2020-09-23 21:48:11 +00:00
|
|
|
{ DRC_CONSTRAINT_TYPE_SILK_TO_PAD, "silk_to_pad", formatMinMax },
|
|
|
|
{ DRC_CONSTRAINT_TYPE_SILK_TO_SILK, "silk_to_silk", formatMinMax },
|
|
|
|
{ DRC_CONSTRAINT_TYPE_TRACK_WIDTH, "track_width", formatMinMax },
|
2020-09-23 10:46:41 +00:00
|
|
|
{ DRC_CONSTRAINT_TYPE_ANNULAR_WIDTH, "annular_width", formatMinMax },
|
2020-09-23 21:48:11 +00:00
|
|
|
{ DRC_CONSTRAINT_TYPE_DISALLOW, "disallow", nullptr },
|
|
|
|
{ DRC_CONSTRAINT_TYPE_VIA_DIAMETER, "via_diameter", formatMinMax },
|
|
|
|
{ DRC_CONSTRAINT_TYPE_LENGTH, "length", formatMinMax },
|
2020-09-25 18:29:05 +00:00
|
|
|
{ DRC_CONSTRAINT_TYPE_SKEW, "skew", formatMinMax },
|
|
|
|
{ DRC_CONSTRAINT_TYPE_VIA_COUNT, "via_count", formatMinMax }
|
2020-08-26 22:07:31 +00:00
|
|
|
};
|
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
for( auto& fmt : formats )
|
2020-08-26 22:07:31 +00:00
|
|
|
{
|
2020-09-11 15:04:11 +00:00
|
|
|
if( fmt.type == constraint.m_Type )
|
2020-08-26 22:07:31 +00:00
|
|
|
{
|
|
|
|
wxString rv = fmt.name + " ";
|
|
|
|
if( fmt.formatter )
|
|
|
|
rv += fmt.formatter( constraint );
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return "?";
|
2020-06-13 23:28:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-16 20:38:23 +00:00
|
|
|
/**
|
|
|
|
* @throws PARSE_ERROR
|
|
|
|
*/
|
2020-09-17 17:56:20 +00:00
|
|
|
void DRC_ENGINE::loadRules( const wxFileName& aPath )
|
2020-09-12 23:05:32 +00:00
|
|
|
{
|
|
|
|
if( aPath.FileExists() )
|
|
|
|
{
|
2020-09-17 17:56:20 +00:00
|
|
|
std::vector<DRC_RULE*> rules;
|
2020-09-12 23:05:32 +00:00
|
|
|
|
|
|
|
FILE* fp = wxFopen( aPath.GetFullPath(), wxT( "rt" ) );
|
|
|
|
|
|
|
|
if( fp )
|
|
|
|
{
|
2020-09-17 17:56:20 +00:00
|
|
|
DRC_RULES_PARSER parser( fp, aPath.GetFullPath() );
|
|
|
|
parser.Parse( rules, m_reporter );
|
2020-09-18 14:24:09 +00:00
|
|
|
}
|
2020-09-17 17:56:20 +00:00
|
|
|
|
|
|
|
// Copy the rules into the member variable afterwards so that if Parse() throws then
|
|
|
|
// the possibly malformed rules won't contaminate the current ruleset.
|
|
|
|
|
|
|
|
for( DRC_RULE* rule : rules )
|
|
|
|
m_rules.push_back( rule );
|
2020-09-18 14:24:09 +00:00
|
|
|
}
|
2020-09-12 23:05:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-11 15:04:11 +00:00
|
|
|
bool DRC_ENGINE::CompileRules()
|
2020-06-13 23:28:08 +00:00
|
|
|
{
|
2020-09-11 15:04:11 +00:00
|
|
|
ReportAux( wxString::Format( "Compiling Rules (%d rules, %d conditions): ",
|
|
|
|
(int) m_rules.size(),
|
|
|
|
(int) m_ruleConditions.size() ) );
|
2020-06-13 23:28:08 +00:00
|
|
|
|
2020-09-11 15:04:11 +00:00
|
|
|
for( DRC_TEST_PROVIDER* provider : m_testProviders )
|
2020-06-13 23:28:08 +00:00
|
|
|
{
|
2020-06-18 16:55:22 +00:00
|
|
|
ReportAux( wxString::Format( "- Provider: '%s': ", provider->GetName() ) );
|
2020-09-14 17:54:14 +00:00
|
|
|
drc_dbg( 7, "do prov %s", provider->GetName() );
|
2020-06-18 16:55:22 +00:00
|
|
|
|
2020-09-14 17:54:14 +00:00
|
|
|
for( DRC_CONSTRAINT_TYPE_T id : provider->GetConstraintTypes() )
|
2020-06-13 23:28:08 +00:00
|
|
|
{
|
2020-09-12 19:28:22 +00:00
|
|
|
drc_dbg( 7, "do id %d", id );
|
|
|
|
|
|
|
|
if( m_constraintMap.find( id ) == m_constraintMap.end() )
|
2020-09-14 17:54:14 +00:00
|
|
|
m_constraintMap[ id ] = new std::vector<CONSTRAINT_WITH_CONDITIONS*>();
|
2020-06-13 23:28:08 +00:00
|
|
|
|
2020-09-11 23:25:10 +00:00
|
|
|
for( DRC_RULE* rule : m_rules )
|
2020-08-11 22:17:43 +00:00
|
|
|
{
|
2020-09-11 15:04:11 +00:00
|
|
|
DRC_RULE_CONDITION* condition = nullptr;
|
2020-08-26 22:07:31 +00:00
|
|
|
bool compileOk = false;
|
2020-09-11 15:04:11 +00:00
|
|
|
std::vector<DRC_CONSTRAINT> matchingConstraints;
|
2020-09-14 17:54:14 +00:00
|
|
|
drc_dbg( 7, "Scan provider %s, rule %s", provider->GetName(), rule->m_Name );
|
2020-08-11 22:17:43 +00:00
|
|
|
|
2020-09-11 23:25:10 +00:00
|
|
|
if( rule->m_Condition && !rule->m_Condition->GetExpression().IsEmpty() )
|
2020-08-26 22:07:31 +00:00
|
|
|
{
|
2020-09-11 15:04:11 +00:00
|
|
|
condition = rule->m_Condition;
|
2020-08-26 22:07:31 +00:00
|
|
|
compileOk = condition->Compile( nullptr, 0, 0 ); // fixme
|
|
|
|
}
|
|
|
|
|
2020-09-11 15:04:11 +00:00
|
|
|
for( const DRC_CONSTRAINT& constraint : rule->m_Constraints )
|
2020-06-13 23:28:08 +00:00
|
|
|
{
|
2020-09-11 15:04:11 +00:00
|
|
|
drc_dbg(7, "scan constraint id %d\n", constraint.m_Type );
|
2020-08-11 22:17:43 +00:00
|
|
|
|
2020-09-11 15:04:11 +00:00
|
|
|
if( constraint.m_Type != id )
|
|
|
|
continue;
|
2020-06-18 16:55:22 +00:00
|
|
|
|
2020-09-11 15:04:11 +00:00
|
|
|
CONSTRAINT_WITH_CONDITIONS* rcons = new CONSTRAINT_WITH_CONDITIONS;
|
2020-06-17 22:36:54 +00:00
|
|
|
|
2020-09-12 23:38:35 +00:00
|
|
|
rcons->layerTest = rule->m_LayerCondition;
|
|
|
|
rcons->condition = condition;
|
2020-08-26 22:07:31 +00:00
|
|
|
|
2020-09-11 15:04:11 +00:00
|
|
|
matchingConstraints.push_back( constraint );
|
2020-08-11 22:17:43 +00:00
|
|
|
|
2020-09-11 15:04:11 +00:00
|
|
|
rcons->constraint = constraint;
|
|
|
|
rcons->parentRule = rule;
|
2020-09-14 17:54:14 +00:00
|
|
|
m_constraintMap[ id ]->push_back( rcons );
|
2020-06-13 23:28:08 +00:00
|
|
|
}
|
2020-08-26 22:07:31 +00:00
|
|
|
|
|
|
|
if( !matchingConstraints.empty() )
|
|
|
|
{
|
2020-09-11 15:04:11 +00:00
|
|
|
ReportAux( wxString::Format( " |- Rule: '%s' ",
|
|
|
|
rule->m_Name ) );
|
|
|
|
|
2020-08-26 22:07:31 +00:00
|
|
|
if( condition )
|
2020-09-11 15:04:11 +00:00
|
|
|
{
|
|
|
|
ReportAux( wxString::Format( " |- condition: '%s' compile: %s",
|
|
|
|
condition->GetExpression(),
|
|
|
|
compileOk ? "OK" : "ERROR" ) );
|
|
|
|
}
|
2020-08-26 22:07:31 +00:00
|
|
|
|
2020-09-11 15:04:11 +00:00
|
|
|
for (const DRC_CONSTRAINT& constraint : matchingConstraints )
|
2020-08-26 22:07:31 +00:00
|
|
|
{
|
2020-09-11 15:04:11 +00:00
|
|
|
ReportAux( wxString::Format( " |- constraint: %s",
|
|
|
|
formatConstraint( constraint ) ) );
|
2020-08-26 22:07:31 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-13 23:28:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-16 20:38:23 +00:00
|
|
|
/**
|
|
|
|
* @throws PARSE_ERROR
|
|
|
|
*/
|
2020-09-12 23:38:35 +00:00
|
|
|
void DRC_ENGINE::InitEngine( const wxFileName& aRulePath )
|
2020-06-13 23:28:08 +00:00
|
|
|
{
|
2020-06-17 22:36:54 +00:00
|
|
|
m_testProviders = DRC_TEST_PROVIDER_REGISTRY::Instance().GetTestProviders();
|
|
|
|
|
2020-09-12 00:22:46 +00:00
|
|
|
for( DRC_TEST_PROVIDER* provider : m_testProviders )
|
2020-06-18 16:55:22 +00:00
|
|
|
{
|
|
|
|
ReportAux( wxString::Format( "Create DRC provider: '%s'", provider->GetName() ) );
|
2020-06-17 22:36:54 +00:00
|
|
|
provider->SetDRCEngine( this );
|
2020-06-18 16:55:22 +00:00
|
|
|
}
|
|
|
|
|
2020-09-17 17:56:20 +00:00
|
|
|
m_ruleConditions.clear();
|
|
|
|
m_rules.clear();
|
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
loadImplicitRules();
|
2020-09-17 17:56:20 +00:00
|
|
|
loadRules( aRulePath );
|
2020-09-12 00:22:46 +00:00
|
|
|
|
2020-06-13 23:28:08 +00:00
|
|
|
CompileRules();
|
2020-09-12 19:28:22 +00:00
|
|
|
|
|
|
|
for( int ii = DRCE_FIRST; ii < DRCE_LAST; ++ii )
|
|
|
|
m_errorLimits[ ii ] = INT_MAX;
|
2020-09-11 23:25:10 +00:00
|
|
|
}
|
2020-07-23 14:22:45 +00:00
|
|
|
|
2020-09-11 23:25:10 +00:00
|
|
|
|
2020-09-14 17:54:14 +00:00
|
|
|
void DRC_ENGINE::RunTests( EDA_UNITS aUnits, bool aTestTracksAgainstZones,
|
|
|
|
bool aReportAllTrackErrors, bool aTestFootprints )
|
2020-09-11 23:25:10 +00:00
|
|
|
{
|
2020-09-14 17:54:14 +00:00
|
|
|
m_userUnits = aUnits;
|
|
|
|
|
|
|
|
// Note: set these first. The phase counts may be dependent on some of them.
|
|
|
|
m_testTracksAgainstZones = aTestTracksAgainstZones;
|
|
|
|
m_reportAllTrackErrors = aReportAllTrackErrors;
|
|
|
|
m_testFootprints = aTestFootprints;
|
|
|
|
|
2020-09-15 20:49:51 +00:00
|
|
|
if( m_progressReporter )
|
|
|
|
{
|
|
|
|
int phases = 0;
|
2020-09-14 17:54:14 +00:00
|
|
|
|
2020-09-15 20:49:51 +00:00
|
|
|
for( DRC_TEST_PROVIDER* provider : m_testProviders )
|
2020-09-18 14:24:09 +00:00
|
|
|
{
|
|
|
|
if( provider->IsEnabled() )
|
|
|
|
{
|
2020-09-15 20:49:51 +00:00
|
|
|
phases += provider->GetNumPhases();
|
2020-09-18 14:24:09 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-14 17:54:14 +00:00
|
|
|
|
2020-09-15 20:17:32 +00:00
|
|
|
m_progressReporter->AddPhases( phases );
|
2020-09-15 20:49:51 +00:00
|
|
|
}
|
2020-09-11 23:25:10 +00:00
|
|
|
|
2020-09-12 19:28:22 +00:00
|
|
|
for( int ii = DRCE_FIRST; ii < DRCE_LAST; ++ii )
|
|
|
|
{
|
|
|
|
if( m_designSettings->Ignore( ii ) )
|
|
|
|
m_errorLimits[ ii ] = 0;
|
|
|
|
else
|
|
|
|
m_errorLimits[ ii ] = INT_MAX;
|
|
|
|
}
|
|
|
|
|
2020-09-11 23:25:10 +00:00
|
|
|
for( DRC_TEST_PROVIDER* provider : m_testProviders )
|
2020-06-17 22:36:54 +00:00
|
|
|
{
|
2020-09-18 14:24:09 +00:00
|
|
|
if( !provider->IsEnabled() )
|
|
|
|
continue;
|
|
|
|
|
2020-09-14 17:54:14 +00:00
|
|
|
drc_dbg( 0, "Running test provider: '%s'\n", provider->GetName() );
|
2020-07-23 14:22:45 +00:00
|
|
|
|
2020-06-18 16:55:22 +00:00
|
|
|
ReportAux( wxString::Format( "Run DRC provider: '%s'", provider->GetName() ) );
|
2020-09-18 19:57:54 +00:00
|
|
|
|
|
|
|
if( !provider->Run() )
|
|
|
|
break;
|
2020-06-17 22:36:54 +00:00
|
|
|
}
|
2020-06-13 23:28:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-11 16:24:27 +00:00
|
|
|
DRC_CONSTRAINT DRC_ENGINE::EvalRulesForItems( DRC_CONSTRAINT_TYPE_T aConstraintId,
|
2020-09-15 19:13:45 +00:00
|
|
|
const BOARD_ITEM* a, const BOARD_ITEM* b,
|
|
|
|
PCB_LAYER_ID aLayer, REPORTER* aReporter )
|
2020-06-13 23:28:08 +00:00
|
|
|
{
|
2020-09-11 23:25:10 +00:00
|
|
|
#define REPORT( s ) { if( aReporter ) { aReporter->Report( s ); } }
|
2020-09-15 11:06:15 +00:00
|
|
|
#define UNITS aReporter ? aReporter->GetUnits() : EDA_UNITS::MILLIMETRES
|
2020-09-17 15:27:07 +00:00
|
|
|
/*
|
|
|
|
* NOTE: all string manipulation MUST be kept inside the REPORT macro. It absolutely
|
|
|
|
* kills performance when running bulk DRC tests (where aReporter is nullptr).
|
|
|
|
*/
|
2020-09-11 23:25:10 +00:00
|
|
|
|
2020-09-15 19:13:45 +00:00
|
|
|
const BOARD_CONNECTED_ITEM* connectedA = dynamic_cast<const BOARD_CONNECTED_ITEM*>( a );
|
|
|
|
const BOARD_CONNECTED_ITEM* connectedB = dynamic_cast<const BOARD_CONNECTED_ITEM*>( b );
|
2020-09-16 20:38:23 +00:00
|
|
|
const DRC_CONSTRAINT* constraintRef = nullptr;
|
|
|
|
bool implicit = false;
|
2020-09-14 17:54:14 +00:00
|
|
|
|
2020-09-11 16:24:27 +00:00
|
|
|
// Local overrides take precedence
|
|
|
|
if( aConstraintId == DRC_CONSTRAINT_TYPE_CLEARANCE )
|
|
|
|
{
|
2020-09-11 23:25:10 +00:00
|
|
|
int overrideA = 0;
|
|
|
|
int overrideB = 0;
|
|
|
|
|
2020-09-14 17:54:14 +00:00
|
|
|
if( connectedA && connectedA->GetLocalClearanceOverrides( nullptr ) > 0 )
|
2020-09-11 23:25:10 +00:00
|
|
|
{
|
2020-09-14 17:54:14 +00:00
|
|
|
overrideA = connectedA->GetLocalClearanceOverrides( &m_msg );
|
2020-09-11 23:25:10 +00:00
|
|
|
|
2020-09-14 17:54:14 +00:00
|
|
|
REPORT( "" )
|
2020-09-11 23:25:10 +00:00
|
|
|
REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
|
2020-09-15 11:06:15 +00:00
|
|
|
a->GetSelectMenuText( UNITS ),
|
|
|
|
MessageTextFromValue( UNITS, overrideA, true ) ) )
|
2020-09-11 23:25:10 +00:00
|
|
|
}
|
|
|
|
|
2020-09-14 17:54:14 +00:00
|
|
|
if( connectedB && connectedB->GetLocalClearanceOverrides( nullptr ) > 0 )
|
2020-09-11 23:25:10 +00:00
|
|
|
{
|
2020-09-14 17:54:14 +00:00
|
|
|
overrideB = connectedB->GetLocalClearanceOverrides( &m_msg );
|
2020-09-11 16:24:27 +00:00
|
|
|
|
2020-09-14 17:54:14 +00:00
|
|
|
REPORT( "" )
|
2020-09-11 23:25:10 +00:00
|
|
|
REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
|
2020-09-15 11:06:15 +00:00
|
|
|
b->GetSelectMenuText( UNITS ),
|
|
|
|
MessageTextFromValue( UNITS, overrideB, true ) ) )
|
2020-09-11 23:25:10 +00:00
|
|
|
}
|
2020-09-11 16:24:27 +00:00
|
|
|
|
2020-09-11 23:25:10 +00:00
|
|
|
if( overrideA || overrideB )
|
2020-09-11 16:24:27 +00:00
|
|
|
{
|
|
|
|
DRC_CONSTRAINT constraint( DRC_CONSTRAINT_TYPE_CLEARANCE, m_msg );
|
2020-09-11 23:25:10 +00:00
|
|
|
constraint.m_Value.SetMin( std::max( overrideA, overrideB ) );
|
2020-09-11 16:24:27 +00:00
|
|
|
return constraint;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-16 20:38:23 +00:00
|
|
|
if( m_constraintMap.count( aConstraintId ) )
|
2020-06-17 22:36:54 +00:00
|
|
|
{
|
2020-09-18 14:24:09 +00:00
|
|
|
std::vector<CONSTRAINT_WITH_CONDITIONS*>* ruleset = m_constraintMap[ aConstraintId ];
|
2020-09-13 10:37:20 +00:00
|
|
|
|
2020-09-18 14:24:09 +00:00
|
|
|
// Last matching rule wins, so process in reverse order
|
|
|
|
for( int ii = (int) ruleset->size() - 1; ii >= 0; --ii )
|
|
|
|
{
|
|
|
|
const CONSTRAINT_WITH_CONDITIONS* rcons = ruleset->at( ii );
|
|
|
|
implicit = rcons->parentRule && rcons->parentRule->m_Implicit;
|
2020-09-15 15:35:09 +00:00
|
|
|
|
2020-09-18 14:24:09 +00:00
|
|
|
REPORT( "" )
|
2020-09-15 15:35:09 +00:00
|
|
|
|
2020-09-17 15:27:07 +00:00
|
|
|
if( aConstraintId == DRC_CONSTRAINT_TYPE_CLEARANCE )
|
2020-09-18 14:24:09 +00:00
|
|
|
{
|
2020-09-17 15:27:07 +00:00
|
|
|
int clearance = rcons->constraint.m_Value.Min();
|
|
|
|
REPORT( wxString::Format( implicit ? _( "Checking %s; clearance: %s." )
|
|
|
|
: _( "Checking rule %s; clearance: %s."),
|
|
|
|
rcons->constraint.GetName(),
|
|
|
|
MessageTextFromValue( UNITS, clearance, true ) ) )
|
2020-09-18 14:24:09 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-09-17 15:27:07 +00:00
|
|
|
REPORT( wxString::Format( implicit ? _( "Checking %s." )
|
|
|
|
: _( "Checking rule %s."),
|
|
|
|
rcons->constraint.GetName() ) )
|
2020-09-18 14:24:09 +00:00
|
|
|
}
|
2020-09-15 15:35:09 +00:00
|
|
|
|
2020-09-16 20:38:23 +00:00
|
|
|
if( aLayer != UNDEFINED_LAYER && !rcons->layerTest.test( aLayer ) )
|
2020-09-14 17:54:14 +00:00
|
|
|
{
|
2020-09-16 20:38:23 +00:00
|
|
|
if( rcons->parentRule )
|
|
|
|
{
|
|
|
|
REPORT( wxString::Format( _( "Rule layer \"%s\" not matched." ),
|
|
|
|
rcons->parentRule->m_LayerSource ) )
|
|
|
|
REPORT( "Rule not applied." )
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
2020-09-14 17:54:14 +00:00
|
|
|
}
|
2020-09-13 10:37:20 +00:00
|
|
|
|
2020-09-16 20:38:23 +00:00
|
|
|
if( !rcons->condition || rcons->condition->GetExpression().IsEmpty() )
|
2020-09-13 10:37:20 +00:00
|
|
|
{
|
2020-09-16 20:38:23 +00:00
|
|
|
REPORT( implicit ? _( "Unconditional constraint applied." )
|
|
|
|
: _( "Unconditional rule applied." ) )
|
2020-09-13 10:37:20 +00:00
|
|
|
|
2020-09-14 17:54:14 +00:00
|
|
|
constraintRef = &rcons->constraint;
|
|
|
|
break;
|
2020-09-13 10:37:20 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-09-16 20:38:23 +00:00
|
|
|
// Don't report on implicit rule conditions; they're synthetic.
|
|
|
|
if( !implicit )
|
|
|
|
{
|
|
|
|
REPORT( wxString::Format( _( "Checking rule condition \"%s\"." ),
|
|
|
|
rcons->condition->GetExpression() ) )
|
|
|
|
}
|
|
|
|
|
|
|
|
if( rcons->condition->EvaluateFor( a, b, aLayer, aReporter ) )
|
|
|
|
{
|
|
|
|
REPORT( implicit ? _( "Constraint applicable." )
|
2020-09-21 09:45:54 +00:00
|
|
|
: _( "Rule applied. (No further rules will be checked.)" ) )
|
2020-09-16 20:38:23 +00:00
|
|
|
|
|
|
|
constraintRef = &rcons->constraint;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
REPORT( implicit ? _( "Membership not satisfied; constraint not applicable." )
|
|
|
|
: _( "Condition not satisfied; rule not applied." ) )
|
|
|
|
}
|
2020-09-13 10:37:20 +00:00
|
|
|
}
|
2020-06-17 22:36:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-14 17:54:14 +00:00
|
|
|
// Unfortunately implicit rules don't work for local clearances (such as zones) because
|
|
|
|
// they have to be max'ed with netclass values (which are already implicit rules), and our
|
|
|
|
// rule selection paradigm is "winner takes all".
|
2020-09-20 01:20:41 +00:00
|
|
|
if( constraintRef && aConstraintId == DRC_CONSTRAINT_TYPE_CLEARANCE && implicit )
|
2020-09-14 17:54:14 +00:00
|
|
|
{
|
|
|
|
int global = constraintRef->m_Value.Min();
|
|
|
|
int localA = connectedA ? connectedA->GetLocalClearance( nullptr ) : 0;
|
|
|
|
int localB = connectedB ? connectedB->GetLocalClearance( nullptr ) : 0;
|
|
|
|
int clearance = global;
|
|
|
|
|
|
|
|
if( localA > 0 )
|
|
|
|
{
|
|
|
|
REPORT( "" )
|
|
|
|
REPORT( wxString::Format( _( "Local clearance on %s; clearance: %s." ),
|
2020-09-15 11:06:15 +00:00
|
|
|
a->GetSelectMenuText( UNITS ),
|
|
|
|
MessageTextFromValue( UNITS, localA, true ) ) )
|
2020-09-14 17:54:14 +00:00
|
|
|
|
|
|
|
if( localA > clearance )
|
|
|
|
clearance = connectedA->GetLocalClearance( &m_msg );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( localB > 0 )
|
|
|
|
{
|
|
|
|
REPORT( "" )
|
|
|
|
REPORT( wxString::Format( _( "Local clearance on %s; clearance: %s." ),
|
2020-09-15 11:06:15 +00:00
|
|
|
b->GetSelectMenuText( UNITS ),
|
|
|
|
MessageTextFromValue( UNITS, localB, true ) ) )
|
2020-09-14 17:54:14 +00:00
|
|
|
|
|
|
|
if( localB > clearance )
|
|
|
|
clearance = connectedB->GetLocalClearance( &m_msg );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( localA > global || localB > global )
|
|
|
|
{
|
|
|
|
DRC_CONSTRAINT constraint( DRC_CONSTRAINT_TYPE_CLEARANCE, m_msg );
|
|
|
|
constraint.m_Value.SetMin( clearance );
|
|
|
|
return constraint;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-04 23:11:06 +00:00
|
|
|
// fixme: return optional<drc_constraint>, let the particular test decide what to do if no matching constraint
|
|
|
|
// is found
|
2020-09-23 21:48:11 +00:00
|
|
|
static DRC_CONSTRAINT nullConstraint( DRC_CONSTRAINT_TYPE_NULL );
|
2020-09-04 23:11:06 +00:00
|
|
|
nullConstraint.m_DisallowFlags = 0;
|
|
|
|
|
2020-09-14 17:54:14 +00:00
|
|
|
return constraintRef ? *constraintRef : nullConstraint;
|
2020-09-12 23:05:32 +00:00
|
|
|
|
|
|
|
#undef REPORT
|
2020-09-15 11:06:15 +00:00
|
|
|
#undef UNITS
|
2020-06-13 23:28:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-14 17:54:14 +00:00
|
|
|
bool DRC_ENGINE::IsErrorLimitExceeded( int error_code )
|
|
|
|
{
|
2020-09-16 11:45:12 +00:00
|
|
|
assert( error_code >= 0 && error_code <= DRCE_LAST );
|
2020-09-14 17:54:14 +00:00
|
|
|
return m_errorLimits[ error_code ] <= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
void DRC_ENGINE::ReportViolation( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos )
|
2020-06-13 23:28:08 +00:00
|
|
|
{
|
2020-09-14 17:54:14 +00:00
|
|
|
m_errorLimits[ aItem->GetErrorCode() ] -= 1;
|
|
|
|
|
|
|
|
if( m_violationHandler )
|
|
|
|
m_violationHandler( aItem, aPos );
|
|
|
|
|
2020-06-18 16:55:22 +00:00
|
|
|
if( m_reporter )
|
|
|
|
{
|
2020-08-25 17:42:52 +00:00
|
|
|
wxString msg = wxString::Format( "Test '%s': %s (code %d)",
|
2020-09-11 15:04:11 +00:00
|
|
|
aItem->GetViolatingTest()->GetName(),
|
|
|
|
aItem->GetErrorMessage(),
|
|
|
|
aItem->GetErrorCode() );
|
2020-08-25 17:42:52 +00:00
|
|
|
|
2020-09-12 23:05:32 +00:00
|
|
|
DRC_RULE* rule = aItem->GetViolatingRule();
|
2020-08-25 17:42:52 +00:00
|
|
|
|
|
|
|
if( rule )
|
2020-09-11 15:04:11 +00:00
|
|
|
msg += wxString::Format( ", violating rule: '%s'", rule->m_Name );
|
2020-09-14 08:02:07 +00:00
|
|
|
|
2020-09-11 15:04:11 +00:00
|
|
|
m_reporter->Report( msg );
|
2020-09-14 08:02:07 +00:00
|
|
|
|
2020-08-11 22:15:50 +00:00
|
|
|
wxString violatingItemsStr = "Violating items: ";
|
|
|
|
|
2020-09-14 17:54:14 +00:00
|
|
|
m_reporter->Report( wxString::Format( " |- violating position (%d, %d)",
|
|
|
|
aPos.x,
|
|
|
|
aPos.y ) );
|
2020-06-13 23:28:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-11 15:04:11 +00:00
|
|
|
void DRC_ENGINE::ReportAux ( const wxString& aStr )
|
2020-06-13 23:28:08 +00:00
|
|
|
{
|
2020-06-18 16:55:22 +00:00
|
|
|
if( !m_reporter )
|
2020-06-13 23:28:08 +00:00
|
|
|
return;
|
|
|
|
|
2020-06-18 16:55:22 +00:00
|
|
|
m_reporter->Report( aStr, RPT_SEVERITY_INFO );
|
2020-06-13 23:28:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-18 19:57:54 +00:00
|
|
|
bool DRC_ENGINE::ReportProgress( double aProgress )
|
2020-06-13 23:28:08 +00:00
|
|
|
{
|
2020-06-18 16:55:22 +00:00
|
|
|
if( !m_progressReporter )
|
2020-09-18 19:57:54 +00:00
|
|
|
return true;
|
2020-06-13 23:28:08 +00:00
|
|
|
|
2020-06-18 16:55:22 +00:00
|
|
|
m_progressReporter->SetCurrentProgress( aProgress );
|
2020-09-18 19:57:54 +00:00
|
|
|
return m_progressReporter->KeepRefreshing( false );
|
2020-06-13 23:28:08 +00:00
|
|
|
}
|
|
|
|
|
2020-08-18 14:17:16 +00:00
|
|
|
|
2020-09-18 19:57:54 +00:00
|
|
|
bool DRC_ENGINE::ReportPhase( const wxString& aMessage )
|
2020-06-13 23:28:08 +00:00
|
|
|
{
|
2020-06-18 16:55:22 +00:00
|
|
|
if( !m_progressReporter )
|
2020-09-18 19:57:54 +00:00
|
|
|
return true;
|
2020-06-13 23:28:08 +00:00
|
|
|
|
2020-09-15 11:06:15 +00:00
|
|
|
m_progressReporter->AdvancePhase( aMessage );
|
2020-09-18 19:57:54 +00:00
|
|
|
return m_progressReporter->KeepRefreshing( false );
|
2020-06-13 23:28:08 +00:00
|
|
|
}
|
|
|
|
|
2020-08-18 14:17:16 +00:00
|
|
|
|
2020-06-30 08:44:12 +00:00
|
|
|
#if 0
|
2020-09-11 15:04:11 +00:00
|
|
|
DRC_CONSTRAINT DRC_ENGINE::GetWorstGlobalConstraint( DRC_CONSTRAINT_TYPE_T ruleID )
|
2020-06-30 08:44:12 +00:00
|
|
|
{
|
|
|
|
DRC_CONSTRAINT rv;
|
|
|
|
|
|
|
|
rv.m_Value.SetMin( std::numeric_limits<int>::max() );
|
|
|
|
rv.m_Value.SetMax( std::numeric_limits<int>::min() );
|
|
|
|
for( auto rule : QueryRulesById( ruleID ) )
|
|
|
|
{
|
|
|
|
auto mm = rule->GetConstraint().m_Value;
|
|
|
|
if( mm.HasMax() )
|
|
|
|
rv.m_Value.SetMax( std::max( mm.Max(), rv.m_Value.Max() ) );
|
|
|
|
if( mm.HasMin() )
|
|
|
|
rv.m_Value.SetMin( std::min( mm.Min(), rv.m_Value.Min() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-08-18 14:17:16 +00:00
|
|
|
|
2020-09-11 15:04:11 +00:00
|
|
|
std::vector<DRC_CONSTRAINT> DRC_ENGINE::QueryConstraintsById( DRC_CONSTRAINT_TYPE_T constraintID )
|
2020-06-30 08:44:12 +00:00
|
|
|
{
|
2020-09-11 15:04:11 +00:00
|
|
|
std::vector<DRC_CONSTRAINT> rv;
|
2020-09-12 23:05:32 +00:00
|
|
|
|
2020-09-16 20:38:23 +00:00
|
|
|
if( m_constraintMap.count( constraintID ) )
|
|
|
|
{
|
2020-09-18 14:24:09 +00:00
|
|
|
for ( CONSTRAINT_WITH_CONDITIONS* c : *m_constraintMap[constraintID] )
|
|
|
|
rv.push_back( c->constraint );
|
2020-09-16 20:38:23 +00:00
|
|
|
}
|
2020-09-12 23:05:32 +00:00
|
|
|
|
2020-06-30 08:44:12 +00:00
|
|
|
return rv;
|
|
|
|
}
|
2020-06-13 23:28:08 +00:00
|
|
|
|
2020-07-23 14:22:45 +00:00
|
|
|
|
2020-09-13 10:37:20 +00:00
|
|
|
bool DRC_ENGINE::HasRulesForConstraintType( DRC_CONSTRAINT_TYPE_T constraintID )
|
2020-07-23 14:22:45 +00:00
|
|
|
{
|
2020-08-12 22:19:34 +00:00
|
|
|
//drc_dbg(10,"hascorrect id %d size %d\n", ruleID, m_ruleMap[ruleID]->sortedRules.size( ) );
|
2020-09-16 20:38:23 +00:00
|
|
|
if( m_constraintMap.count( constraintID ) )
|
|
|
|
return m_constraintMap[ constraintID ]->size() > 0;
|
|
|
|
|
|
|
|
return false;
|
2020-07-23 14:22:45 +00:00
|
|
|
}
|
|
|
|
|
2020-08-11 22:15:50 +00:00
|
|
|
|
2020-09-11 15:04:11 +00:00
|
|
|
bool DRC_ENGINE::QueryWorstConstraint( DRC_CONSTRAINT_TYPE_T aConstraintId,
|
|
|
|
DRC_CONSTRAINT& aConstraint,
|
|
|
|
DRC_CONSTRAINT_QUERY_T aQueryType )
|
2020-08-11 22:15:50 +00:00
|
|
|
{
|
|
|
|
if( aQueryType == DRCCQ_LARGEST_MINIMUM )
|
|
|
|
{
|
|
|
|
int worst = 0;
|
2020-09-11 15:04:11 +00:00
|
|
|
|
2020-09-12 23:05:32 +00:00
|
|
|
for( const DRC_CONSTRAINT& constraint : QueryConstraintsById( aConstraintId ) )
|
2020-08-11 22:15:50 +00:00
|
|
|
{
|
2020-08-11 22:17:43 +00:00
|
|
|
if( constraint.GetValue().HasMin() )
|
2020-08-11 22:15:50 +00:00
|
|
|
{
|
2020-08-11 22:17:43 +00:00
|
|
|
int current = constraint.GetValue().Min();
|
2020-08-11 22:15:50 +00:00
|
|
|
|
|
|
|
if( current > worst )
|
|
|
|
{
|
|
|
|
worst = current;
|
2020-08-11 22:17:43 +00:00
|
|
|
aConstraint = constraint;
|
2020-08-11 22:15:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return worst > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2020-09-23 21:48:11 +00:00
|
|
|
|
|
|
|
|
|
|
|
DRC_TEST_PROVIDER* DRC_ENGINE::GetTestProvider( const wxString& name ) const
|
|
|
|
{
|
|
|
|
for( auto prov : m_testProviders )
|
|
|
|
if( name == prov->GetName() )
|
|
|
|
return prov;
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|