Separate polygonization error from chaining error.

This way we can report anything that doesn't exactly chain while still
applying  a fudge factor for our own stuff.

Fixes https://gitlab.com/kicad/code/kicad/issues/1795
This commit is contained in:
Jeff Young 2020-12-24 21:00:41 +00:00
parent 359c29639f
commit ef25c78a04
6 changed files with 63 additions and 35 deletions

View File

@ -473,8 +473,11 @@ bool BOARD_ADAPTER::createBoardPolygon( wxString* aErrorMsg )
return false;
}
int chainingEpsilon = Millimeter2iu( 0.02 ); // max dist from one endPt to next startPt
success = BuildFootprintPolygonOutlines( m_board, m_board_poly,
m_board->GetDesignSettings().m_MaxError );
m_board->GetDesignSettings().m_MaxError,
chainingEpsilon );
// Make polygon strictly simple to avoid issues (especially in 3D viewer)
m_board_poly.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );

View File

@ -1844,8 +1844,10 @@ bool BOARD::NormalizeAreaPolygon( PICKED_ITEMS_LIST * aNewZonesList, ZONE* aCurr
bool BOARD::GetBoardPolygonOutlines( SHAPE_POLY_SET& aOutlines,
OUTLINE_ERROR_HANDLER* aErrorHandler )
{
int chainingEpsilon = Millimeter2iu( 0.02 ); // max dist from one endPt to next startPt
bool success = BuildBoardPolygonOutlines( this, aOutlines, GetDesignSettings().m_MaxError,
aErrorHandler );
chainingEpsilon, aErrorHandler );
// Make polygon strictly simple to avoid issues (especially in 3D viewer)
aOutlines.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );

View File

@ -185,11 +185,13 @@ 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 error distance when polygonizing a curve (internal units)
* @param aErrorMax is the max error distance when polygonizing a curve (internal units)
* @param aChainingEpsilon is the max error distance when polygonizing a curve (internal units)
* @param aErrorHandler = an optional error handler
*/
bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET& aPolygons,
int aTolerance, OUTLINE_ERROR_HANDLER* aErrorHandler )
int aErrorMax, int aChainingEpsilon,
OUTLINE_ERROR_HANDLER* aErrorHandler )
{
if( aSegList.size() == 0 )
return true;
@ -237,7 +239,7 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
wxPoint center = graphic->GetCenter();
double angle = -graphic->GetAngle();
double radius = graphic->GetRadius();
int steps = GetArcToSegmentCount( radius, aTolerance, angle / 10.0 );
int steps = GetArcToSegmentCount( radius, aErrorMax, angle / 10.0 );
wxPoint pt;
for( int step = 1; step<=steps; ++step )
@ -432,11 +434,11 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
wxPoint pcenter = graphic->GetCenter();
double angle = -graphic->GetAngle();
double radius = graphic->GetRadius();
int steps = GetArcToSegmentCount( radius, aTolerance, angle / 10.0 );
int steps = GetArcToSegmentCount( radius, aErrorMax, angle / 10.0 );
if( !close_enough( prevPt, pstart, aTolerance ) )
if( !close_enough( prevPt, pstart, aChainingEpsilon ) )
{
wxASSERT( close_enough( prevPt, graphic->GetArcEnd(), aTolerance ) );
wxASSERT( close_enough( prevPt, graphic->GetArcEnd(), aChainingEpsilon ) );
angle = -angle;
std::swap( pstart, pend );
@ -514,7 +516,7 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
// Get next closest segment.
PCB_SHAPE* nextGraphic = findNext( graphic, prevPt, aSegList, aTolerance );
PCB_SHAPE* nextGraphic = findNext( graphic, prevPt, aSegList, aChainingEpsilon );
if( nextGraphic && !( nextGraphic->GetFlags() & SKIP_STRUCT ) )
{
@ -526,7 +528,7 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
// Finished, or ran into trouble...
if( close_enough( startPt, prevPt, aTolerance ) )
if( close_enough( startPt, prevPt, aChainingEpsilon ) )
{
polygonComplete = true;
break;
@ -595,7 +597,7 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
double angle = 3600.0;
wxPoint start = center;
int radius = graphic->GetRadius();
int steps = GetArcToSegmentCount( radius, aTolerance, 360.0 );
int steps = GetArcToSegmentCount( radius, aErrorMax, 360.0 );
wxPoint nextPt;
start.x += radius;
@ -673,11 +675,12 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
wxPoint pcenter = graphic->GetCenter();
double angle = -graphic->GetAngle();
int radius = graphic->GetRadius();
int steps = GetArcToSegmentCount( radius, aTolerance, angle / 10.0 );
int steps = GetArcToSegmentCount( radius, aErrorMax, angle / 10.0 );
if( !close_enough( prevPt, pstart, aTolerance ) )
if( !close_enough( prevPt, pstart, aChainingEpsilon ) )
{
wxASSERT( close_enough( prevPt, graphic->GetArcEnd(), aTolerance ) );
wxASSERT( close_enough( prevPt, graphic->GetArcEnd(),
aChainingEpsilon ) );
angle = -angle;
std::swap( pstart, pend );
@ -757,7 +760,7 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
// Get next closest segment.
PCB_SHAPE* nextGraphic = findNext( graphic, prevPt, aSegList, aTolerance );
PCB_SHAPE* nextGraphic = findNext( graphic, prevPt, aSegList, aChainingEpsilon );
if( nextGraphic && !( nextGraphic->GetFlags() & SKIP_STRUCT ) )
{
@ -769,7 +772,7 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
// Finished, or ran into trouble...
if( close_enough( startPt, prevPt, aTolerance ) )
if( close_enough( startPt, prevPt, aChainingEpsilon ) )
{
break;
}
@ -842,8 +845,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, int aTolerance,
OUTLINE_ERROR_HANDLER* aErrorHandler )
bool BuildBoardPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines, int aErrorMax,
int aChainingEpsilon, OUTLINE_ERROR_HANDLER* aErrorHandler )
{
PCB_TYPE_COLLECTOR items;
bool success = false;
@ -863,7 +866,8 @@ bool BuildBoardPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines, int aT
if( segList.size() )
{
success = ConvertOutlineToPolygon( segList, aOutlines, aTolerance, aErrorHandler );
success = ConvertOutlineToPolygon( segList, aOutlines, aErrorMax, aChainingEpsilon,
aErrorHandler );
}
if( !success || !aOutlines.OutlineCount() )
@ -1055,8 +1059,8 @@ int findEndSegments( SHAPE_LINE_CHAIN& aChain, SEG& aStartSeg, SEG& aEndSeg )
* * If copper is located outside a closed outline, then that outline will be treated
* as a hole, and the outer edge will be formed using the bounding box.
*/
bool BuildFootprintPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines, int aTolerance,
OUTLINE_ERROR_HANDLER* aErrorHandler )
bool BuildFootprintPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines, int aErrorMax,
int aChainingEpsilon, OUTLINE_ERROR_HANDLER* aErrorHandler )
{
PCB_TYPE_COLLECTOR items;
@ -1075,7 +1079,8 @@ bool BuildFootprintPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines, in
segList.push_back( static_cast<PCB_SHAPE*>( items[ii] ) );
}
bool success = ConvertOutlineToPolygon( segList, outlines, aTolerance, aErrorHandler );
bool success = ConvertOutlineToPolygon( segList, outlines, aErrorMax, aChainingEpsilon,
aErrorHandler );
FOOTPRINT* footprint = aBoard->GetFirstFootprint();

View File

@ -45,20 +45,22 @@ const std::function<void( const wxString& msg, BOARD_ITEM* itemA, BOARD_ITEM* it
* 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 error distance when polygonizing a curve (internal units)
* @param aErrorMax is the max error distance when polygonizing a curve (internal units)
* @param aChainingEpsilon is the max distance from one endPt to the next startPt (internal units)
* @param aErrorHandler = an optional error handler
*/
bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET& aPolygons,
int aTolerance, OUTLINE_ERROR_HANDLER* aErrorHandler = nullptr );
int aErrorMax, int aChainingEpsilon,
OUTLINE_ERROR_HANDLER* aErrorHandler = nullptr );
/**
* Extracts the board outlines and build a closed polygon
* from lines, arcs and circle items on edge cut layer
* Any closed outline inside the main outline is a hole
* 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
* Extracts the board outlines and build a closed polygon from lines, arcs and circle items on
* edge cut layer. Any closed outline inside the main outline is a hole. 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, int aTolerance,
extern bool BuildBoardPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines,
int aErrorMax, int aChainingEpsilon,
OUTLINE_ERROR_HANDLER* aErrorHandler = nullptr );

View File

@ -80,7 +80,7 @@ private:
void DRC_TEST_PROVIDER_MISC::testOutline()
{
SHAPE_POLY_SET boardOutlines;
SHAPE_POLY_SET dummyOutline;
bool errorHandled = false;
OUTLINE_ERROR_HANDLER errorHandler =
@ -95,7 +95,12 @@ void DRC_TEST_PROVIDER_MISC::testOutline()
errorHandled = true;
};
if( !m_board->GetBoardPolygonOutlines( boardOutlines, &errorHandler ) )
// Use a really tight chaining epsilon here so that we report errors that might affect
// other tools (such as STEP export).
constexpr int chainingEpsilon = Millimeter2iu( 0.02 ) / 100;
if( BuildBoardPolygonOutlines( m_board, dummyOutline, m_board->GetDesignSettings().m_MaxError,
chainingEpsilon, &errorHandler ) )
{
if( errorHandled )
{

View File

@ -1801,17 +1801,28 @@ void FOOTPRINT::BuildPolyCourtyards( OUTLINE_ERROR_HANDLER* aErrorHandler )
if( !list_front.size() && !list_back.size() )
return;
constexpr int errorMax = Millimeter2iu( 0.02 ); /* error max for polygonization */
int errorMax = Millimeter2iu( 0.02 ); // max error for polygonization
int chainingEpsilon = Millimeter2iu( 0.02 ); // max dist from one endPt to next startPt
if( ConvertOutlineToPolygon( list_front, m_poly_courtyard_front, errorMax, aErrorHandler ) )
if( ConvertOutlineToPolygon( list_front, m_poly_courtyard_front, errorMax, chainingEpsilon,
aErrorHandler ) )
{
m_poly_courtyard_front.CacheTriangulation( false );
}
else
{
SetFlags( MALFORMED_F_COURTYARD );
}
if( ConvertOutlineToPolygon( list_back, m_poly_courtyard_back, errorMax, aErrorHandler ) )
if( ConvertOutlineToPolygon( list_back, m_poly_courtyard_back, errorMax, chainingEpsilon,
aErrorHandler ) )
{
m_poly_courtyard_back.CacheTriangulation( false );
}
else
{
SetFlags( MALFORMED_B_COURTYARD );
}
}