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<FOOTPRINT*, int> componentShapes;
 static std::map<int, wxString> 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<int>( padref->GetShape() ) -
-          static_cast<int>( padcmp->GetShape() ) ) != 0 )
+    if( ( diff = static_cast<int>( aPadRef->GetShape() ) -
+          static_cast<int>( aPadCmp->GetShape() ) ) != 0 )
         return diff;
 
-    if( ( diff = padref->GetDrillShape() - padcmp->GetDrillShape() ) != 0)
+    if( ( diff = static_cast<int>( aPadRef->m_attribute ) -
+          static_cast<int>( 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<int>( aPadRef->m_editPrimitives.size() ) -
+          static_cast<int>( 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
     {