Performance enhancements.

1) cache pad polygon outlines
   huge improvement in connectivity performance and a decent
   improvement in DRC performance
2) don't pre-allocate CONTEXT stack
   significant improvement in DRC rule performance
2) don't keep re-encoding strings
   decent improvement in DRC rule performance
This commit is contained in:
Jeff Young 2020-07-25 12:58:17 +01:00
parent d1d7f5e7fa
commit bf445c1a95
14 changed files with 95 additions and 104 deletions

View File

@ -817,10 +817,8 @@ void BOARD_ADAPTER::buildPadShapeThickOutlineAsSegments( const D_PAD* aPad,
}
// For other shapes, add outlines as thick segments in polygon buffer
SHAPE_POLY_SET corners;
aPad->TransformShapeWithClearanceToPolygon( corners, 0 );
const SHAPE_LINE_CHAIN& path = corners.COutline( 0 );
const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon();
const SHAPE_LINE_CHAIN& path = corners->COutline( 0 );
for( int j = 0; j < path.PointCount(); j++ )
{

View File

@ -46,10 +46,8 @@ void BOARD_ADAPTER::buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
}
// For other shapes, add outlines as thick segments in polygon buffer
SHAPE_POLY_SET corners;
aPad->TransformShapeWithClearanceToPolygon( corners, 0 );
const SHAPE_LINE_CHAIN& path = corners.COutline( 0 );
const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon();
const SHAPE_LINE_CHAIN& path = corners->COutline( 0 );
for( int ii = 0; ii < path.PointCount(); ++ii )
{

View File

@ -108,7 +108,7 @@ std::string UOP::Format() const
else if( val->GetType() == VT_NUMERIC )
snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "PUSH NUM [%.10f]", val->AsDouble() );
else
snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "PUSH STR [%s]", val->AsString().c_str() );
snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "PUSH STR [%s]", val->AsChars() );
}
break;

View File

@ -23,8 +23,8 @@
#include <cstddef>
#include <functional>
#include <map>
#include <string>
#include <stack>
#include <base_units.h>
@ -175,10 +175,10 @@ public:
m_valueDbl( 0 )
{};
VALUE( std::string aStr ) :
VALUE( const wxString& aStr ) :
m_type( VT_STRING ),
m_valueDbl( 0 ),
m_valueStr( std::move( aStr ) )
m_valueStr( aStr )
{};
VALUE( const double aVal ) :
@ -191,11 +191,16 @@ public:
return m_valueDbl;
}
const std::string& AsString() const
const wxString& AsString() const
{
return m_valueStr;
}
const char* AsChars() const
{
return m_valueStr.ToStdString().c_str();
}
bool operator==( const VALUE& b ) const
{
if( m_type == VT_NUMERIC && b.m_type == VT_NUMERIC )
@ -214,7 +219,7 @@ public:
m_valueDbl = aValue;
}
void Set( const std::string& aValue )
void Set( const wxString& aValue )
{
m_type = VT_STRING;
m_valueStr = aValue;
@ -237,7 +242,7 @@ public:
private:
VAR_TYPE_T m_type;
double m_valueDbl;
std::string m_valueStr;
wxString m_valueStr;
};
@ -256,47 +261,42 @@ public:
class CONTEXT
{
public:
const int c_memSize = 128;
CONTEXT()
~CONTEXT()
{
m_sp = 0;
for( int i = 0; i < c_memSize; i++ )
m_heap.emplace_back( VALUE() );
for( VALUE* value : m_ownedValues )
delete value;
}
VALUE* AllocValue()
{
assert( m_memPos < c_memSize );
auto rv = &m_heap[ m_memPos++ ];
return rv;
VALUE* value = new VALUE();
m_ownedValues.push_back( value );
return value;
}
void Push( VALUE* v )
{
m_stack[m_sp++] = v;
m_stack.push( v );
}
VALUE* Pop()
{
m_sp--;
return m_stack[m_sp];
VALUE* value = m_stack.top();
m_stack.pop();
return value;
}
int SP() const
{
return m_sp;
return m_stack.size();
}
ERROR_STATUS GetErrorStatus() const { return m_errorStatus; }
void ReportError( const wxString& aErrorMsg );
private:
std::vector<VALUE> m_heap;
VALUE* m_stack[128];
int m_sp = 0;
int m_memPos = 0;
std::vector<VALUE*> m_ownedValues;
std::stack<VALUE*> m_stack;
ERROR_STATUS m_errorStatus;
};
@ -467,9 +467,9 @@ protected:
return uop;
}
UOP* makeUop( int op, std::string value )
UOP* makeUop( int op, const wxString& value )
{
UOP* uop = new UOP( op, new VALUE( std::move( value ) ) );
UOP* uop = new UOP( op, new VALUE( value ) );
return uop;
}

View File

@ -168,27 +168,6 @@ bool D_PAD::IsFlipped() const
}
int D_PAD::calcBoundingRadius() const
{
int radius = 0;
SHAPE_POLY_SET polygons;
TransformShapeWithClearanceToPolygon( polygons, 0 );
for( int cnt = 0; cnt < polygons.OutlineCount(); ++cnt )
{
const SHAPE_LINE_CHAIN& poly = polygons.COutline( cnt );
for( int ii = 0; ii < poly.PointCount(); ++ii )
{
int dist = KiROUND( ( poly.CPoint( ii ) - m_Pos ).EuclideanNorm() );
radius = std::max( radius, dist );
}
}
return radius + 1;
}
int D_PAD::GetRoundRectCornerRadius() const
{
return KiROUND( std::min( m_Size.x, m_Size.y ) * m_roundedCornerScale );
@ -229,6 +208,15 @@ const std::vector<std::shared_ptr<SHAPE>>& D_PAD::GetEffectiveShapes() const
}
const std::shared_ptr<SHAPE_POLY_SET>& D_PAD::GetEffectivePolygon() const
{
if( m_shapesDirty )
BuildEffectiveShapes();
return m_effectivePolygon;
}
const SHAPE_SEGMENT* D_PAD::GetEffectiveHoleShape() const
{
if( m_shapesDirty )
@ -367,9 +355,27 @@ void D_PAD::BuildEffectiveShapes() const
}
}
// Polygon
//
m_effectivePolygon = std::make_shared<SHAPE_POLY_SET>();
TransformShapeWithClearanceToPolygon( *m_effectivePolygon, 0 );
// Bounding box and radius
//
m_effectiveBoundingRadius = calcBoundingRadius();
m_effectiveBoundingRadius = 0;
for( int cnt = 0; cnt < m_effectivePolygon->OutlineCount(); ++cnt )
{
const SHAPE_LINE_CHAIN& poly = m_effectivePolygon->COutline( cnt );
for( int ii = 0; ii < poly.PointCount(); ++ii )
{
int dist = KiROUND( ( poly.CPoint( ii ) - m_Pos ).EuclideanNorm() );
m_effectiveBoundingRadius = std::max( m_effectiveBoundingRadius, dist );
}
}
m_effectiveBoundingRadius += 1;
// reset the bbox to uninitialized state to prepare for merging
m_effectiveBoundingBox = EDA_RECT();
@ -798,10 +804,7 @@ bool D_PAD::HitTest( const wxPoint& aPosition, int aAccuracy ) const
if( delta.SquaredEuclideanNorm() > SEG::Square( boundingRadius ) )
return false;
SHAPE_POLY_SET polySet;
TransformShapeWithClearanceToPolygon( polySet, aAccuracy );
return polySet.Contains( aPosition );
return GetEffectivePolygon()->Contains( aPosition, -1, aAccuracy );
}
@ -827,12 +830,9 @@ bool D_PAD::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) con
selRect.Append( VECTOR2I( arect.GetRight(), arect.GetBottom() ) );
selRect.Append( VECTOR2I( arect.GetLeft(), arect.GetBottom() ) );
SHAPE_POLY_SET padPoly;
TransformShapeWithClearanceToPolygon( padPoly, aAccuracy );
selRect.BooleanIntersection( *GetEffectivePolygon(), SHAPE_POLY_SET::PM_FAST );
selRect.BooleanIntersection( padPoly, SHAPE_POLY_SET::PM_FAST );
double padArea = padPoly.Outline( 0 ).Area();
double padArea = GetEffectivePolygon()->Outline( 0 ).Area();
double intersection = selRect.Outline( 0 ).Area();
if( intersection > ( padArea * 0.99 ) )

View File

@ -397,6 +397,8 @@ public:
*/
const std::vector<std::shared_ptr<SHAPE>>& GetEffectiveShapes() const;
const std::shared_ptr<SHAPE_POLY_SET>& GetEffectivePolygon() const;
/**
* Function GetEffectiveHoleShape
* Returns a list of SHAPE objects representing the pad's hole.
@ -611,12 +613,6 @@ public:
private:
/**
* Function calcBoundingRadius
* returns a calculated radius of a bounding circle for this pad.
*/
int calcBoundingRadius() const;
void addPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError ) const;
private:
@ -639,6 +635,7 @@ private:
mutable EDA_RECT m_effectiveBoundingBox;
mutable std::vector<std::shared_ptr<SHAPE>> m_effectiveShapes;
mutable std::shared_ptr<SHAPE_SEGMENT> m_effectiveHoleShape;
mutable std::shared_ptr<SHAPE_POLY_SET> m_effectivePolygon;
/*
* How to build the custom shape in zone, to create the clearance area:

View File

@ -684,8 +684,8 @@ void CN_VISITOR::checkZoneZoneConnection( CN_ZONE* aZoneA, CN_ZONE* aZoneB )
bool CN_VISITOR::operator()( CN_ITEM* aCandidate )
{
const auto parentA = aCandidate->Parent();
const auto parentB = m_item->Parent();
const BOARD_CONNECTED_ITEM* parentA = aCandidate->Parent();
const BOARD_CONNECTED_ITEM* parentB = m_item->Parent();
if( !aCandidate->Valid() || !m_item->Valid() )
return true;

View File

@ -66,6 +66,12 @@ const VECTOR2I CN_ITEM::GetAnchor( int n ) const
switch( pad->GetShape() )
{
case PAD_SHAPE_TRAPEZOID:
// Because the trap delta is applied as +1/2 at one end and -1/2 at the other,
// the midpoint is actually unchanged. Therefore all the cardinal points are
// the same as for a rectangle.
KI_FALLTHROUGH;
case PAD_SHAPE_RECT:
case PAD_SHAPE_CIRCLE:
case PAD_SHAPE_OVAL:
@ -89,7 +95,6 @@ const VECTOR2I CN_ITEM::GetAnchor( int n ) const
return pt1;
case PAD_SHAPE_TRAPEZOID:
case PAD_SHAPE_CUSTOM:
{
switch( n )
@ -104,9 +109,8 @@ const VECTOR2I CN_ITEM::GetAnchor( int n ) const
if( pad->GetOrientation() )
RotatePoint( pt1, pad->ShapePos(), pad->GetOrientation() );
SHAPE_POLY_SET padPolySet;
pad->TransformShapeWithClearanceToPolygon( padPolySet, 0, ARC_LOW_DEF );
const SHAPE_LINE_CHAIN& padOutline = padPolySet.COutline( 0 );
const std::shared_ptr<SHAPE_POLY_SET>& padPolySet = pad->GetEffectivePolygon();
const SHAPE_LINE_CHAIN& padOutline = padPolySet->COutline( 0 );
SHAPE_LINE_CHAIN::INTERSECTIONS intersections;
padOutline.Intersect( SEG( pt0, pt1 ), intersections );

View File

@ -227,8 +227,7 @@ bool DRC_KEEPOUT_TESTER::checkPads( MODULE* aModule )
if( ( m_keepoutFlags & DISALLOW_PADS ) > 0 )
{
SHAPE_POLY_SET outline;
pad->TransformShapeWithClearanceToPolygon( outline, 0 );
SHAPE_POLY_SET outline = *pad->GetEffectivePolygon();
// Build the common area between pad and the keepout area:
outline.BooleanIntersection( *m_zone->Outline(), SHAPE_POLY_SET::PM_FAST );

View File

@ -132,7 +132,7 @@ LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
//printf("item %p get enum: '%s'\n", item , (const char*) str.c_str() );
}
return LIBEVAL::VALUE( (const char*) str.c_str() );
return LIBEVAL::VALUE( str );
}
}
}

View File

@ -239,15 +239,14 @@ void BRDITEMS_PLOTTER::PlotPad( D_PAD* aPad, COLOR4D aColor, EDA_DRAW_MODE_T aPl
case PAD_SHAPE_CHAMFERED_RECT:
case PAD_SHAPE_CUSTOM:
{
SHAPE_POLY_SET polygons;
aPad->TransformShapeWithClearanceToPolygon( polygons, 0 );
const std::shared_ptr<SHAPE_POLY_SET>& polygons = aPad->GetEffectivePolygon();
if( polygons.OutlineCount() == 0 )
break;
m_plotter->FlashPadCustom( shape_pos, aPad->GetSize(), &polygons, aPlotMode,
if( polygons->OutlineCount() )
{
m_plotter->FlashPadCustom( shape_pos, aPad->GetSize(), polygons.get(), aPlotMode,
&gbr_metadata );
}
}
break;
}
}

View File

@ -634,12 +634,10 @@ std::unique_ptr<PNS::SOLID> PNS_KICAD_IFACE_BASE::syncPad( D_PAD* aPad )
// JEY TODO:
// TOM TODO: move to SHAPE_COMPOUND...
SHAPE_POLY_SET outline;
aPad->TransformShapeWithClearanceToPolygon( outline, 0 );
const std::shared_ptr<SHAPE_POLY_SET>& outline = aPad->GetEffectivePolygon();
SHAPE_SIMPLE* shape = new SHAPE_SIMPLE();
for( auto iter = outline.CIterate( 0 ); iter; iter++ )
for( auto iter = outline->CIterate( 0 ); iter; iter++ )
shape->Append( *iter );
solid->SetShape( shape );

View File

@ -296,9 +296,7 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* a
if( !rect_area.Collide( SEG( shape_pos, shape_pos ), bb_radius ) )
continue;
SHAPE_POLY_SET padOutline;
pad->TransformShapeWithClearanceToPolygon( padOutline, 0 );
const std::shared_ptr<SHAPE_POLY_SET>& padOutline = pad->GetEffectivePolygon();
OPT<SEG> minSeg;
SEG::ecoord center2center_squared = 0;

View File

@ -47,7 +47,7 @@ bool testEvalExpr( const std::string expr, LIBEVAL::VALUE expectedResult, bool e
if( expectedResult.GetType() == LIBEVAL::VT_NUMERIC )
printf("result: %s (got %.10f expected: %.10f)\n", ok ? "OK" : "FAIL", result.AsDouble(), expectedResult.AsDouble() );
else
printf("result: %s (got '%s' expected: '%s')\n", ok ? "OK" : "FAIL", result.AsString().c_str(), expectedResult.AsString().c_str() );
printf("result: %s (got '%s' expected: '%s')\n", ok ? "OK" : "FAIL", result.AsChars(), expectedResult.AsChars() );
if (!ok )
{