Encourage use of full DRC for board & footprint malformed outlines.

It shows much more detail.  Removes some nag dialogs and places
hypertext links in others.

Also fixes the auto-layer-showing to correctly show Edge.Cuts or
F.CrtYd or B.CrtYd for errors relating to them.

Fixes https://gitlab.com/kicad/code/kicad/issues/6446
This commit is contained in:
Jeff Young 2020-11-20 13:55:10 +00:00
parent 0a7ef25453
commit b123318cf6
20 changed files with 173 additions and 146 deletions

View File

@ -461,27 +461,26 @@ bool BOARD_ADAPTER::createBoardPolygon( wxString* aErrorMsg )
{
m_board_poly.RemoveAllContours();
bool success = false;
wxString msg;
bool success;
if( m_board->IsFootprintHolder() )
{
success = BuildFootprintPolygonOutlines( m_board, m_board_poly,
m_board->GetDesignSettings().m_MaxError, &msg );
m_board->GetDesignSettings().m_MaxError, nullptr );
// Make polygon strictly simple to avoid issues (especially in 3D viewer)
m_board_poly.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
if( aErrorMsg )
*aErrorMsg = msg;
if( !success && aErrorMsg )
*aErrorMsg = _( "Footprint outline is malformed. Run DRC for a full analysis." );
}
else
{
success = m_board->GetBoardPolygonOutlines( m_board_poly, &msg );
success = m_board->GetBoardPolygonOutlines( m_board_poly );
if( aErrorMsg )
*aErrorMsg = _( "Board outline is not closed:" ) + wxS( " " )+ msg;
if( !success && aErrorMsg )
*aErrorMsg = _( "Board outline is malformed. Run DRC for a full analysis." );
}
return success;

View File

@ -119,8 +119,9 @@ typedef const INSPECTOR_FUNC& INSPECTOR; /// std::function passed to nested u
#define IS_PASTED (1 << 17) ///< Modifier on IS_NEW which indicates it came from clipboard
#define TRACK_LOCKED (1 << 18) ///< Pcbnew: track locked: protected from global deletion
#define TRACK_AR (1 << 19) ///< Pcbnew: autorouted track
#define OBSOLETE_1 (1 << 20) ///< Not presently used
#define MALFORMED_COURTYARD (1 << 21)
#define MALFORMED_F_COURTYARD (1 << 20)
#define MALFORMED_B_COURTYARD (1 << 21)
#define MALFORMED_COURTYARDS ( MALFORMED_F_COURTYARD | MALFORMED_B_COURTYARD )
#define BEGIN_ONPAD (1 << 22) ///< Pcbnew: flag set for track segment starting on a pad
#define END_ONPAD (1 << 23) ///< Pcbnew: flag set for track segment ending on a pad
#define HOLE_PROXY (1 << 24) ///< Indicates the BOARD_ITEM is a proxy for its hole

View File

@ -113,7 +113,7 @@ int AR_AUTOPLACER::genPlacementRoutingMatrix()
return 0;
// Build the board shape
m_board->GetBoardPolygonOutlines( m_boardShape /*, aErrorText, aErrorLocation*/ );
m_board->GetBoardPolygonOutlines( m_boardShape );
m_topFreeArea = m_boardShape;
m_bottomFreeArea = m_boardShape;

View File

@ -1842,12 +1842,12 @@ bool BOARD::NormalizeAreaPolygon( PICKED_ITEMS_LIST * aNewZonesList, ZONE* aCurr
}
bool BOARD::GetBoardPolygonOutlines( SHAPE_POLY_SET& aOutlines, wxString* aErrorText,
bool BOARD::GetBoardPolygonOutlines( SHAPE_POLY_SET& aOutlines,
std::vector<wxPoint>* aDiscontinuities,
std::vector<wxPoint>* aIntersections )
{
bool success = BuildBoardPolygonOutlines( this, aOutlines, GetDesignSettings().m_MaxError,
aErrorText, aDiscontinuities, aIntersections );
aDiscontinuities, aIntersections );
// Make polygon strictly simple to avoid issues (especially in 3D viewer)
aOutlines.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );

View File

@ -588,8 +588,6 @@ public:
* Any closed outline inside the main outline is a hole
* All contours should be closed, i.e. have valid vertices to build a closed polygon
* @param aOutlines The SHAPE_POLY_SET to fill in with outlines/holes.
* @param aErrorText = an optional wxString for an error message with the coordinate of the
* first discontinuity or self-intersection
* @param aDiscontinuities = an optional array of wxPoint giving the locations of
* discontinuities in the outline
* @param aIntersections = an optional array of wxPoint giving the locations of self-
@ -597,7 +595,7 @@ public:
*
* @return true if success, false if a contour is not valid
*/
bool GetBoardPolygonOutlines( SHAPE_POLY_SET& aOutlines, wxString* aErrorText = nullptr,
bool GetBoardPolygonOutlines( SHAPE_POLY_SET& aOutlines,
std::vector<wxPoint>* aDiscontinuities = nullptr,
std::vector<wxPoint>* aIntersections = nullptr );

View File

@ -191,17 +191,14 @@ static PCB_SHAPE* findNext( PCB_SHAPE* aShape, const wxPoint& aPoint,
* These closed inner outlines are considered as holes in the main outline
* @param aSegList the initial list of drawsegments (only lines, circles and arcs).
* @param aPolygons will contain the complex polygon.
* @param aTolerance is the max distance between points that is still accepted as connected
* (internal units)
* @param aErrorText is a wxString to return error message.
* @param aTolerance is the max error distance when polygonizing a curve (internal units)
* @param aDiscontinuities = an optional array of wxPoint giving the locations of
* discontinuities in the outline
* @param aIntersections = an optional array of wxPoint giving the locations of self-
* intersections in the outline
*/
bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET& aPolygons,
unsigned int aTolerance, wxString* aErrorText,
std::vector<wxPoint>* aDiscontinuities,
int aTolerance, std::vector<wxPoint>* aDiscontinuities,
std::vector<wxPoint>* aIntersections )
{
if( aSegList.size() == 0 )
@ -519,15 +516,6 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
}
else // encountered discontinuity
{
if( aErrorText )
{
msg.Printf( _( "Unable to find edge with an endpoint of (%s, %s)." ),
StringFromValue( EDA_UNITS::MILLIMETRES, prevPt.x ),
StringFromValue( EDA_UNITS::MILLIMETRES, prevPt.y ) );
*aErrorText << msg << "\n";
}
if( aDiscontinuities )
aDiscontinuities->emplace_back( prevPt );
@ -731,15 +719,6 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
}
else // encountered discontinuity
{
if( aErrorText )
{
msg.Printf( _( "Unable to find edge with an endpoint of (%s, %s)." ),
StringFromValue( EDA_UNITS::MILLIMETRES, prevPt.x ),
StringFromValue( EDA_UNITS::MILLIMETRES, prevPt.y ) );
*aErrorText << msg << "\n";
}
if( aDiscontinuities )
aDiscontinuities->emplace_back( prevPt );
@ -795,8 +774,8 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
* Any closed outline inside the main outline is a hole
* All contours should be closed, i.e. valid closed polygon vertices
*/
bool BuildBoardPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines, unsigned int aTolerance,
wxString* aErrorText, std::vector<wxPoint>* aDiscontinuities,
bool BuildBoardPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines, int aTolerance,
std::vector<wxPoint>* aDiscontinuities,
std::vector<wxPoint>* aIntersections )
{
PCB_TYPE_COLLECTOR items;
@ -817,12 +796,8 @@ bool BuildBoardPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines, unsign
if( segList.size() )
{
success = ConvertOutlineToPolygon( segList, aOutlines, aTolerance, aErrorText,
aDiscontinuities, aIntersections );
}
else if( aErrorText )
{
*aErrorText = _( "No edges found on Edge.Cuts layer." );
success = ConvertOutlineToPolygon( segList, aOutlines, aTolerance, aDiscontinuities,
aIntersections );
}
if( !success || !aOutlines.OutlineCount() )
@ -1035,8 +1010,8 @@ bool BuildFootprintPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines,
segList.push_back( static_cast<PCB_SHAPE*>( items[ii] ) );
}
bool success = ConvertOutlineToPolygon( segList, outlines, aTolerance, aErrorText,
aDiscontinuities, aIntersections );
bool success = ConvertOutlineToPolygon( segList, outlines, aTolerance, aDiscontinuities,
aIntersections );
FOOTPRINT* footprint = aBoard->GetFirstFootprint();

View File

@ -41,17 +41,14 @@ class wxPoint;
* These closed inner outlines are considered as holes in the main outline
* @param aSegList the initial list of drawsegments (only lines, circles and arcs).
* @param aPolygons will contain the complex polygon.
* @param aTolerance is the max distance between points that is still accepted as connected
* (internal units)
* @param aErrorText is a wxString to return error message.
* @param aTolerance is the max error distance when polygonizing a curve (internal units)
* @param aDiscontinuities = an optional array of wxPoint giving the locations of
* discontinuities in the outline
* @param aIntersections = an optional array of wxPoint giving the locations of self-
* intersections in the outline
*/
bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET& aPolygons,
unsigned int aTolerance, wxString* aErrorText,
std::vector<wxPoint>* aDiscontinuities = nullptr,
int aTolerance, std::vector<wxPoint>* aDiscontinuities = nullptr,
std::vector<wxPoint>* aIntersections = nullptr );
@ -62,8 +59,7 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
* All contours should be closed, i.e. are valid vertices for a closed polygon
* return true if success, false if a contour is not valid
*/
extern bool BuildBoardPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines,
unsigned int aTolerance, wxString* aErrorText,
extern bool BuildBoardPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines, int aTolerance,
std::vector<wxPoint>* aDiscontinuities = nullptr,
std::vector<wxPoint>* aIntersections = nullptr );

View File

@ -23,8 +23,9 @@
#include <dialog_constraints_reporter.h>
#include <pcb_edit_frame.h>
#include <tool/tool_manager.h>
#include <wx_html_report_box.h>
#include <tools/pcb_actions.h>
DIALOG_CONSTRAINTS_REPORTER::DIALOG_CONSTRAINTS_REPORTER( PCB_EDIT_FRAME* aParent ) :
DIALOG_CONSTRAINTS_REPORTER_BASE( aParent ),
@ -47,7 +48,10 @@ void DIALOG_CONSTRAINTS_REPORTER::DeleteAllPages()
void DIALOG_CONSTRAINTS_REPORTER::OnErrorLinkClicked( wxHtmlLinkEvent& event )
{
m_frame->ShowBoardSetupDialog( _( "Rules" ) );
if( event.GetLinkInfo().GetHref() == "boardsetup" )
m_frame->ShowBoardSetupDialog( _( "Rules" ) );
else if( event.GetLinkInfo().GetHref() == "drc" )
m_frame->GetToolManager()->RunAction( PCB_ACTIONS::runDRC, true );
}

View File

@ -306,26 +306,46 @@ void DIALOG_DRC::OnDRCItemSelected( wxDataViewEvent& aEvent )
if( item && node )
{
PCB_LAYER_ID principalLayer = item->GetLayer();
std::shared_ptr<RC_ITEM> rc_item = node->m_RcItem;
LSET violationLayers;
std::shared_ptr<RC_ITEM> rc_item = node->m_RcItem;
BOARD_ITEM* a = board->GetItem( rc_item->GetMainItemID() );
BOARD_ITEM* b = board->GetItem( rc_item->GetAuxItemID() );
BOARD_ITEM* c = board->GetItem( rc_item->GetAuxItem2ID() );
BOARD_ITEM* d = board->GetItem( rc_item->GetAuxItem3ID() );
if( rc_item->GetErrorCode() == DRCE_MALFORMED_COURTYARD )
{
BOARD_ITEM* a = board->GetItem( rc_item->GetMainItemID() );
LSET violationLayers;
if( a && ( a->GetFlags() & MALFORMED_B_COURTYARD ) > 0
&& ( a->GetFlags() & MALFORMED_F_COURTYARD ) == 0 )
{
principalLayer = B_CrtYd;
}
else
{
principalLayer = F_CrtYd;
}
}
else if (rc_item->GetErrorCode() == DRCE_INVALID_OUTLINE )
{
principalLayer = Edge_Cuts;
}
else
{
BOARD_ITEM* a = board->GetItem( rc_item->GetMainItemID() );
BOARD_ITEM* b = board->GetItem( rc_item->GetAuxItemID() );
BOARD_ITEM* c = board->GetItem( rc_item->GetAuxItem2ID() );
BOARD_ITEM* d = board->GetItem( rc_item->GetAuxItem3ID() );
if( a )
violationLayers &= a->GetLayerSet();
if( a )
violationLayers &= a->GetLayerSet();
if( b )
violationLayers &= b->GetLayerSet();
if( b )
violationLayers &= b->GetLayerSet();
if( c )
violationLayers &= c->GetLayerSet();
if( c )
violationLayers &= c->GetLayerSet();
if( d )
violationLayers &= d->GetLayerSet();
if( d )
violationLayers &= d->GetLayerSet();
}
if( violationLayers.count() )
principalLayer = violationLayers.Seq().front();
@ -339,7 +359,7 @@ void DIALOG_DRC::OnDRCItemSelected( wxDataViewEvent& aEvent )
if( ( violationLayers & board->GetVisibleLayers() ) == 0 )
{
m_brdEditor->GetAppearancePanel()->SetLayerVisible( item->GetLayer(), true );
m_brdEditor->GetAppearancePanel()->SetLayerVisible( principalLayer, true );
m_brdEditor->GetCanvas()->Refresh();
}

View File

@ -205,8 +205,8 @@ void PCB_EDIT_FRAME::OnExportSTEP( wxCommandEvent& event )
{
if( !doAutoSave() )
{
DisplayErrorMessage( this,
_( "STEP export failed! Please save the PCB and try again" ) );
DisplayErrorMessage( this, _( "STEP export failed! "
"Please save the PCB and try again" ) );
return;
}
@ -245,9 +245,9 @@ void DIALOG_EXPORT_STEP::onExportButton( wxCommandEvent& aEvent )
wxString msg;
// Check if the board outline is continuous
if( !BuildBoardPolygonOutlines( m_parent->GetBoard(), outline, Millimeter2iu( 0.01 ), &msg ) )
if( !BuildBoardPolygonOutlines( m_parent->GetBoard(), outline, Millimeter2iu( 0.01 ) ) )
{
DisplayErrorMessage( this, _( "Cannot determine the board outline." ), msg );
DisplayErrorMessage( this, _( "Board outline is malformed. Run DRC for a full analysis." ) );
return;
}

View File

@ -87,18 +87,40 @@ void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefinitions()
if( !reportProgress( ii++, m_board->Footprints().size(), delta ) )
return;
if( ( footprint->GetFlags() & MALFORMED_COURTYARD ) != 0 )
if( ( footprint->GetFlags() & MALFORMED_COURTYARDS ) != 0 )
{
if( m_drcEngine->IsErrorLimitExceeded( DRCE_MALFORMED_COURTYARD) )
continue;
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MALFORMED_COURTYARD );
std::vector<wxPoint> discontinuities;
std::vector<wxPoint> intersections;
m_msg.Printf( drcItem->GetErrorText() + wxS( " " ) + _( "(not a closed shape)" ) );
// Run courtyard test again to get error locations
footprint->BuildPolyCourtyards( &discontinuities, &intersections);
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( footprint );
reportViolation( drcItem, footprint->GetPosition());
for( wxPoint pt : discontinuities )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MALFORMED_COURTYARD );
m_msg.Printf( _( "(not a closed shape)" ) );
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + m_msg );
drcItem->SetItems( footprint );
reportViolation( drcItem, pt );
}
for( wxPoint pt : intersections )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MALFORMED_COURTYARD );
m_msg.Printf( _( "(self-intersecting)" ) );
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + m_msg );
drcItem->SetItems( footprint );
reportViolation( drcItem, pt );
}
}
else if( footprint->GetPolyCourtyardFront().OutlineCount() == 0
&& footprint->GetPolyCourtyardBack().OutlineCount() == 0 )
@ -108,7 +130,7 @@ void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefinitions()
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MISSING_COURTYARD );
drcItem->SetItems( footprint );
reportViolation( drcItem, footprint->GetPosition());
reportViolation( drcItem, footprint->GetPosition() );
}
else
{

View File

@ -85,34 +85,43 @@ void DRC_TEST_PROVIDER_MISC::testOutline()
SHAPE_POLY_SET boardOutlines;
if( m_board->GetBoardPolygonOutlines( boardOutlines, nullptr, &discontinuities,
&intersections ) )
if(! m_board->GetBoardPolygonOutlines( boardOutlines, &discontinuities, &intersections ) )
{
return;
}
if( boardOutlines.IsEmpty() )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_INVALID_OUTLINE );
for( wxPoint pt : discontinuities )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_INVALID_OUTLINE );
m_msg.Printf( _( "(no edges found on Edge.Cuts layer)" ) );
m_msg.Printf( _( "(not a closed shape)" ) );
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + m_msg );
drcItem->SetItems( m_board );
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + m_msg );
drcItem->SetItems( m_board );
reportViolation( drcItem, m_board->GetBoundingBox().Centre() );
}
reportViolation( drcItem, pt );
}
for( wxPoint pt : discontinuities )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_INVALID_OUTLINE );
for( wxPoint pt : intersections )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_INVALID_OUTLINE );
m_msg.Printf( _( "(not a closed shape)" ) );
m_msg.Printf( _( "(self-intersecting)" ) );
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + m_msg );
drcItem->SetItems( m_board );
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + m_msg );
drcItem->SetItems( m_board );
reportViolation( drcItem, pt );
}
reportViolation( drcItem, pt );
for( wxPoint pt : intersections )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_INVALID_OUTLINE );
m_msg.Printf( _( "(self-intersecting)" ) );
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + m_msg );
drcItem->SetItems( m_board );
reportViolation( drcItem, pt );
}
}
}

View File

@ -299,6 +299,7 @@ bool HYPERLYNX_EXPORTER::writeBoardInfo()
if( !m_board->GetBoardPolygonOutlines( outlines ) )
{
wxLogError( _( "Board outline is malformed. Run DRC for a full analysis." ) );
return false;
}

View File

@ -829,13 +829,10 @@ static void export_vrml_drawings( MODEL_VRML& aModel, BOARD* pcb )
static void export_vrml_board( MODEL_VRML& aModel, BOARD* aPcb )
{
SHAPE_POLY_SET pcbOutlines; // stores the board main outlines
wxString msg;
if( !aPcb->GetBoardPolygonOutlines( pcbOutlines, &msg ) )
if( !aPcb->GetBoardPolygonOutlines( pcbOutlines ) )
{
msg << "\n\n" <<
_( "Unable to calculate the board outlines; fall back to using the board boundary box." );
wxMessageBox( msg );
wxLogWarning( _( "Board outline is malformed. Run DRC for a full analysis." ) );
}
int seg;
@ -864,18 +861,14 @@ static void export_vrml_board( MODEL_VRML& aModel, BOARD* aPcb )
if( seg < 0 )
{
msg << "\n\n" <<
_( "VRML Export Failed: Could not add holes to contours." );
wxMessageBox( msg );
wxLogError( _( "VRML Export Failed: Could not add holes to contours." ) );
return;
}
for( int j = 0; j < hole.PointCount(); j++ )
{
aModel.m_holes.AddVertex( seg, (double)hole.CPoint(j).x * BOARD_SCALE,
-((double)hole.CPoint(j).y * BOARD_SCALE ) );
aModel.m_holes.AddVertex( seg, (double) hole.CPoint(j).x * BOARD_SCALE,
-( (double) hole.CPoint(j).y * BOARD_SCALE ) );
}
aModel.m_holes.EnsureWinding( seg, true );

View File

@ -173,16 +173,18 @@ int PLACEFILE_GERBER_WRITER::CreatePlaceFile( wxString& aFullFilename, PCB_LAYER
// We plot the footprint courtyard when possible.
// If not, the pads bounding box will be used.
bool useFpPadsBbox = true;
bool onBack = aLayer == B_Cu;
footprint->BuildPolyCourtyards();
if( ( footprint->GetFlags() & MALFORMED_COURTYARD ) == 0 )
int checkFlag = onBack ? MALFORMED_B_COURTYARD : MALFORMED_F_COURTYARD;
if( ( footprint->GetFlags() & checkFlag ) == 0 )
{
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CMP_COURTYARD );
SHAPE_POLY_SET& courtyard = aLayer == B_Cu ?
footprint->GetPolyCourtyardBack():
footprint->GetPolyCourtyardFront();
SHAPE_POLY_SET& courtyard = onBack ? footprint->GetPolyCourtyardBack()
: footprint->GetPolyCourtyardFront();
for( int ii = 0; ii < courtyard.OutlineCount(); ii++ )
{

View File

@ -1693,11 +1693,12 @@ std::shared_ptr<SHAPE> FOOTPRINT::GetEffectiveShape( PCB_LAYER_ID aLayer ) const
}
void FOOTPRINT::BuildPolyCourtyards()
void FOOTPRINT::BuildPolyCourtyards( std::vector<wxPoint>* aDiscontinuities,
std::vector<wxPoint>* aIntersections )
{
m_poly_courtyard_front.RemoveAllContours();
m_poly_courtyard_back.RemoveAllContours();
ClearFlags( MALFORMED_COURTYARD );
ClearFlags( MALFORMED_COURTYARDS );
// Build the courtyard area from graphic items on the courtyard.
// Only PCB_FP_SHAPE_T have meaning, graphic texts are ignored.
@ -1717,26 +1718,18 @@ void FOOTPRINT::BuildPolyCourtyards()
if( !list_front.size() && !list_back.size() )
return;
wxString error_msg;
#define ARC_ERROR_MAX 0.02 /* error max in mm to approximate a arc by segments */
if( !ConvertOutlineToPolygon( list_front, m_poly_courtyard_front,
(unsigned) Millimeter2iu( ARC_ERROR_MAX ), &error_msg ) )
if( !ConvertOutlineToPolygon( list_front, m_poly_courtyard_front, Millimeter2iu( ARC_ERROR_MAX ),
aDiscontinuities, aIntersections ) )
{
SetFlags( MALFORMED_COURTYARD );
SetFlags( MALFORMED_F_COURTYARD );
}
if( !ConvertOutlineToPolygon( list_back, m_poly_courtyard_back,
(unsigned) Millimeter2iu( ARC_ERROR_MAX ), &error_msg ) )
if( !ConvertOutlineToPolygon( list_back, m_poly_courtyard_back, Millimeter2iu( ARC_ERROR_MAX ),
aDiscontinuities, aIntersections ) )
{
SetFlags( MALFORMED_COURTYARD );
}
if( !error_msg.IsEmpty() )
{
wxLogMessage( wxString::Format( _( "Processing courtyard of \"%s\": %s" ),
GetFPID().Format().wx_str(),
error_msg ) );
SetFlags( MALFORMED_B_COURTYARD );
}
}

View File

@ -666,10 +666,11 @@ public:
/**
* Builds complex polygons of the courtyard areas from graphic items on the courtyard layers
* @remark sets the MALFORMED_FRONT_COURTYARD and MALFORMED_BACK_COURTYARD status flags if
* the given courtyard layer does not contain a (single) closed shape
* @remark sets the MALFORMED_F_COURTYARD and MALFORMED_B_COURTYARD status flags if the given
* courtyard layer does not contain a (single) closed shape
*/
void BuildPolyCourtyards();
void BuildPolyCourtyards( std::vector<wxPoint>* aDiscontinuities = nullptr,
std::vector<wxPoint>* aIntersections = nullptr );
virtual std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER ) const override;

View File

@ -250,7 +250,7 @@ static void insideArea( LIBEVAL::CONTEXT* aCtx, void* self )
{
FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
if( ( footprint->GetFlags() & MALFORMED_COURTYARD ) != 0 )
if( ( footprint->GetFlags() & MALFORMED_COURTYARDS ) != 0 )
{
aCtx->ReportError( _( "Footprint's courtyard is not a single, closed shape." ) );
return false;

View File

@ -831,10 +831,12 @@ PADSTACK* SPECCTRA_DB::makeVia( const ::VIA* aVia )
void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary )
{
wxString errMessage;
SHAPE_POLY_SET outlines;
aBoard->GetBoardPolygonOutlines( outlines, &errMessage );
if( !aBoard->GetBoardPolygonOutlines( outlines ) )
{
wxLogWarning( _( "Board outline is malformed. Run DRC for a full analysis." ) );
}
for( int cnt = 0; cnt < outlines.OutlineCount(); cnt++ ) // Should be one outline
{
@ -878,9 +880,6 @@ void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary )
poly_ko->AppendPoint( mapPt( pos ) );
}
}
if( !errMessage.IsEmpty() )
wxLogMessage( errMessage );
}

View File

@ -39,7 +39,10 @@
void DIALOG_INSPECTION_REPORTER::OnErrorLinkClicked( wxHtmlLinkEvent& event )
{
m_frame->ShowBoardSetupDialog( _( "Rules" ) );
if( event.GetLinkInfo().GetHref() == "boardsetup" )
m_frame->ShowBoardSetupDialog( _( "Rules" ) );
else if( event.GetLinkInfo().GetHref() == "drc" )
m_frame->GetToolManager()->RunAction( PCB_ACTIONS::runDRC, true );
}
@ -399,6 +402,7 @@ int PCB_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selection.GetItem( 0 ) );
DRC_ENGINE drcEngine( m_frame->GetBoard(), &m_frame->GetBoard()->GetDesignSettings() );
bool courtyardError = false;
bool compileError = false;
try
@ -419,6 +423,9 @@ int PCB_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
zone->CacheBoundingBox();
footprint->BuildPolyCourtyards();
if( ( footprint->GetFlags() & MALFORMED_COURTYARDS ) != 0 )
courtyardError = true;
}
if( item->Type() == PCB_TRACE_T )
@ -575,6 +582,13 @@ int PCB_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
}
else
{
if( courtyardError )
{
r->Report( "" );
r->Report( _( "Report may be incomplete: some footprint courtyards are malformed. " )
+ "<a href='drc'>" + _( "Run DRC for a full analysis." ) + "</a>" );
}
auto constraint = drcEngine.EvalRulesForItems( DISALLOW_CONSTRAINT, item, nullptr,
UNDEFINED_LAYER, r );