void CLAYER_TRIANGLES::AddToMiddleContourns( const SHAPE_POLY_SET &aPolySet,
                                             float zBot,
                                             float zTop,
                                             double aBiuTo3Du,
                                             bool aInvertFaceDirection )
{
    wxASSERT( aPolySet.OutlineCount() > 0 );

    if( aPolySet.OutlineCount() == 0 )
        return;

    // Calculate an estimation of points to reserve
    unsigned int nrContournPointsToReserve = 0;

    for( int i = 0; i < aPolySet.OutlineCount(); ++i )
    {
        const SHAPE_LINE_CHAIN& pathOutline = aPolySet.COutline( i );

        nrContournPointsToReserve += pathOutline.PointCount();

        for( int h = 0; h < aPolySet.HoleCount( i ); ++h )
        {
            const SHAPE_LINE_CHAIN &hole = aPolySet.CHole( i, h );

            nrContournPointsToReserve += hole.PointCount();
        }
    }

    // Request to reserve more space
    m_layer_middle_contourns_quads->Reserve_More( nrContournPointsToReserve * 2,
                                                  true );

    #pragma omp parallel for
    for( signed int i = 0; i < aPolySet.OutlineCount(); ++i )
    {
        // Add outline
        const SHAPE_LINE_CHAIN& pathOutline = aPolySet.COutline( i );

        AddToMiddleContourns( pathOutline, zBot, zTop, aBiuTo3Du, aInvertFaceDirection );

        // Add holes for this outline
        for( int h = 0; h < aPolySet.HoleCount( i ); ++h )
        {
            const SHAPE_LINE_CHAIN &hole = aPolySet.CHole( i, h );
            AddToMiddleContourns( hole, zBot, zTop, aBiuTo3Du, aInvertFaceDirection );
        }
    }
}
void Convert_shape_line_polygon_to_triangles( const SHAPE_POLY_SET &aPolyList,
                                              CGENERICCONTAINER2D &aDstContainer,
                                              float aBiuTo3DunitsScale ,
                                              const BOARD_ITEM &aBoardItem )
{
    unsigned int nOutlines = aPolyList.OutlineCount();


    for( unsigned int idx = 0; idx < nOutlines; ++idx )
    {
        const SHAPE_LINE_CHAIN &outlinePath = aPolyList.COutline( idx );

        wxASSERT( outlinePath.PointCount() >= 3 );

        std::vector<SFVEC2I64> scaledOutline;
        scaledOutline.resize( outlinePath.PointCount() );

        // printf("\nidx: %u\n", idx);

        // Apply a scale to the points
        for( unsigned int i = 0;
             i < (unsigned int)outlinePath.PointCount();
             ++i )
        {
            const VECTOR2I& a = outlinePath.CPoint( i );

#ifdef APPLY_EDGE_SHRINK
            scaledOutline[i] = SFVEC2I64( (glm::int64)a.x * POLY_SCALE_FACT,
                                          (glm::int64)a.y * POLY_SCALE_FACT );
#else
            scaledOutline[i] = SFVEC2I64( (glm::int64)a.x,
                                          (glm::int64)a.y );
#endif
        }

#ifdef APPLY_EDGE_SHRINK
        // Apply a modification to the points
        EdgeShrink( scaledOutline );
#endif
        // Copy to a array of pointers
        std::vector<p2t::Point*> polyline;
        polyline.resize( outlinePath.PointCount() );

        for( unsigned int i = 0;
             i < (unsigned int)scaledOutline.size();
             ++i )
        {
            const SFVEC2I64 &a = scaledOutline[i];

            //printf("%lu %lu\n", a.x, a.y);

            polyline[i] = new p2t::Point( (double)a.x,
                                          (double)a.y );
        }

        // Start creating the structured to be triangulated
        p2t::CDT* cdt = new p2t::CDT( polyline );

        // Add holes for this outline
        unsigned int nHoles = aPolyList.HoleCount( idx );

        std::vector< std::vector<p2t::Point*> > polylineHoles;

        polylineHoles.resize( nHoles );

        for( unsigned int idxHole = 0; idxHole < nHoles; ++idxHole )
        {
            const SHAPE_LINE_CHAIN &outlineHoles = aPolyList.CHole( idx,
                                                                    idxHole );

            wxASSERT( outlineHoles.PointCount() >= 3 );

            std::vector<SFVEC2I64> scaledHole;
            scaledHole.resize( outlineHoles.PointCount() );

            // Apply a scale to the points
            for( unsigned int i = 0;
                 i < (unsigned int)outlineHoles.PointCount();
                 ++i )
            {
                const VECTOR2I &h = outlineHoles.CPoint( i );
#ifdef APPLY_EDGE_SHRINK
                scaledHole[i] = SFVEC2I64( (glm::int64)h.x * POLY_SCALE_FACT,
                                           (glm::int64)h.y * POLY_SCALE_FACT );
#else
                scaledHole[i] = SFVEC2I64( (glm::int64)h.x,
                                           (glm::int64)h.y );
#endif
            }

#ifdef APPLY_EDGE_SHRINK
            // Apply a modification to the points
            EdgeShrink( scaledHole );
#endif

            // Resize and reserve space
            polylineHoles[idxHole].resize( outlineHoles.PointCount() );

            for( unsigned int i = 0;
                 i < (unsigned int)outlineHoles.PointCount();
                 ++i )
            {
                const SFVEC2I64 &h = scaledHole[i];

                polylineHoles[idxHole][i] = new p2t::Point( h.x, h.y );
            }

            cdt->AddHole( polylineHoles[idxHole] );
        }

        // Triangulate
        cdt->Triangulate();

        // Hint: if you find any crashes on the triangulation poly2tri library,
        // you can use the following site to debug the points and it will mark
        // the errors in the polygon:
        // http://r3mi.github.io/poly2tri.js/


        // Get and add triangles
        std::vector<p2t::Triangle*> triangles;
        triangles = cdt->GetTriangles();

#ifdef APPLY_EDGE_SHRINK
        const double conver_d = (double)aBiuTo3DunitsScale *
                                POLY_SCALE_FACT_INVERSE;
#else
        const double conver_d = (double)aBiuTo3DunitsScale;
#endif
        for( unsigned int i = 0; i < triangles.size(); ++i )
        {
            p2t::Triangle& t = *triangles[i];

            p2t::Point& a = *t.GetPoint( 0 );
            p2t::Point& b = *t.GetPoint( 1 );
            p2t::Point& c = *t.GetPoint( 2 );

            aDstContainer.Add( new CTRIANGLE2D( SFVEC2F( a.x * conver_d,
                                                        -a.y * conver_d ),
                                                SFVEC2F( b.x * conver_d,
                                                        -b.y * conver_d ),
                                                SFVEC2F( c.x * conver_d,
                                                        -c.y * conver_d ),
                                                aBoardItem ) );
        }

        // Delete created data
        delete cdt;

        // Free points
        FreeClear(polyline);

        for( unsigned int idxHole = 0; idxHole < nHoles; ++idxHole )
        {
            FreeClear( polylineHoles[idxHole] );
        }
    }
}
/* Plot outlines of copper, for copper layer
 */
void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter,
                        LSET aLayerMask, const PCB_PLOT_PARAMS& aPlotOpt )
{

    BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
    itemplotter.SetLayerSet( aLayerMask );

    SHAPE_POLY_SET outlines;

    for( LSEQ seq = aLayerMask.Seq( plot_seq, DIM( plot_seq ) );  seq;  ++seq )
    {
        LAYER_ID layer = *seq;

        outlines.RemoveAllContours();
        aBoard->ConvertBrdLayerToPolygonalContours( layer, outlines );

        outlines.Simplify();

        // Plot outlines
        std::vector< wxPoint > cornerList;

        // Now we have one or more basic polygons: plot each polygon
        for( int ii = 0; ii < outlines.OutlineCount(); ii++ )
        {
            for(int kk = 0; kk <= outlines.HoleCount (ii); kk++ )
            {
                cornerList.clear();
                const SHAPE_LINE_CHAIN& path = (kk == 0) ? outlines.COutline( ii ) : outlines.CHole( ii, kk - 1 );

                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] );

                aPlotter->PlotPoly( cornerList, NO_FILL );
            }
        }

        // Plot pad holes
        if( aPlotOpt.GetDrillMarksType() != PCB_PLOT_PARAMS::NO_DRILL_SHAPE )
        {
            for( MODULE* module = aBoard->m_Modules; module; module = module->Next() )
            {
                for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() )
                {
                    wxSize hole = pad->GetDrillSize();

                    if( hole.x == 0 || hole.y == 0 )
                        continue;

                    if( hole.x == hole.y )
                        aPlotter->Circle( pad->GetPosition(), hole.x, NO_FILL );
                    else
                    {
                        wxPoint drl_start, drl_end;
                        int width;
                        pad->GetOblongDrillGeometry( drl_start, drl_end, width );
                        aPlotter->ThickSegment( pad->GetPosition() + drl_start,
                                                pad->GetPosition() + drl_end, width, SKETCH );
                    }
                }
            }
        }

        // Plot vias holes
        for( TRACK* track = aBoard->m_Track; track; track = track->Next() )
        {
            const VIA* via = dyn_cast<const VIA*>( track );

            if( via && via->IsOnLayer( layer ) )    // via holes can be not through holes
            {
                aPlotter->Circle( via->GetPosition(), via->GetDrillValue(), NO_FILL );
            }
        }
    }
}