← Back to team overview

kicad-developers team mailing list archive

[PATCH] Better SHAPE_CONVEX for the PNS router

 

Hi everybody,

below is an improved patch to add a SHAPE_CONVEX for the PNS router. The
patch was generated against revision 5508.

In this version nice tight octagonal "hulls" are created for convex
polygons. I think it should work for arbitrary convex polygons (as long
as the requested distance between polygon and hull is larger than about
20) - but this probably just means I overlooked some corner case.

A trace snaking around some pads each arbitrarily rotated looks quite
weird... ;-)

I also think I figured out the "breakouts" stuff. This works nicely for
pads rotated by 45 degrees, but looks weird if the pad is rotated e.g.
by 30 degrees.

Finally I fixed a small bug in SHAPE_LINE_CHAIN, which ignored the
parameter aClearance when computing a bounding box.


Enjoy,

MGri


=== modified file 'common/geometry/shape_collisions.cpp'
--- common/geometry/shape_collisions.cpp	2015-03-09 10:06:54 +0000
+++ common/geometry/shape_collisions.cpp	2015-03-12 19:44:01 +0000
@@ -30,6 +30,7 @@
 #include <geometry/shape_circle.h>
 #include <geometry/shape_rect.h>
 #include <geometry/shape_segment.h>
+#include <geometry/shape_convex.h>
 
 typedef VECTOR2I::extended_type ecoord;
 
@@ -165,6 +166,32 @@
 }
 
 
+static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_CONVEX& aB, int aClearance,
+                            bool aNeedMTV, VECTOR2I& aMTV )
+{
+    bool found;
+    const SHAPE_LINE_CHAIN& lc( aB.Vertices() );
+
+    found = lc.Distance( aA.GetCenter() ) <= aClearance + aA.GetRadius();
+
+    if( !aNeedMTV || !found )
+        return found;
+
+    SHAPE_CIRCLE cmoved( aA );
+    VECTOR2I f_total( 0, 0 );
+
+    for( int s = 0; s < lc.SegmentCount(); s++ )
+    {
+        VECTOR2I f = pushoutForce( cmoved, lc.CSegment( s ), aClearance );
+        cmoved.SetCenter( cmoved.GetCenter() + f );
+        f_total += f;
+    }
+
+    aMTV = f_total;
+    return found;
+}
+
+
 static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_SEGMENT& aSeg, int aClearance,
                             bool aNeedMTV, VECTOR2I& aMTV )
 {
@@ -189,6 +216,20 @@
 }
 
 
+static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_CONVEX& aB, int aClearance,
+                            bool aNeedMTV, VECTOR2I& aMTV )
+{
+    return Collide( aA, aB.Vertices(), aClearance, aNeedMTV, aMTV );
+}
+
+
+static inline bool Collide( const SHAPE_CONVEX& aA, const SHAPE_CONVEX& aB, int aClearance,
+                            bool aNeedMTV, VECTOR2I& aMTV )
+{
+    return Collide( aA.Vertices(), aB.Vertices(), aClearance, aNeedMTV, aMTV );
+}
+
+
 static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
                             bool aNeedMTV, VECTOR2I& aMTV )
 {
@@ -204,6 +245,13 @@
 }
 
 
+static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_CONVEX& aB, int aClearance,
+                            bool aNeedMTV, VECTOR2I& aMTV )
+{
+    return Collide( aA, aB.Vertices(), aClearance, aNeedMTV, aMTV );
+}
+
+
 static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_SEGMENT& aSeg, int aClearance,
                             bool aNeedMTV, VECTOR2I& aMTV )
 {
@@ -228,6 +276,13 @@
 }
 
 
+static inline bool Collide( const SHAPE_CONVEX& aA, const SHAPE_SEGMENT& aB, int aClearance,
+                            bool aNeedMTV, VECTOR2I& aMTV )
+{
+    return Collide( aA.Vertices(), aB, aClearance, aNeedMTV, aMTV );
+}
+
+
 template<class ShapeAType, class ShapeBType>
 inline bool CollCase( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeedMTV, VECTOR2I& aMTV )
 {
@@ -264,6 +319,9 @@
                 case SH_SEGMENT:
                     return CollCase<SHAPE_RECT, SHAPE_SEGMENT>( aA, aB, aClearance, aNeedMTV, aMTV );
 
+                case SH_CONVEX:
+                    return CollCase<SHAPE_RECT, SHAPE_CONVEX>( aA, aB, aClearance, aNeedMTV, aMTV );
+                    
                 default:
                     break;
             }
@@ -283,6 +341,9 @@
                 case SH_SEGMENT:
                     return CollCase<SHAPE_CIRCLE, SHAPE_SEGMENT>( aA, aB, aClearance, aNeedMTV, aMTV );
 
+                case SH_CONVEX:
+                    return CollCase<SHAPE_CIRCLE, SHAPE_CONVEX>( aA, aB, aClearance, aNeedMTV, aMTV );
+                    
                 default:
                     break;
             }
@@ -302,6 +363,9 @@
                 case SH_SEGMENT:
                     return CollCase<SHAPE_LINE_CHAIN, SHAPE_SEGMENT>( aA, aB, aClearance, aNeedMTV, aMTV );
 
+                case SH_CONVEX:
+                    return CollCase<SHAPE_LINE_CHAIN, SHAPE_CONVEX>( aA, aB, aClearance, aNeedMTV, aMTV );
+                    
                 default:
                     break;
             }
@@ -321,10 +385,35 @@
                 case SH_SEGMENT:
                     return CollCase<SHAPE_SEGMENT, SHAPE_SEGMENT>( aA, aB, aClearance, aNeedMTV, aMTV );
 
-                default:
-                    break;
-            }
-
+                case SH_CONVEX:
+                    return CollCase<SHAPE_CONVEX, SHAPE_SEGMENT>( aB, aA, aClearance, aNeedMTV, aMTV );
+                    
+                default:
+                    break;
+            }
+
+        case SH_CONVEX:
+            switch( aB->Type() )
+            {
+                case SH_RECT:
+                    return CollCase<SHAPE_RECT, SHAPE_CONVEX>( aB, aA, aClearance, aNeedMTV, aMTV );
+
+                case SH_CIRCLE:
+                    return CollCase<SHAPE_CIRCLE, SHAPE_CONVEX>( aB, aA, aClearance, aNeedMTV, aMTV );
+
+                case SH_LINE_CHAIN:
+                    return CollCase<SHAPE_LINE_CHAIN, SHAPE_CONVEX>( aB, aA, aClearance, aNeedMTV, aMTV );
+
+                case SH_SEGMENT:
+                    return CollCase<SHAPE_CONVEX, SHAPE_SEGMENT>( aA, aB, aClearance, aNeedMTV, aMTV );
+
+                case SH_CONVEX:
+                    return CollCase<SHAPE_CONVEX, SHAPE_CONVEX>( aA, aB, aClearance, aNeedMTV, aMTV );
+                    
+                default:
+                    break;
+            }
+            
         default:
             break;
     }

=== modified file 'common/geometry/shape_line_chain.cpp'
--- common/geometry/shape_line_chain.cpp	2015-03-06 14:26:47 +0000
+++ common/geometry/shape_line_chain.cpp	2015-03-12 19:44:01 +0000
@@ -499,6 +499,26 @@
 }
 
 
+const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const SEG& aSeg, int& dist ) const
+{
+    int nearest = 0;
+
+    dist = INT_MAX;
+    for( int i = 0; i < PointCount(); i++ )
+    {
+        int d = aSeg.LineDistance( CPoint( i ) );
+
+        if( d < dist )
+        {
+            dist = d;
+            nearest = i;
+        }
+    }
+
+    return CPoint( nearest );
+}
+
+
 const std::string SHAPE_LINE_CHAIN::Format() const
 {
     std::stringstream ss;

=== added file 'include/geometry/shape_convex.h'
--- include/geometry/shape_convex.h	1970-01-01 00:00:00 +0000
+++ include/geometry/shape_convex.h	2015-03-12 21:13:00 +0000
@@ -0,0 +1,189 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2015 Kicad Developers, see change_log.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#ifndef __SHAPE_CONVEX_H
+#define __SHAPE_CONVEX_H
+
+#include <vector>
+
+#include <geometry/shape.h>
+#include <geometry/seg.h>
+#include <geometry/shape_line_chain.h>
+
+/**
+ * Class SHAPE_CONVEX
+ *
+ * Represents a convex polygon consisting of a zero-thickness closed chain of
+ * connected line segments.
+ *
+ * Internally the vertices are held in a SHAPE_LINE_CHAIN, please note that
+ * there is a "virtual" line segment between the last and first vertex.
+ */
+class SHAPE_CONVEX : public SHAPE
+{
+public:
+    /**
+     * Constructor
+     * Creates an empty polygon
+     */
+    SHAPE_CONVEX() :
+        SHAPE( SH_CONVEX )
+    {
+        m_points.SetClosed( true );
+    }
+
+    SHAPE_CONVEX( const SHAPE_CONVEX& aOther ) :
+	    SHAPE( SH_CONVEX ), m_points( aOther.m_points )
+    {}
+
+    SHAPE* Clone() const
+    {
+        return new SHAPE_CONVEX( *this );
+    }
+
+    /**
+     * Function Clear()
+     * Removes all points from the polygon.
+     */
+    void Clear()
+    {
+        m_points.Clear();
+    }
+
+    /// @copydoc SHAPE::BBox()
+    const BOX2I BBox( int aClearance = 0 ) const
+    {
+        return m_points.BBox( aClearance );
+    }
+
+    /**
+     * Function PointCount()
+     *
+     * Returns the number of points (vertices) in this polygon
+     * @return number of points
+     */
+    int PointCount() const
+    {
+        return m_points.PointCount();
+    }
+
+    /**
+     * Function Point()
+     *
+     * Returns a reference to a given point in the polygon. Negative indices
+     * count from the end of the point list, e.g. -1 means "last point", -2
+     * means "second to last point" and so on.
+     * @param aIndex index of the point
+     * @return reference to the point
+     */
+    VECTOR2I& Point( int aIndex )
+    {
+        return m_points.Point( aIndex );
+    }
+
+    /**
+     * Function CPoint()
+     *
+     * Returns a const reference to a given point in the polygon. Negative
+     * indices count from the end of the point list, e.g. -1 means "last
+     * point", -2 means "second to last point" and so on.
+     * @param aIndex index of the point
+     * @return const reference to the point
+     */
+    const VECTOR2I& CPoint( int aIndex ) const
+    {
+        return m_points.CPoint( aIndex );
+    }
+
+    /**
+     * Function CDPoint()
+     *
+     * Returns a given point as a vector with elements of type double.
+     * 
+     * @param aIndex index of the point
+     * @return the point with elements of type double
+     */
+    const VECTOR2D CDPoint( int aIndex ) const
+    {
+        const VECTOR2I& v = CPoint( aIndex );
+        return VECTOR2D( v.x, v.y );
+    }
+
+    /**
+     * Function Vertices()
+     *
+     * Returns the list of vertices defining this convex polygon.
+     *
+     * @return the list of vertices defining this convex polygon
+     */
+    const SHAPE_LINE_CHAIN& Vertices() const
+    {
+        return m_points;
+    }
+    
+    /**
+     * Function Append()
+     *
+     * Appends a new point at the end of the polygon.
+     * @param aX is X coordinate of the new point
+     * @param aY is Y coordinate of the new point
+     */
+    void Append( int aX, int aY )
+    {
+        VECTOR2I v( aX, aY );
+        Append( v );
+    }
+
+    /**
+     * Function Append()
+     *
+     * Appends a new point at the end of the polygon.
+     * @param aP the new point
+     */
+    void Append( const VECTOR2I& aP )
+    {
+        m_points.Append( aP );
+    }
+
+    /// @copydoc SHAPE::Collide()
+    bool Collide( const SEG& aSeg, int aClearance = 0 ) const
+    {
+        return m_points.Collide( aSeg, aClearance );
+    }
+
+    void Move( const VECTOR2I& aVector )
+    {
+        m_points.Move( aVector );
+    }
+
+    bool IsSolid() const
+    {
+        return true;
+    }
+
+private:
+    // vertices
+    SHAPE_LINE_CHAIN m_points;
+};
+
+#endif // __SHAPE_CONVEX_H

=== modified file 'include/geometry/shape_line_chain.h'
--- include/geometry/shape_line_chain.h	2015-03-06 14:26:47 +0000
+++ include/geometry/shape_line_chain.h	2015-03-12 19:44:01 +0000
@@ -264,6 +264,9 @@
         BOX2I bbox;
         bbox.Compute( m_points );
 
+        if( aClearance != 0 )
+            bbox.Inflate( aClearance );
+
         return bbox;
     }
 
@@ -535,6 +538,17 @@
      */
     const VECTOR2I NearestPoint( const VECTOR2I& aP ) const;
 
+    /**
+     * Function NearestPoint()
+     *
+     * Finds a point on the line chain that is closest to the line defined
+     * by the points of segment aSeg, also returns the distance.
+     * @param aSeg Segment defining the line.
+     * @param dist reference receiving the distance to the nearest point.
+     * @return the nearest point.
+     */
+    const VECTOR2I NearestPoint( const SEG& aSeg, int& dist ) const;
+
     /// @copydoc SHAPE::Format()
     const std::string Format() const;
 

=== modified file 'pcbnew/router/pns_logger.cpp'
--- pcbnew/router/pns_logger.cpp	2015-03-02 16:20:48 +0000
+++ pcbnew/router/pns_logger.cpp	2015-03-12 19:44:01 +0000
@@ -29,6 +29,7 @@
 #include <geometry/shape_line_chain.h>
 #include <geometry/shape_rect.h>
 #include <geometry/shape_circle.h>
+#include <geometry/shape_convex.h>
 
 PNS_LOGGER::PNS_LOGGER( )
 {
@@ -173,6 +174,17 @@
             break;
         }
 
+        case SH_CONVEX:
+        {
+            const SHAPE_CONVEX* c = (const SHAPE_CONVEX*) aSh;
+            m_theLog << "convex " << c->PointCount() << " ";
+
+            for( int i = 0; i < c->PointCount(); i++ )
+                m_theLog << c->CPoint( i ).x << " " << c->CPoint( i ).y << " ";
+
+            break;
+        }
+
         default:
             break;
     }

=== modified file 'pcbnew/router/pns_optimizer.cpp'
--- pcbnew/router/pns_optimizer.cpp	2015-03-10 14:38:27 +0000
+++ pcbnew/router/pns_optimizer.cpp	2015-03-12 21:34:12 +0000
@@ -22,6 +22,7 @@
 
 #include <geometry/shape_line_chain.h>
 #include <geometry/shape_rect.h>
+#include <geometry/shape_convex.h>
 
 #include "pns_line.h"
 #include "pns_diff_pair.h"
@@ -659,6 +660,48 @@
 }
 
 
+PNS_OPTIMIZER::BREAKOUT_LIST PNS_OPTIMIZER::convexBreakouts( int aWidth,
+        const SHAPE* aShape, bool aPermitDiagonal ) const
+{
+    BREAKOUT_LIST breakouts;
+    const SHAPE_CONVEX* convex = static_cast<const SHAPE_CONVEX*>( aShape );
+
+    BOX2I bbox = convex->BBox( 0 );
+    VECTOR2I p0 = bbox.Centre();
+    // must be large enough to guarantee intersecting the convex polygon
+    int length = bbox.GetSize().EuclideanNorm() / 2 + 5;
+
+    for( int angle = 0; angle < 360; angle += ( aPermitDiagonal ? 45 : 90 ) )
+    {
+        SHAPE_LINE_CHAIN l;
+        VECTOR2I v0( p0 + VECTOR2I( length, 0 ).Rotate( angle * M_PI / 180.0 ) );
+        SHAPE_LINE_CHAIN::INTERSECTIONS intersections;
+        int n = convex->Vertices().Intersect( SEG( p0, v0 ), intersections );
+        // if n == 1 intersected a segment
+        // if n == 2 intersected the common point of 2 segments
+        // n == 0 can not happen I think, but...
+        if( n > 0 )
+        {
+            l.Append( p0 );
+
+            // for a breakout distance relative to the distance between
+            // center and polygon edge
+            //l.Append( intersections[0].p + (v0 - p0).Resize( (intersections[0].p - p0).EuclideanNorm() * 0.4 ) );
+
+            // for an absolute breakout distance, e.g. 0.1 mm
+            l.Append( intersections[0].p + (v0 - p0).Resize( 100000 ) );
+
+            // for the breakout right on the polygon edge
+            //l.Append( intersections[0].p );
+
+            breakouts.push_back( l );
+        }
+    }
+
+    return breakouts;
+}
+
+
 PNS_OPTIMIZER::BREAKOUT_LIST PNS_OPTIMIZER::rectBreakouts( int aWidth,
         const SHAPE* aShape, bool aPermitDiagonal ) const
 {
@@ -743,6 +786,9 @@
         case SH_CIRCLE:
             return circleBreakouts( aWidth, shape, aPermitDiagonal );
 
+        case SH_CONVEX:
+            return convexBreakouts( aWidth, shape, aPermitDiagonal );
+
         default:
             break;
         }

=== modified file 'pcbnew/router/pns_optimizer.h'
--- pcbnew/router/pns_optimizer.h	2015-02-18 16:53:46 +0000
+++ pcbnew/router/pns_optimizer.h	2015-03-12 19:44:01 +0000
@@ -158,6 +158,7 @@
     BREAKOUT_LIST circleBreakouts( int aWidth, const SHAPE* aShape, bool aPermitDiagonal ) const;
     BREAKOUT_LIST rectBreakouts( int aWidth, const SHAPE* aShape, bool aPermitDiagonal ) const;
     BREAKOUT_LIST ovalBreakouts( int aWidth, const SHAPE* aShape, bool aPermitDiagonal ) const;
+    BREAKOUT_LIST convexBreakouts( int aWidth, const SHAPE* aShape, bool aPermitDiagonal ) const;
     BREAKOUT_LIST computeBreakouts( int aWidth, const PNS_ITEM* aItem, bool aPermitDiagonal ) const;
 
     int smartPadsSingle( PNS_LINE* aLine, PNS_ITEM* aPad, bool aEnd, int aEndVertex );

=== modified file 'pcbnew/router/pns_router.cpp'
--- pcbnew/router/pns_router.cpp	2015-03-11 22:48:53 +0000
+++ pcbnew/router/pns_router.cpp	2015-03-12 19:44:01 +0000
@@ -34,6 +34,7 @@
 #include <geometry/shape_line_chain.h>
 #include <geometry/shape_rect.h>
 #include <geometry/shape_circle.h>
+#include <geometry/shape_convex.h>
 
 #include "trace.h"
 #include "pns_node.h"
@@ -202,52 +203,142 @@
     solid->SetPos( c );
 
     double orient = aPad->GetOrientation() / 10.0;
-    bool nonOrtho = false;
 
-    if( orient == 90.0 || orient == 270.0 )
-        sz = VECTOR2I( sz.y, sz.x );
-    else if( orient != 0.0 && orient != 180.0 )
+    if( aPad->GetShape() == PAD_CIRCLE )
     {
-        // rotated pads are replaced by for the moment by circles due to my laziness ;)
-        solid->SetShape( new SHAPE_CIRCLE( c, std::min( sz.x, sz.y ) / 2 ) );
-        nonOrtho = true;
+        solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) );
     }
-
-    if( !nonOrtho )
+    else 
     {
-        switch( aPad->GetShape() )
-        {
-        case PAD_CIRCLE:
-            solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) );
-            break;
-
-        case PAD_OVAL:
-            if( sz.x == sz.y )
-                solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) );
-            else
-            {
-                VECTOR2I delta;
-
-                if( sz.x > sz.y )
-                    delta = VECTOR2I( ( sz.x - sz.y ) / 2, 0 );
-                else
-                    delta = VECTOR2I( 0, ( sz.y - sz.x ) / 2 );
-
-                SHAPE_SEGMENT* shape = new SHAPE_SEGMENT( c - delta, c + delta,
-                                                          std::min( sz.x, sz.y ) );
-                solid->SetShape( shape );
-            }
-            break;
-
-        case PAD_RECT:
-            solid->SetShape( new SHAPE_RECT( c - sz / 2, sz.x, sz.y ) );
-            break;
-
-        default:
-            TRACEn( 0, "unsupported pad shape" );
-            delete solid;
-
-            return NULL;
+        if( orient == 0.0 || orient == 90.0 || orient == 180.0 || orient == 270.0 )
+        {
+            if( orient == 90.0 || orient == 270.0 )
+                sz = VECTOR2I( sz.y, sz.x );
+            
+            switch( aPad->GetShape() )
+            {
+            // PAD_CIRCLE already handled above
+
+            case PAD_OVAL:
+                if( sz.x == sz.y )
+                    solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) );
+                else
+                {
+                    VECTOR2I delta;
+
+                    if( sz.x > sz.y )
+                        delta = VECTOR2I( ( sz.x - sz.y ) / 2, 0 );
+                    else
+                        delta = VECTOR2I( 0, ( sz.y - sz.x ) / 2 );
+
+                    SHAPE_SEGMENT* shape = new SHAPE_SEGMENT( c - delta, c + delta,
+                                                              std::min( sz.x, sz.y ) );
+                    solid->SetShape( shape );
+                }
+                break;
+
+            case PAD_RECT:
+                solid->SetShape( new SHAPE_RECT( c - sz / 2, sz.x, sz.y ) );
+                break;
+
+            case PAD_TRAPEZOID:
+            {
+                wxPoint coords[4];
+                aPad->BuildPadPolygon( coords, wxSize( 0, 0 ), aPad->GetOrientation() );
+
+                SHAPE_CONVEX* shape = new SHAPE_CONVEX();
+                for( int ii = 0; ii < 4; ii++ )
+                {
+                    shape->Append( wx_c + coords[ii] );
+                }
+                    
+                solid->SetShape( shape );
+                break;
+            }
+                
+
+            default:
+                TRACEn( 0, "unsupported pad shape" );
+                delete solid;
+
+                return NULL;
+            }
+        }
+        else
+        {
+            switch( aPad->GetShape() )
+            {
+            // PAD_CIRCLE already handled above
+
+            case PAD_OVAL:
+                if( sz.x == sz.y )
+                    solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) );
+                else
+                {
+                    wxPoint start;
+                    wxPoint end;
+                    wxPoint corner;
+
+                    SHAPE_CONVEX* shape = new SHAPE_CONVEX();
+
+                    int w = aPad->BuildSegmentFromOvalShape( start, end, 0.0, wxSize( 0, 0 ) );
+
+                    if( start.y == 0 )
+                        corner = wxPoint( start.x, -(w / 2) );
+                    else
+                        corner = wxPoint( w / 2, start.y );
+                    RotatePoint( &start, aPad->GetOrientation() );
+                    RotatePoint( &corner, aPad->GetOrientation() );
+                    shape->Append( wx_c + corner );
+
+                    for( int rot = 100; rot <= 1800; rot += 100 )
+                    {
+                        wxPoint p( corner );
+                        RotatePoint( &p, start, rot );
+                        shape->Append( wx_c + p );
+                    }
+                        
+                    if( end.y == 0 )
+                        corner = wxPoint( end.x, w / 2 );
+                    else
+                        corner = wxPoint( -(w / 2), end.y );
+                    RotatePoint( &end, aPad->GetOrientation() );
+                    RotatePoint( &corner, aPad->GetOrientation() );
+                    shape->Append( wx_c + corner );
+
+                    for( int rot = 100; rot <= 1800; rot += 100 )
+                    {
+                        wxPoint p( corner );
+                        RotatePoint( &p, end, rot );
+                        shape->Append( wx_c + p );
+                    }
+
+                    solid->SetShape( shape );
+                }
+                break;
+
+            case PAD_RECT:
+            case PAD_TRAPEZOID:
+            {
+                wxPoint coords[4];
+                aPad->BuildPadPolygon( coords, wxSize( 0, 0 ), aPad->GetOrientation() );
+
+                SHAPE_CONVEX* shape = new SHAPE_CONVEX();
+                for( int ii = 0; ii < 4; ii++ )
+                {
+                    shape->Append( wx_c + coords[ii] );
+                }
+                    
+                solid->SetShape( shape );
+                break;
+            }
+
+            default:
+                TRACEn( 0, "unsupported pad shape" );
+                delete solid;
+
+                return NULL;
+            }
         }
     }
 

=== modified file 'pcbnew/router/pns_solid.cpp'
--- pcbnew/router/pns_solid.cpp	2015-02-18 16:53:46 +0000
+++ pcbnew/router/pns_solid.cpp	2015-03-12 19:44:01 +0000
@@ -24,6 +24,7 @@
 #include <geometry/shape_line_chain.h>
 #include <geometry/shape_rect.h>
 #include <geometry/shape_circle.h>
+#include <geometry/shape_convex.h>
 
 #include "pns_solid.h"
 #include "pns_utils.h"
@@ -54,6 +55,13 @@
         return SegmentHull( *seg, aClearance, aWalkaroundThickness );
     }
 
+    case SH_CONVEX:
+    {
+        SHAPE_CONVEX* convex = static_cast<SHAPE_CONVEX*>( m_shape );
+
+        return ConvexHull( *convex, cl );
+    }
+
     default:
         break;
     }

=== modified file 'pcbnew/router/pns_utils.cpp'
--- pcbnew/router/pns_utils.cpp	2015-03-03 09:36:44 +0000
+++ pcbnew/router/pns_utils.cpp	2015-03-12 19:44:01 +0000
@@ -81,6 +81,74 @@
 }
 
 
+static void MoveDiagonal( SEG& diagonal, const SHAPE_LINE_CHAIN& vertices, int clearance )
+{
+    int dist;
+
+    vertices.NearestPoint( diagonal, dist );
+    dist -= HULL_MARGIN;
+    VECTOR2I moveBy = (diagonal.A - diagonal.B).Perpendicular().Resize( dist - clearance );
+    diagonal.A += moveBy;
+    diagonal.B += moveBy;
+}
+
+
+const SHAPE_LINE_CHAIN ConvexHull( const SHAPE_CONVEX& convex, int clearance )
+{
+    // this defines the horizontal and vertical lines in the hull octagon
+    BOX2I box = convex.BBox( clearance + HULL_MARGIN );
+    box.Normalize();
+
+    SEG topline = SEG( VECTOR2I( box.GetX(), box.GetY() + box.GetHeight() ),
+                       VECTOR2I( box.GetX() + box.GetWidth(), box.GetY() + box.GetHeight() ) );
+    SEG rightline = SEG( VECTOR2I( box.GetX() + box.GetWidth(), box.GetY() + box.GetHeight() ),
+                         VECTOR2I( box.GetX() + box.GetWidth(), box.GetY() ) );
+    SEG bottomline = SEG( VECTOR2I( box.GetX() + box.GetWidth(), box.GetY() ),
+			  box.GetOrigin() );
+    SEG leftline = SEG( box.GetOrigin(), VECTOR2I( box.GetX(), box.GetY() + box.GetHeight() ) );
+
+    const SHAPE_LINE_CHAIN& vertices = convex.Vertices();
+    
+    // top right diagonal
+    VECTOR2I corner = box.GetOrigin() + box.GetSize();
+    SEG toprightline = SEG( corner,
+                            corner + VECTOR2I( box.GetHeight(), -box.GetHeight() ) );
+    MoveDiagonal( toprightline, vertices, clearance );
+
+    // bottom right diagonal
+    corner = box.GetOrigin() + VECTOR2I( box.GetWidth(), 0 );
+    SEG bottomrightline = SEG( corner + VECTOR2I( box.GetHeight(), box.GetHeight() ),
+                               corner );
+    MoveDiagonal( bottomrightline, vertices, clearance );
+
+    // bottom left diagonal
+    corner = box.GetOrigin();
+    SEG bottomleftline = SEG( corner,
+                              corner + VECTOR2I( -box.GetHeight(), box.GetHeight() ) );
+    MoveDiagonal( bottomleftline, vertices, clearance );
+
+    // top left diagonal
+    corner = box.GetOrigin() + VECTOR2I( 0, box.GetHeight() );
+    SEG topleftline = SEG( corner + VECTOR2I( -box.GetHeight(), -box.GetHeight() ),
+                           corner );
+    MoveDiagonal( topleftline, vertices, clearance );
+
+    SHAPE_LINE_CHAIN octagon;
+    octagon.SetClosed( true );
+    
+    octagon.Append( leftline.IntersectLines( bottomleftline ).get() );
+    octagon.Append( bottomline.IntersectLines( bottomleftline ).get() );
+    octagon.Append( bottomline.IntersectLines( bottomrightline ).get() );
+    octagon.Append( rightline.IntersectLines( bottomrightline ).get() );
+    octagon.Append( rightline.IntersectLines( toprightline ).get() );
+    octagon.Append( topline.IntersectLines( toprightline ).get() );
+    octagon.Append( topline.IntersectLines( topleftline ).get() );
+    octagon.Append( leftline.IntersectLines( topleftline ).get() );
+
+    return octagon;
+}
+
+
 SHAPE_RECT ApproximateSegmentAsRect( const SHAPE_SEGMENT& aSeg )
 {
     SHAPE_RECT r;

=== modified file 'pcbnew/router/pns_utils.h'
--- pcbnew/router/pns_utils.h	2015-02-18 16:53:46 +0000
+++ pcbnew/router/pns_utils.h	2015-03-12 19:44:01 +0000
@@ -26,6 +26,7 @@
 #include <geometry/shape_line_chain.h>
 #include <geometry/shape_segment.h>
 #include <geometry/shape_rect.h>
+#include <geometry/shape_convex.h>
 
 #define HULL_MARGIN 10
 
@@ -39,6 +40,16 @@
 const SHAPE_LINE_CHAIN SegmentHull ( const SHAPE_SEGMENT& aSeg, int aClearance,
                                      int aWalkaroundThickness );
 
+/**
+ * Function ConvexHull()
+ *
+ * Creates an octagonal hull around a convex polygon.
+ * @param convex The convex polygon.
+ * @param clearance The minimum distance between polygon and hull.
+ * @return A closed line chain describing the octagon.
+ */
+const SHAPE_LINE_CHAIN ConvexHull( const SHAPE_CONVEX& convex, int clearance );
+
 SHAPE_RECT ApproximateSegmentAsRect( const SHAPE_SEGMENT& aSeg );
 
 void DrawDebugPoint( VECTOR2I aP, int aColor );

=== modified file 'pcbnew/router/router_preview_item.cpp'
--- pcbnew/router/router_preview_item.cpp	2015-03-03 10:50:50 +0000
+++ pcbnew/router/router_preview_item.cpp	2015-03-12 19:44:01 +0000
@@ -18,9 +18,12 @@
  * with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <deque>
+
 #include <gal/color4d.h>
 
 #include <geometry/shape_rect.h>
+#include <geometry/shape_convex.h>
 
 #include "class_track.h"
 #include <pcb_painter.h>
@@ -227,6 +230,28 @@
             }
 
         case SH_CONVEX:
+        {
+            const SHAPE_CONVEX* c = (const SHAPE_CONVEX*) m_shape;
+            std::deque<VECTOR2D> polygon = std::deque<VECTOR2D>();
+            for( int i = 0; i < c->PointCount(); i++ )
+            {
+                polygon.push_back( c->CDPoint( i ) );
+            }
+            aGal->DrawPolygon( polygon );
+
+            if( m_clearance > 0 )
+            {
+                aGal->SetLayerDepth( ClearanceOverlayDepth );
+                aGal->SetStrokeColor( COLOR4D( DARKDARKGRAY ) );
+                aGal->SetIsStroke( true );
+                aGal->SetLineWidth( 2 * m_clearance );
+                // need the implicit last segment to be explicit for DrawPolyline
+                polygon.push_back( c->CDPoint( 0 ) );                
+                aGal->DrawPolyline( polygon );
+            }
+            break;
+        }
+	    
         case SH_POLYGON:
         case SH_COMPOUND:
             break;          // Not yet in use