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 );
}
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 );
    }
}
/*
 * 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 );
    }
}
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 ) );
}
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() );
}
Example #7
0
std::unique_ptr<PNS::SOLID> PNS_KICAD_IFACE::syncPad( D_PAD* aPad )
{
    LAYER_RANGE layers( 0, MAX_CU_LAYERS - 1 );

    // ignore non-copper pads
    if( ( aPad->GetLayerSet() & LSET::AllCuMask()).none() )
        return NULL;

    switch( aPad->GetAttribute() )
    {
    case PAD_ATTRIB_STANDARD:
        break;

    case PAD_ATTRIB_SMD:
    case PAD_ATTRIB_HOLE_NOT_PLATED:
    case PAD_ATTRIB_CONN:
        {
            LSET lmsk = aPad->GetLayerSet();
            bool is_copper = false;

            for( int i = 0; i < MAX_CU_LAYERS; i++ )
            {
                if( lmsk[i] )
                {
                    is_copper = true;

                    if( aPad->GetAttribute() != PAD_ATTRIB_HOLE_NOT_PLATED )
                        layers = LAYER_RANGE( i );

                    break;
                }
            }

            if( !is_copper )
                return NULL;
        }
        break;

    default:
        wxLogTrace( "PNS", "unsupported pad type 0x%x", aPad->GetAttribute() );
        return NULL;
    }

    std::unique_ptr< PNS::SOLID > solid( new PNS::SOLID );

    solid->SetLayers( layers );
    solid->SetNet( aPad->GetNetCode() );
    solid->SetParent( aPad );

    wxPoint wx_c = aPad->ShapePos();
    wxSize  wx_sz = aPad->GetSize();
    wxPoint offset = aPad->GetOffset();

    VECTOR2I c( wx_c.x, wx_c.y );
    VECTOR2I sz( wx_sz.x, wx_sz.y );

    RotatePoint( &offset, aPad->GetOrientation() );

    solid->SetPos( VECTOR2I( c.x - offset.x, c.y - offset.y ) );
    solid->SetOffset( VECTOR2I( offset.x, offset.y ) );

    double orient = aPad->GetOrientation() / 10.0;

    if( aPad->GetShape() == PAD_SHAPE_CIRCLE )
    {
        solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) );
    }
    else if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
    {
        SHAPE_POLY_SET outline;
        outline.Append( aPad->GetCustomShapeAsPolygon() );
        aPad->CustomShapeAsPolygonToBoardPosition( &outline, wx_c, aPad->GetOrientation() );

        SHAPE_CONVEX* shape = new SHAPE_CONVEX();

        // We use the convex hull of the pad shape, because PnS knows
        // only convex shapes.
        std::vector<wxPoint> convex_hull;
        BuildConvexHull( convex_hull, outline );

        for( unsigned ii = 0; ii < convex_hull.size(); ii++ )
            shape->Append( convex_hull[ii] );

        solid->SetShape( shape );
    }
    else
    {
        if( orient == 0.0 || orient == 90.0 || orient == 180.0 || orient == 270.0 )
        {
            if( orient == 90.0 || orient == 270.0 )
                sz = VECTOR2I( sz.y, sz.x );

            switch( aPad->GetShape() )
            {
            case PAD_SHAPE_OVAL:
                if( sz.x == sz.y )
                    solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) );
                else
                {
                    VECTOR2I delta;

                    if( sz.x > sz.y )
                        delta = VECTOR2I( ( sz.x - sz.y ) / 2, 0 );
                    else
                        delta = VECTOR2I( 0, ( sz.y - sz.x ) / 2 );

                    SHAPE_SEGMENT* shape = new SHAPE_SEGMENT( c - delta, c + delta,
                                                              std::min( sz.x, sz.y ) );
                    solid->SetShape( shape );
                }
                break;

            case PAD_SHAPE_RECT:
                solid->SetShape( new SHAPE_RECT( c - sz / 2, sz.x, sz.y ) );
                break;

            case PAD_SHAPE_TRAPEZOID:
            {
                wxPoint coords[4];
                aPad->BuildPadPolygon( coords, wxSize( 0, 0 ), aPad->GetOrientation() );
                SHAPE_CONVEX* shape = new SHAPE_CONVEX();

                for( int ii = 0; ii < 4; ii++ )
                {
                    shape->Append( wx_c + coords[ii] );
                }

                solid->SetShape( shape );
                break;
            }

            case PAD_SHAPE_ROUNDRECT:
            {
                SHAPE_POLY_SET outline;
                const int segmentToCircleCount = 64;

                aPad->BuildPadShapePolygon( outline, wxSize( 0, 0 ), segmentToCircleCount, 1.0 );

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

                for( int ii = 0; ii < poly.PointCount(); ++ii )
                {
                    shape->Append( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );
                }

                solid->SetShape( shape );
            }
                break;

            default:
                wxLogTrace( "PNS", "unsupported pad shape" );
                return nullptr;
            }
        }
        else
        {
            switch( aPad->GetShape() )
            {
            // PAD_SHAPE_CIRCLE and PAD_SHAPE_CUSTOM already handled above

            case PAD_SHAPE_OVAL:
                if( sz.x == sz.y )
                    solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) );
                else
                {
                    wxPoint start;
                    wxPoint end;
                    wxPoint corner;

                    SHAPE_CONVEX* shape = new SHAPE_CONVEX();

                    int w = aPad->BuildSegmentFromOvalShape( start, end, 0.0, wxSize( 0, 0 ) );

                    if( start.y == 0 )
                        corner = wxPoint( start.x, -( w / 2 ) );
                    else
                        corner = wxPoint( w / 2, start.y );

                    RotatePoint( &start, aPad->GetOrientation() );
                    RotatePoint( &corner, aPad->GetOrientation() );
                    shape->Append( wx_c + corner );

                    for( int rot = 100; rot <= 1800; rot += 100 )
                    {
                        wxPoint p( corner );
                        RotatePoint( &p, start, rot );
                        shape->Append( wx_c + p );
                    }

                    if( end.y == 0 )
                        corner = wxPoint( end.x, w / 2 );
                    else
                        corner = wxPoint( -( w / 2 ), end.y );

                    RotatePoint( &end, aPad->GetOrientation() );
                    RotatePoint( &corner, aPad->GetOrientation() );
                    shape->Append( wx_c + corner );

                    for( int rot = 100; rot <= 1800; rot += 100 )
                    {
                        wxPoint p( corner );
                        RotatePoint( &p, end, rot );
                        shape->Append( wx_c + p );
                    }

                    solid->SetShape( shape );
                }
                break;

            case PAD_SHAPE_RECT:
            case PAD_SHAPE_TRAPEZOID:
            {
                wxPoint coords[4];
                aPad->BuildPadPolygon( coords, wxSize( 0, 0 ), aPad->GetOrientation() );

                SHAPE_CONVEX* shape = new SHAPE_CONVEX();
                for( int ii = 0; ii < 4; ii++ )
                {
                    shape->Append( wx_c + coords[ii] );
                }

                solid->SetShape( shape );
                break;
            }

            case PAD_SHAPE_ROUNDRECT:
            {
                SHAPE_POLY_SET outline;
                const int segmentToCircleCount = 32;
                aPad->BuildPadShapePolygon( outline, wxSize( 0, 0 ),
                                            segmentToCircleCount, 1.0 );

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

                for( int ii = 0; ii < poly.PointCount(); ++ii )
                {
                    shape->Append( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );
                }

                solid->SetShape( shape );
                break;
            }

            default:
                wxLogTrace( "PNS", "unsupported pad shape" );
                return nullptr;
            }
        }
    }
    return solid;
}
Example #8
0
void Convert_path_polygon_to_polygon_blocks_and_dummy_blocks(
        const SHAPE_POLY_SET &aMainPath,
        CGENERICCONTAINER2D &aDstContainer,
        float aBiuTo3DunitsScale,
        float aDivFactor,
        const BOARD_ITEM &aBoardItem )
{
    BOX2I pathBounds = aMainPath.BBox();

    // Get the path

    wxASSERT( aMainPath.OutlineCount() == 1 );
    const SHAPE_POLY_SET::POLYGON& curr_polywithholes = aMainPath.CPolygon( 0 );

    wxASSERT( curr_polywithholes.size() == 1 );
    const SHAPE_LINE_CHAIN& path = curr_polywithholes[0];   // a simple polygon

    // Convert the points to segments class
    CBBOX2D bbox;
    bbox.Reset();

    // Contains the main list of segments and each segment normal interpolated
    SEGMENTS_WIDTH_NORMALS segments_and_normals;

    // Contains a closed polygon used to calc if points are inside
    SEGMENTS segments;

    segments_and_normals.resize( path.PointCount() );
    segments.resize( path.PointCount() );

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

        const SFVEC2F point ( (float)( a.x) * aBiuTo3DunitsScale,
                              (float)(-a.y) * aBiuTo3DunitsScale );

        bbox.Union( point );
        segments_and_normals[i].m_Start = point;
        segments[i].m_Start = point;
    }

    bbox.ScaleNextUp();


    // Calc the slopes, normals and some statistics about this polygon
    unsigned int i;
    unsigned int j = segments_and_normals.size() - 1;

    // Temporary normal to the segment, it will later be used for interpolation
    std::vector< SFVEC2F >  tmpSegmentNormals;
    tmpSegmentNormals.resize( segments_and_normals.size() );

    float medOfTheSquaresSegmentLength = 0.0f;
#ifdef PRINT_STATISTICS_3D_VIEWER
    float minLength = FLT_MAX;
#endif

    for( i = 0; i < segments_and_normals.size(); j = i++ )
    {
        const SFVEC2F slope = segments_and_normals[j].m_Start -
                              segments_and_normals[i].m_Start;

        segments_and_normals[i].m_Precalc_slope = slope;

        // Calculate constants for each segment
        segments[i].m_inv_JY_minus_IY = 1.0f / ( segments_and_normals[j].m_Start.y -
                                                 segments_and_normals[i].m_Start.y );

        segments[i].m_JX_minus_IX = ( segments_and_normals[j].m_Start.x -
                                      segments_and_normals[i].m_Start.x );

        // The normal orientation expect a fixed polygon orientation (!TODO: which one?)
        //tmpSegmentNormals[i] = glm::normalize( SFVEC2F( -slope.y, +slope.x ) );
        tmpSegmentNormals[i] = glm::normalize( SFVEC2F( slope.y, -slope.x ) );

        const float length = slope.x * slope.x + slope.y * slope.y;

#ifdef PRINT_STATISTICS_3D_VIEWER
        if( length < minLength )
            minLength = length;
#endif

        medOfTheSquaresSegmentLength += length;
    }

#ifdef PRINT_STATISTICS_3D_VIEWER
    float minSegmentLength = sqrt( minLength );
#endif

    // This calc an approximation of medium lengths, that will be used to calc
    // the size of the division.
    medOfTheSquaresSegmentLength /= segments_and_normals.size();
    medOfTheSquaresSegmentLength = sqrt( medOfTheSquaresSegmentLength );


    // Compute the normal interpolation
    // If calculate the dot between the segments, if they are above/below some
    // threshould it will not interpolated it (ex: if you are in a edge corner
    // or in a smooth transaction)
    j = segments_and_normals.size() - 1;
    for( i = 0; i < segments_and_normals.size(); j = i++ )
    {
        const SFVEC2F normalBeforeSeg = tmpSegmentNormals[j];
        const SFVEC2F normalSeg       = tmpSegmentNormals[i];
        const SFVEC2F normalAfterSeg  = tmpSegmentNormals[ (i + 1) %
                                                           segments_and_normals.size() ];

        const float dotBefore = glm::dot( normalBeforeSeg, normalSeg );
        const float dotAfter  = glm::dot( normalAfterSeg,  normalSeg );

        if( dotBefore < 0.7f )
            segments_and_normals[i].m_Normals.m_Start = normalSeg;
        else
            segments_and_normals[i].m_Normals.m_Start =
                glm::normalize( (((normalBeforeSeg * dotBefore ) + normalSeg) * 0.5f) );

        if( dotAfter < 0.7f )
            segments_and_normals[i].m_Normals.m_End = normalSeg;
        else
            segments_and_normals[i].m_Normals.m_End =
                glm::normalize( (((normalAfterSeg  * dotAfter  ) + normalSeg) * 0.5f) );
    }

    if( aDivFactor == 0.0f )
        aDivFactor = medOfTheSquaresSegmentLength;

    SFVEC2UI grid_divisions;
    grid_divisions.x = (unsigned int)( (bbox.GetExtent().x / aDivFactor) );
    grid_divisions.y = (unsigned int)( (bbox.GetExtent().y / aDivFactor) );

    grid_divisions = glm::clamp( grid_divisions ,
                                 SFVEC2UI( 1, 1 ),
                                 SFVEC2UI( MAX_NR_DIVISIONS, MAX_NR_DIVISIONS ) );

    // Calculate the steps advance of the grid
    SFVEC2F blockAdvance;

    blockAdvance.x = bbox.GetExtent().x / (float)grid_divisions.x;
    blockAdvance.y = bbox.GetExtent().y / (float)grid_divisions.y;

    wxASSERT( blockAdvance.x > 0.0f );
    wxASSERT( blockAdvance.y > 0.0f );

    const int leftToRight_inc = (pathBounds.GetRight()  - pathBounds.GetLeft()) /
                                grid_divisions.x;

    const int topToBottom_inc = (pathBounds.GetBottom() - pathBounds.GetTop())  /
                                grid_divisions.y;

    // Statistics
    unsigned int stats_n_empty_blocks = 0;
    unsigned int stats_n_dummy_blocks = 0;
    unsigned int stats_n_poly_blocks = 0;
    unsigned int stats_sum_size_of_polygons = 0;


    // Step by each block of a grid trying to extract segments and create
    // polygon blocks

    int topToBottom = pathBounds.GetTop();
    float blockY = bbox.Max().y;

    for( unsigned int iy = 0; iy < grid_divisions.y; iy++ )
    {

        int leftToRight = pathBounds.GetLeft();
        float blockX = bbox.Min().x;

        for( unsigned int ix = 0; ix < grid_divisions.x; ix++ )
        {
            CBBOX2D blockBox( SFVEC2F( blockX,
                                       blockY - blockAdvance.y ),
                              SFVEC2F( blockX + blockAdvance.x,
                                       blockY                  ) );

            // Make the box large to it will catch (intersect) the edges
            blockBox.ScaleNextUp();
            blockBox.ScaleNextUp();
            blockBox.ScaleNextUp();

            SEGMENTS_WIDTH_NORMALS extractedSegments;

            extractPathsFrom( segments_and_normals, blockBox, extractedSegments );


            if( extractedSegments.empty() )
            {

                SFVEC2F p1( blockBox.Min().x, blockBox.Min().y );
                SFVEC2F p2( blockBox.Max().x, blockBox.Min().y );
                SFVEC2F p3( blockBox.Max().x, blockBox.Max().y );
                SFVEC2F p4( blockBox.Min().x, blockBox.Max().y );

                if( polygon_IsPointInside( segments, p1 ) ||
                    polygon_IsPointInside( segments, p2 ) ||
                    polygon_IsPointInside( segments, p3 ) ||
                    polygon_IsPointInside( segments, p4 ) )
                {
                    // In this case, the segments are not intersecting the
                    // polygon, so it means that if any point is inside it,
                    // then all other are inside the polygon.
                    // This is a full bbox inside, so add a dummy box

                    aDstContainer.Add( new CDUMMYBLOCK2D( blockBox, aBoardItem ) );
                    stats_n_dummy_blocks++;
                }
                else
                {
                    // Points are outside, so this block complety missed the polygon
                    // In this case, no objects need to be added
                    stats_n_empty_blocks++;
                }
            }
            else
            {
                // At this point, the borders of polygon were intersected by the
                // bounding box, so we must calculate a new polygon that will
                // close that small block.
                // This block will be used to calculate if points are inside
                // the (sub block) polygon.

                SHAPE_POLY_SET subBlockPoly;

                SHAPE_LINE_CHAIN sb = SHAPE_LINE_CHAIN(
                                        VECTOR2I( leftToRight,
                                                  topToBottom ),
                                        VECTOR2I( leftToRight + leftToRight_inc,
                                                  topToBottom ),
                                        VECTOR2I( leftToRight + leftToRight_inc,
                                                  topToBottom + topToBottom_inc ),
                                        VECTOR2I( leftToRight,
                                                  topToBottom + topToBottom_inc ) );

                //sb.Append( leftToRight, topToBottom );
                sb.SetClosed( true );

                subBlockPoly.AddOutline( sb );

                // We need here a strictly simple polygon with outlines and holes
                SHAPE_POLY_SET solution;
                solution.BooleanIntersection( aMainPath,
                                              subBlockPoly,
                                              SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );

                OUTERS_AND_HOLES outersAndHoles;

                outersAndHoles.m_Holes.clear();
                outersAndHoles.m_Outers.clear();

                for( int idx = 0; idx < solution.OutlineCount(); idx++ )
                {
                    const SHAPE_LINE_CHAIN & outline = solution.Outline( idx );

                    SEGMENTS solutionSegment;

                    polygon_Convert( outline, solutionSegment, aBiuTo3DunitsScale );
                    outersAndHoles.m_Outers.push_back( solutionSegment );

                    stats_sum_size_of_polygons += solutionSegment.size();

                    for( int holeIdx = 0;
                         holeIdx < solution.HoleCount( idx );
                         holeIdx++ )
                    {
                        const SHAPE_LINE_CHAIN & hole = solution.Hole( idx, holeIdx );

                        polygon_Convert( hole, solutionSegment, aBiuTo3DunitsScale );
                        outersAndHoles.m_Holes.push_back( solutionSegment );
                        stats_sum_size_of_polygons += solutionSegment.size();
                    }

                }

                if( !outersAndHoles.m_Outers.empty() )
                {
                    aDstContainer.Add( new CPOLYGONBLOCK2D( extractedSegments,
                                                            outersAndHoles,
                                                            aBoardItem ) );
                    stats_n_poly_blocks++;
                }
            }

            blockX += blockAdvance.x;
            leftToRight += leftToRight_inc;
        }

        blockY -= blockAdvance.y;
        topToBottom += topToBottom_inc;
    }

#ifdef PRINT_STATISTICS_3D_VIEWER
    printf( "////////////////////////////////////////////////////////////////////////////////\n" );
    printf( "Convert_path_polygon_to_polygon_blocks_and_dummy_blocks\n" );
    printf( "  grid_divisions (%u, %u)\n", grid_divisions.x, grid_divisions.y );
    printf( "  N Total Blocks %u\n", grid_divisions.x * grid_divisions.y );
    printf( "  N Empty Blocks %u\n", stats_n_empty_blocks );
    printf( "  N Dummy Blocks %u\n", stats_n_dummy_blocks );
    printf( "  N Polyg Blocks %u\n", stats_n_poly_blocks );
    printf( "  Med N Seg Poly %u\n", stats_sum_size_of_polygons / stats_n_poly_blocks );
    printf( "  medOfTheSquaresSegmentLength %f\n", medOfTheSquaresSegmentLength );
    printf( "  minSegmentLength             %f\n", minSegmentLength );
    printf( "  aDivFactor                   %f\n", aDivFactor );
    printf( "////////////////////////////////////////////////////////////////////////////////\n" );
#endif
}