Exemple #1
0
/* Build the filled solid areas data from real outlines (stored in m_Poly)
 * The solid areas can be more than one on copper layers, and do not have holes
 * ( holes are linked by overlapping segments to the main outline)
 */
bool ZONE_FILLER::fillSingleZone( const ZONE_CONTAINER* aZone, SHAPE_POLY_SET& aRawPolys,
                                  SHAPE_POLY_SET& aFinalPolys ) const
{
    SHAPE_POLY_SET smoothedPoly;

    /* 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 ( !aZone->BuildSmoothedPoly( smoothedPoly ) )
        return false;

    if( aZone->IsOnCopperLayer() )
    {
        computeRawFilledAreas( aZone, smoothedPoly, aRawPolys, aFinalPolys );
    }
    else
    {
        aRawPolys = smoothedPoly;
        aFinalPolys = smoothedPoly;
        aFinalPolys.Inflate( -aZone->GetMinThickness() / 2, 16 );
        aFinalPolys.Fracture( SHAPE_POLY_SET::PM_FAST );
    }

    return true;
}
/* Build a pad outline as non filled polygon, to draw pads on silkscreen layer
 * Used only to draw pads outlines on silkscreen layers.
 */
void EDA_3D_CANVAS::buildPadShapeThickOutlineAsPolygon( const D_PAD*  aPad,
                                                SHAPE_POLY_SET& aCornerBuffer,
                                                int             aWidth,
                                                int             aCircleToSegmentsCount,
                                                double          aCorrectionFactor )
{
    if( aPad->GetShape() == PAD_SHAPE_CIRCLE )    // Draw a ring
    {
        TransformRingToPolygon( aCornerBuffer, aPad->ShapePos(),
                                aPad->GetSize().x / 2, aCircleToSegmentsCount, aWidth );
        return;
    }

    // For other shapes, draw polygon outlines
    SHAPE_POLY_SET corners;
    aPad->BuildPadShapePolygon( corners, wxSize( 0, 0 ),
                                aCircleToSegmentsCount, aCorrectionFactor );

    // Add outlines as thick segments in polygon buffer

    const SHAPE_LINE_CHAIN& path = corners.COutline( 0 );

    for( int ii = 0; ii < path.PointCount(); ii++ )
    {
        const VECTOR2I& a = path.CPoint( ii );
        const VECTOR2I& b = path.CPoint( ii + 1 );

        TransformRoundedEndsSegmentToPolygon( aCornerBuffer,
                                              wxPoint( a.x, a.y ),
                                              wxPoint( b.x, b.y ),
                                              aCircleToSegmentsCount, aWidth );
    }
}
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 Polygon_Calc_BBox_3DU( const SHAPE_POLY_SET &aPolysList,
                            CBBOX2D &aOutBBox ,
                            float aBiuTo3DunitsScale )
{
    aOutBBox.Reset();

    for( int idx = 0; idx < aPolysList.OutlineCount(); ++idx )
    {
        // Each polygon in aPolysList is a polygon with holes
        const SHAPE_POLY_SET::POLYGON& curr_polywithholes = aPolysList.CPolygon( idx );

        for( unsigned ipoly = 0; ipoly < curr_polywithholes.size(); ++ipoly )
        {
            const SHAPE_LINE_CHAIN& path = curr_polywithholes[ipoly]; // a simple polygon

             for( int jj = 0; jj < path.PointCount(); jj++ )
             {
                 const VECTOR2I& a = path.CPoint( jj );

                 aOutBBox.Union( SFVEC2F( (float) a.x * aBiuTo3DunitsScale,
                                          (float)-a.y * aBiuTo3DunitsScale ) );
             }
        }
    }

    aOutBBox.ScaleNextUp();
}
void Convert_shape_line_polygon_to_triangles( SHAPE_POLY_SET &aPolyList,
                                              CGENERICCONTAINER2D &aDstContainer,
                                              float aBiuTo3DunitsScale ,
                                              const BOARD_ITEM &aBoardItem )
{

    aPolyList.CacheTriangulation();
    const double conver_d = (double)aBiuTo3DunitsScale;

    for( unsigned int j = 0; j < aPolyList.TriangulatedPolyCount(); j++ )
    {
        auto triPoly = aPolyList.TriangulatedPolygon( j );

        for( size_t i = 0; i < triPoly->GetTriangleCount(); i++ )
        {
            VECTOR2I a;
            VECTOR2I b;
            VECTOR2I c;
            triPoly->GetTriangle( i, a, b, c );

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

    }
}
void HPGL_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize,
                                        int aCornerRadius, double aOrient,
                                        EDA_DRAW_MODE_T aTraceMode )
{
    SHAPE_POLY_SET outline;
    const int segmentToCircleCount = 32;

    wxSize size = aSize;

    if( aTraceMode == FILLED )
    {
        // in filled mode, the pen diameter is removed from size
        // to keep the pad size
        size.x -= KiROUND( penDiameter ) / 2;
        size.x = std::max( size.x, 0);
        size.y -= KiROUND( penDiameter ) / 2;
        size.y = std::max( size.y, 0);

        // keep aCornerRadius to a value < min size x,y < 2:
        aCornerRadius = std::min( aCornerRadius, std::min( size.x, size.y ) /2 );
    }

    TransformRoundRectToPolygon( outline, aPadPos, size, aOrient,
                                 aCornerRadius, segmentToCircleCount );

    // TransformRoundRectToPolygon creates only one convex polygon
    std::vector< wxPoint > cornerList;
    cornerList.reserve( segmentToCircleCount + 4 );
    SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );

    for( int ii = 0; ii < poly.PointCount(); ++ii )
        cornerList.push_back( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );

    PlotPoly( cornerList, aTraceMode == FILLED ? FILLED_SHAPE : NO_FILL );
}
/*
 * Function BuildPadShapePolygon
 * Build the Corner list of the polygonal shape,
 * depending on shape, extra size (clearance ...) pad and orientation
 * Note: for Round and oval pads this function is equivalent to
 * TransformShapeWithClearanceToPolygon, but not for other shapes
 */
void D_PAD::BuildPadShapePolygon( SHAPE_POLY_SET& aCornerBuffer,
                                  wxSize aInflateValue, int aSegmentsPerCircle,
                                  double aCorrectionFactor ) const
{
    wxPoint corners[4];
    wxPoint PadShapePos = ShapePos();         /* Note: for pad having a shape offset,
                                                     * the pad position is NOT the shape position */
    switch( GetShape() )
    {
    case PAD_SHAPE_CIRCLE:
    case PAD_SHAPE_OVAL:
        TransformShapeWithClearanceToPolygon( aCornerBuffer, aInflateValue.x,
                                              aSegmentsPerCircle, aCorrectionFactor );
        break;

    case PAD_SHAPE_TRAPEZOID:
    case PAD_SHAPE_RECT:
        aCornerBuffer.NewOutline();

        BuildPadPolygon( corners, aInflateValue, m_Orient );
        for( int ii = 0; ii < 4; ii++ )
        {
            corners[ii] += PadShapePos;          // Shift origin to position
            aCornerBuffer.Append( corners[ii].x, corners[ii].y );
        }

        break;
    }
}
/**
 * Function TransformBoundingBoxWithClearanceToPolygon
 * Convert the text bounding box to a rectangular 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 text bounding box
 */
void TEXTE_PCB::TransformBoundingBoxWithClearanceToPolygon(
                    SHAPE_POLY_SET& aCornerBuffer,
                    int             aClearanceValue ) const
{
    if( GetText().Length() == 0 )
        return;

    wxPoint  corners[4];    // Buffer of polygon corners

    EDA_RECT rect = GetTextBox( -1 );
    rect.Inflate( aClearanceValue );
    corners[0].x = rect.GetOrigin().x;
    corners[0].y = rect.GetOrigin().y;
    corners[1].y = corners[0].y;
    corners[1].x = rect.GetRight();
    corners[2].x = corners[1].x;
    corners[2].y = rect.GetBottom();
    corners[3].y = corners[2].y;
    corners[3].x = corners[0].x;

    aCornerBuffer.NewOutline();

    for( int ii = 0; ii < 4; ii++ )
    {
        // Rotate polygon
        RotatePoint( &corners[ii].x, &corners[ii].y, m_Pos.x, m_Pos.y, m_Orient );
        aCornerBuffer.Append( corners[ii].x, corners[ii].y );
    }
}
void GERBER_PLOTTER::FlashPadCustom( const wxPoint& aPadPos, const wxSize& aSize,
                                     SHAPE_POLY_SET* aPolygons,
                                     EDA_DRAW_MODE_T aTraceMode, void* aData )

{
    // A Pad custom is plotted as polygon.

    // A flashed circle @aPadPos is added (anchor pad)
    // However, because the anchor pad can be circle or rect, we use only
    // a circle not bigger than the rect.
    // the main purpose is to print a flashed DCode as pad anchor
    if( aTraceMode == FILLED )
        FlashPadCircle( aPadPos, std::min( aSize.x, aSize.y ), aTraceMode, aData );

    GBR_METADATA gbr_metadata;

    if( aData )
    {
        gbr_metadata = *static_cast<GBR_METADATA*>( aData );
        // If the pad is drawn on a copper layer,
        // set attribute to GBR_APERTURE_ATTRIB_CONDUCTOR
        if( gbr_metadata.IsCopper() )
            gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CONDUCTOR );

        wxString attrname( ".P" );
        gbr_metadata.m_NetlistMetadata.ClearAttribute( &attrname );   // not allowed on inner layers
    }

    SHAPE_POLY_SET polyshape = *aPolygons;

    if( aTraceMode != FILLED )
    {
        SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH, &gbr_metadata );
        polyshape.Inflate( -GetCurrentLineWidth()/2, 16 );
    }

    std::vector< wxPoint > cornerList;

    for( int cnt = 0; cnt < polyshape.OutlineCount(); ++cnt )
    {
        SHAPE_LINE_CHAIN& poly = polyshape.Outline( cnt );

        cornerList.clear();

        for( int ii = 0; ii < poly.PointCount(); ++ii )
            cornerList.push_back( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );

        // Close polygon
        cornerList.push_back( cornerList[0] );

        PlotPoly( cornerList,
                  aTraceMode == FILLED ? FILLED_SHAPE : NO_FILL,
                  aTraceMode == FILLED ? 0 : GetCurrentLineWidth(), &gbr_metadata );
    }
}
void GERBER_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize,
                                     int aCornerRadius, double aOrient,
                                     EDA_DRAW_MODE_T aTraceMode, void* aData )

{
    GBR_METADATA gbr_metadata;

    if( aData )
    {
        gbr_metadata = *static_cast<GBR_METADATA*>( aData );
        // If the pad is drawn on a copper layer,
        // set attribute to GBR_APERTURE_ATTRIB_CONDUCTOR
        if( gbr_metadata.IsCopper() )
            gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CONDUCTOR );

        wxString attrname( ".P" );
        gbr_metadata.m_NetlistMetadata.ClearAttribute( &attrname );   // not allowed on inner layers
    }

    if( aTraceMode != FILLED )
        SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH, &gbr_metadata );

    // Currently, a Pad RoundRect is plotted as polygon.
    // TODO: use Aperture macro and flash it
    SHAPE_POLY_SET outline;
    const int segmentToCircleCount = 64;
    TransformRoundRectToPolygon( outline, aPadPos, aSize, aOrient,
                                 aCornerRadius, segmentToCircleCount );

    if( aTraceMode != FILLED )
        outline.Inflate( -GetCurrentLineWidth()/2, 16 );

    std::vector< wxPoint > cornerList;
    // TransformRoundRectToPolygon creates only one convex polygon
    SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
    cornerList.reserve( poly.PointCount() + 1 );

    for( int ii = 0; ii < poly.PointCount(); ++ii )
        cornerList.push_back( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );

    // Close polygon
    cornerList.push_back( cornerList[0] );

    PlotPoly( cornerList, aTraceMode == FILLED ? FILLED_SHAPE : NO_FILL,
              aTraceMode == FILLED ? 0 : GetCurrentLineWidth(), &gbr_metadata );

    // Now, flash a pad anchor, if a netlist attribute is set
    // (remove me when a Aperture macro will be used)
    if( aData && aTraceMode == FILLED )
    {
        int diameter = std::min( aSize.x, aSize.y );
        FlashPadCircle( aPadPos, diameter, aTraceMode , aData );
    }
}
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 );
        }
    }
}
const CPOLYGONS_LIST ConvertPolySetToPolyList(const SHAPE_POLY_SET& aPolyset)
{
    CPOLYGONS_LIST list;
    CPolyPt corner, firstCorner;

    const SHAPE_POLY_SET::POLYGON& poly = aPolyset.CPolygon( 0 );

    for( unsigned int jj = 0; jj < poly.size() ; jj++ )
    {
        const SHAPE_LINE_CHAIN& path = poly[jj];

        for( int i = 0; i < path.PointCount(); i++ )
        {
            const VECTOR2I &v = path.CPoint( i );

            corner.x    = v.x;
            corner.y    = v.y;
            corner.end_contour = false;

            if( i == 0 )
                firstCorner = corner;

            list.AddCorner( corner );
        }

        firstCorner.end_contour = true;
        list.AddCorner( firstCorner );
    }

    return list;
}
void ZONE_CONTAINER::TransformSolidAreasShapesToPolygonSet(
        SHAPE_POLY_SET& aCornerBuffer, int aError ) const
{
    if( GetFilledPolysList().IsEmpty() )
        return;

    // add filled areas polygons
    aCornerBuffer.Append( m_FilledPolysList );
    auto board = GetBoard();
    int maxError = ARC_HIGH_DEF;

    if( board )
        maxError = board->GetDesignSettings().m_MaxError;

    // add filled areas outlines, which are drawn with thick lines
    for( int i = 0; i < m_FilledPolysList.OutlineCount(); i++ )
    {
        const SHAPE_LINE_CHAIN& path = m_FilledPolysList.COutline( i );

        for( int j = 0; j < path.PointCount(); j++ )
        {
            const VECTOR2I& a = path.CPoint( j );
            const VECTOR2I& b = path.CPoint( j + 1 );

            TransformRoundedEndsSegmentToPolygon( aCornerBuffer, wxPoint( a.x, a.y ),
                    wxPoint( b.x, b.y ), maxError, GetMinThickness() );
        }
    }
}
 /* Function TransformSolidAreasShapesToPolygonSet
 * Convert solid areas full shapes to polygon set
 * (the full shape is the polygon area with a thick outline)
 * Used in 3D view
 * Arcs (ends of segments) are approximated by segments
 * aCornerBuffer = a buffer to store the polygons
 * aCircleToSegmentsCount = the number of segments to approximate a circle
 * aCorrectionFactor = the correction to apply to arcs radius to roughly
 * keep arc radius when approximated by segments
 */
void ZONE_CONTAINER::TransformSolidAreasShapesToPolygonSet(
        SHAPE_POLY_SET& aCornerBuffer,
        int                    aCircleToSegmentsCount,
        double                 aCorrectionFactor )
{
    if( GetFilledPolysList().IsEmpty() )
        return;

    // add filled areas polygons
    aCornerBuffer.Append( m_FilledPolysList );

    // add filled areas outlines, which are drawn with thick lines
    for( int i = 0; i < m_FilledPolysList.OutlineCount(); i++ )
    {
        const SHAPE_LINE_CHAIN& path = m_FilledPolysList.COutline( i );

        for( int j = 0; j < path.PointCount(); j++ )
        {
            const VECTOR2I& a = path.CPoint( j );
            const VECTOR2I& b = path.CPoint( j + 1 );

            TransformRoundedEndsSegmentToPolygon( aCornerBuffer, wxPoint( a.x, a.y ), wxPoint( b.x, b.y ),
                                                    aCircleToSegmentsCount,
                                                    GetMinThickness() );
        }
    }
}
/*
 * Function BuildPadShapePolygon
 * Build the Corner list of the polygonal shape,
 * depending on shape, extra size (clearance ...) pad and orientation
 * Note: for Round and oval pads this function is equivalent to
 * TransformShapeWithClearanceToPolygon, but not for other shapes
 */
void D_PAD::BuildPadShapePolygon(
        SHAPE_POLY_SET& aCornerBuffer, wxSize aInflateValue, int aError ) const
{
    wxPoint corners[4];
    wxPoint padShapePos = ShapePos();       /* Note: for pad having a shape offset,
                                             * the pad position is NOT the shape position */
    switch( GetShape() )
    {
    case PAD_SHAPE_CIRCLE:
    case PAD_SHAPE_OVAL:
    case PAD_SHAPE_ROUNDRECT:
    case PAD_SHAPE_CHAMFERED_RECT:
    {
        // We are using TransformShapeWithClearanceToPolygon to build the shape.
        // Currently, this method uses only the same inflate value for X and Y dirs.
        // so because here this is not the case, we use a inflated dummy pad to build
        // the polygonal shape
        // TODO: remove this dummy pad when TransformShapeWithClearanceToPolygon will use
        // a wxSize to inflate the pad size
        D_PAD dummy( *this );
        dummy.SetSize( GetSize() + aInflateValue + aInflateValue );
        dummy.TransformShapeWithClearanceToPolygon( aCornerBuffer, 0 );
    }
        break;

    case PAD_SHAPE_TRAPEZOID:
    case PAD_SHAPE_RECT:
        aCornerBuffer.NewOutline();

        BuildPadPolygon( corners, aInflateValue, m_Orient );
        for( int ii = 0; ii < 4; ii++ )
        {
            corners[ii] += padShapePos;          // Shift origin to position
            aCornerBuffer.Append( corners[ii].x, corners[ii].y );
        }

        break;

    case PAD_SHAPE_CUSTOM:
        // for a custom shape, that is in fact a polygon (with holes), we can use only a inflate value.
        // so use ( aInflateValue.x + aInflateValue.y ) / 2 as polygon inflate value.
        // (different values for aInflateValue.x and aInflateValue.y has no sense for a custom pad)
        TransformShapeWithClearanceToPolygon(
                aCornerBuffer, ( aInflateValue.x + aInflateValue.y ) / 2 );
        break;
    }
}
void ZONE_CONTAINER::TransformShapeWithClearanceToPolygon(
        SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue, int aError, bool ignoreLineWidth ) const
{
    wxASSERT_MSG( !ignoreLineWidth, "IgnoreLineWidth has no meaning for zones." );

    aCornerBuffer = m_FilledPolysList;
    aCornerBuffer.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
}
// The helper function for D_CODE::ConvertShapeToPolygon().
// Add a hole to a polygon
static void addHoleToPolygon( SHAPE_POLY_SET*       aPolygon,
                              APERTURE_DEF_HOLETYPE aHoleShape,
                              wxSize                aSize,
                              wxPoint               aAnchorPos )
{
    wxPoint currpos;
    SHAPE_POLY_SET holeBuffer;

    if( aHoleShape == APT_DEF_ROUND_HOLE )
    {
        TransformCircleToPolygon( holeBuffer, wxPoint( 0, 0 ), aSize.x / 2, SEGS_CNT );
    }
    else if( aHoleShape == APT_DEF_RECT_HOLE )
    {
        holeBuffer.NewOutline();
        currpos.x = aSize.x / 2;
        currpos.y = aSize.y / 2;
        holeBuffer.Append( VECTOR2I( currpos ) );       // link to hole and begin hole
        currpos.x -= aSize.x;
        holeBuffer.Append( VECTOR2I( currpos ) );
        currpos.y -= aSize.y;
        holeBuffer.Append( VECTOR2I( currpos ) );
        currpos.x += aSize.x;
        holeBuffer.Append( VECTOR2I( currpos ) );
        currpos.y += aSize.y;
        holeBuffer.Append( VECTOR2I( currpos ) );       // close hole
    }

    aPolygon->BooleanSubtract( holeBuffer, SHAPE_POLY_SET::PM_FAST );

    // Needed for legacy canvas only
    aPolygon->Fracture( SHAPE_POLY_SET::PM_FAST );
}
/*
 * Function DrawApertureMacroShape
 * Draw the primitive shape for flashed items.
 * When an item is flashed, this is the shape of the item
 */
void APERTURE_MACRO::DrawApertureMacroShape( GERBER_DRAW_ITEM* aParent,
                                             EDA_RECT* aClipBox, wxDC* aDC,
                                             COLOR4D aColor,
                                             wxPoint aShapePos, bool aFilledShape )
{
    SHAPE_POLY_SET* shapeBuffer = GetApertureMacroShape( aParent, aShapePos );

    if( shapeBuffer->OutlineCount() == 0 )
        return;

    for( int ii = 0; ii < shapeBuffer->OutlineCount(); ii++ )
    {
        SHAPE_LINE_CHAIN& poly = shapeBuffer->Outline( ii );

        GRClosedPoly( aClipBox, aDC,
                      poly.PointCount(), (wxPoint*)&poly.Point( 0 ), aFilledShape, aColor, aColor );
    }
}
const SHAPE_POLY_SET ConvertPolyListToPolySet( const CPOLYGONS_LIST& aList )
{
    SHAPE_POLY_SET rv;

    unsigned corners_count = aList.GetCornersCount();

    // Enter main outline: this is the first contour
    unsigned ic = 0;

    if( !corners_count )
        return rv;

    int index = 0;

    while( ic < corners_count )
    {
        int hole = -1;

        if( index == 0 )
        {
            rv.NewOutline();
            hole = -1;
        }
        else
        {
            hole = rv.NewHole();
        }

        while( ic < corners_count )
        {
            rv.Append( aList.GetX( ic ), aList.GetY( ic ), 0, hole );

            if( aList.IsEndContour( ic ) )
                break;

            ic++;
        }
        ic++;

        index++;
    }

    return rv;
}
/**
 * Function TransformRoundRectToPolygon
 * convert a rectangle with rounded corners to a polygon
 * Convert arcs to multiple straight lines
 * @param aCornerBuffer = a buffer to store the polygon
 * @param aPosition = the coordinate of the center of the rectangle
 * @param aSize = the size of the rectangle
 * @param aRadius = radius of rounded corners
 * @param aRotation = rotation in 0.1 degrees of the rectangle
 * @param aCircleToSegmentsCount = the number of segments to approximate a circle
 */
void TransformRoundRectToPolygon( SHAPE_POLY_SET& aCornerBuffer,
                                  const wxPoint& aPosition, const wxSize& aSize,
                                  double aRotation, int aCornerRadius,
                                  int aCircleToSegmentsCount )
{
    wxPoint corners[4];
    GetRoundRectCornerCenters( corners, aCornerRadius, aPosition, aSize, aRotation );

    SHAPE_POLY_SET outline;
    outline.NewOutline();

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

    outline.Inflate( aCornerRadius, aCircleToSegmentsCount );

    // Add the outline:
    aCornerBuffer.Append( outline );
}
void DXF_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize,
                                     int aCornerRadius, double aOrient,
                                     EDA_DRAW_MODE_T aTraceMode, void* aData )
{
    SHAPE_POLY_SET outline;
    const int segmentToCircleCount = 64;
    TransformRoundRectToPolygon( outline, aPadPos, aSize, aOrient,
                                 aCornerRadius, segmentToCircleCount );

    // TransformRoundRectToPolygon creates only one convex polygon
    SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );

    MoveTo( wxPoint( poly.Point( 0 ).x, poly.Point( 0 ).y ) );

    for( int ii = 1; ii < poly.PointCount(); ++ii )
        LineTo( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );

    FinishTo( wxPoint( poly.Point( 0 ).x, poly.Point( 0 ).y ) );
}
/* This function is used to extract a board outlines (3D view, automatic zones build ...)
 * Any closed outline inside the main outline is a hole
 * All contours should be closed, i.e. valid closed polygon vertices
 */
bool BuildBoardPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines,
        wxString* aErrorText, unsigned int aTolerance, wxPoint* aErrorLocation )
{
    PCB_TYPE_COLLECTOR  items;

    // Get all the DRAWSEGMENTS and module graphics into 'items',
    // then keep only those on layer == Edge_Cuts.
    static const KICAD_T  scan_graphics[] = { PCB_LINE_T, PCB_MODULE_EDGE_T, EOT };
    items.Collect( aBoard, scan_graphics );

    // Make a working copy of aSegList, because the list is modified during calculations
    std::vector< DRAWSEGMENT* > segList;

    for( int ii = 0; ii < items.GetCount(); ii++ )
    {
        if( items[ii]->GetLayer() == Edge_Cuts )
            segList.push_back( static_cast< DRAWSEGMENT* >( items[ii] ) );
    }

    bool success = ConvertOutlineToPolygon( segList, aOutlines, aErrorText, aTolerance, aErrorLocation );

    if( !success || !aOutlines.OutlineCount() )
    {
        // Creates a valid polygon outline is not possible.
        // So uses the board edge cuts bounding box to create a
        // rectangular outline
        // When no edge cuts items, build a contour
        // from global bounding box

        EDA_RECT bbbox = aBoard->GetBoardEdgesBoundingBox();

        // If null area, uses the global bounding box.
        if( ( bbbox.GetWidth() ) == 0 || ( bbbox.GetHeight() == 0 ) )
            bbbox = aBoard->ComputeBoundingBox();

        // Ensure non null area. If happen, gives a minimal size.
        if( ( bbbox.GetWidth() ) == 0 || ( bbbox.GetHeight() == 0 ) )
            bbbox.Inflate( Millimeter2iu( 1.0 ) );

        aOutlines.RemoveAllContours();
        aOutlines.NewOutline();

        wxPoint corner;
        aOutlines.Append( bbbox.GetOrigin() );

        corner.x = bbbox.GetOrigin().x;
        corner.y = bbbox.GetEnd().y;
        aOutlines.Append( corner );

        aOutlines.Append( bbbox.GetEnd() );

        corner.x = bbbox.GetEnd().x;
        corner.y = bbbox.GetOrigin().y;
        aOutlines.Append( corner );
    }

    return success;
}
SHAPE_POLY_SET* APERTURE_MACRO::GetApertureMacroShape( const GERBER_DRAW_ITEM* aParent,
                                                       wxPoint aShapePos )
{
    SHAPE_POLY_SET holeBuffer;
    bool hasHole = false;

    m_shape.RemoveAllContours();

    for( AM_PRIMITIVES::iterator prim_macro = primitives.begin();
         prim_macro != primitives.end(); ++prim_macro )
    {
        if( prim_macro->primitive_id == AMP_COMMENT )
            continue;

        if( prim_macro->IsAMPrimitiveExposureOn( aParent ) )
            prim_macro->DrawBasicShape( aParent, m_shape, aShapePos );
        else
        {
            prim_macro->DrawBasicShape( aParent, holeBuffer, aShapePos );

            if( holeBuffer.OutlineCount() )     // we have a new hole in shape: remove the hole
            {
                m_shape.BooleanSubtract( holeBuffer, SHAPE_POLY_SET::PM_FAST );
                holeBuffer.RemoveAllContours();
                hasHole = true;
            }
        }
    }

    // If a hole is defined inside a polygon, we must fracture the polygon
    // to be able to drawn it (i.e link holes by overlapping edges)
    if( hasHole )
        m_shape.Fracture( SHAPE_POLY_SET::PM_FAST );

    m_boundingBox = EDA_RECT( wxPoint( 0, 0 ), wxSize( 1, 1 ) );
    auto bb = m_shape.BBox();
    wxPoint center( bb.Centre().x, bb.Centre().y );
    m_boundingBox.Move( aParent->GetABPosition( center ) );
    m_boundingBox.Inflate( bb.GetWidth() / 2, bb.GetHeight() / 2 );

    return &m_shape;
}
/**
 * Function TransformCircleToPolygon
 * convert a circle to a polygon, using multiple straight lines
 * @param aCornerBuffer = a buffer to store the polygon
 * @param aCenter = the center of the circle
 * @param aRadius = the radius of the circle
 * @param aCircleToSegmentsCount = the number of segments to approximate a circle
 * Note: the polygon is inside the circle, so if you want to have the polygon
 * outside the circle, you should give aRadius calculated with a corrrection factor
 */
void TransformCircleToPolygon( SHAPE_POLY_SET& aCornerBuffer,
                               wxPoint aCenter, int aRadius,
                               int aCircleToSegmentsCount )
{
    wxPoint corner_position;
    int     delta       = 3600 / aCircleToSegmentsCount;    // rot angle in 0.1 degree
    int     halfstep    = 1800 / aCircleToSegmentsCount;    // the starting value for rot angles

    aCornerBuffer.NewOutline();

    for( int ii = 0; ii < aCircleToSegmentsCount; ii++ )
    {
        corner_position.x   = aRadius;
        corner_position.y   = 0;
        int     angle = (ii * delta) + halfstep;
        RotatePoint( &corner_position.x, &corner_position.y, angle );
        corner_position += aCenter;
        aCornerBuffer.Append( corner_position.x, corner_position.y );
    }
}
/**
 * Function TransformRingToPolygon
 * Creates a polygon from a ring
 * Convert arcs to multiple straight segments
 * @param aCornerBuffer = a buffer to store the polygon
 * @param aCentre = centre of the arc or circle
 * @param aRadius = radius of the circle
 * @param aCircleToSegmentsCount = the number of segments to approximate a circle
 * @param aWidth = width (thickness) of the ring
 */
void TransformRingToPolygon( SHAPE_POLY_SET& aCornerBuffer,
                             wxPoint aCentre, int aRadius,
                             int aCircleToSegmentsCount, int aWidth )
{
    int     delta = 3600 / aCircleToSegmentsCount;   // rotate angle in 0.1 degree

    // Compute the corners posituions and creates poly
    wxPoint curr_point;
    int     inner_radius    = aRadius - ( aWidth / 2 );
    int     outer_radius    = inner_radius + aWidth;

    aCornerBuffer.NewOutline();

    // Draw the inner circle of the ring
    for( int ii = 0; ii < 3600; ii += delta )
    {
        curr_point.x    = inner_radius;
        curr_point.y    = 0;
        RotatePoint( &curr_point, ii );
        curr_point      += aCentre;
        aCornerBuffer.Append( curr_point.x, curr_point.y );
    }

    // Draw the last point of inner circle
    aCornerBuffer.Append( aCentre.x + inner_radius, aCentre.y );

    // Draw the outer circle of the ring
    for( int ii = 0; ii < 3600; ii += delta )
    {
        curr_point.x    = outer_radius;
        curr_point.y    = 0;
        RotatePoint( &curr_point, -ii );
        curr_point      += aCentre;
        aCornerBuffer.Append( curr_point.x, curr_point.y );
    }

    // Draw the last point of outer circle
    aCornerBuffer.Append( aCentre.x + outer_radius, aCentre.y );
    aCornerBuffer.Append( aCentre.x + inner_radius, aCentre.y );
}
bool BOARD::CombineAreas( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_ref,
                          ZONE_CONTAINER* area_to_combine )
{
    if( area_ref == area_to_combine )
    {
        wxASSERT( 0 );
        return false;
    }

    SHAPE_POLY_SET mergedOutlines = *area_ref->Outline();
    SHAPE_POLY_SET areaToMergePoly = *area_to_combine->Outline();

    mergedOutlines.BooleanAdd( areaToMergePoly, SHAPE_POLY_SET::PM_FAST  );
    mergedOutlines.Simplify( SHAPE_POLY_SET::PM_FAST );

    // We should have one polygon with hole
    // We can have 2 polygons with hole, if the 2 initial polygons have only one common corner
    // and therefore cannot be merged (they are dectected as intersecting)
    // but we should never have more than 2 polys
    if( mergedOutlines.OutlineCount() > 2 )
    {
        wxLogMessage(wxT("BOARD::CombineAreas error: more than 2 polys after merging") );
        return false;
    }

    if( mergedOutlines.OutlineCount() > 1 )
        return false;

    // Update the area with the new merged outline
    delete area_ref->Outline();
    area_ref->SetOutline( new SHAPE_POLY_SET( mergedOutlines ) );

    RemoveArea( aDeletedList, area_to_combine );

    area_ref->SetLocalFlags( 1 );
    area_ref->Hatch();

    return true;
}
void CINFO3D_VISU::buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
                                                SHAPE_POLY_SET& aCornerBuffer,
                                                int             aWidth ) const
{
    if( aPad->GetShape() == PAD_SHAPE_CIRCLE )    // Draw a ring
    {
        unsigned int nr_sides_per_circle = GetNrSegmentsCircle( ( aPad->GetSize().x / 2 +
                                                                  aWidth / 2 ) * 2 );

        TransformRingToPolygon( aCornerBuffer, aPad->ShapePos(),
                                aPad->GetSize().x / 2, nr_sides_per_circle, aWidth );
        return;
    }

    // For other shapes, draw polygon outlines
    SHAPE_POLY_SET corners;

    unsigned int nr_sides_per_circle = GetNrSegmentsCircle( glm::min( aPad->GetSize().x,
                                                                      aPad->GetSize().y) );

    buildPadShapePolygon( aPad, corners, wxSize( 0, 0 ),
                                nr_sides_per_circle, GetCircleCorrectionFactor( nr_sides_per_circle ) );

    // Add outlines as thick segments in polygon buffer

    const SHAPE_LINE_CHAIN& path = corners.COutline( 0 );

    for( int ii = 0; ii < path.PointCount(); ++ii )
    {
        const VECTOR2I& a = path.CPoint( ii );
        const VECTOR2I& b = path.CPoint( ii + 1 );

        TransformRoundedEndsSegmentToPolygon( aCornerBuffer,
                                              wxPoint( a.x, a.y ),
                                              wxPoint( b.x, b.y ),
                                              nr_sides_per_circle,
                                              aWidth );
    }
}
void PSLIKE_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize,
                                        int aCornerRadius, double aOrient,
                                        EDA_DRAW_MODE_T aTraceMode, void* aData )
{
    wxSize size( aSize );

    if( aTraceMode == FILLED )
        SetCurrentLineWidth( 0 );
    else
    {
        SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH );
        size.x -= GetCurrentLineWidth();
        size.y -= GetCurrentLineWidth();
        aCornerRadius -= GetCurrentLineWidth()/2;
    }


    SHAPE_POLY_SET outline;
    const int segmentToCircleCount = 64;
    TransformRoundRectToPolygon( outline, aPadPos, size, aOrient,
                                 aCornerRadius, segmentToCircleCount );

    std::vector< wxPoint > cornerList;
    cornerList.reserve( segmentToCircleCount + 5 );
    // TransformRoundRectToPolygon creates only one convex polygon
    SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );

    for( int ii = 0; ii < poly.PointCount(); ++ii )
        cornerList.push_back( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );

    // Close polygon
    cornerList.push_back( cornerList[0] );

    PlotPoly( cornerList, ( aTraceMode == FILLED ) ? FILLED_SHAPE : NO_FILL,
              GetCurrentLineWidth() );
}
/**
 * Function TransformRingToPolygon
 * Creates a polygon from a ring
 * Convert arcs to multiple straight segments
 * @param aCornerBuffer = a buffer to store the polygon
 * @param aCentre = centre of the arc or circle
 * @param aRadius = radius of the circle
 * @param aCircleToSegmentsCount = the number of segments to approximate a circle
 * @param aWidth = width (thickness) of the ring
 */
void TransformRingToPolygon( SHAPE_POLY_SET& aCornerBuffer,
                             wxPoint aCentre, int aRadius,
                             int aCircleToSegmentsCount, int aWidth )
{
    // Compute the corners positions and creates the poly
    wxPoint curr_point;
    int     inner_radius    = aRadius - ( aWidth / 2 );
    int     outer_radius    = inner_radius + aWidth;

    if( inner_radius <= 0 )
    {   //In this case, the ring is just a circle (no hole inside)
        TransformCircleToPolygon( aCornerBuffer, aCentre, aRadius + ( aWidth / 2 ),
                                  aCircleToSegmentsCount );
        return;
    }

    aCornerBuffer.NewOutline();

    // Draw the inner circle of the ring
    int     delta = 3600 / aCircleToSegmentsCount;   // rotate angle in 0.1 degree

    for( int ii = 0; ii < 3600; ii += delta )
    {
        curr_point.x    = inner_radius;
        curr_point.y    = 0;
        RotatePoint( &curr_point, ii );
        curr_point      += aCentre;
        aCornerBuffer.Append( curr_point.x, curr_point.y );
    }

    // Draw the last point of inner circle
    aCornerBuffer.Append( aCentre.x + inner_radius, aCentre.y );

    // Draw the outer circle of the ring
    // the first point creates also a segment from the inner to the outer polygon
    for( int ii = 0; ii < 3600; ii += delta )
    {
        curr_point.x    = outer_radius;
        curr_point.y    = 0;
        RotatePoint( &curr_point, -ii );
        curr_point      += aCentre;
        aCornerBuffer.Append( curr_point.x, curr_point.y );
    }

    // Draw the last point of outer circle
    aCornerBuffer.Append( aCentre.x + outer_radius, aCentre.y );

    // And connect the outer polygon to the inner polygon,.
    // because a segment from inner to the outer polygon was already created,
    // the final polygon is the inner and the outer outlines connected by
    // 2 overlapping segments
    aCornerBuffer.Append( aCentre.x + inner_radius, aCentre.y );
}
// This is the same function as in board_items_to_polygon_shape_transform.cpp
// but it adds the rect/trapezoid shapes with a different winding
void CINFO3D_VISU::buildPadShapePolygon( const D_PAD* aPad,
                                         SHAPE_POLY_SET& aCornerBuffer,
                                         wxSize aInflateValue,
                                         int aSegmentsPerCircle,
                                         double aCorrectionFactor ) const
{
    wxPoint corners[4];
    wxPoint PadShapePos = aPad->ShapePos(); /* Note: for pad having a shape offset,
                                             * the pad position is NOT the shape position */
    switch( aPad->GetShape() )
    {
    case PAD_SHAPE_CIRCLE:
    case PAD_SHAPE_OVAL:
    case PAD_SHAPE_ROUNDRECT:
        aPad->TransformShapeWithClearanceToPolygon( aCornerBuffer, aInflateValue.x,
                                                    aSegmentsPerCircle, aCorrectionFactor );
        break;

    case PAD_SHAPE_TRAPEZOID:
    case PAD_SHAPE_RECT:
    {
        SHAPE_LINE_CHAIN aLineChain;

        aPad->BuildPadPolygon( corners, aInflateValue, aPad->GetOrientation() );

        for( int ii = 0; ii < 4; ++ii )
        {
            corners[3-ii] += PadShapePos;          // Shift origin to position
            aLineChain.Append( corners[3-ii].x, corners[3-ii].y );
        }

        aLineChain.SetClosed( true );

        aCornerBuffer.AddOutline( aLineChain );
    }
        break;

    default:
        wxFAIL_MSG( wxT( "CINFO3D_VISU::buildPadShapePolygon: found a not implemented pad shape (new shape?)" ) );
        break;
    }
}