diff --git a/pcbnew/class_drawsegment.cpp b/pcbnew/class_drawsegment.cpp
index 38bef2b070..8c6a6951ba 100644
--- a/pcbnew/class_drawsegment.cpp
+++ b/pcbnew/class_drawsegment.cpp
@@ -79,9 +79,9 @@ void DRAWSEGMENT::Rotate( const wxPoint& aRotCentre, double aAngle )
         break;
 
     case S_POLYGON:
-        for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ )
+        for( auto iter = m_Poly.Iterate(); iter; iter++ )
         {
-            RotatePoint( &m_PolyPoints[ii], aRotCentre, aAngle);
+            RotatePoint( *iter, VECTOR2I(aRotCentre), aAngle);
         }
         break;
 
@@ -411,10 +411,12 @@ const EDA_RECT DRAWSEGMENT::GetBoundingBox() const
     {
         wxPoint p_end;
         MODULE* module = GetParentModule();
+        bool first = true;
 
-        for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ )
+        for( auto iter = m_Poly.CIterate(); iter; iter++ )
         {
-            wxPoint pt = m_PolyPoints[ii];
+            wxPoint pt ( iter->x, iter->y );
+
 
             if( module ) // Transform, if we belong to a module
             {
@@ -422,19 +424,27 @@ const EDA_RECT DRAWSEGMENT::GetBoundingBox() const
                 pt += module->GetPosition();
             }
 
-            if( ii == 0 )
+
+            if( first )
+            {
                 p_end = pt;
+                bbox.SetX( pt.x );
+                bbox.SetY( pt.y );
+                first = false;
+            }
+            else
+            {
 
-            bbox.SetX( std::min( bbox.GetX(), pt.x ) );
-            bbox.SetY( std::min( bbox.GetY(), pt.y ) );
-            p_end.x   = std::max( p_end.x, pt.x );
-            p_end.y   = std::max( p_end.y, pt.y );
+                bbox.SetX( std::min( bbox.GetX(), pt.x ) );
+                bbox.SetY( std::min( bbox.GetY(), pt.y ) );
+
+                p_end.x   = std::max( p_end.x, pt.x );
+                p_end.y   = std::max( p_end.y, pt.y );
+            }
         }
-
         bbox.SetEnd( p_end );
-    }
         break;
-
+	}
     default:
         break;
     }
@@ -508,6 +518,18 @@ bool DRAWSEGMENT::HitTest( const wxPoint& aPosition ) const
         break;
 
     case S_POLYGON:     // not yet handled
+        {
+            #define MAX_DIST_IN_MM 0.25
+            int distmax = Millimeter2iu( 0.25 );
+            SHAPE_POLY_SET::VERTEX_INDEX dummy;
+            auto poly = m_Poly;
+
+            if( poly.CollideVertex( VECTOR2I( aPosition ), dummy, distmax ) )
+                return true;
+
+            if( poly.CollideEdge( VECTOR2I( aPosition ), dummy, distmax ) )
+                return true;
+        }
         break;
 
     default:
@@ -710,3 +732,26 @@ void DRAWSEGMENT::computeArcBBox( EDA_RECT& aBBox ) const
         angle -= 900;
     }
 }
+
+void DRAWSEGMENT::SetPolyPoints( const std::vector<wxPoint>& aPoints )
+{
+    m_Poly.RemoveAllContours();
+    m_Poly.NewOutline();
+    
+    for ( auto p : aPoints )
+    {
+        m_Poly.Append( p.x, p.y );
+    }
+}
+
+const std::vector<wxPoint> DRAWSEGMENT::GetPolyPoints() const
+{
+    std::vector<wxPoint> rv;
+
+    for ( auto iter = m_Poly.CIterate(); iter; iter++ )
+    {
+        rv.push_back( wxPoint( iter->x, iter->y ) );
+    }
+
+    return rv;
+}
diff --git a/pcbnew/class_drawsegment.h b/pcbnew/class_drawsegment.h
index 4ea38f5417..35bb464641 100644
--- a/pcbnew/class_drawsegment.h
+++ b/pcbnew/class_drawsegment.h
@@ -36,6 +36,7 @@
 #include <trigo.h>
 #include <common.h>
 
+#include <geometry/shape_poly_set.h>
 
 class LINE_READER;
 class EDA_DRAW_FRAME;
@@ -57,7 +58,7 @@ protected:
     wxPoint     m_BezierC2;     ///< Bezier Control Point 2
 
     std::vector<wxPoint>    m_BezierPoints;
-    std::vector<wxPoint>    m_PolyPoints;
+    SHAPE_POLY_SET    m_Poly;
 
     // Computes the bounding box for an arc
     void computeArcBBox( EDA_RECT& aBBox ) const;
@@ -165,19 +166,18 @@ public:
 
     // Accessors:
     const std::vector<wxPoint>& GetBezierPoints() const { return m_BezierPoints; }
-    const std::vector<wxPoint>& GetPolyPoints() const   { return m_PolyPoints; }
-    // same accessor, to add/change corners of the polygon
-    std::vector<wxPoint>& GetPolyPoints()               { return m_PolyPoints; }
+
+    const std::vector<wxPoint> GetPolyPoints() const;
+    SHAPE_POLY_SET& GetPolyShape() { return m_Poly; }
+    const SHAPE_POLY_SET& GetPolyShape() const { return m_Poly; }
+    void SetPolyShape( const SHAPE_POLY_SET& aShape ) { m_Poly = aShape; }
 
     void SetBezierPoints( const std::vector<wxPoint>& aPoints )
     {
         m_BezierPoints = aPoints;
     }
 
-    void SetPolyPoints( const std::vector<wxPoint>& aPoints )
-    {
-        m_PolyPoints = aPoints;
-    }
+    void SetPolyPoints( const std::vector<wxPoint>& aPoints );
 
     void Draw( EDA_DRAW_PANEL* panel, wxDC* DC,
                GR_DRAWMODE aDrawMode, const wxPoint& aOffset = ZeroOffset ) override;
diff --git a/pcbnew/class_edge_mod.cpp b/pcbnew/class_edge_mod.cpp
index b79305ab1a..268b7c53c8 100644
--- a/pcbnew/class_edge_mod.cpp
+++ b/pcbnew/class_edge_mod.cpp
@@ -202,7 +202,12 @@ void EDGE_MODULE::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE draw_mode,
         {
         // We must compute absolute coordinates from m_PolyPoints
         // which are relative to module position, orientation 0
-        std::vector<wxPoint> points = m_PolyPoints;
+        std::vector<wxPoint> points;
+
+        for( auto iter = m_Poly.CIterate(); iter; iter++ )
+        {
+            points.push_back( wxPoint( iter->x,iter->y ) );
+        }
 
         for( unsigned ii = 0; ii < points.size(); ii++ )
         {
@@ -300,8 +305,11 @@ void EDGE_MODULE::Flip( const wxPoint& aCentre )
     case S_POLYGON:
         // polygon corners coordinates are always relative to the
         // footprint position, orientation 0
-        for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ )
-            MIRROR( m_PolyPoints[ii].y, 0 );
+        for( auto iter = m_Poly.Iterate(); iter; iter++ )
+        {
+            MIRROR( iter->y, 0 );
+        }
+	break;
     }
 
     // DRAWSEGMENT items are not usually on copper layers, but
@@ -338,12 +346,12 @@ void EDGE_MODULE::Mirror( wxPoint aCentre, bool aMirrorAroundXAxis )
     case S_POLYGON:
         // polygon corners coordinates are always relative to the
         // footprint position, orientation 0
-        for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ )
+        for( auto iter = m_Poly.Iterate(); iter; iter++ )
         {
             if( aMirrorAroundXAxis )
-                MIRROR( m_PolyPoints[ii].y, aCentre.y );
+                MIRROR( iter->y, aCentre.y );
             else
-                MIRROR( m_PolyPoints[ii].x, aCentre.x );
+                MIRROR( iter->x, aCentre.x );
         }
     }
 
@@ -378,8 +386,8 @@ void EDGE_MODULE::Move( const wxPoint& aMoveVector )
     case S_POLYGON:
         // polygon corners coordinates are always relative to the
         // footprint position, orientation 0
-        for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ )
-            m_PolyPoints[ii] += aMoveVector;
+        for( auto iter = m_Poly.Iterate(); iter; iter++ )
+            *iter += VECTOR2I( aMoveVector );
     }
 
     SetDrawCoord();
diff --git a/pcbnew/class_pad.h b/pcbnew/class_pad.h
index c1ac8b0c68..08fd95d45c 100644
--- a/pcbnew/class_pad.h
+++ b/pcbnew/class_pad.h
@@ -272,13 +272,16 @@ public:
      *   a filled circle or ring ( if thickness == 0, this is a filled circle, else a ring)
      *   a arc
      */
-    void AddPrimitive( std::vector<wxPoint>& aPoly, int aThickness );  ///< add a polygonal basic shape
+    void AddPrimitive( const SHAPE_POLY_SET& aPoly, int aThickness );  ///< add a polygonal basic shape
+    void AddPrimitive( const std::vector<wxPoint>& aPoly, int aThickness );  ///< add a polygonal basic shape
     void AddPrimitive( wxPoint aStart, wxPoint aEnd, int aThickness ); ///< segment basic shape
     void AddPrimitive( wxPoint aCenter, int aRadius, int aThickness ); ///< ring or circle basic shape
     void AddPrimitive( wxPoint aCenter, wxPoint aStart,
                         int aArcAngle, int aThickness );    ///< arc basic shape
 
 
+    bool GetBestAnchorPosition( VECTOR2I& aPos );
+
     /**
      * Merge all basic shapes, converted to a polygon in one polygon,
      * in m_customShapeAsPolygon
@@ -726,6 +729,9 @@ private:
      */
     int boundingRadius() const;
 
+    bool buildCustomPadPolygon( SHAPE_POLY_SET* aMergedPolygon,
+                                int aCircleToSegmentsCount );
+
 private:    // Private variable members:
 
     // Actually computed and cached on demand by the accessor
diff --git a/pcbnew/class_pad_custom_shape_functions.cpp b/pcbnew/class_pad_custom_shape_functions.cpp
index 25a4a58457..34e4779f45 100644
--- a/pcbnew/class_pad_custom_shape_functions.cpp
+++ b/pcbnew/class_pad_custom_shape_functions.cpp
@@ -66,7 +66,18 @@ void PAD_CS_PRIMITIVE::ExportTo( DRAWSEGMENT* aTarget )
  * add a free shape to the shape list.
  * the shape is a polygon (can be with thick outline), segment, circle or arc
  */
-void D_PAD::AddPrimitive( std::vector<wxPoint>& aPoly, int aThickness )
+
+void D_PAD::AddPrimitive( const SHAPE_POLY_SET& aPoly, int aThickness )
+{
+    std::vector<wxPoint> points;
+
+    for( auto iter = aPoly.CIterate(); iter; iter++ )
+        points.push_back( wxPoint( iter->x, iter->y ) );
+
+    AddPrimitive( points, aThickness );
+}
+
+void D_PAD::AddPrimitive( const std::vector<wxPoint>& aPoly, int aThickness )
 {
     PAD_CS_PRIMITIVE shape( S_POLYGON );
     shape.m_Poly = aPoly;
@@ -135,38 +146,10 @@ void D_PAD::DeletePrimitivesList()
 }
 
 
-/* Merge all basic shapes, converted to a polygon in one polygon,
- * return true if OK, false in there is more than one polygon
- * in aMergedPolygon
- */
-bool D_PAD::MergePrimitivesAsPolygon(  SHAPE_POLY_SET* aMergedPolygon,
-                                        int aCircleToSegmentsCount )
+bool D_PAD::buildCustomPadPolygon( SHAPE_POLY_SET* aMergedPolygon,
+                                   int aCircleToSegmentsCount )
+
 {
-    // if aMergedPolygon == NULL, use m_customShapeAsPolygon as target
-
-    if( !aMergedPolygon )
-        aMergedPolygon = &m_customShapeAsPolygon;
-
-    aMergedPolygon->RemoveAllContours();
-
-    // Add the anchor pad shape in aMergedPolygon, others in aux_polyset:
-    // The anchor pad is always at 0,0
-    switch( GetAnchorPadShape() )
-    {
-    default:
-    case PAD_SHAPE_CIRCLE:
-        TransformCircleToPolygon( *aMergedPolygon, wxPoint( 0,0 ), GetSize().x/2,
-                              aCircleToSegmentsCount );
-        break;
-
-    case PAD_SHAPE_RECT:
-        {
-        SHAPE_RECT rect( -GetSize().x/2, -GetSize().y/2, GetSize().x, GetSize().y );
-        aMergedPolygon->AddOutline( rect.Outline() );
-        }
-        break;
-    }
-
     SHAPE_POLY_SET aux_polyset;
 
     for( unsigned cnt = 0; cnt < m_basicShapes.size(); ++cnt )
@@ -212,7 +195,9 @@ bool D_PAD::MergePrimitivesAsPolygon(  SHAPE_POLY_SET* aMergedPolygon,
                 polyset.NewOutline();
 
                 for( unsigned ii = 0; ii < poly.size(); ii++ )
+                {
                     polyset.Append( poly[ii].x, poly[ii].y );
+                }
 
                 polyset.Inflate( bshape.m_Thickness/2, 32 );
 
@@ -230,13 +215,79 @@ bool D_PAD::MergePrimitivesAsPolygon(  SHAPE_POLY_SET* aMergedPolygon,
         }
     }
 
-    // Merge all polygons:
+    aux_polyset.Simplify( SHAPE_POLY_SET::PM_FAST );
+
+    // Merge all polygons, if more than one, pick the largest (area-wise)
     if( aux_polyset.OutlineCount() )
     {
+
+        if( aux_polyset.OutlineCount() >= 2)
+        {
+            int bestOutline = 0;
+            double maxArea = 0.0;
+
+            for( int i = 0; i < aux_polyset.OutlineCount(); i++ )
+            {
+                double area = aux_polyset.COutline(i).Area();
+
+                if ( area > maxArea )
+                {
+                    maxArea = area;
+                    bestOutline = i;
+                }
+            }
+
+            if( bestOutline != 0 )
+                aux_polyset.Polygon( 0 ) = aux_polyset.Polygon( bestOutline );
+
+            for (int i = 1; i < aux_polyset.OutlineCount(); i++ )
+            {
+                aux_polyset.DeletePolygon( i );
+            }
+        }
+
         aMergedPolygon->BooleanAdd( aux_polyset, SHAPE_POLY_SET::PM_FAST );
         aMergedPolygon->Fracture( SHAPE_POLY_SET::PM_FAST );
     }
 
+    return aMergedPolygon->OutlineCount() <= 1;
+}
+
+/* Merge all basic shapes, converted to a polygon in one polygon,
+ * return true if OK, false in there is more than one polygon
+ * in aMergedPolygon
+ */
+bool D_PAD::MergePrimitivesAsPolygon(  SHAPE_POLY_SET* aMergedPolygon,
+                                        int aCircleToSegmentsCount )
+{
+    // if aMergedPolygon == NULL, use m_customShapeAsPolygon as target
+
+    if( !aMergedPolygon )
+        aMergedPolygon = &m_customShapeAsPolygon;
+
+    aMergedPolygon->RemoveAllContours();
+
+    // Add the anchor pad shape in aMergedPolygon, others in aux_polyset:
+    // The anchor pad is always at 0,0
+    switch( GetAnchorPadShape() )
+    {
+    default:
+    case PAD_SHAPE_CIRCLE:
+        TransformCircleToPolygon( *aMergedPolygon, wxPoint( 0,0 ), GetSize().x/2,
+                              aCircleToSegmentsCount );
+        break;
+
+    case PAD_SHAPE_RECT:
+        {
+        SHAPE_RECT rect( -GetSize().x/2, -GetSize().y/2, GetSize().x, GetSize().y );
+        aMergedPolygon->AddOutline( rect.Outline() );
+        }
+        break;
+    }
+
+    if ( !buildCustomPadPolygon( aMergedPolygon, aCircleToSegmentsCount ) )
+        return false;
+
     m_boundingRadius = -1;  // The current bouding radius is no more valid.
 
     return aMergedPolygon->OutlineCount() <= 1;
@@ -265,3 +316,79 @@ void D_PAD::CustomShapeAsPolygonToBoardPosition( SHAPE_POLY_SET * aMergedPolygon
         }
     }
 }
+
+bool D_PAD::GetBestAnchorPosition( VECTOR2I& aPos )
+{
+    SHAPE_POLY_SET poly;
+
+    if ( !buildCustomPadPolygon( &poly, 16 ) )
+        return false;
+
+    const int minSteps = 10;
+    const int maxSteps = 50;
+
+    int stepsX, stepsY;
+
+    auto bbox = poly.BBox();
+
+    if( bbox.GetWidth() < bbox.GetHeight() )
+    {
+        stepsX = minSteps;
+        stepsY = minSteps * (double) bbox.GetHeight() / (double )(bbox.GetWidth() + 1);
+    }
+    else
+    {
+        stepsY = minSteps;
+        stepsX = minSteps * (double) bbox.GetWidth() / (double )(bbox.GetHeight() + 1);
+    }
+
+    stepsX = std::max(minSteps, std::min( maxSteps, stepsX ) );
+    stepsY = std::max(minSteps, std::min( maxSteps, stepsY ) );
+
+    auto center = bbox.Centre();
+
+    auto minDist = std::numeric_limits<int64_t>::max();
+    int64_t minDistEdge;
+
+    if( GetAnchorPadShape() == PAD_SHAPE_CIRCLE )
+    {
+        minDistEdge = GetSize().x;
+    }
+    else
+    {
+        minDistEdge = std::max( GetSize().x, GetSize().y );
+    }
+
+    boost::optional<VECTOR2I> bestAnchor;
+
+    for ( int y = 0; y < stepsY ; y++ )
+        for ( int x = 0; x < stepsX; x++ )
+        {
+            VECTOR2I p = bbox.GetPosition();
+            p.x += rescale( x, bbox.GetWidth(), (stepsX - 1) );
+            p.y += rescale( y, bbox.GetHeight(), (stepsY - 1) );
+
+            if ( poly.Contains(p) )
+            {
+
+                auto dist = (center - p).EuclideanNorm();
+                auto distEdge = poly.COutline(0).Distance( p, true );
+                if ( distEdge >= minDistEdge )
+                {
+                    if ( dist < minDist )
+                    {
+                        bestAnchor = p;
+                        minDist = dist;
+                    }
+                }
+            }
+        }
+
+        if ( bestAnchor )
+        {
+            aPos = *bestAnchor;
+            return true;
+        }
+
+        return false;
+}
diff --git a/pcbnew/dialogs/dialog_graphic_item_properties.cpp b/pcbnew/dialogs/dialog_graphic_item_properties.cpp
index 7452df69a4..8aa50a8cfa 100644
--- a/pcbnew/dialogs/dialog_graphic_item_properties.cpp
+++ b/pcbnew/dialogs/dialog_graphic_item_properties.cpp
@@ -312,6 +312,9 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::Validate()
 
         break;
 
+    case S_POLYGON:
+        break;
+
     default:
 
         // Check start and end are not the same.
diff --git a/pcbnew/dialogs/dialog_pad_properties.cpp b/pcbnew/dialogs/dialog_pad_properties.cpp
index 04e6bc46fd..65b32b7d69 100644
--- a/pcbnew/dialogs/dialog_pad_properties.cpp
+++ b/pcbnew/dialogs/dialog_pad_properties.cpp
@@ -329,7 +329,7 @@ void DIALOG_PAD_PROPERTIES::OnPaintShowPanel( wxPaintEvent& event )
 
         case S_POLYGON:         // polygon
         {
-            std::vector<wxPoint>& poly = dummySegment.GetPolyPoints();
+            std::vector<wxPoint> poly = dummySegment.GetPolyPoints();
             GRClosedPoly( NULL, &dc, poly.size(), &poly[0], /* filled */ true,
                           primitive.m_Thickness, hcolor, hcolor );
         }
@@ -1160,11 +1160,9 @@ void DIALOG_PAD_PROPERTIES::redraw()
 
             case S_POLYGON:         // polygon
             {
-                std::vector<wxPoint>& poly = dummySegment->GetPolyPoints();
-
-                for( unsigned ii = 0; ii < poly.size(); ii++ )
+                for( auto iter = dummySegment->GetPolyShape().Iterate(); iter; iter++ )
                 {
-                    poly[ii] += m_dummyPad->GetPosition();
+                    (*iter) += VECTOR2I( m_dummyPad->GetPosition() );
                 }
             }
                 break;
diff --git a/pcbnew/librairi.cpp b/pcbnew/librairi.cpp
index 298bdd58f8..549fc34c51 100644
--- a/pcbnew/librairi.cpp
+++ b/pcbnew/librairi.cpp
@@ -253,7 +253,7 @@ MODULE* try_load_footprint( const wxFileName& aFileName, IO_MGR::PCB_FILE_T aFil
 }
 
 
-MODULE* FOOTPRINT_EDIT_FRAME::Import_Module()
+MODULE* FOOTPRINT_EDIT_FRAME::Import_Module( const wxString& aName )
 {
     wxString        lastOpenedPathForLoading = m_mruPath;
     wxConfigBase*   config = Kiface().KifaceSettings();
@@ -261,7 +261,12 @@ MODULE* FOOTPRINT_EDIT_FRAME::Import_Module()
     if( config )
         config->Read( EXPORT_IMPORT_LASTPATH_KEY, &lastOpenedPathForLoading );
 
-    wxFileName fn = getFootprintFilenameFromUser( this, lastOpenedPathForLoading );
+    wxFileName fn;
+
+    if( aName != wxT("") )
+        fn = aName;
+    else
+        fn = getFootprintFilenameFromUser( this, lastOpenedPathForLoading );
 
     if( !fn.IsOk() )
         return NULL;
diff --git a/pcbnew/microwave.cpp b/pcbnew/microwave.cpp
index ed5c1faee2..0b2e62a124 100644
--- a/pcbnew/microwave.cpp
+++ b/pcbnew/microwave.cpp
@@ -634,7 +634,7 @@ MODULE* PCB_EDIT_FRAME::Create_MuWavePolygonShape()
     module->GraphicalItemsList().PushFront( edge );
 
     // Get the corner buffer of the polygonal edge
-    std::vector<wxPoint>& polyPoints = edge->GetPolyPoints();
+    std::vector<wxPoint> polyPoints;
     polyPoints.reserve( PolyEdges.size() + 2 );
 
     // Init start point coord:
@@ -670,6 +670,7 @@ MODULE* PCB_EDIT_FRAME::Create_MuWavePolygonShape()
         break;
     }
 
+    edge->SetPolyPoints( polyPoints );
     PolyEdges.clear();
     module->CalculateBoundingBox();
     GetBoard()->m_Status_Pcb = 0;
diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp
index f975950abc..bb6fe3f807 100644
--- a/pcbnew/tools/edit_tool.cpp
+++ b/pcbnew/tools/edit_tool.cpp
@@ -295,12 +295,13 @@ bool EDIT_TOOL::Init()
     menu.AddItem( PCB_ACTIONS::properties, SELECTION_CONDITIONS::Count( 1 )
                       || SELECTION_CONDITIONS::OnlyTypes( GENERAL_COLLECTOR::Tracks ) );
 
+
     menu.AddItem( PCB_ACTIONS::moveExact, SELECTION_CONDITIONS::NotEmpty );
     menu.AddItem( PCB_ACTIONS::positionRelative, SELECTION_CONDITIONS::NotEmpty );
     menu.AddItem( PCB_ACTIONS::duplicate, SELECTION_CONDITIONS::NotEmpty );
     menu.AddItem( PCB_ACTIONS::createArray, SELECTION_CONDITIONS::NotEmpty );
 
-    menu.AddSeparator();
+
     menu.AddItem( PCB_ACTIONS::copyToClipboard, SELECTION_CONDITIONS::NotEmpty );
     menu.AddItem( PCB_ACTIONS::cutToClipboard, SELECTION_CONDITIONS::NotEmpty );
     menu.AddItem( PCB_ACTIONS::pasteFromClipboard );
@@ -308,6 +309,8 @@ bool EDIT_TOOL::Init()
 
     // Mirror only available in modedit
     menu.AddItem( PCB_ACTIONS::mirror, editingModuleCondition && SELECTION_CONDITIONS::NotEmpty );
+    menu.AddItem( PCB_ACTIONS::createPadFromShapes, editingModuleCondition && SELECTION_CONDITIONS::NotEmpty );
+    menu.AddItem( PCB_ACTIONS::explodePadToShapes, editingModuleCondition && SELECTION_CONDITIONS::NotEmpty );
 
     // Footprint actions
     menu.AddItem( PCB_ACTIONS::editFootprintInFpEditor,
diff --git a/pcbnew/tools/module_editor_tools.cpp b/pcbnew/tools/module_editor_tools.cpp
index 37548cd9d3..31777ef61f 100644
--- a/pcbnew/tools/module_editor_tools.cpp
+++ b/pcbnew/tools/module_editor_tools.cpp
@@ -59,6 +59,14 @@ TOOL_ACTION PCB_ACTIONS::placePad( "pcbnew.ModuleEditor.placePad",
         AS_GLOBAL, 0,
         _( "Add Pad" ), _( "Add a pad" ), NULL, AF_ACTIVATE );
 
+TOOL_ACTION PCB_ACTIONS::createPadFromShapes( "pcbnew.ModuleEditor.createPadFromShapes",
+        AS_CONTEXT, 0,
+        _( "Create Pad from Selected Shapes" ), _( "Creates a custom-shaped pads from a set of selected shapes" ) );
+
+TOOL_ACTION PCB_ACTIONS::explodePadToShapes( "pcbnew.ModuleEditor.explodePadToShapes",
+        AS_CONTEXT, 0,
+        _( "Explode Selected Pad to Graphical Shapes" ), _( "Converts a custom-shaped pads to a set of graphical shapes" ) );
+
 TOOL_ACTION PCB_ACTIONS::enumeratePads( "pcbnew.ModuleEditor.enumeratePads",
         AS_GLOBAL, 0,
         _( "Enumerate Pads" ), _( "Enumerate pads" ), pad_enumerate_xpm, AF_ACTIVATE );
@@ -321,10 +329,209 @@ int MODULE_EDITOR_TOOLS::ModuleEdgeOutlines( const TOOL_EVENT& aEvent )
     return 0;
 }
 
+int MODULE_EDITOR_TOOLS::ExplodePadToShapes( const TOOL_EVENT& aEvent )
+{
+    SELECTION& selection = m_toolMgr->GetTool<SELECTION_TOOL>()->GetSelection();
+    BOARD_COMMIT commit( frame() );
+
+    if( selection.Size() != 1 )
+        return 0;
+
+    if( selection[0]->Type() != PCB_PAD_T )
+        return 0;
+
+    auto pad = static_cast<D_PAD*>( selection[0] );
+
+    if( pad->GetShape() != PAD_SHAPE_CUSTOM )
+        return 0;
+
+    commit.Modify( pad );
+
+    wxPoint anchor = pad->GetPosition();
+
+    for( auto prim : pad->GetPrimitives() )
+    {
+        auto ds = new EDGE_MODULE( board()->m_Modules );
+
+        ds->SetLayer( pad->GetLayer() );
+        ds->SetShape( prim.m_Shape );
+        ds->SetStart( prim.m_Start + anchor );
+        ds->SetEnd( prim.m_End + anchor );
+        ds->SetWidth( prim.m_Thickness );
+
+        for( auto&p : prim.m_Poly )
+            p += anchor;
+
+        ds->SetPolyPoints( prim.m_Poly );
+        ds->SetAngle( prim.m_ArcAngle );
+
+        commit.Add( ds );
+    }
+
+    pad->SetShape( pad->GetAnchorPadShape() );
+    commit.Push( _("Explode pad to shapes") );
+
+    m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
+
+    return 0;
+}
+
+
+int MODULE_EDITOR_TOOLS::CreatePadFromShapes( const TOOL_EVENT& aEvent )
+{
+    SELECTION& selection = m_toolMgr->GetTool<SELECTION_TOOL>()->GetSelection();
+
+    std::unique_ptr<D_PAD> pad ( new D_PAD ( board()->m_Modules ) );
+    D_PAD *refPad = nullptr;
+    bool multipleRefPadsFound = false;
+    bool illegalItemsFound = false;
+
+    std::vector<PAD_CS_PRIMITIVE> shapes;
+
+    BOARD_COMMIT commit( frame() );
+
+    for( auto item : selection )
+    {
+        switch( item->Type() )
+        {
+            case PCB_PAD_T:
+            {
+                if( refPad )
+                    multipleRefPadsFound = true;
+
+                refPad = static_cast<D_PAD*>( item );
+                break;
+            }
+
+            case PCB_MODULE_EDGE_T:
+            {
+                auto em = static_cast<EDGE_MODULE*> ( item );
+
+                PAD_CS_PRIMITIVE shape( em->GetShape() );
+                shape.m_Start = em->GetStart();
+                shape.m_End = em->GetEnd();
+                shape.m_Radius = em->GetRadius();
+                shape.m_Thickness = em->GetWidth();
+                shape.m_ArcAngle = em->GetAngle();
+
+                for ( auto p : em->GetPolyPoints() )
+                    shape.m_Poly.push_back(p);
+
+                shapes.push_back(shape);
+
+                break;
+            }
+
+            default:
+            {
+                illegalItemsFound = true;
+                break;
+            }
+        }
+    }
+
+    if( refPad && selection.Size() == 1 )
+    {
+        // don't convert a pad into itself...
+        return 0;
+    }
+
+    if( multipleRefPadsFound )
+    {
+        DisplayErrorMessage( frame(), _("Cannot convert items to a custom-shaped pad: selection contains more than one reference pad. ") );
+        return 0;
+    }
+
+    if( illegalItemsFound )
+    {
+        DisplayErrorMessage( frame(), _("Cannot convert items to a custom-shaped pad: selection contains unsupported items. Only graphical lines, circles, arcs and polygons are allowed.") );
+        return 0;
+    }
+
+    if( refPad )
+    {
+        pad.reset( static_cast<D_PAD*>( refPad->Clone() ) );
+    }
+    else
+    {
+        pad->SetAnchorPadShape( PAD_SHAPE_CIRCLE );
+        pad->SetAttribute( PAD_ATTRIB_SMD );
+        pad->SetLayerSet( D_PAD::SMDMask() );
+        pad->SetSize ( wxSize( 10000, 10000 ) );
+        pad->IncrementPadName( true, true );
+    }
+
+
+    pad->SetPrimitives( shapes );
+    pad->SetShape ( PAD_SHAPE_CUSTOM );
+
+    boost::optional<VECTOR2I> anchor;
+    VECTOR2I tmp;
+
+    if( refPad )
+    {
+        anchor = pad->GetPosition();
+    }
+    else if( pad->GetBestAnchorPosition( tmp ) )
+    {
+        anchor = tmp;
+    }
+
+    if( !anchor )
+    {
+        DisplayErrorMessage( frame(), _("Cannot convert items to a custom-shaped pad: unable to determine the anchor point position. Consider adding a small anchor pad to the selection and try again.") );
+        return 0;
+    }
+
+
+    // relocate the shapes, they are relative to the anchor pad position
+    for( auto& shape : shapes )
+    {
+        shape.m_Start.x -= anchor->x;
+        shape.m_Start.y -= anchor->y;
+        shape.m_End.x -= anchor->x;
+        shape.m_End.y -= anchor->y;
+
+        for( auto&p : shape.m_Poly )
+        {
+            p.x -= anchor->x;
+            p.y -= anchor->y;
+        }
+    }
+
+
+    pad->SetPosition( wxPoint( anchor->x, anchor->y ) );
+    pad->SetPrimitives( shapes );
+
+    bool result = pad->MergePrimitivesAsPolygon();
+
+    if( !result )
+    {
+        DisplayErrorMessage( frame(), _("Cannot convert items to a custom-shaped pad: selected items do not form a single solid shape.") );
+        return 0;
+    }
+
+    auto padPtr = pad.release();
+
+    commit.Add( padPtr );
+    for ( auto item : selection )
+    {
+        commit.Remove( item );
+    }
+
+    m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
+    m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, padPtr );
+
+    commit.Push(_("Create Pad From Selected Shapes") );
+
+    return 0;
+}
 
 void MODULE_EDITOR_TOOLS::setTransitions()
 {
     Go( &MODULE_EDITOR_TOOLS::PlacePad,            PCB_ACTIONS::placePad.MakeEvent() );
+    Go( &MODULE_EDITOR_TOOLS::CreatePadFromShapes, PCB_ACTIONS::createPadFromShapes.MakeEvent() );
+    Go( &MODULE_EDITOR_TOOLS::ExplodePadToShapes,  PCB_ACTIONS::explodePadToShapes.MakeEvent() );
     Go( &MODULE_EDITOR_TOOLS::EnumeratePads,       PCB_ACTIONS::enumeratePads.MakeEvent() );
     Go( &MODULE_EDITOR_TOOLS::ModuleTextOutlines,  PCB_ACTIONS::moduleTextOutlines.MakeEvent() );
     Go( &MODULE_EDITOR_TOOLS::ModuleEdgeOutlines,  PCB_ACTIONS::moduleEdgeOutlines.MakeEvent() );
diff --git a/pcbnew/tools/module_editor_tools.h b/pcbnew/tools/module_editor_tools.h
index 37ba71a66c..3524fc1935 100644
--- a/pcbnew/tools/module_editor_tools.h
+++ b/pcbnew/tools/module_editor_tools.h
@@ -82,6 +82,21 @@ public:
      */
     int ModuleEdgeOutlines( const TOOL_EVENT& aEvent );
 
+    /**
+     * Function CreatePadFromShapes()
+     *
+     * Creates a custom-shaped pad from a set of selected graphical shapes
+     */
+    int CreatePadFromShapes( const TOOL_EVENT& aEvent );
+
+    /**
+     * Function ExplodePadToShapes()
+     *
+     * Breaks apart a complex-shaped part into a set of graphical shapes
+     */
+    int ExplodePadToShapes( const TOOL_EVENT& aEvent );
+
+
     ///> Sets up handlers for various events.
     void setTransitions() override;
 
diff --git a/pcbnew/tools/pad_tool.cpp b/pcbnew/tools/pad_tool.cpp
index 7c67095449..e240c02666 100644
--- a/pcbnew/tools/pad_tool.cpp
+++ b/pcbnew/tools/pad_tool.cpp
@@ -80,6 +80,7 @@ public:
         Add( PCB_ACTIONS::applyPadSettings );
         Add( PCB_ACTIONS::pushPadSettings );
 
+
         // show modedit-specific items
         if( m_editingFootprint )
         {