void DXF_PLOTTER::ThickSegment( const wxPoint& aStart, const wxPoint& aEnd, int aWidth,
                                EDA_DRAW_MODE_T aPlotMode, void* aData )
{
    if( aPlotMode == SKETCH )
    {
        std::vector<wxPoint> cornerList;
        SHAPE_POLY_SET outlineBuffer;
        TransformOvalClearanceToPolygon( outlineBuffer,
                aStart, aEnd, aWidth, 32 , 1.0 );
        const SHAPE_LINE_CHAIN& path = outlineBuffer.COutline(0 );

        for( int jj = 0; jj < path.PointCount(); jj++ )
            cornerList.push_back( wxPoint( path.CPoint( jj ).x , path.CPoint( jj ).y ) );

        // Ensure the polygon is closed
        if( cornerList[0] != cornerList[cornerList.size() - 1] )
            cornerList.push_back( cornerList[0] );

        PlotPoly( cornerList, NO_FILL );
    }
    else
    {
        MoveTo( aStart );
        FinishTo( aEnd );
    }
}
void TRACK::TransformShapeWithClearanceToPolygon(
        SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue, int aError, bool ignoreLineWidth ) const
{
    wxASSERT_MSG( !ignoreLineWidth, "IgnoreLineWidth has no meaning for tracks." );

    int    radius = ( m_Width / 2 ) + aClearanceValue;

    switch( Type() )
    {
    case PCB_VIA_T:
    {
        TransformCircleToPolygon( aCornerBuffer, m_Start, radius, aError );
    }
        break;

    default:
        TransformOvalClearanceToPolygon( aCornerBuffer, m_Start, m_End,
                m_Width + ( 2 * aClearanceValue ), aError );
        break;
    }
}
void D_PAD::TransformShapeWithClearanceToPolygon(
        SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue, int aError, bool ignoreLineWidth ) const
{
    wxASSERT_MSG( !ignoreLineWidth, "IgnoreLineWidth has no meaning for pads." );

    double  angle = m_Orient;
    int     dx = (m_Size.x / 2) + aClearanceValue;
    int     dy = (m_Size.y / 2) + aClearanceValue;

    wxPoint padShapePos = ShapePos();               /* Note: for pad having a shape offset,
                                                     * the pad position is NOT the shape position */

    switch( GetShape() )
    {
    case PAD_SHAPE_CIRCLE:
    {
        TransformCircleToPolygon( aCornerBuffer, padShapePos, dx, aError );
    }
        break;

    case PAD_SHAPE_OVAL:
        // An oval pad has the same shape as a segment with rounded ends
        {
        int width;
        wxPoint shape_offset;
        if( dy > dx )   // Oval pad X/Y ratio for choosing translation axis
        {
            shape_offset.y = dy - dx;
            width = dx * 2;
        }
        else    //if( dy <= dx )
        {
            shape_offset.x = dy - dx;
            width = dy * 2;
        }

        RotatePoint( &shape_offset, angle );
        wxPoint start = padShapePos - shape_offset;
        wxPoint end = padShapePos + shape_offset;
        TransformOvalClearanceToPolygon( aCornerBuffer, start, end, width, aError );
        }
        break;

    case PAD_SHAPE_TRAPEZOID:
    case PAD_SHAPE_RECT:
    {
        wxPoint corners[4];
        BuildPadPolygon( corners, wxSize( 0, 0 ), angle );

        SHAPE_POLY_SET outline;
        outline.NewOutline();

        for( int ii = 0; ii < 4; ii++ )
        {
            corners[ii] += padShapePos;
            outline.Append( corners[ii].x, corners[ii].y );
        }

        int    numSegs = std::max( GetArcToSegmentCount( aClearanceValue, aError, 360.0 ), 6 );
        double correction = GetCircletoPolyCorrectionFactor( numSegs );

        int rounding_radius = KiROUND( aClearanceValue * correction );
        outline.Inflate( rounding_radius, numSegs );

        aCornerBuffer.Append( outline );
    }
        break;

    case PAD_SHAPE_CHAMFERED_RECT:
    case PAD_SHAPE_ROUNDRECT:
    {
        SHAPE_POLY_SET outline;
        int            radius = GetRoundRectCornerRadius() + aClearanceValue;
        int            numSegs = std::max( GetArcToSegmentCount( radius, aError, 360.0 ), 6 );
        double         correction = GetCircletoPolyCorrectionFactor( numSegs );
        int            clearance = KiROUND( aClearanceValue * correction );
        int            rounding_radius = GetRoundRectCornerRadius() + clearance;
        wxSize         shapesize( m_Size );

        shapesize.x += clearance * 2;
        shapesize.y += clearance * 2;
        bool doChamfer = GetShape() == PAD_SHAPE_CHAMFERED_RECT;

        TransformRoundChamferedRectToPolygon( outline, padShapePos, shapesize, angle,
                rounding_radius, doChamfer ? GetChamferRectRatio() : 0.0,
                doChamfer ? GetChamferPositions() : 0, aError );

        aCornerBuffer.Append( outline );
    }
        break;

    case PAD_SHAPE_CUSTOM:
    {
        int    numSegs = std::max( GetArcToSegmentCount( aClearanceValue, aError, 360.0 ), 6 );
        double correction = GetCircletoPolyCorrectionFactor( numSegs );
        int    clearance = KiROUND( aClearanceValue * correction );
        SHAPE_POLY_SET outline;     // Will contain the corners in board coordinates
        outline.Append( m_customShapeAsPolygon );
        CustomShapeAsPolygonToBoardPosition( &outline, GetPosition(), GetOrientation() );
        outline.Simplify( SHAPE_POLY_SET::PM_FAST );
        outline.Inflate( clearance, numSegs );
        outline.Fracture( SHAPE_POLY_SET::PM_FAST );
        aCornerBuffer.Append( outline );
    }
        break;
    }
}
void DRAWSEGMENT::TransformShapeWithClearanceToPolygon(
        SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue, int aError, bool ignoreLineWidth ) const
{
    // The full width of the lines to create:
    int linewidth = ignoreLineWidth ? 0 : m_Width;

    linewidth += 2 * aClearanceValue;

    // Creating a reliable clearance shape for circles and arcs is not so easy, due to
    // the error created by segment approximation.
    // for a circle this is not so hard: create a polygon from a circle slightly bigger:
    // thickness = linewidth + s_error_max, and radius = initial radius + s_error_max/2
    // giving a shape with a suitable internal radius and external radius
    // For an arc this is more tricky: TODO

    switch( m_Shape )
    {
    case S_CIRCLE:
        TransformRingToPolygon(
                aCornerBuffer, GetCenter(), GetRadius(), aError, linewidth );
        break;

    case S_ARC:
        TransformArcToPolygon(
                aCornerBuffer, GetCenter(), GetArcStart(), m_Angle, aError, linewidth );
        break;

    case S_SEGMENT:
        TransformOvalClearanceToPolygon(
                aCornerBuffer, m_Start, m_End, linewidth, aError );
        break;

    case S_POLYGON:
        if( IsPolyShapeValid() )
        {
            // The polygon is expected to be a simple polygon
            // not self intersecting, no hole.
            MODULE* module = GetParentModule();     // NULL for items not in footprints
            double orientation = module ? module->GetOrientation() : 0.0;
            wxPoint offset;

            if( module )
                offset = module->GetPosition();

            // Build the polygon with the actual position and orientation:
            std::vector< wxPoint> poly;
            poly = BuildPolyPointsList();

            for( unsigned ii = 0; ii < poly.size(); ii++ )
            {
                RotatePoint( &poly[ii], orientation );
                poly[ii] += offset;
            }

            // If the polygon is not filled, treat it as a closed set of lines
            if( !IsPolygonFilled() )
            {
                for( size_t ii = 1; ii < poly.size(); ii++ )
                {
                    TransformOvalClearanceToPolygon( aCornerBuffer, poly[ii - 1], poly[ii],
                            linewidth, aError );
                }

                TransformOvalClearanceToPolygon( aCornerBuffer, poly.back(), poly.front(),
                        linewidth, aError );
                break;
            }

            // Generate polygons for the outline + clearance
            // This code is compatible with a polygon with holes linked to external outline
            // by overlapping segments.

            // Insert the initial polygon:
            aCornerBuffer.NewOutline();

            for( unsigned ii = 0; ii < poly.size(); ii++ )
                aCornerBuffer.Append( poly[ii].x, poly[ii].y );

            if( linewidth )     // Add thick outlines
            {
                wxPoint corner1( poly[poly.size()-1] );

                for( unsigned ii = 0; ii < poly.size(); ii++ )
                {
                    wxPoint corner2( poly[ii] );

                    if( corner2 != corner1 )
                    {
                        TransformRoundedEndsSegmentToPolygon(
                                aCornerBuffer, corner1, corner2, aError, linewidth );
                    }

                    corner1 = corner2;
                }
            }
        }
        break;

    case S_CURVE:       // Bezier curve
        {
            std::vector<wxPoint> ctrlPoints = { m_Start, m_BezierC1, m_BezierC2, m_End };
            BEZIER_POLY converter( ctrlPoints );
            std::vector< wxPoint> poly;
            converter.GetPoly( poly, m_Width );

            for( unsigned ii = 1; ii < poly.size(); ii++ )
            {
                TransformRoundedEndsSegmentToPolygon(
                        aCornerBuffer, poly[ii - 1], poly[ii], aError, linewidth );
            }
        }
        break;

    default:
        break;
    }
}