MODULE::CoverageRatio(): replace wxRegion (not working for us on Windows) by polygons to calculate areas.

At least on Windows, using wxRegion generates crashes.

Fixes: lp:1740646
https://bugs.launchpad.net/kicad/+bug/1740646
This commit is contained in:
jean-pierre charras 2017-12-31 17:46:38 +01:00
parent 03e9f0c94a
commit 11d1188fdf
2 changed files with 38 additions and 11 deletions

View File

@ -626,6 +626,8 @@ const VECTOR2I SHAPE_LINE_CHAIN::PointAlong( int aPathLength ) const
double SHAPE_LINE_CHAIN::Area() const double SHAPE_LINE_CHAIN::Area() const
{ {
// see https://www.mathopenref.com/coordpolygonarea2.html
if( !m_closed ) if( !m_closed )
return 0.0; return 0.0;

View File

@ -1240,35 +1240,60 @@ wxString MODULE::GetReferencePrefix() const
} }
double CalcArea( wxRegion aRegion ) // Calculate the area of aPolySet, after fracturation, because
// polygons with no hole are expected.
static double polygonArea( SHAPE_POLY_SET& aPolySet )
{ {
double area = 0.0; double area = 0.0;
for( wxRegionIterator iterator( aRegion ); iterator.HaveRects(); iterator++ ) for( int ii = 0; ii < aPolySet.OutlineCount(); ii++ )
{ {
wxRect aRect = iterator.GetRect(); SHAPE_LINE_CHAIN& outline = aPolySet.Outline( ii );
area += static_cast<double>( aRect.GetWidth() ) * aRect.GetHeight(); // Ensure the curr outline is closed, to calculate area
} outline.SetClosed( true );
area += outline.Area();
}
return area; return area;
} }
// a helper function to add a rectangular polygon aRect to aPolySet
static void addRect( SHAPE_POLY_SET& aPolySet, wxRect aRect )
{
aPolySet.NewOutline();
aPolySet.Append( aRect.GetX(), aRect.GetY() );
aPolySet.Append( aRect.GetX()+aRect.width, aRect.GetY() );
aPolySet.Append( aRect.GetX()+aRect.width, aRect.GetY()+aRect.height );
aPolySet.Append( aRect.GetX(), aRect.GetY()+aRect.height );
}
double MODULE::CoverageRatio() const double MODULE::CoverageRatio() const
{ {
double moduleArea = GetFootprintRect().GetArea(); double moduleArea = GetFootprintRect().GetArea();
wxRegion uncoveredRegion( GetFootprintRect() ); SHAPE_POLY_SET coveredRegion;
addRect(coveredRegion, GetFootprintRect() );
// build hole list if full area
SHAPE_POLY_SET holes;
for( D_PAD* pad = m_Pads; pad; pad = pad->Next() ) for( D_PAD* pad = m_Pads; pad; pad = pad->Next() )
uncoveredRegion.Subtract( pad->GetBoundingBox() ); addRect( holes, pad->GetBoundingBox() );
for( BOARD_ITEM* item = m_Drawings; item; item = item->Next() ) for( BOARD_ITEM* item = m_Drawings; item; item = item->Next() )
uncoveredRegion.Subtract( item->GetBoundingBox() ); addRect( holes, item->GetBoundingBox() );
uncoveredRegion.Subtract( m_Reference->GetBoundingBox() ); addRect( holes, m_Reference->GetBoundingBox() );
uncoveredRegion.Subtract( m_Value->GetBoundingBox() ); addRect( holes, m_Value->GetBoundingBox() );
double coveredArea = moduleArea - CalcArea( uncoveredRegion ); SHAPE_POLY_SET uncoveredRegion;
uncoveredRegion.BooleanSubtract( coveredRegion, holes, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
uncoveredRegion.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
uncoveredRegion.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
double uncoveredRegionArea = polygonArea( uncoveredRegion );
double coveredArea = moduleArea - uncoveredRegionArea;
double ratio = ( coveredArea / moduleArea ); double ratio = ( coveredArea / moduleArea );
return std::min( ratio, 1.0 ); return std::min( ratio, 1.0 );
} }