From 7724c581fde02c673dfc84c222168ae7459c3170 Mon Sep 17 00:00:00 2001 From: Mathias Grimmberger Date: Thu, 2 Jul 2015 16:09:43 +0200 Subject: [PATCH] router: support for non-90 degree pad orientations --- common/geometry/shape_collisions.cpp | 89 ++++++++++++++++ common/geometry/shape_line_chain.cpp | 20 ++++ include/geometry/shape_line_chain.h | 14 +++ pcbnew/router/pns_logger.cpp | 12 +++ pcbnew/router/pns_optimizer.cpp | 46 ++++++++ pcbnew/router/pns_optimizer.h | 1 + pcbnew/router/pns_router.cpp | 148 ++++++++++++++++++++------ pcbnew/router/pns_solid.cpp | 8 ++ pcbnew/router/pns_utils.cpp | 68 ++++++++++++ pcbnew/router/pns_utils.h | 11 ++ pcbnew/router/router_preview_item.cpp | 26 ++++- 11 files changed, 410 insertions(+), 33 deletions(-) diff --git a/common/geometry/shape_collisions.cpp b/common/geometry/shape_collisions.cpp index 25a611600a..92442cbe2e 100644 --- a/common/geometry/shape_collisions.cpp +++ b/common/geometry/shape_collisions.cpp @@ -30,6 +30,7 @@ #include #include #include +#include typedef VECTOR2I::extended_type ecoord; @@ -165,6 +166,32 @@ static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN& aB, } +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_LINE_CHAIN& } +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_LINE_CHAIN& aB, in } +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_LINE_CHAIN& aA, const SHAPE_SEGMENT& aB, } +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 inline bool CollCase( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeedMTV, VECTOR2I& aMTV ) { @@ -264,6 +319,9 @@ bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeed case SH_SEGMENT: return CollCase( aA, aB, aClearance, aNeedMTV, aMTV ); + case SH_CONVEX: + return CollCase( aA, aB, aClearance, aNeedMTV, aMTV ); + default: break; } @@ -283,6 +341,9 @@ bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeed case SH_SEGMENT: return CollCase( aA, aB, aClearance, aNeedMTV, aMTV ); + case SH_CONVEX: + return CollCase( aA, aB, aClearance, aNeedMTV, aMTV ); + default: break; } @@ -302,6 +363,9 @@ bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeed case SH_SEGMENT: return CollCase( aA, aB, aClearance, aNeedMTV, aMTV ); + case SH_CONVEX: + return CollCase( aA, aB, aClearance, aNeedMTV, aMTV ); + default: break; } @@ -321,6 +385,31 @@ bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeed case SH_SEGMENT: return CollCase( aA, aB, aClearance, aNeedMTV, aMTV ); + case SH_CONVEX: + return CollCase( aB, aA, aClearance, aNeedMTV, aMTV ); + + default: + break; + } + + case SH_CONVEX: + switch( aB->Type() ) + { + case SH_RECT: + return CollCase( aB, aA, aClearance, aNeedMTV, aMTV ); + + case SH_CIRCLE: + return CollCase( aB, aA, aClearance, aNeedMTV, aMTV ); + + case SH_LINE_CHAIN: + return CollCase( aB, aA, aClearance, aNeedMTV, aMTV ); + + case SH_SEGMENT: + return CollCase( aA, aB, aClearance, aNeedMTV, aMTV ); + + case SH_CONVEX: + return CollCase( aA, aB, aClearance, aNeedMTV, aMTV ); + default: break; } diff --git a/common/geometry/shape_line_chain.cpp b/common/geometry/shape_line_chain.cpp index dbb3d4f1a9..c9e5431ac9 100644 --- a/common/geometry/shape_line_chain.cpp +++ b/common/geometry/shape_line_chain.cpp @@ -499,6 +499,26 @@ const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const VECTOR2I& aP ) const } +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; diff --git a/include/geometry/shape_line_chain.h b/include/geometry/shape_line_chain.h index 9ff86d735b..8bf0410806 100644 --- a/include/geometry/shape_line_chain.h +++ b/include/geometry/shape_line_chain.h @@ -264,6 +264,9 @@ public: BOX2I bbox; bbox.Compute( m_points ); + if( aClearance != 0 ) + bbox.Inflate( aClearance ); + return bbox; } @@ -535,6 +538,17 @@ public: */ 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; diff --git a/pcbnew/router/pns_logger.cpp b/pcbnew/router/pns_logger.cpp index e0f8d6ac4b..a7cec96bfc 100644 --- a/pcbnew/router/pns_logger.cpp +++ b/pcbnew/router/pns_logger.cpp @@ -29,6 +29,7 @@ #include #include #include +#include PNS_LOGGER::PNS_LOGGER( ) { @@ -173,6 +174,17 @@ void PNS_LOGGER::dumpShape( const SHAPE* aSh ) 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; } diff --git a/pcbnew/router/pns_optimizer.cpp b/pcbnew/router/pns_optimizer.cpp index 5558d8de72..c32900fb88 100644 --- a/pcbnew/router/pns_optimizer.cpp +++ b/pcbnew/router/pns_optimizer.cpp @@ -22,6 +22,7 @@ #include #include +#include #include "pns_line.h" #include "pns_diff_pair.h" @@ -659,6 +660,48 @@ PNS_OPTIMIZER::BREAKOUT_LIST PNS_OPTIMIZER::circleBreakouts( int aWidth, } +PNS_OPTIMIZER::BREAKOUT_LIST PNS_OPTIMIZER::convexBreakouts( int aWidth, + const SHAPE* aShape, bool aPermitDiagonal ) const +{ + BREAKOUT_LIST breakouts; + const SHAPE_CONVEX* convex = static_cast( 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 @@ PNS_OPTIMIZER::BREAKOUT_LIST PNS_OPTIMIZER::computeBreakouts( int aWidth, case SH_CIRCLE: return circleBreakouts( aWidth, shape, aPermitDiagonal ); + case SH_CONVEX: + return convexBreakouts( aWidth, shape, aPermitDiagonal ); + default: break; } diff --git a/pcbnew/router/pns_optimizer.h b/pcbnew/router/pns_optimizer.h index 84072693cb..36bced6c45 100644 --- a/pcbnew/router/pns_optimizer.h +++ b/pcbnew/router/pns_optimizer.h @@ -158,6 +158,7 @@ private: 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 ); diff --git a/pcbnew/router/pns_router.cpp b/pcbnew/router/pns_router.cpp index 6ad61e2af0..691894ee19 100644 --- a/pcbnew/router/pns_router.cpp +++ b/pcbnew/router/pns_router.cpp @@ -207,53 +207,137 @@ PNS_ITEM* PNS_ROUTER::syncPad( D_PAD* aPad ) 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 ) ); + } else { - if( !nonOrtho ) - { - switch( aPad->GetShape() ) + if( orient == 0.0 || orient == 90.0 || orient == 180.0 || orient == 270.0 ) { - case PAD_CIRCLE: - solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) ); - break; + if( orient == 90.0 || orient == 270.0 ) + sz = VECTOR2I( sz.y, sz.x ); - case PAD_OVAL: - if( sz.x == sz.y ) - solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) ); - else + switch( aPad->GetShape() ) { - VECTOR2I delta; - if( sz.x > sz.y ) - delta = VECTOR2I( ( sz.x - sz.y ) / 2, 0 ); + case PAD_OVAL: + if( sz.x == sz.y ) + solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) ); else - delta = VECTOR2I( 0, ( sz.y - sz.x ) / 2 ); + { + 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] ); + } - SHAPE_SEGMENT* shape = new SHAPE_SEGMENT( c - delta, c + delta, - std::min( sz.x, sz.y ) ); solid->SetShape( shape ); + break; } - 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; + } + } else { + switch( aPad->GetShape() ) + { + // PAD_CIRCLE already handled above - default: - TRACEn( 0, "unsupported pad shape" ); - delete solid; + case PAD_OVAL: + if( sz.x == sz.y ) + solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) ); + else + { + wxPoint start; + wxPoint end; + wxPoint corner; - return NULL; + 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; + } } } - return solid; } diff --git a/pcbnew/router/pns_solid.cpp b/pcbnew/router/pns_solid.cpp index 0bcca8c254..7682d51420 100644 --- a/pcbnew/router/pns_solid.cpp +++ b/pcbnew/router/pns_solid.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include "pns_solid.h" #include "pns_utils.h" @@ -54,6 +55,13 @@ const SHAPE_LINE_CHAIN PNS_SOLID::Hull( int aClearance, int aWalkaroundThickness return SegmentHull( *seg, aClearance, aWalkaroundThickness ); } + case SH_CONVEX: + { + SHAPE_CONVEX* convex = static_cast( m_shape ); + + return ConvexHull( *convex, cl ); + } + default: break; } diff --git a/pcbnew/router/pns_utils.cpp b/pcbnew/router/pns_utils.cpp index 6046fa222d..d4d2c2fbec 100644 --- a/pcbnew/router/pns_utils.cpp +++ b/pcbnew/router/pns_utils.cpp @@ -81,6 +81,74 @@ const SHAPE_LINE_CHAIN SegmentHull ( const SHAPE_SEGMENT& aSeg, int aClearance, } +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; diff --git a/pcbnew/router/pns_utils.h b/pcbnew/router/pns_utils.h index bb02d9dbf6..011bf3eee9 100644 --- a/pcbnew/router/pns_utils.h +++ b/pcbnew/router/pns_utils.h @@ -26,6 +26,7 @@ #include #include #include +#include #define HULL_MARGIN 10 @@ -39,6 +40,16 @@ const SHAPE_LINE_CHAIN OctagonalHull( const VECTOR2I& aP0, const VECTOR2I& aSize 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 ); diff --git a/pcbnew/router/router_preview_item.cpp b/pcbnew/router/router_preview_item.cpp index 1e4974f554..274e04539c 100644 --- a/pcbnew/router/router_preview_item.cpp +++ b/pcbnew/router/router_preview_item.cpp @@ -18,9 +18,11 @@ * with this program. If not, see . */ +#include #include #include +#include #include "class_track.h" #include @@ -233,7 +235,29 @@ void ROUTER_PREVIEW_ITEM::ViewDraw( int aLayer, KIGFX::GAL* aGal ) const break; } - case SH_CONVEX: + case SH_CONVEX: + { + const SHAPE_CONVEX* c = (const SHAPE_CONVEX*) m_shape; + std::deque polygon = std::deque(); + 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_POLY_SET: case SH_COMPOUND: break; // Not yet in use