From 067533928b9a74ea34517238098a5b743da28597 Mon Sep 17 00:00:00 2001 From: Jon Evans Date: Sun, 8 Mar 2026 23:56:30 -0400 Subject: [PATCH] Reduce memory usage of EDA_SHAPE pt 2 --- common/eda_shape.cpp | 130 ++++++++++++++++++++++--------------- eeschema/sch_rule_area.cpp | 2 +- eeschema/sch_shape.cpp | 12 ++-- include/eda_shape.h | 15 ++--- pcbnew/pcb_shape.cpp | 4 +- pcbnew/pcb_textbox.cpp | 2 +- 6 files changed, 93 insertions(+), 72 deletions(-) diff --git a/common/eda_shape.cpp b/common/eda_shape.cpp index f945d44919..44ddb0e3cb 100644 --- a/common/eda_shape.cpp +++ b/common/eda_shape.cpp @@ -107,8 +107,8 @@ EDA_SHAPE::EDA_SHAPE( const SHAPE& aShape ) : { auto line = static_cast( aShape ); m_shape = SHAPE_T::POLY; - m_poly = SHAPE_POLY_SET(); - m_poly.AddOutline( line ); + GetPolyShape() = SHAPE_POLY_SET(); + GetPolyShape().AddOutline( line ); SetWidth( line.Width() ); break; } @@ -135,7 +135,7 @@ EDA_SHAPE::EDA_SHAPE( const SHAPE& aShape ) : { auto poly = static_cast( aShape ); m_shape = SHAPE_T::POLY; - poly.TransformToPolygon( m_poly, 0, ERROR_INSIDE ); + poly.TransformToPolygon( GetPolyShape(), 0, ERROR_INSIDE ); break; } @@ -168,10 +168,11 @@ EDA_SHAPE::EDA_SHAPE( const EDA_SHAPE& aOther ) : m_bezierC1( aOther.m_bezierC1 ), m_bezierC2( aOther.m_bezierC2 ), m_bezierPoints( aOther.m_bezierPoints ), - m_poly( aOther.m_poly ), m_editState( aOther.m_editState ), m_proxyItem( aOther.m_proxyItem ) { + if( aOther.m_poly ) + m_poly = std::make_unique( *aOther.m_poly ); } @@ -197,7 +198,10 @@ EDA_SHAPE& EDA_SHAPE::operator=( const EDA_SHAPE& aOther ) m_bezierC1 = aOther.m_bezierC1; m_bezierC2 = aOther.m_bezierC2; m_bezierPoints = aOther.m_bezierPoints; - m_poly = aOther.m_poly; + if( aOther.m_poly ) + m_poly = std::make_unique( *aOther.m_poly ); + else + m_poly.reset(); m_editState = aOther.m_editState; m_proxyItem = aOther.m_proxyItem; @@ -429,7 +433,7 @@ VECTOR2I EDA_SHAPE::getPosition() const if( m_shape == SHAPE_T::ARC ) return getCenter(); else if( m_shape == SHAPE_T::POLY ) - return m_poly.CVertex( 0 ); + return GetPolyShape().CVertex( 0 ); else return m_start; } @@ -451,8 +455,8 @@ double EDA_SHAPE::GetLength() const return GetStart().Distance( GetEnd() ); case SHAPE_T::POLY: - for( int ii = 0; ii < m_poly.COutline( 0 ).SegmentCount(); ii++ ) - length += m_poly.COutline( 0 ).CSegment( ii ).Length(); + for( int ii = 0; ii < GetPolyShape().COutline( 0 ).SegmentCount(); ii++ ) + length += GetPolyShape().COutline( 0 ).CSegment( ii ).Length(); return length; @@ -575,10 +579,10 @@ bool EDA_SHAPE::IsClosed() const return false; case SHAPE_T::POLY: - if( m_poly.IsEmpty() ) + if( GetPolyShape().IsEmpty() ) return false; else - return m_poly.Outline( 0 ).IsClosed(); + return GetPolyShape().Outline( 0 ).IsClosed(); case SHAPE_T::BEZIER: if( m_bezierPoints.size() < 3 ) @@ -710,7 +714,7 @@ void EDA_SHAPE::UpdateHatching() const if( !IsClosed() ) return; - shapeBuffer = m_poly.CloneDropTriangulation(); + shapeBuffer = GetPolyShape().CloneDropTriangulation(); break; default: @@ -834,7 +838,7 @@ void EDA_SHAPE::move( const VECTOR2I& aMoveVector ) break; case SHAPE_T::POLY: - m_poly.Move( aMoveVector ); + GetPolyShape().Move( aMoveVector ); break; case SHAPE_T::BEZIER: @@ -883,9 +887,9 @@ void EDA_SHAPE::scale( double aScale ) { std::vector pts; - for( int ii = 0; ii < m_poly.OutlineCount(); ++ ii ) + for( int ii = 0; ii < GetPolyShape().OutlineCount(); ++ ii ) { - for( const VECTOR2I& pt : m_poly.Outline( ii ).CPoints() ) + for( const VECTOR2I& pt : GetPolyShape().Outline( ii ).CPoints() ) { pts.emplace_back( pt ); scalePt( pts.back() ); @@ -944,14 +948,14 @@ void EDA_SHAPE::rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) // Convert non-cardinally-rotated rect to a diamond ROUNDRECT rr( SHAPE_RECT( GetStart(), GetRectangleWidth(), GetRectangleHeight() ), m_cornerRadius ); m_shape = SHAPE_T::POLY; - rr.TransformToPolygon( m_poly, getMaxError() ); - m_poly.Rotate( aAngle, aRotCentre ); + rr.TransformToPolygon( GetPolyShape(), getMaxError() ); + GetPolyShape().Rotate( aAngle, aRotCentre ); } break; case SHAPE_T::POLY: - m_poly.Rotate( aAngle, aRotCentre ); + GetPolyShape().Rotate( aAngle, aRotCentre ); break; case SHAPE_T::BEZIER: @@ -998,7 +1002,7 @@ void EDA_SHAPE::flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection ) break; case SHAPE_T::POLY: - m_poly.Mirror( aCentre, aFlipDirection ); + GetPolyShape().Mirror( aCentre, aFlipDirection ); break; case SHAPE_T::BEZIER: @@ -1347,10 +1351,10 @@ const BOX2I EDA_SHAPE::getBoundingBox() const break; case SHAPE_T::POLY: - if( m_poly.IsEmpty() ) + if( GetPolyShape().IsEmpty() ) break; - for( auto iter = m_poly.CIterate(); iter; iter++ ) + for( auto iter = GetPolyShape().CIterate(); iter; iter++ ) bbox.Merge( *iter ); break; @@ -1504,26 +1508,26 @@ bool EDA_SHAPE::hitTest( const VECTOR2I& aPosition, int aAccuracy ) const return false; case SHAPE_T::POLY: - if( m_poly.OutlineCount() < 1 ) // empty poly + if( GetPolyShape().OutlineCount() < 1 ) // empty poly return false; if( IsFilledForHitTesting() ) { - if( !m_poly.COutline( 0 ).IsClosed() ) + if( !GetPolyShape().COutline( 0 ).IsClosed() ) { // Only one outline is expected - SHAPE_LINE_CHAIN copy( m_poly.COutline( 0 ) ); + SHAPE_LINE_CHAIN copy( GetPolyShape().COutline( 0 ) ); copy.SetClosed( true ); return copy.Collide( aPosition, maxdist ); } else { - return m_poly.Collide( aPosition, maxdist ); + return GetPolyShape().Collide( aPosition, maxdist ); } } else { - if( m_poly.CollideEdge( aPosition, nullptr, maxdist ) ) + if( GetPolyShape().CollideEdge( aPosition, nullptr, maxdist ) ) return true; if( IsHatchedFill() && GetHatching().Collide( aPosition, maxdist ) ) @@ -1677,9 +1681,9 @@ bool EDA_SHAPE::hitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) co // Account for the width of the line arect.Inflate( GetWidth() / 2 ); - for( int ii = 0; ii < m_poly.OutlineCount(); ++ii ) + for( int ii = 0; ii < GetPolyShape().OutlineCount(); ++ii ) { - if( checkOutline( m_poly.Outline( ii ) ) ) + if( checkOutline( GetPolyShape().Outline( ii ) ) ) return true; } @@ -1925,11 +1929,11 @@ void EDA_SHAPE::computeArcBBox( BOX2I& aBBox ) const void EDA_SHAPE::SetPolyPoints( const std::vector& aPoints ) { - m_poly.RemoveAllContours(); - m_poly.NewOutline(); + GetPolyShape().RemoveAllContours(); + GetPolyShape().NewOutline(); for( const VECTOR2I& p : aPoints ) - m_poly.Append( p.x, p.y ); + GetPolyShape().Append( p.x, p.y ); } @@ -2073,9 +2077,9 @@ std::vector EDA_SHAPE::GetPolyPoints() const { std::vector points; - for( int ii = 0; ii < m_poly.OutlineCount(); ++ii ) + for( int ii = 0; ii < GetPolyShape().OutlineCount(); ++ii ) { - const SHAPE_LINE_CHAIN& outline = m_poly.COutline( ii ); + const SHAPE_LINE_CHAIN& outline = GetPolyShape().COutline( ii ); int pointCount = outline.PointCount(); if( pointCount ) @@ -2091,6 +2095,23 @@ std::vector EDA_SHAPE::GetPolyPoints() const } +SHAPE_POLY_SET& EDA_SHAPE::GetPolyShape() +{ + if( !m_poly ) + m_poly = std::make_unique(); + + return *m_poly; +} + +const SHAPE_POLY_SET& EDA_SHAPE::GetPolyShape() const +{ + if( !m_poly ) + m_poly = std::make_unique(); + + return *m_poly; +} + + bool EDA_SHAPE::IsPolyShapeValid() const { // return true if the polygonal shape is valid (has more than 2 points) @@ -2133,12 +2154,12 @@ void EDA_SHAPE::beginEdit( const VECTOR2I& aPosition ) break; case SHAPE_T::POLY: - m_poly.NewOutline(); - m_poly.Outline( 0 ).SetClosed( false ); + GetPolyShape().NewOutline(); + GetPolyShape().Outline( 0 ).SetClosed( false ); // Start and end of the first segment (co-located for now) - m_poly.Outline( 0 ).Append( aPosition ); - m_poly.Outline( 0 ).Append( aPosition, true ); + GetPolyShape().Outline( 0 ).Append( aPosition ); + GetPolyShape().Outline( 0 ).Append( aPosition, true ); break; default: @@ -2166,7 +2187,7 @@ bool EDA_SHAPE::continueEdit( const VECTOR2I& aPosition ) case SHAPE_T::POLY: { - SHAPE_LINE_CHAIN& poly = m_poly.Outline( 0 ); + SHAPE_LINE_CHAIN& poly = GetPolyShape().Outline( 0 ); // do not add zero-length segments if( poly.CPoint( (int) poly.GetPointCount() - 2 ) != poly.CLastPoint() ) @@ -2334,7 +2355,8 @@ void EDA_SHAPE::calcEdit( const VECTOR2I& aPosition ) } case SHAPE_T::POLY: - m_poly.Outline( 0 ).SetPoint( m_poly.Outline( 0 ).GetPointCount() - 1, aPosition ); + GetPolyShape().Outline( 0 ).SetPoint( GetPolyShape().Outline( 0 ).GetPointCount() - 1, + aPosition ); break; default: @@ -2356,7 +2378,7 @@ void EDA_SHAPE::endEdit( bool aClosed ) case SHAPE_T::POLY: { - SHAPE_LINE_CHAIN& poly = m_poly.Outline( 0 ); + SHAPE_LINE_CHAIN& poly = GetPolyShape().Outline( 0 ); // do not include last point twice if( poly.GetPointCount() > 2 ) @@ -2435,14 +2457,14 @@ int EDA_SHAPE::Compare( const EDA_SHAPE* aOther ) const } else if( m_shape == SHAPE_T::POLY ) { - TEST( m_poly.TotalVertices(), aOther->m_poly.TotalVertices() ); + TEST( GetPolyShape().TotalVertices(), aOther->GetPolyShape().TotalVertices() ); } for( size_t ii = 0; ii < m_bezierPoints.size(); ++ii ) TEST_PT( m_bezierPoints[ii], aOther->m_bezierPoints[ii] ); - for( int ii = 0; ii < m_poly.TotalVertices(); ++ii ) - TEST_PT( m_poly.CVertex( ii ), aOther->m_poly.CVertex( ii ) ); + for( int ii = 0; ii < GetPolyShape().TotalVertices(); ++ii ) + TEST_PT( GetPolyShape().CVertex( ii ), aOther->GetPolyShape().CVertex( ii ) ); TEST_E( m_stroke.GetWidth(), aOther->m_stroke.GetWidth() ); TEST( (int) m_stroke.GetLineStyle(), (int) aOther->m_stroke.GetLineStyle() ); @@ -2543,9 +2565,9 @@ void EDA_SHAPE::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, int aClearance if( solidFill ) { - for( int ii = 0; ii < m_poly.OutlineCount(); ++ii ) + for( int ii = 0; ii < GetPolyShape().OutlineCount(); ++ii ) { - const SHAPE_LINE_CHAIN& poly = m_poly.Outline( ii ); + const SHAPE_LINE_CHAIN& poly = GetPolyShape().Outline( ii ); SHAPE_POLY_SET tmp; tmp.NewOutline(); @@ -2567,9 +2589,9 @@ void EDA_SHAPE::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, int aClearance } else { - for( int ii = 0; ii < m_poly.OutlineCount(); ++ii ) + for( int ii = 0; ii < GetPolyShape().OutlineCount(); ++ii ) { - const SHAPE_LINE_CHAIN& poly = m_poly.Outline( ii ); + const SHAPE_LINE_CHAIN& poly = GetPolyShape().Outline( ii ); for( int jj = 0; jj < (int) poly.SegmentCount(); ++jj ) { @@ -2665,9 +2687,9 @@ bool EDA_SHAPE::operator==( const EDA_SHAPE& aOther ) const if( m_bezierPoints != aOther.m_bezierPoints ) return false; - for( int ii = 0; ii < m_poly.TotalVertices(); ++ii ) + for( int ii = 0; ii < GetPolyShape().TotalVertices(); ++ii ) { - if( m_poly.CVertex( ii ) != aOther.m_poly.CVertex( ii ) ) + if( GetPolyShape().CVertex( ii ) != aOther.GetPolyShape().CVertex( ii ) ) return false; } @@ -2719,8 +2741,8 @@ double EDA_SHAPE::Similarity( const EDA_SHAPE& aOther ) const } { - int m = m_poly.TotalVertices(); - int n = aOther.m_poly.TotalVertices(); + int m = GetPolyShape().TotalVertices(); + int n = aOther.GetPolyShape().TotalVertices(); std::vector poly; std::vector otherPoly; VECTOR2I lastPt( 0, 0 ); @@ -2732,16 +2754,16 @@ double EDA_SHAPE::Similarity( const EDA_SHAPE& aOther ) const // will not be a match but the rest of the sequence will. for( int ii = 0; ii < m; ++ii ) { - poly.emplace_back( lastPt - m_poly.CVertex( ii ) ); - lastPt = m_poly.CVertex( ii ); + poly.emplace_back( lastPt - GetPolyShape().CVertex( ii ) ); + lastPt = GetPolyShape().CVertex( ii ); } lastPt = VECTOR2I( 0, 0 ); for( int ii = 0; ii < n; ++ii ) { - otherPoly.emplace_back( lastPt - aOther.m_poly.CVertex( ii ) ); - lastPt = aOther.m_poly.CVertex( ii ); + otherPoly.emplace_back( lastPt - aOther.GetPolyShape().CVertex( ii ) ); + lastPt = aOther.GetPolyShape().CVertex( ii ); } size_t longest = alg::longest_common_subset( poly, otherPoly ); diff --git a/eeschema/sch_rule_area.cpp b/eeschema/sch_rule_area.cpp index f4a791e23c..1a80d6a1ce 100644 --- a/eeschema/sch_rule_area.cpp +++ b/eeschema/sch_rule_area.cpp @@ -131,7 +131,7 @@ void SCH_RULE_AREA::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OP ptList.clear(); - const std::vector& polyPoints = m_poly.Outline( 0 ).CPoints(); + const std::vector& polyPoints = GetPolyShape().Outline( 0 ).CPoints(); for( const VECTOR2I& pt : polyPoints ) ptList.push_back( pt ); diff --git a/eeschema/sch_shape.cpp b/eeschema/sch_shape.cpp index b760052c58..6ad57754ae 100644 --- a/eeschema/sch_shape.cpp +++ b/eeschema/sch_shape.cpp @@ -214,7 +214,7 @@ void SCH_SHAPE::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& { ptList.clear(); - for( const VECTOR2I& pt : m_poly.Outline( 0 ).CPoints() ) + for( const VECTOR2I& pt : GetPolyShape().Outline( 0 ).CPoints() ) ptList.push_back( renderSettings->TransformCoordinate( pt ) + aOffset ); } else if( GetShape() == SHAPE_T::BEZIER ) @@ -399,7 +399,7 @@ wxString SCH_SHAPE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFu case SHAPE_T::POLY: return wxString::Format( _( "Polyline, %d points" ), - int( m_poly.Outline( 0 ).GetPointCount() ) ); + int( GetPolyShape().Outline( 0 ).GetPointCount() ) ); case SHAPE_T::BEZIER: return wxString::Format( _( "Bezier Curve, %d points" ), @@ -458,13 +458,13 @@ void SCH_SHAPE::AddPoint( const VECTOR2I& aPosition ) { if( GetShape() == SHAPE_T::POLY ) { - if( m_poly.IsEmpty() ) + if( GetPolyShape().IsEmpty() ) { - m_poly.NewOutline(); - m_poly.Outline( 0 ).SetClosed( false ); + GetPolyShape().NewOutline(); + GetPolyShape().Outline( 0 ).SetClosed( false ); } - m_poly.Outline( 0 ).Append( aPosition, true ); + GetPolyShape().Outline( 0 ).Append( aPosition, true ); } else { diff --git a/include/eda_shape.h b/include/eda_shape.h index b222774ff6..9e08a6b648 100644 --- a/include/eda_shape.h +++ b/include/eda_shape.h @@ -345,9 +345,8 @@ public: */ int GetPointCount() const; - // Accessors to the polygonal shape - SHAPE_POLY_SET& GetPolyShape() { return m_poly; } - const SHAPE_POLY_SET& GetPolyShape() const { return m_poly; } + SHAPE_POLY_SET& GetPolyShape(); + const SHAPE_POLY_SET& GetPolyShape() const; /** * @return true if the polygonal shape is valid (has more than 2 points). @@ -356,13 +355,13 @@ public: void SetPolyShape( const SHAPE_POLY_SET& aShape ) { - m_poly = aShape; + GetPolyShape() = aShape; - for( int ii = 0; ii < m_poly.OutlineCount(); ++ii ) + for( int ii = 0; ii < GetPolyShape().OutlineCount(); ++ii ) { - if( m_poly.HoleCount( ii ) ) + if( GetPolyShape().HoleCount( ii ) ) { - m_poly.Fracture(); + GetPolyShape().Fracture(); break; } } @@ -534,7 +533,7 @@ protected: VECTOR2I m_bezierC2; // Bezier Control Point 2 std::vector m_bezierPoints; - SHAPE_POLY_SET m_poly; // Stores the S_POLYGON shape + mutable std::unique_ptr m_poly; // Stores the S_POLYGON shape int m_editState; bool m_proxyItem; // A shape storing proxy information (ie: a pad diff --git a/pcbnew/pcb_shape.cpp b/pcbnew/pcb_shape.cpp index 9506253052..d2f570c0fd 100644 --- a/pcbnew/pcb_shape.cpp +++ b/pcbnew/pcb_shape.cpp @@ -515,9 +515,9 @@ void PCB_SHAPE::Normalize() }; // Convert a poly back to a rectangle if appropriate - if( m_poly.OutlineCount() == 1 && m_poly.Outline( 0 ).SegmentCount() == 4 ) + if( GetPolyShape().OutlineCount() == 1 && GetPolyShape().Outline( 0 ).SegmentCount() == 4 ) { - SHAPE_LINE_CHAIN& outline = m_poly.Outline( 0 ); + SHAPE_LINE_CHAIN& outline = GetPolyShape().Outline( 0 ); if( horizontal( outline.Segment( 0 ) ) && vertical( outline.Segment( 1 ) ) diff --git a/pcbnew/pcb_textbox.cpp b/pcbnew/pcb_textbox.cpp index 777ee2af57..e03519dd7b 100644 --- a/pcbnew/pcb_textbox.cpp +++ b/pcbnew/pcb_textbox.cpp @@ -743,7 +743,7 @@ void PCB_TEXTBOX::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID { aBuffer.NewOutline(); - const SHAPE_LINE_CHAIN& poly = m_poly.Outline( 0 ); + const SHAPE_LINE_CHAIN& poly = GetPolyShape().Outline( 0 ); for( int ii = 0; ii < poly.PointCount(); ++ii ) aBuffer.Append( poly.GetPoint( ii ) );