From 06f206104d0268cb97e730d8c7005f6216b8038c Mon Sep 17 00:00:00 2001 From: Wayne Stambaugh Date: Wed, 24 Nov 2021 12:52:17 -0500 Subject: [PATCH] Pcbnew: fix chamfered rectangular pad definitions in GenCAD exporter. The pad comparison function was never updated when chamfered rectangular and custom pads were added so if more that one variant of either of those pad types existed in a design, only the first one would get generated and assign to every pad of that type. The custom pad primitive comparison has not be implemented so the exported designs may be broken for custom pads. --- pcbnew/exporters/export_gencad.cpp | 41 ++++++++++++------------ pcbnew/pad.cpp | 51 ++++++++++++++++++++---------- pcbnew/pad.h | 2 +- 3 files changed, 56 insertions(+), 38 deletions(-) diff --git a/pcbnew/exporters/export_gencad.cpp b/pcbnew/exporters/export_gencad.cpp index 0884e29aec..d9f588f410 100644 --- a/pcbnew/exporters/export_gencad.cpp +++ b/pcbnew/exporters/export_gencad.cpp @@ -63,8 +63,8 @@ static void CreateShapesSection( FILE* aFile, BOARD* aPcb ); static void CreatePadsShapesSection( FILE* aFile, BOARD* aPcb ); static void FootprintWriteShape( FILE* File, FOOTPRINT* aFootprint, const wxString& aShapeName ); -// layer names for Gencad export +// layer names for Gencad export static std::string GenCADLayerName( int aCuCount, PCB_LAYER_ID aId ) { if( IsCopperLayer( aId ) ) @@ -179,6 +179,7 @@ static std::string fmt_mask( LSET aSet ) return StrPrintf( "%08x", (unsigned) ( aSet & LSET::AllCuMask() ).to_ulong() ); } + // Export options static bool flipBottomPads; static bool uniquePins; @@ -192,6 +193,7 @@ static int GencadOffsetX, GencadOffsetY; static std::map componentShapes; static std::map shapeNames; + static const wxString getShapeName( FOOTPRINT* aFootprint ) { static const wxString invalid( "invalid" ); @@ -208,9 +210,11 @@ static const wxString getShapeName( FOOTPRINT* aFootprint ) return itName->second; } + // GerbTool chokes on units different than INCH so this is the conversion factor const static double SCALE_FACTOR = 1000.0 * IU_PER_MILS; + /* Two helper functions to calculate coordinates of footprints in gencad values * (GenCAD Y axis from bottom to top) */ @@ -398,7 +402,6 @@ static void CreatePadsShapesSection( FILE* aFile, BOARD* aPcb ) vias.end() ); // Emit vias pads - for( PCB_VIA* via : vias ) { viastacks.push_back( via ); @@ -420,8 +423,10 @@ static void CreatePadsShapesSection( FILE* aFile, BOARD* aPcb ) pad->SetSubRatsnest( pad_name_number ); + // @warning: This code is not 100% correct. The #PAD::Compare function does not test + // custom pad primitives so there may be duplicate custom pads in the export. if( old_pad && 0 == PAD::Compare( old_pad, pad ) ) - continue; // already created + continue; old_pad = pad; @@ -443,6 +448,7 @@ static void CreatePadsShapesSection( FILE* aFile, BOARD* aPcb ) case PAD_SHAPE::CIRCLE: fprintf( aFile, " ROUND %g\n", pad->GetDrillSize().x / SCALE_FACTOR ); + /* Circle is center, radius */ fprintf( aFile, "CIRCLE %g %g %g\n", off.x / SCALE_FACTOR, @@ -582,21 +588,14 @@ static void CreatePadsShapesSection( FILE* aFile, BOARD* aPcb ) SHAPE_POLY_SET outline; int maxError = aPcb->GetDesignSettings().m_MaxError; + wxPoint padOffset( 0, 0 ); - TransformRoundChamferedRectToPolygon( outline, pad->GetPosition(), pad->GetSize(), - pad->GetOrientation(), pad->GetRoundRectCornerRadius(), - pad->GetChamferRectRatio(), pad->GetChamferPositions(), 0, maxError, - ERROR_INSIDE ); - - // The chamfered rectangle polygon code calculates the absolute board position so - // the footprint position has to be subtracted off polygon points to get the - // pad position relative to the footprint. - FOOTPRINT* parent = pad->GetParent(); - - wxPoint parentPos( 0, 0 ); - - if( parent ) - parentPos = parent->GetPosition(); + TransformRoundChamferedRectToPolygon( outline, padOffset, pad->GetSize(), + pad->GetOrientation(), + pad->GetRoundRectCornerRadius(), + pad->GetChamferRectRatio(), + pad->GetChamferPositions(), 0, maxError, + ERROR_INSIDE ); for( int jj = 0; jj < outline.OutlineCount(); ++jj ) { @@ -607,10 +606,10 @@ static void CreatePadsShapesSection( FILE* aFile, BOARD* aPcb ) { int next = ( ii + 1 ) % pointCount; fprintf( aFile, "LINE %g %g %g %g\n", - ( -parentPos.x + off.x + poly.CPoint( ii ).x ) / SCALE_FACTOR, - ( parentPos.y - off.y - poly.CPoint( ii ).y ) / SCALE_FACTOR, - ( -parentPos.x + off.x + poly.CPoint( next ).x ) / SCALE_FACTOR, - ( parentPos.y - off.y - poly.CPoint( next ).y ) / SCALE_FACTOR ); + poly.CPoint( ii ).x / SCALE_FACTOR, + -poly.CPoint( ii ).y / SCALE_FACTOR, + poly.CPoint( next ).x / SCALE_FACTOR, + -poly.CPoint( next ).y / SCALE_FACTOR ); } } diff --git a/pcbnew/pad.cpp b/pcbnew/pad.cpp index 27206eb622..079bf0d3f8 100644 --- a/pcbnew/pad.cpp +++ b/pcbnew/pad.cpp @@ -1032,48 +1032,67 @@ bool PAD::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const } -int PAD::Compare( const PAD* padref, const PAD* padcmp ) +int PAD::Compare( const PAD* aPadRef, const PAD* aPadCmp ) { int diff; - if( ( diff = static_cast( padref->GetShape() ) - - static_cast( padcmp->GetShape() ) ) != 0 ) + if( ( diff = static_cast( aPadRef->GetShape() ) - + static_cast( aPadCmp->GetShape() ) ) != 0 ) return diff; - if( ( diff = padref->GetDrillShape() - padcmp->GetDrillShape() ) != 0) + if( ( diff = static_cast( aPadRef->m_attribute ) - + static_cast( aPadCmp->m_attribute ) ) != 0 ) return diff; - if( ( diff = padref->m_drill.x - padcmp->m_drill.x ) != 0 ) + if( ( diff = aPadRef->m_drillShape - aPadCmp->m_drillShape ) != 0 ) return diff; - if( ( diff = padref->m_drill.y - padcmp->m_drill.y ) != 0 ) + if( ( diff = aPadRef->m_drill.x - aPadCmp->m_drill.x ) != 0 ) return diff; - if( ( diff = padref->m_size.x - padcmp->m_size.x ) != 0 ) + if( ( diff = aPadRef->m_drill.y - aPadCmp->m_drill.y ) != 0 ) return diff; - if( ( diff = padref->m_size.y - padcmp->m_size.y ) != 0 ) + if( ( diff = aPadRef->m_size.x - aPadCmp->m_size.x ) != 0 ) return diff; - if( ( diff = padref->m_offset.x - padcmp->m_offset.x ) != 0 ) + if( ( diff = aPadRef->m_size.y - aPadCmp->m_size.y ) != 0 ) return diff; - if( ( diff = padref->m_offset.y - padcmp->m_offset.y ) != 0 ) + if( ( diff = aPadRef->m_offset.x - aPadCmp->m_offset.x ) != 0 ) return diff; - if( ( diff = padref->m_deltaSize.x - padcmp->m_deltaSize.x ) != 0 ) + if( ( diff = aPadRef->m_offset.y - aPadCmp->m_offset.y ) != 0 ) return diff; - if( ( diff = padref->m_deltaSize.y - padcmp->m_deltaSize.y ) != 0 ) + if( ( diff = aPadRef->m_deltaSize.x - aPadCmp->m_deltaSize.x ) != 0 ) return diff; - // TODO: test custom shapes + if( ( diff = aPadRef->m_deltaSize.y - aPadCmp->m_deltaSize.y ) != 0 ) + return diff; + + if( ( diff = aPadRef->m_roundedCornerScale - aPadCmp->m_roundedCornerScale ) != 0 ) + return diff; + + if( ( diff = aPadRef->m_chamferPositions - aPadCmp->m_chamferPositions ) != 0 ) + return diff; + + if( ( diff = aPadRef->m_chamferScale - aPadCmp->m_chamferScale ) != 0 ) + return diff; + + if( ( diff = static_cast( aPadRef->m_editPrimitives.size() ) - + static_cast( aPadCmp->m_editPrimitives.size() ) ) != 0 ) + return diff; + + // @todo: Compare custom pad primitives for pads that have the same number of primitives + // here. Currently there is no compare function for PCB_SHAPE objects. // Dick: specctra_export needs this // Lorenzo: gencad also needs it to implement padstacks! #if __cplusplus >= 201103L - long long d = padref->m_layerMask.to_ullong() - padcmp->m_layerMask.to_ullong(); + long long d = aPadRef->m_layerMask.to_ullong() - aPadCmp->m_layerMask.to_ullong(); + if( d < 0 ) return -1; else if( d > 0 ) @@ -1082,8 +1101,8 @@ int PAD::Compare( const PAD* padref, const PAD* padcmp ) return 0; #else // these strings are not typically constructed, since we don't get here often. - std::string s1 = padref->m_layerMask.to_string(); - std::string s2 = padcmp->m_layerMask.to_string(); + std::string s1 = aPadRef->m_layerMask.to_string(); + std::string s2 = aPadCmp->m_layerMask.to_string(); return s1.compare( s2 ); #endif } diff --git a/pcbnew/pad.h b/pcbnew/pad.h index 7c8151ca17..252e8b9b46 100644 --- a/pcbnew/pad.h +++ b/pcbnew/pad.h @@ -612,7 +612,7 @@ public: * @return less than 0 if left less than right, 0 if equal, or greater than 0 if left * greater than right. */ - static int Compare( const PAD* padref, const PAD* padcmp ); + static int Compare( const PAD* aPadRef, const PAD* aPadCmp ); void Move( const wxPoint& aMoveVector ) override {