/* generate shapes of graphic items (outlines) on layer aLayer as polygons,
 * and adds these polygons to aCornerBuffer
 * aCornerBuffer = the buffer to store polygons
 * aInflateValue = a value to inflate shapes
 * aCircleToSegmentsCount = number of segments to approximate a circle
 * aCorrectionFactor = the correction to apply to the circle radius
 *  to generate the polygon.
 *  if aCorrectionFactor = 1.0, the polygon is inside the circle
 *  the radius of circle approximated by segments is
 *  initial radius * aCorrectionFactor
 */
void MODULE::TransformGraphicShapesWithClearanceToPolygonSet(
                        LAYER_NUM aLayer,
                        CPOLYGONS_LIST& aCornerBuffer,
                        int                    aInflateValue,
                        int                    aCircleToSegmentsCount,
                        double                 aCorrectionFactor )
{
    std::vector<TEXTE_MODULE *> texts;  // List of TEXTE_MODULE to convert
    EDGE_MODULE* outline;

    for( EDA_ITEM* item = GraphicalItems(); item != NULL; item = item->Next() )
    {
        switch( item->Type() )
        {
        case PCB_MODULE_TEXT_T:
            if( ((TEXTE_MODULE*)item)->GetLayer() == aLayer )
                texts.push_back( (TEXTE_MODULE *) item );
            break;

        case PCB_MODULE_EDGE_T:
            outline = (EDGE_MODULE*) item;
            if( outline->GetLayer() != aLayer )
                break;

            switch( outline->GetShape() )
            {
            case S_SEGMENT:
                TransformRoundedEndsSegmentToPolygon( aCornerBuffer,
                                           outline->GetStart(),
                                           outline->GetEnd(),
                                           aCircleToSegmentsCount,
                                           outline->GetWidth() );
                break;

            case S_CIRCLE:
                TransformRingToPolygon( aCornerBuffer, outline->GetCenter(),
                                outline->GetRadius(), aCircleToSegmentsCount,
                                outline->GetWidth() );
                break;

            case S_ARC:
                TransformArcToPolygon( aCornerBuffer,
                            outline->GetCenter(), outline->GetArcStart(),
                            outline->GetAngle(),
                            aCircleToSegmentsCount, outline->GetWidth() );
                break;

            case S_POLYGON:
                // for outline shape = S_POLYGON:
                // We must compute true coordinates from m_PolyPoints
                // which are relative to module position and module orientation = 0
                for( unsigned ii = 0; ii < outline->GetPolyPoints().size(); ii++ )
                {
                    CPolyPt corner( outline->GetPolyPoints()[ii] );
                    RotatePoint( &corner.x, &corner.y, GetOrientation() );
                    corner.x += GetPosition().x;
                    corner.y += GetPosition().y;
                    aCornerBuffer.Append( corner );
                }
                aCornerBuffer.CloseLastContour();
                break;

            default:
                DBG( printf( "Error: Shape %d not implemented!\n",
                        outline->GetShape() ); )
                break;
            }
                break;

            default:
                break;
        }
    }
bool D_PAD::buildCustomPadPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError )

{
    SHAPE_POLY_SET aux_polyset;

    for( unsigned cnt = 0; cnt < m_basicShapes.size(); ++cnt )
    {
        const PAD_CS_PRIMITIVE& bshape = m_basicShapes[cnt];

        switch( bshape.m_Shape )
        {
        case S_CURVE:
        {
            std::vector<wxPoint> ctrlPoints = { bshape.m_Start, bshape.m_Ctrl1, bshape.m_Ctrl2, bshape.m_End };
            BEZIER_POLY converter( ctrlPoints );
            std::vector< wxPoint> poly;
            converter.GetPoly( poly, bshape.m_Thickness );

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

        case S_SEGMENT:         // usual segment : line with rounded ends
        {
            TransformRoundedEndsSegmentToPolygon(
                    aux_polyset, bshape.m_Start, bshape.m_End, aError, bshape.m_Thickness );
            break;
        }

        case S_ARC:             // Arc with rounded ends
        {
            TransformArcToPolygon( aux_polyset, bshape.m_Start, bshape.m_End, bshape.m_ArcAngle,
                    aError, bshape.m_Thickness );
            break;
        }

        case S_CIRCLE:          //  ring or circle
        {
            if( bshape.m_Thickness )    // ring
                TransformRingToPolygon(
                        aux_polyset, bshape.m_Start, bshape.m_Radius, aError, bshape.m_Thickness );
            else                // Filled circle
                TransformCircleToPolygon( aux_polyset, bshape.m_Start, bshape.m_Radius, aError );
            break;
        }

        case S_POLYGON:         // polygon
            if( bshape.m_Poly.size() < 2 )
                break;      // Malformed polygon.

            {
            // Insert the polygon:
            const std::vector< wxPoint>& poly = bshape.m_Poly;
            aux_polyset.NewOutline();

            if( bshape.m_Thickness )
            {
                SHAPE_POLY_SET polyset;
                polyset.NewOutline();

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

                int numSegs = std::max(
                        GetArcToSegmentCount( bshape.m_Thickness / 2, aError, 360.0 ), 6 );
                polyset.Inflate( bshape.m_Thickness / 2, numSegs );

                aux_polyset.Append( polyset );
            }

            else
                for( unsigned ii = 0; ii < poly.size(); ii++ )
                    aux_polyset.Append( poly[ii].x, poly[ii].y );
            }
            break;

        default:
            break;
        }
    }

    aux_polyset.Simplify( SHAPE_POLY_SET::PM_FAST );

    // Merge all polygons with the initial pad anchor shape
    if( aux_polyset.OutlineCount() )
    {
        aMergedPolygon->BooleanAdd( aux_polyset, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
        aMergedPolygon->Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
    }

    return aMergedPolygon->OutlineCount() <= 1;
}
/**
 * Function TransformShapeWithClearanceToPolygon
 * Convert the track shape to a closed polygon
 * Used in filling zones calculations
 * Circles and arcs are approximated by segments
 * @param aCornerBuffer = a buffer to store the polygon
 * @param aClearanceValue = the clearance around the pad
 * @param aCircleToSegmentsCount = the number of segments to approximate a circle
 * @param aCorrectionFactor = the correction to apply to circles radius to keep
 * clearance when the circle is approxiamted by segment bigger or equal
 * to the real clearance value (usually near from 1.0)
 */
void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
                                                        int             aClearanceValue,
                                                        int             aCircleToSegmentsCount,
                                                        double          aCorrectionFactor ) const
{
    // The full width of the lines to create:
    int linewidth = m_Width + (2 * aClearanceValue);

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

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

    case S_SEGMENT:
        TransformRoundedEndsSegmentToPolygon( aCornerBuffer, m_Start, m_End,
                                              aCircleToSegmentsCount, linewidth );
        break;

    case S_POLYGON:
        if ( GetPolyPoints().size() < 2 )
            break;      // Malformed polygon.
        {
        // 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;

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

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

        // 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
        {
            CPolyPt corner1( poly[poly.size()-1] );

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

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

                corner1 = corner2;
            }
        }
        }
        break;

    case S_CURVE:       // Bezier curve (TODO: not yet in use)
        break;

    default:
        break;
    }
}