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 // For other shapes, add outlines as thick segments in polygon buffer
SHAPE_POLY_SET corners; const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon();
aPad->TransformShapeWithClearanceToPolygon( corners, 0 ); const SHAPE_LINE_CHAIN& path = corners->COutline( 0 );
const SHAPE_LINE_CHAIN& path = corners.COutline( 0 );
for( int j = 0; j < path.PointCount(); j++ ) 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 // For other shapes, add outlines as thick segments in polygon buffer
SHAPE_POLY_SET corners; const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon();
aPad->TransformShapeWithClearanceToPolygon( corners, 0 ); const SHAPE_LINE_CHAIN& path = corners->COutline( 0 );
const SHAPE_LINE_CHAIN& path = corners.COutline( 0 );
for( int ii = 0; ii < path.PointCount(); ++ii ) 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 ) else if( val->GetType() == VT_NUMERIC )
snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "PUSH NUM [%.10f]", val->AsDouble() ); snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "PUSH NUM [%.10f]", val->AsDouble() );
else 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; break;

View File

@ -23,8 +23,8 @@
#include <cstddef> #include <cstddef>
#include <functional> #include <functional>
#include <map>
#include <string> #include <string>
#include <stack>
#include <base_units.h> #include <base_units.h>
@ -175,10 +175,10 @@ public:
m_valueDbl( 0 ) m_valueDbl( 0 )
{}; {};
VALUE( std::string aStr ) : VALUE( const wxString& aStr ) :
m_type( VT_STRING ), m_type( VT_STRING ),
m_valueDbl( 0 ), m_valueDbl( 0 ),
m_valueStr( std::move( aStr ) ) m_valueStr( aStr )
{}; {};
VALUE( const double aVal ) : VALUE( const double aVal ) :
@ -191,11 +191,16 @@ public:
return m_valueDbl; return m_valueDbl;
} }
const std::string& AsString() const const wxString& AsString() const
{ {
return m_valueStr; return m_valueStr;
} }
const char* AsChars() const
{
return m_valueStr.ToStdString().c_str();
}
bool operator==( const VALUE& b ) const bool operator==( const VALUE& b ) const
{ {
if( m_type == VT_NUMERIC && b.m_type == VT_NUMERIC ) if( m_type == VT_NUMERIC && b.m_type == VT_NUMERIC )
@ -214,7 +219,7 @@ public:
m_valueDbl = aValue; m_valueDbl = aValue;
} }
void Set( const std::string& aValue ) void Set( const wxString& aValue )
{ {
m_type = VT_STRING; m_type = VT_STRING;
m_valueStr = aValue; m_valueStr = aValue;
@ -237,7 +242,7 @@ public:
private: private:
VAR_TYPE_T m_type; VAR_TYPE_T m_type;
double m_valueDbl; double m_valueDbl;
std::string m_valueStr; wxString m_valueStr;
}; };
@ -256,47 +261,42 @@ public:
class CONTEXT class CONTEXT
{ {
public: public:
const int c_memSize = 128; ~CONTEXT()
CONTEXT()
{ {
m_sp = 0; for( VALUE* value : m_ownedValues )
delete value;
for( int i = 0; i < c_memSize; i++ )
m_heap.emplace_back( VALUE() );
} }
VALUE* AllocValue() VALUE* AllocValue()
{ {
assert( m_memPos < c_memSize ); VALUE* value = new VALUE();
auto rv = &m_heap[ m_memPos++ ]; m_ownedValues.push_back( value );
return rv; return value;
} }
void Push( VALUE* v ) void Push( VALUE* v )
{ {
m_stack[m_sp++] = v; m_stack.push( v );
} }
VALUE* Pop() VALUE* Pop()
{ {
m_sp--; VALUE* value = m_stack.top();
return m_stack[m_sp]; m_stack.pop();
return value;
} }
int SP() const int SP() const
{ {
return m_sp; return m_stack.size();
} }
ERROR_STATUS GetErrorStatus() const { return m_errorStatus; } ERROR_STATUS GetErrorStatus() const { return m_errorStatus; }
void ReportError( const wxString& aErrorMsg ); void ReportError( const wxString& aErrorMsg );
private: private:
std::vector<VALUE> m_heap; std::vector<VALUE*> m_ownedValues;
VALUE* m_stack[128]; std::stack<VALUE*> m_stack;
int m_sp = 0;
int m_memPos = 0;
ERROR_STATUS m_errorStatus; ERROR_STATUS m_errorStatus;
}; };
@ -467,9 +467,9 @@ protected:
return uop; 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; 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 int D_PAD::GetRoundRectCornerRadius() const
{ {
return KiROUND( std::min( m_Size.x, m_Size.y ) * m_roundedCornerScale ); 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 const SHAPE_SEGMENT* D_PAD::GetEffectiveHoleShape() const
{ {
if( m_shapesDirty ) 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 // 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 // reset the bbox to uninitialized state to prepare for merging
m_effectiveBoundingBox = EDA_RECT(); m_effectiveBoundingBox = EDA_RECT();
@ -798,10 +804,7 @@ bool D_PAD::HitTest( const wxPoint& aPosition, int aAccuracy ) const
if( delta.SquaredEuclideanNorm() > SEG::Square( boundingRadius ) ) if( delta.SquaredEuclideanNorm() > SEG::Square( boundingRadius ) )
return false; return false;
SHAPE_POLY_SET polySet; return GetEffectivePolygon()->Contains( aPosition, -1, aAccuracy );
TransformShapeWithClearanceToPolygon( polySet, aAccuracy );
return polySet.Contains( aPosition );
} }
@ -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.GetRight(), arect.GetBottom() ) );
selRect.Append( VECTOR2I( arect.GetLeft(), arect.GetBottom() ) ); selRect.Append( VECTOR2I( arect.GetLeft(), arect.GetBottom() ) );
SHAPE_POLY_SET padPoly; selRect.BooleanIntersection( *GetEffectivePolygon(), SHAPE_POLY_SET::PM_FAST );
TransformShapeWithClearanceToPolygon( padPoly, aAccuracy );
selRect.BooleanIntersection( padPoly, SHAPE_POLY_SET::PM_FAST ); double padArea = GetEffectivePolygon()->Outline( 0 ).Area();
double padArea = padPoly.Outline( 0 ).Area();
double intersection = selRect.Outline( 0 ).Area(); double intersection = selRect.Outline( 0 ).Area();
if( intersection > ( padArea * 0.99 ) ) if( intersection > ( padArea * 0.99 ) )

View File

@ -397,6 +397,8 @@ public:
*/ */
const std::vector<std::shared_ptr<SHAPE>>& GetEffectiveShapes() const; const std::vector<std::shared_ptr<SHAPE>>& GetEffectiveShapes() const;
const std::shared_ptr<SHAPE_POLY_SET>& GetEffectivePolygon() const;
/** /**
* Function GetEffectiveHoleShape * Function GetEffectiveHoleShape
* Returns a list of SHAPE objects representing the pad's hole. * Returns a list of SHAPE objects representing the pad's hole.
@ -611,12 +613,6 @@ public:
private: 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; void addPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError ) const;
private: private:
@ -639,6 +635,7 @@ private:
mutable EDA_RECT m_effectiveBoundingBox; mutable EDA_RECT m_effectiveBoundingBox;
mutable std::vector<std::shared_ptr<SHAPE>> m_effectiveShapes; mutable std::vector<std::shared_ptr<SHAPE>> m_effectiveShapes;
mutable std::shared_ptr<SHAPE_SEGMENT> m_effectiveHoleShape; 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: * 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 ) bool CN_VISITOR::operator()( CN_ITEM* aCandidate )
{ {
const auto parentA = aCandidate->Parent(); const BOARD_CONNECTED_ITEM* parentA = aCandidate->Parent();
const auto parentB = m_item->Parent(); const BOARD_CONNECTED_ITEM* parentB = m_item->Parent();
if( !aCandidate->Valid() || !m_item->Valid() ) if( !aCandidate->Valid() || !m_item->Valid() )
return true; return true;

View File

@ -66,6 +66,12 @@ const VECTOR2I CN_ITEM::GetAnchor( int n ) const
switch( pad->GetShape() ) 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_RECT:
case PAD_SHAPE_CIRCLE: case PAD_SHAPE_CIRCLE:
case PAD_SHAPE_OVAL: case PAD_SHAPE_OVAL:
@ -89,7 +95,6 @@ const VECTOR2I CN_ITEM::GetAnchor( int n ) const
return pt1; return pt1;
case PAD_SHAPE_TRAPEZOID:
case PAD_SHAPE_CUSTOM: case PAD_SHAPE_CUSTOM:
{ {
switch( n ) switch( n )
@ -104,9 +109,8 @@ const VECTOR2I CN_ITEM::GetAnchor( int n ) const
if( pad->GetOrientation() ) if( pad->GetOrientation() )
RotatePoint( pt1, pad->ShapePos(), pad->GetOrientation() ); RotatePoint( pt1, pad->ShapePos(), pad->GetOrientation() );
SHAPE_POLY_SET padPolySet; const std::shared_ptr<SHAPE_POLY_SET>& padPolySet = pad->GetEffectivePolygon();
pad->TransformShapeWithClearanceToPolygon( padPolySet, 0, ARC_LOW_DEF ); const SHAPE_LINE_CHAIN& padOutline = padPolySet->COutline( 0 );
const SHAPE_LINE_CHAIN& padOutline = padPolySet.COutline( 0 );
SHAPE_LINE_CHAIN::INTERSECTIONS intersections; SHAPE_LINE_CHAIN::INTERSECTIONS intersections;
padOutline.Intersect( SEG( pt0, pt1 ), 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 ) if( ( m_keepoutFlags & DISALLOW_PADS ) > 0 )
{ {
SHAPE_POLY_SET outline; SHAPE_POLY_SET outline = *pad->GetEffectivePolygon();
pad->TransformShapeWithClearanceToPolygon( outline, 0 );
// Build the common area between pad and the keepout area: // Build the common area between pad and the keepout area:
outline.BooleanIntersection( *m_zone->Outline(), SHAPE_POLY_SET::PM_FAST ); 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() ); //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_CHAMFERED_RECT:
case PAD_SHAPE_CUSTOM: case PAD_SHAPE_CUSTOM:
{ {
SHAPE_POLY_SET polygons; const std::shared_ptr<SHAPE_POLY_SET>& polygons = aPad->GetEffectivePolygon();
aPad->TransformShapeWithClearanceToPolygon( polygons, 0 );
if( polygons.OutlineCount() == 0 ) if( polygons->OutlineCount() )
break; {
m_plotter->FlashPadCustom( shape_pos, aPad->GetSize(), polygons.get(), aPlotMode,
m_plotter->FlashPadCustom( shape_pos, aPad->GetSize(), &polygons, aPlotMode,
&gbr_metadata ); &gbr_metadata );
} }
}
break; break;
} }
} }

View File

@ -634,12 +634,10 @@ std::unique_ptr<PNS::SOLID> PNS_KICAD_IFACE_BASE::syncPad( D_PAD* aPad )
// JEY TODO: // JEY TODO:
// TOM TODO: move to SHAPE_COMPOUND... // TOM TODO: move to SHAPE_COMPOUND...
SHAPE_POLY_SET outline; const std::shared_ptr<SHAPE_POLY_SET>& outline = aPad->GetEffectivePolygon();
aPad->TransformShapeWithClearanceToPolygon( outline, 0 );
SHAPE_SIMPLE* shape = new SHAPE_SIMPLE(); 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 ); shape->Append( *iter );
solid->SetShape( shape ); 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 ) ) if( !rect_area.Collide( SEG( shape_pos, shape_pos ), bb_radius ) )
continue; continue;
SHAPE_POLY_SET padOutline; const std::shared_ptr<SHAPE_POLY_SET>& padOutline = pad->GetEffectivePolygon();
pad->TransformShapeWithClearanceToPolygon( padOutline, 0 );
OPT<SEG> minSeg; OPT<SEG> minSeg;
SEG::ecoord center2center_squared = 0; 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 ) if( expectedResult.GetType() == LIBEVAL::VT_NUMERIC )
printf("result: %s (got %.10f expected: %.10f)\n", ok ? "OK" : "FAIL", result.AsDouble(), expectedResult.AsDouble() ); printf("result: %s (got %.10f expected: %.10f)\n", ok ? "OK" : "FAIL", result.AsDouble(), expectedResult.AsDouble() );
else 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 ) if (!ok )
{ {