/* draw the solid polygon found in aPolysList
 * The first polygon is the main polygon, others are holes
 * See Draw3D_SolidHorizontalPolyPolygons for more info
 */
void Draw3D_SolidHorizontalPolygonWithHoles( const CPOLYGONS_LIST& aPolysList,
        int aZpos, int aThickness,
        double aBiuTo3DUnits, bool aUseTextures )
{
    CPOLYGONS_LIST polygon;

    ConvertPolysListWithHolesToOnePolygon( aPolysList, polygon );
    Draw3D_SolidHorizontalPolyPolygons( polygon, aZpos, aThickness, aBiuTo3DUnits, aUseTextures );
}
/*
 * Function Draw3D_ZaxisOblongCylinder:
 * draw a segment with an oblong hole.
 * Used to draw oblong holes
 * If aHeight = height of the cylinder is 0, only one ring will be drawn
 * If aThickness = 0, only one cylinder will be drawn
 */
void Draw3D_ZaxisOblongCylinder( wxPoint aAxis1Pos, wxPoint aAxis2Pos,
                                 int aRadius, int aHeight, int aThickness,
                                 int aZpos, double aBiuTo3DUnits  )
{
    const int slice = SEGM_PER_CIRCLE;

    // Build the points to approximate oblong cylinder by segments
    CPOLYGONS_LIST outer_cornerBuffer;

    int segm_width = (aRadius * 2) + aThickness;
    TransformRoundedEndsSegmentToPolygon( outer_cornerBuffer, aAxis1Pos,
                                          aAxis2Pos, slice, segm_width );

    // Draw the oblong outer cylinder
    if( aHeight )
        Draw3D_VerticalPolygonalCylinder( outer_cornerBuffer, aHeight, aZpos,
                                          false, aBiuTo3DUnits );

    if( aThickness )
    {
        CPOLYGONS_LIST inner_cornerBuffer;
        segm_width = aRadius * 2;
        TransformRoundedEndsSegmentToPolygon( inner_cornerBuffer, aAxis1Pos,
                                              aAxis2Pos, slice, segm_width );

        // Draw the oblong inner cylinder
        if( aHeight )
            Draw3D_VerticalPolygonalCylinder( inner_cornerBuffer, aHeight,
                                              aZpos, true, aBiuTo3DUnits );

        // Build the horizontal full polygon shape
        // (outer polygon shape - inner polygon shape)
        outer_cornerBuffer.Append( inner_cornerBuffer );

        CPOLYGONS_LIST polygon;
        ConvertPolysListWithHolesToOnePolygon( outer_cornerBuffer, polygon );

        // draw top (front) horizontal side (ring)
        SetNormalZpos();
        Draw3D_SolidHorizontalPolyPolygons( polygon, aZpos + aHeight, 0, aBiuTo3DUnits, false );

        if( aHeight )
        {
            // draw bottom (back) horizontal side (ring)
            SetNormalZneg();
            Draw3D_SolidHorizontalPolyPolygons( polygon, aZpos, 0, aBiuTo3DUnits, false );
        }
    }

    SetNormalZpos();
}
/* draw a cylinder (a tube) using 3D primitives.
 * the cylinder axis is parallel to the Z axis
 * If aHeight = height of the cylinder is 0, only one ring will be drawn
 * If aThickness = 0, only one cylinder will be drawn
 */
void Draw3D_ZaxisCylinder( wxPoint aCenterPos, int aRadius,
                           int aHeight, int aThickness,
                           int aZpos, double aBiuTo3DUnits )
{
    const int slice = SEGM_PER_CIRCLE;
    CPOLYGONS_LIST outer_cornerBuffer;

    TransformCircleToPolygon( outer_cornerBuffer, aCenterPos,
                              aRadius + (aThickness / 2), slice );

    std::vector<S3D_VERTEX> coords;
    coords.resize( 4 );

    CPOLYGONS_LIST inner_cornerBuffer;
    if( aThickness )    // build the the vertical inner polygon (hole)
        TransformCircleToPolygon( inner_cornerBuffer, aCenterPos,
                                  aRadius - (aThickness / 2), slice );

    if( aHeight )
    {
        // Draw the vertical outer side
        Draw3D_VerticalPolygonalCylinder( outer_cornerBuffer,
                                          aHeight, aZpos, false, aBiuTo3DUnits );
        if( aThickness )
            // Draws the vertical inner side (hole)
            Draw3D_VerticalPolygonalCylinder( inner_cornerBuffer,
                                              aHeight, aZpos, true, aBiuTo3DUnits );
    }

    if( aThickness )
    {
        // draw top (front) and bottom (back) horizontal sides (rings)
        SetNormalZpos();
        outer_cornerBuffer.Append( inner_cornerBuffer );
        CPOLYGONS_LIST polygon;

        ConvertPolysListWithHolesToOnePolygon( outer_cornerBuffer, polygon );
        // draw top (front) horizontal ring
        Draw3D_SolidHorizontalPolyPolygons( polygon, aZpos + aHeight, 0, aBiuTo3DUnits, false );

        if( aHeight )
        {
            // draw bottom (back) horizontal ring
            SetNormalZneg();
            Draw3D_SolidHorizontalPolyPolygons( polygon, aZpos, 0, aBiuTo3DUnits, false );
        }
    }

    SetNormalZpos();
}
bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb,
        CPOLYGONS_LIST* aCornerBuffer )
{
    if( aCornerBuffer == NULL )
        m_FilledPolysList.RemoveAllContours();

    /* convert outlines + holes to outlines without holes (adding extra segments if necessary)
     * m_Poly data is expected normalized, i.e. NormalizeAreaOutlines was used after building
     * this zone
     */

    if( GetNumCorners() <= 2 )  // malformed zone. polygon calculations do not like it ...
        return 0;

    // Make a smoothed polygon out of the user-drawn polygon if required
    if( m_smoothedPoly )
    {
        delete m_smoothedPoly;
        m_smoothedPoly = NULL;
    }

    switch( m_cornerSmoothingType )
    {
    case ZONE_SETTINGS::SMOOTHING_CHAMFER:
        m_smoothedPoly = m_Poly->Chamfer( m_cornerRadius );
        break;
    case ZONE_SETTINGS::SMOOTHING_FILLET:
        m_smoothedPoly = m_Poly->Fillet( m_cornerRadius, m_ArcToSegmentsCount );
        break;
    default:
        m_smoothedPoly = new CPolyLine;
        m_smoothedPoly->Copy( m_Poly );
        break;
    }

    if( aCornerBuffer )
        ConvertPolysListWithHolesToOnePolygon( m_smoothedPoly->m_CornersList,
                                               *aCornerBuffer );
    else
        ConvertPolysListWithHolesToOnePolygon( m_smoothedPoly->m_CornersList,
                                               m_FilledPolysList );

    /* For copper layers, we now must add holes in the Polygon list.
     * holes are pads and tracks with their clearance area
     * for non copper layers just recalculate the m_FilledPolysList
     * with m_ZoneMinThickness taken in account
     */
    if( ! aCornerBuffer )
    {
        if( IsOnCopperLayer() )
            AddClearanceAreasPolygonsToPolysList( aPcb );
        else
        {
            // This KI_POLYGON_SET is the area(s) to fill, with m_ZoneMinThickness/2
            KI_POLYGON_SET polyset_zone_solid_areas;
            int         margin = m_ZoneMinThickness / 2;

            /* First, creates the main polygon (i.e. the filled area using only one outline)
             * to reserve a m_ZoneMinThickness/2 margin around the outlines and holes
             * this margin is the room to redraw outlines with segments having a width set to
             * m_ZoneMinThickness
             * so m_ZoneMinThickness is the min thickness of the filled zones areas
             * the polygon is stored in polyset_zone_solid_areas
             */
            CopyPolygonsFromFilledPolysListToKiPolygonList( polyset_zone_solid_areas );
            polyset_zone_solid_areas -= margin;
            // put solid area in m_FilledPolysList:
            m_FilledPolysList.RemoveAllContours();
            CopyPolygonsFromKiPolygonListToFilledPolysList( polyset_zone_solid_areas );
        }
        if ( m_FillMode )   // if fill mode uses segments, create them:
            FillZoneAreasWithSegments( );
    }

    return 1;
}