DRC_TEST_PROVIDER_MISC::testOutline(): add test to detect questionable items.
Graphic items (segments, rects, circles) on Edge.Cuts can create issues when building board outlines, when they are very small (a few nm in size), because they are not easily handled when trying to search connected graphics. Also protect RC_ITEM::SetItems() against null pointer. Fixes #15865 https://gitlab.com/kicad/code/kicad/-/issues/15865
This commit is contained in:
parent
b0f4adf052
commit
499f3ca95b
|
@ -64,6 +64,7 @@ void RC_ITEM::SetItems( const EDA_ITEM* aItem, const EDA_ITEM* bItem,
|
|||
{
|
||||
m_ids.clear();
|
||||
|
||||
if( aItem )
|
||||
m_ids.push_back( aItem->m_Uuid );
|
||||
|
||||
if( bItem )
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#include <geometry/shape_poly_set.h>
|
||||
#include <geometry/geometry_utils.h>
|
||||
#include <convert_shape_list_to_polygon.h>
|
||||
#include <board.h>
|
||||
#include <collectors.h>
|
||||
|
||||
#include <wx/log.h>
|
||||
|
||||
|
@ -582,8 +584,116 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aShapeList, SHAPE_POLY_SE
|
|||
}
|
||||
|
||||
|
||||
#include <board.h>
|
||||
#include <collectors.h>
|
||||
/* This function is used to test a board outlines graphic items for validity
|
||||
* i.e. null or very small segments, rects and circles
|
||||
*/
|
||||
bool TestBoardOutlinesGraphicItems( BOARD* aBoard, int aMinDist,
|
||||
OUTLINE_ERROR_HANDLER* aErrorHandler )
|
||||
{
|
||||
bool success = true;
|
||||
PCB_TYPE_COLLECTOR items;
|
||||
int min_dist = std::max( 0, aMinDist );
|
||||
|
||||
// Get all the shapes into 'items', then keep only those on layer == Edge_Cuts.
|
||||
items.Collect( aBoard, { PCB_SHAPE_T } );
|
||||
|
||||
std::vector<PCB_SHAPE*> segList;
|
||||
|
||||
for( int ii = 0; ii < items.GetCount(); ii++ )
|
||||
{
|
||||
PCB_SHAPE* seg = static_cast<PCB_SHAPE*>( items[ii] );
|
||||
|
||||
if( seg->GetLayer() == Edge_Cuts )
|
||||
segList.push_back( seg );
|
||||
}
|
||||
|
||||
for( FOOTPRINT* fp : aBoard->Footprints() )
|
||||
{
|
||||
PCB_TYPE_COLLECTOR fpItems;
|
||||
fpItems.Collect( fp, { PCB_SHAPE_T } );
|
||||
|
||||
for( int ii = 0; ii < fpItems.GetCount(); ii++ )
|
||||
{
|
||||
PCB_SHAPE* fpSeg = static_cast<PCB_SHAPE*>( fpItems[ii] );
|
||||
|
||||
if( fpSeg->GetLayer() == Edge_Cuts )
|
||||
segList.push_back( fpSeg );
|
||||
}
|
||||
}
|
||||
|
||||
// Now Test vailidty of collected items
|
||||
for( PCB_SHAPE* graphic : segList )
|
||||
{
|
||||
switch( graphic->GetShape() )
|
||||
{
|
||||
case SHAPE_T::RECTANGLE:
|
||||
{
|
||||
VECTOR2I seg = graphic->GetEnd() - graphic->GetStart();
|
||||
int dim = seg.EuclideanNorm();
|
||||
|
||||
if( dim <= min_dist )
|
||||
{
|
||||
success = false;
|
||||
|
||||
if( aErrorHandler )
|
||||
{
|
||||
(*aErrorHandler)( wxString::Format( _( "(Rectangle has null or very small size: %d nm)" ),
|
||||
dim ),
|
||||
graphic, nullptr, graphic->GetStart() );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SHAPE_T::CIRCLE:
|
||||
{
|
||||
if( graphic->GetRadius() <= min_dist )
|
||||
{
|
||||
success = false;
|
||||
|
||||
if( aErrorHandler )
|
||||
{
|
||||
(*aErrorHandler)( wxString::Format( _( "(Circle has null or very small radius: %d nm)" ),
|
||||
(int)graphic->GetRadius() ),
|
||||
graphic, nullptr, graphic->GetStart() );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SHAPE_T::SEGMENT:
|
||||
{
|
||||
VECTOR2I seg = graphic->GetEnd() - graphic->GetStart();
|
||||
int dim = seg.EuclideanNorm();
|
||||
|
||||
if( dim <= min_dist )
|
||||
{
|
||||
success = false;
|
||||
|
||||
if( aErrorHandler )
|
||||
{
|
||||
(*aErrorHandler)( wxString::Format( _( "(Segment has null or very small lenght: %d nm)" ), dim ),
|
||||
graphic, nullptr, graphic->GetStart() );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SHAPE_T::ARC:
|
||||
break;
|
||||
|
||||
case SHAPE_T::BEZIER:
|
||||
break;
|
||||
|
||||
default:
|
||||
UNIMPLEMENTED_FOR( graphic->SHAPE_T_asString() );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
/* This function is used to extract a board outlines (3D view, automatic zones build ...)
|
||||
* Any closed outline inside the main outline is a hole
|
||||
|
|
|
@ -32,6 +32,16 @@ typedef
|
|||
const std::function<void( const wxString& msg, BOARD_ITEM* itemA, BOARD_ITEM* itemB,
|
||||
const VECTOR2I& pt )> OUTLINE_ERROR_HANDLER;
|
||||
|
||||
/**
|
||||
* This function is used to test a board graphic items on Edge cut layer for validity
|
||||
* i.e. null segments, 0 size rects and circles
|
||||
* @param aBoard is the board to test
|
||||
* @param aMinDist is the min lenght of a segment (or radius, or diagonal size of a rect)
|
||||
* to be valid
|
||||
* @param aErrorHandler = an optional error handler
|
||||
*/
|
||||
bool TestBoardOutlinesGraphicItems( BOARD* aBoard, int aMinDist,
|
||||
OUTLINE_ERROR_HANDLER* aErrorHandler );
|
||||
/**
|
||||
* Function ConvertOutlineToPolygon
|
||||
* build a polygon set (with holes) from a PCB_SHAPE list, which is expected to be one or more
|
||||
|
|
|
@ -98,9 +98,30 @@ void DRC_TEST_PROVIDER_MISC::testOutline()
|
|||
};
|
||||
|
||||
// Use the standard chaining epsilon here so that we report errors that might affect
|
||||
// other tools (such as STEP export).
|
||||
// other tools (such as 3D viewer).
|
||||
int chainingEpsilon = m_board->GetOutlinesChainingEpsilon();
|
||||
|
||||
if( !TestBoardOutlinesGraphicItems(m_board, chainingEpsilon, &errorHandler ) )
|
||||
{
|
||||
if( errorHandled )
|
||||
{
|
||||
// if there are invalid items on Edge.Cuts, they are already reported
|
||||
}
|
||||
else
|
||||
{
|
||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_INVALID_OUTLINE );
|
||||
wxString msg;
|
||||
|
||||
msg.Printf( _( "(Suspicious items found on Edge.Cuts layer)" ) );
|
||||
|
||||
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
|
||||
drcItem->SetItems( m_board );
|
||||
|
||||
reportViolation( drcItem, m_board->GetBoundingBox().Centre(), Edge_Cuts );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( !BuildBoardPolygonOutlines( m_board, dummyOutline, m_board->GetDesignSettings().m_MaxError,
|
||||
chainingEpsilon, &errorHandler ) )
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue