From 11d1188fdfedcfde1caa4af6324225adf39790a9 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Sun, 31 Dec 2017 17:46:38 +0100 Subject: [PATCH] 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 --- common/geometry/shape_line_chain.cpp | 2 ++ pcbnew/class_module.cpp | 47 +++++++++++++++++++++------- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/common/geometry/shape_line_chain.cpp b/common/geometry/shape_line_chain.cpp index 54da3fad76..5f11b376c2 100644 --- a/common/geometry/shape_line_chain.cpp +++ b/common/geometry/shape_line_chain.cpp @@ -626,6 +626,8 @@ const VECTOR2I SHAPE_LINE_CHAIN::PointAlong( int aPathLength ) const double SHAPE_LINE_CHAIN::Area() const { + // see https://www.mathopenref.com/coordpolygonarea2.html + if( !m_closed ) return 0.0; diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp index 8721be78dc..2b4e5d4b2f 100644 --- a/pcbnew/class_module.cpp +++ b/pcbnew/class_module.cpp @@ -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; - for( wxRegionIterator iterator( aRegion ); iterator.HaveRects(); iterator++ ) + for( int ii = 0; ii < aPolySet.OutlineCount(); ii++ ) { - wxRect aRect = iterator.GetRect(); - area += static_cast( aRect.GetWidth() ) * aRect.GetHeight(); - } + SHAPE_LINE_CHAIN& outline = aPolySet.Outline( ii ); + // Ensure the curr outline is closed, to calculate area + outline.SetClosed( true ); + + area += outline.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 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() ) - uncoveredRegion.Subtract( pad->GetBoundingBox() ); + addRect( holes, pad->GetBoundingBox() ); for( BOARD_ITEM* item = m_Drawings; item; item = item->Next() ) - uncoveredRegion.Subtract( item->GetBoundingBox() ); + addRect( holes, item->GetBoundingBox() ); - uncoveredRegion.Subtract( m_Reference->GetBoundingBox() ); - uncoveredRegion.Subtract( m_Value->GetBoundingBox() ); + addRect( holes, m_Reference->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 ); + return std::min( ratio, 1.0 ); }