void EDA_TEXT::TransformBoundingBoxWithClearanceToPolygon(
        SHAPE_POLY_SET* aCornerBuffer, int aClearanceValue ) const
{
    // Oh dear.  When in UTF-8 mode, wxString puts string iterators in a linked list, and
    // that linked list is not thread-safe.
    std::lock_guard<std::mutex> guard( m_mutex );

    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, GetTextPos().x, GetTextPos().y, GetTextAngle() );
        aCornerBuffer->Append( corners[ii].x, corners[ii].y );
    }
}
wxPoint BOARD_NETLIST_UPDATER::estimateComponentInsertionPosition()
{
    wxPoint bestPosition;

    if( !m_board->IsEmpty() )
    {
        // Position new components below any existing board features.
        EDA_RECT bbox = m_board->ComputeBoundingBox( true );

        if( bbox.GetWidth() || bbox.GetHeight() )
        {
            bestPosition.x = bbox.Centre().x;
            bestPosition.y = bbox.GetBottom() + Millimeter2iu( 10 );
        }
    }
    else
    {
        // Position new components in the center of the page when the board is empty.
        wxSize pageSize = m_board->GetPageSettings().GetSizeIU();

        bestPosition.x = pageSize.GetWidth() / 2;
        bestPosition.y = pageSize.GetHeight() / 2;
    }

    return bestPosition;
}
/* Place module on Routing matrix.
 */
void genModuleOnRoutingMatrix( MODULE* Module )
{
    int         ox, oy, fx, fy;
    int         layerMask;
    D_PAD*      Pad;

    EDA_RECT    fpBBox = Module->GetBoundingBox();

    fpBBox.Inflate( RoutingMatrix.m_GridRouting / 2 );
    ox  = fpBBox.GetX();
    fx  = fpBBox.GetRight();
    oy  = fpBBox.GetY();
    fy  = fpBBox.GetBottom();

    if( ox < RoutingMatrix.m_BrdBox.GetX() )
        ox = RoutingMatrix.m_BrdBox.GetX();

    if( ox > RoutingMatrix.m_BrdBox.GetRight() )
        ox = RoutingMatrix.m_BrdBox.GetRight();

    if( fx < RoutingMatrix.m_BrdBox.GetX() )
        fx = RoutingMatrix.m_BrdBox.GetX();

    if( fx > RoutingMatrix.m_BrdBox.GetRight() )
        fx = RoutingMatrix.m_BrdBox.GetRight();

    if( oy < RoutingMatrix.m_BrdBox.GetY() )
        oy = RoutingMatrix.m_BrdBox.GetY();

    if( oy > RoutingMatrix.m_BrdBox.GetBottom() )
        oy = RoutingMatrix.m_BrdBox.GetBottom();

    if( fy < RoutingMatrix.m_BrdBox.GetY() )
        fy = RoutingMatrix.m_BrdBox.GetY();

    if( fy > RoutingMatrix.m_BrdBox.GetBottom() )
        fy = RoutingMatrix.m_BrdBox.GetBottom();

    layerMask = 0;

    if( Module->GetLayer() == LAYER_N_FRONT )
        layerMask = LAYER_FRONT;

    if( Module->GetLayer() == LAYER_N_BACK )
        layerMask = LAYER_BACK;

    TraceFilledRectangle( ox, oy, fx, fy, layerMask,
                          CELL_is_MODULE, WRITE_OR_CELL );

    // Trace pads + clearance areas.
    for( Pad = Module->Pads(); Pad != NULL; Pad = Pad->Next() )
    {
        int margin = (RoutingMatrix.m_GridRouting / 2) + Pad->GetClearance();
        ::PlacePad( Pad, CELL_is_MODULE, margin, WRITE_OR_CELL );
    }

    // Trace clearance.
    int margin = ( RoutingMatrix.m_GridRouting * Module->GetPadCount() ) / GAIN;
    CreateKeepOutRectangle( ox, oy, fx, fy, margin, KEEP_OUT_MARGIN, layerMask );
}
/**
 * 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 );
    }
}
const EDA_RECT DIMENSION::GetBoundingBox() const
{
    EDA_RECT    bBox;
    int         xmin, xmax, ymin, ymax;

    bBox    = m_Text.GetTextBox( -1 );
    xmin    = bBox.GetX();
    xmax    = bBox.GetRight();
    ymin    = bBox.GetY();
    ymax    = bBox.GetBottom();

    xmin    = std::min( xmin, m_crossBarO.x );
    xmin    = std::min( xmin, m_crossBarF.x );
    ymin    = std::min( ymin, m_crossBarO.y );
    ymin    = std::min( ymin, m_crossBarF.y );
    xmax    = std::max( xmax, m_crossBarO.x );
    xmax    = std::max( xmax, m_crossBarF.x );
    ymax    = std::max( ymax, m_crossBarO.y );
    ymax    = std::max( ymax, m_crossBarF.y );

    xmin    = std::min( xmin, m_featureLineGO.x );
    xmin    = std::min( xmin, m_featureLineGF.x );
    ymin    = std::min( ymin, m_featureLineGO.y );
    ymin    = std::min( ymin, m_featureLineGF.y );
    xmax    = std::max( xmax, m_featureLineGO.x );
    xmax    = std::max( xmax, m_featureLineGF.x );
    ymax    = std::max( ymax, m_featureLineGO.y );
    ymax    = std::max( ymax, m_featureLineGF.y );

    xmin    = std::min( xmin, m_featureLineDO.x );
    xmin    = std::min( xmin, m_featureLineDF.x );
    ymin    = std::min( ymin, m_featureLineDO.y );
    ymin    = std::min( ymin, m_featureLineDF.y );
    xmax    = std::max( xmax, m_featureLineDO.x );
    xmax    = std::max( xmax, m_featureLineDF.x );
    ymax    = std::max( ymax, m_featureLineDO.y );
    ymax    = std::max( ymax, m_featureLineDF.y );

    bBox.SetX( xmin );
    bBox.SetY( ymin );
    bBox.SetWidth( xmax - xmin + 1 );
    bBox.SetHeight( ymax - ymin + 1 );

    bBox.Normalize();

    return bBox;
}
Example #6
0
int SCH_SHEET::GetMinHeight() const
{
    int height = MIN_SHEET_HEIGHT;

    for( size_t i = 0; i < m_pins.size();  i++ )
    {
        int edge = m_pins[i].GetEdge();
        EDA_RECT pinRect = m_pins[i].GetBoundingBox();

        // Make sure pin is on top or bottom side of sheet.
        if( edge == SCH_SHEET_PIN::SHEET_RIGHT_SIDE || edge == SCH_SHEET_PIN::SHEET_LEFT_SIDE )
        {
            if( height < pinRect.GetBottom() - m_pos.y )
                height = pinRect.GetBottom() - m_pos.y;
        }
        else
        {
            if( height < pinRect.GetHeight() )
                height = pinRect.GetHeight();

            for( size_t j = 0; j < m_pins.size(); j++ )
            {
                // Check for pin directly above or below the current pin.
                if( (i == j) || (m_pins[i].GetPosition().x != m_pins[j].GetPosition().x) )
                    continue;

                if( height < pinRect.GetHeight() + m_pins[j].GetBoundingBox().GetHeight() )
                {
                    height = pinRect.GetHeight() + m_pins[j].GetBoundingBox().GetHeight();
                    break;
                }
            }
        }
    }

    return height;
}
Example #7
0
void BOARD_PRINTOUT_CONTROLLER::DrawPage()
{
    wxPoint       offset;
    double        userscale;
    EDA_RECT      boardBoundingBox;
    EDA_RECT      drawRect;
    wxDC*         dc = GetDC();
    BASE_SCREEN*  screen = m_Parent->GetScreen();
    bool          printMirror = m_PrintParams.m_PrintMirror;
    wxSize        pageSizeIU = m_Parent->GetPageSizeIU();

    wxBusyCursor  dummy;

#if defined (PCBNEW)
    BOARD * brd = ((PCB_BASE_FRAME*) m_Parent)->GetBoard();
    boardBoundingBox = brd->ComputeBoundingBox();
    wxString titleblockFilename = brd->GetFileName();
#elif defined (GERBVIEW)
    boardBoundingBox = ((GERBVIEW_FRAME*) m_Parent)->GetGerberLayoutBoundingBox();
    wxString titleblockFilename;    // TODO see if we uses the gerber file name
#else
    #error BOARD_PRINTOUT_CONTROLLER::DrawPage() works only for PCBNEW or GERBVIEW
#endif

    // Use the page size as the drawing area when the board is shown or the user scale
    // is less than 1.
    if( m_PrintParams.PrintBorderAndTitleBlock() )
        boardBoundingBox = EDA_RECT( wxPoint( 0, 0 ), pageSizeIU );

    wxLogTrace( tracePrinting, wxT( "Drawing bounding box:                 x=%d, y=%d, w=%d, h=%d" ),
                boardBoundingBox.GetX(), boardBoundingBox.GetY(),
                boardBoundingBox.GetWidth(), boardBoundingBox.GetHeight() );

    // Compute the PCB size in internal units
    userscale = m_PrintParams.m_PrintScale;

    if( m_PrintParams.m_PrintScale == 0 )   //  fit in page option
    {
        if(boardBoundingBox.GetWidth() && boardBoundingBox.GetHeight())
        {
            int margin = Millimeter2iu( 10.0 ); // add a margin around the drawings
            double scaleX = (double)(pageSizeIU.x - (2 * margin)) /
                            boardBoundingBox.GetWidth();
            double scaleY = (double)(pageSizeIU.y - (2 * margin)) /
                            boardBoundingBox.GetHeight();
            userscale = (scaleX < scaleY) ? scaleX : scaleY;
        }
        else
            userscale = 1.0;
    }

    wxSize scaledPageSize = pageSizeIU;
    drawRect.SetSize( scaledPageSize );
    scaledPageSize.x = wxRound( scaledPageSize.x / userscale );
    scaledPageSize.y = wxRound( scaledPageSize.y / userscale );


    if( m_PrintParams.m_PageSetupData )
    {
        wxLogTrace( tracePrinting, wxT( "Fit size to page margins:         x=%d, y=%d" ),
                    scaledPageSize.x, scaledPageSize.y );

        // Always scale to the size of the paper.
        FitThisSizeToPageMargins( scaledPageSize, *m_PrintParams.m_PageSetupData );
    }

    // Compute Accurate scale 1
    if( m_PrintParams.m_PrintScale == 1.0 )
    {
        // We want a 1:1 scale, regardless the page setup
        // like page size, margin ...
        MapScreenSizeToPaper(); // set best scale and offset (scale is not used)
        int w, h;
        GetPPIPrinter( &w, &h );
        double accurate_Xscale = (double) w / (IU_PER_MILS*1000);
        double accurate_Yscale = (double) h / (IU_PER_MILS*1000);

        if( IsPreview() )  // Scale must take in account the DC size in Preview
        {
            // Get the size of the DC in pixels
            wxSize       PlotAreaSize;
            dc->GetSize( &PlotAreaSize.x, &PlotAreaSize.y );
            GetPageSizePixels( &w, &h );
            accurate_Xscale *= (double)PlotAreaSize.x / w;
            accurate_Yscale *= (double)PlotAreaSize.y / h;
        }
        // Fine scale adjust
        accurate_Xscale *= m_PrintParams.m_XScaleAdjust;
        accurate_Yscale *= m_PrintParams.m_YScaleAdjust;

        // Set print scale for 1:1 exact scale
        dc->SetUserScale( accurate_Xscale, accurate_Yscale );
    }

    // Get the final size of the DC in pixels
    wxSize       PlotAreaSizeInPixels;
    dc->GetSize( &PlotAreaSizeInPixels.x, &PlotAreaSizeInPixels.y );
    wxLogTrace( tracePrinting, wxT( "Plot area in pixels:              x=%d, y=%d" ),
                PlotAreaSizeInPixels.x, PlotAreaSizeInPixels.y );
    double scalex, scaley;
    dc->GetUserScale( &scalex, &scaley );
    wxLogTrace( tracePrinting, wxT( "DC user scale:                    x=%g, y=%g" ),
                scalex, scaley );

    wxSize PlotAreaSizeInUserUnits;
    PlotAreaSizeInUserUnits.x = KiROUND( PlotAreaSizeInPixels.x / scalex );
    PlotAreaSizeInUserUnits.y = KiROUND( PlotAreaSizeInPixels.y / scaley );
    wxLogTrace( tracePrinting, wxT( "Scaled plot area in user units:   x=%d, y=%d" ),
                PlotAreaSizeInUserUnits.x, PlotAreaSizeInUserUnits.y );

    // In module editor, the module is located at 0,0 but for printing
    // it is moved to pageSizeIU.x/2, pageSizeIU.y/2.
    // So the equivalent board must be moved to the center of the page:
    if( m_Parent->IsType( MODULE_EDITOR_FRAME_TYPE ) )
    {
        boardBoundingBox.Move( wxPoint( pageSizeIU.x/2, pageSizeIU.y/2 ) );
    }

    // In some cases the plot origin is the centre of the board outline rather than the center
    // of the selected paper size.
    if( m_PrintParams.CenterOnBoardOutline() )
    {
        // Here we are only drawing the board and it's contents.
        drawRect = boardBoundingBox;
        offset.x += wxRound( (double) -scaledPageSize.x / 2.0 );
        offset.y += wxRound( (double) -scaledPageSize.y / 2.0 );

        wxPoint center = boardBoundingBox.Centre();

        if( printMirror )
        {
            // Calculate the mirrored center of the board.
            center.x = m_Parent->GetPageSizeIU().x - boardBoundingBox.Centre().x;
        }

        offset += center;
    }

    GRResetPenAndBrush( dc );

    EDA_DRAW_PANEL* panel = m_Parent->GetCanvas();
    EDA_RECT        tmp   = *panel->GetClipBox();

    // Set clip box to the max size
    #define MAX_VALUE (INT_MAX/2)   // MAX_VALUE is the max we can use in an integer
                                    // and that allows calculations without overflow
    panel->SetClipBox( EDA_RECT( wxPoint( 0, 0 ), wxSize( MAX_VALUE, MAX_VALUE ) ) );

    screen->m_IsPrinting = true;
    EDA_COLOR_T bg_color = g_DrawBgColor;

    // Print frame reference, if reqquested, before
    if( m_PrintParams.m_Print_Black_and_White )
        GRForceBlackPen( true );

    if( m_PrintParams.PrintBorderAndTitleBlock() )
        m_Parent->DrawWorkSheet( dc, screen, m_PrintParams.m_PenDefaultSize,
                                  IU_PER_MILS, titleblockFilename );

    if( printMirror )
    {
        // To plot mirror, we reverse the x axis, and modify the plot x origin
        dc->SetAxisOrientation( false, false);

        /* Plot offset x is moved by the x plot area size in order to have
         * the old draw area in the new draw area, because the draw origin has not moved
         * (this is the upper left corner) but the X axis is reversed, therefore the plotting area
         * is the x coordinate values from  - PlotAreaSize.x to 0 */
        int x_dc_offset = PlotAreaSizeInPixels.x;
        x_dc_offset = KiROUND( x_dc_offset  * userscale );
        dc->SetDeviceOrigin( x_dc_offset, 0 );

        wxLogTrace( tracePrinting, wxT( "Device origin:                    x=%d, y=%d" ),
                    x_dc_offset, 0 );

        panel->SetClipBox( EDA_RECT( wxPoint( -MAX_VALUE/2, -MAX_VALUE/2 ),
                                     panel->GetClipBox()->GetSize() ) );
    }

    // screen->m_DrawOrg = offset;
    dc->SetLogicalOrigin( offset.x, offset.y );

    wxLogTrace( tracePrinting, wxT( "Logical origin:                   x=%d, y=%d" ),
                offset.x, offset.y );

#if defined(wxUSE_LOG_TRACE) && defined( DEBUG )
    wxRect paperRect = GetPaperRectPixels();
    wxLogTrace( tracePrinting, wxT( "Paper rectangle:                  left=%d, top=%d, "
                                    "right=%d, bottom=%d" ),
                paperRect.GetLeft(), paperRect.GetTop(), paperRect.GetRight(),
                paperRect.GetBottom() );

    int devLeft = dc->LogicalToDeviceX( drawRect.GetX() );
    int devTop = dc->LogicalToDeviceY( drawRect.GetY() );
    int devRight = dc->LogicalToDeviceX( drawRect.GetRight() );
    int devBottom = dc->LogicalToDeviceY( drawRect.GetBottom() );
    wxLogTrace( tracePrinting, wxT( "Final device rectangle:           left=%d, top=%d, "
                                    "right=%d, bottom=%d\n" ),
                devLeft, devTop, devRight, devBottom );
#endif

    g_DrawBgColor = WHITE;

    /* when printing in color mode, we use the graphic OR mode that gives the same look as
     * the screen but because the background is white when printing, we must use a trick:
     * In order to plot on a white background in OR mode we must:
     * 1 - Plot all items in black, this creates a local black background
     * 2 - Plot in OR mode on black "local" background
     */
    if( !m_PrintParams.m_Print_Black_and_White )
    {
        // Creates a "local" black background
        GRForceBlackPen( true );
        m_Parent->PrintPage( dc, m_PrintParams.m_PrintMaskLayer,
                             printMirror, &m_PrintParams );
        GRForceBlackPen( false );
    }
    else
        GRForceBlackPen( true );


#if defined (GERBVIEW)
    // In B&W mode, do not force black pen for Gerbview
    // because negative objects need a white pen, not a black pen
    // B&W mode is handled in print page
    GRForceBlackPen( false );
#endif
    m_Parent->PrintPage( dc, m_PrintParams.m_PrintMaskLayer, printMirror,
                         &m_PrintParams );

    g_DrawBgColor = bg_color;
    screen->m_IsPrinting = false;
    panel->SetClipBox( tmp );
    GRForceBlackPen( false );
}
Example #8
0
bool D_PAD::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
{
    EDA_RECT arect = aRect;
    arect.Normalize();
    arect.Inflate( aAccuracy );

    wxPoint shapePos = ShapePos();

    EDA_RECT shapeRect;

    int r;

    EDA_RECT bb = GetBoundingBox();

    wxPoint endCenter;
    int radius;

    if( !arect.Intersects( bb ) )
        return false;

    // This covers total containment for all test cases
    if( arect.Contains( bb ) )
        return true;

    switch( GetShape() )
    {
    case PAD_SHAPE_CIRCLE:
        return arect.IntersectsCircle( GetPosition(), GetBoundingRadius() );
    case PAD_SHAPE_RECT:
        shapeRect.SetOrigin( shapePos );
        shapeRect.Inflate( m_Size.x / 2, m_Size.y / 2 );
        return arect.Intersects( shapeRect, m_Orient );
    case PAD_SHAPE_OVAL:

        // Circlular test if dimensions are equal
        if( m_Size.x == m_Size.y )
            return arect.IntersectsCircle( shapePos, GetBoundingRadius() );

        shapeRect.SetOrigin( shapePos );

        // Horizontal dimension is greater
        if( m_Size.x > m_Size.y )
        {
            radius = m_Size.y / 2;

            shapeRect.Inflate( m_Size.x / 2 - radius, radius );

            endCenter = wxPoint( m_Size.x / 2 - radius, 0 );
            RotatePoint( &endCenter, m_Orient );

            // Test circular ends
            if( arect.IntersectsCircle( shapePos + endCenter, radius ) ||
                arect.IntersectsCircle( shapePos - endCenter, radius ) )
            {
                return true;
            }
        }
        else
        {
            radius = m_Size.x / 2;

            shapeRect.Inflate( radius, m_Size.y / 2 - radius );

            endCenter = wxPoint( 0, m_Size.y / 2 - radius );
            RotatePoint( &endCenter, m_Orient );

            // Test circular ends
            if( arect.IntersectsCircle( shapePos + endCenter, radius ) ||
                arect.IntersectsCircle( shapePos - endCenter, radius ) )
            {
                return true;
            }
        }

        // Test rectangular portion between rounded ends
        if( arect.Intersects( shapeRect, m_Orient ) )
        {
            return true;
        }

        break;
    case PAD_SHAPE_TRAPEZOID:
        /* Trapezoid intersection tests:
         * A) Any points of rect inside trapezoid
         * B) Any points of trapezoid inside rect
         * C) Any sides of trapezoid cross rect
         */
        {

        wxPoint poly[4];
        BuildPadPolygon( poly, wxSize( 0, 0 ), 0 );

        wxPoint corners[4];

        corners[0] = wxPoint( arect.GetLeft(),  arect.GetTop() );
        corners[1] = wxPoint( arect.GetRight(), arect.GetTop() );
        corners[2] = wxPoint( arect.GetRight(), arect.GetBottom() );
        corners[3] = wxPoint( arect.GetLeft(),  arect.GetBottom() );

        for( int i=0; i<4; i++ )
        {
            RotatePoint( &poly[i], m_Orient );
            poly[i] += shapePos;
        }

        for( int ii=0; ii<4; ii++ )
        {
            if( TestPointInsidePolygon( poly, 4, corners[ii] ) )
            {
                return true;
            }

            if( arect.Contains( poly[ii] ) )
            {
                return true;
            }

            if( arect.Intersects( poly[ii], poly[(ii+1) % 4] ) )
            {
                return true;
            }
        }

        return false;

        }
    case PAD_SHAPE_ROUNDRECT:
        /* RoundRect intersection can be broken up into simple tests:
         * a) Test intersection of horizontal rect
         * b) Test intersection of vertical rect
         * c) Test intersection of each corner
         */


        r = GetRoundRectCornerRadius();

        /* Test A - intersection of horizontal rect */
        shapeRect.SetSize( 0, 0 );
        shapeRect.SetOrigin( shapePos );
        shapeRect.Inflate( m_Size.x / 2, m_Size.y / 2 - r );

        // Short-circuit test for zero width or height
        if( shapeRect.GetWidth() > 0 && shapeRect.GetHeight() > 0 &&
            arect.Intersects( shapeRect, m_Orient ) )
        {
            return true;
        }

        /* Test B - intersection of vertical rect */
        shapeRect.SetSize( 0, 0 );
        shapeRect.SetOrigin( shapePos );
        shapeRect.Inflate( m_Size.x / 2 - r, m_Size.y / 2 );

        // Short-circuit test for zero width or height
        if( shapeRect.GetWidth() > 0 && shapeRect.GetHeight() > 0 &&
            arect.Intersects( shapeRect, m_Orient ) )
        {
            return true;
        }

        /* Test C - intersection of each corner */

        endCenter = wxPoint( m_Size.x / 2 - r, m_Size.y / 2 - r );
        RotatePoint( &endCenter, m_Orient );

        if( arect.IntersectsCircle( shapePos + endCenter, r ) ||
            arect.IntersectsCircle( shapePos - endCenter, r ) )
        {
            return true;
        }

        endCenter = wxPoint( m_Size.x / 2 - r, -m_Size.y / 2 + r );
        RotatePoint( &endCenter, m_Orient );

        if( arect.IntersectsCircle( shapePos + endCenter, r ) ||
            arect.IntersectsCircle( shapePos - endCenter, r ) )
        {
            return true;
        }

        break;
    default:
        break;
    }

    return false;
}
bool GENDRILL_WRITER_BASE::genDrillMapFile( const wxString& aFullFileName,
                                            PlotFormat aFormat )
{
    // Remark:
    // Hole list must be created before calling this function, by buildHolesList(),
    // for the right holes set (PTH, NPTH, buried/blind vias ...)

    double          scale = 1.0;
    wxPoint         offset;
    PLOTTER*        plotter = NULL;
    PAGE_INFO dummy( PAGE_INFO::A4, false );

    PCB_PLOT_PARAMS plot_opts;  // starts plotting with default options

    LOCALE_IO       toggle;     // use standard C notation for float numbers

    const PAGE_INFO& page_info =  m_pageInfo ? *m_pageInfo : dummy;

    // Calculate dimensions and center of PCB
    EDA_RECT        bbbox = m_pcb->GetBoardEdgesBoundingBox();

    // Calculate the scale for the format type, scale 1 in HPGL, drawing on
    // an A4 sheet in PS, + text description of symbols
    switch( aFormat )
    {
    case PLOT_FORMAT_GERBER:
        offset  = GetOffset();
        plotter = new GERBER_PLOTTER();
        plotter->SetViewport( offset, IU_PER_MILS/10, scale, false );
        plotter->SetGerberCoordinatesFormat( 5 );   // format x.5 unit = mm
        break;

    case PLOT_FORMAT_HPGL:    // Scale for HPGL format.
    {
        HPGL_PLOTTER* hpgl_plotter = new HPGL_PLOTTER;
        plotter = hpgl_plotter;
        hpgl_plotter->SetPenNumber( plot_opts.GetHPGLPenNum() );
        hpgl_plotter->SetPenSpeed( plot_opts.GetHPGLPenSpeed() );
        plotter->SetPageSettings( page_info );
        plotter->SetViewport( offset, IU_PER_MILS/10, scale, false );
    }
        break;


    default:
        wxASSERT( false );
        // fall through
    case PLOT_FORMAT_PDF:
    case PLOT_FORMAT_POST:
    {
        PAGE_INFO   pageA4( wxT( "A4" ) );
        wxSize      pageSizeIU = pageA4.GetSizeIU();

        // Reserve a margin around the page.
        int         margin = KiROUND( 20 * IU_PER_MM );

        // Calculate a scaling factor to print the board on the sheet
        double      Xscale = double( pageSizeIU.x - ( 2 * margin ) ) / bbbox.GetWidth();

        // We should print the list of drill sizes, so reserve room for it
        // 60% height for board 40% height for list
        int     ypagesize_for_board = KiROUND( pageSizeIU.y * 0.6 );
        double  Yscale = double( ypagesize_for_board - margin ) / bbbox.GetHeight();

        scale = std::min( Xscale, Yscale );

        // Experience shows the scale should not to large, because texts
        // create problem (can be to big or too small).
        // So the scale is clipped at 3.0;
        scale = std::min( scale, 3.0 );

        offset.x    = KiROUND( double( bbbox.Centre().x ) -
                               ( pageSizeIU.x / 2.0 ) / scale );
        offset.y    = KiROUND( double( bbbox.Centre().y ) -
                               ( ypagesize_for_board / 2.0 ) / scale );

        if( aFormat == PLOT_FORMAT_PDF )
            plotter = new PDF_PLOTTER;
        else
            plotter = new PS_PLOTTER;

        plotter->SetPageSettings( pageA4 );
        plotter->SetViewport( offset, IU_PER_MILS/10, scale, false );
    }
        break;

    case PLOT_FORMAT_DXF:
    {
        DXF_PLOTTER* dxf_plotter = new DXF_PLOTTER;
        plotter = dxf_plotter;
        plotter->SetPageSettings( page_info );
        plotter->SetViewport( offset, IU_PER_MILS/10, scale, false );
    }
        break;

    case PLOT_FORMAT_SVG:
    {
        SVG_PLOTTER* svg_plotter = new SVG_PLOTTER;
        plotter = svg_plotter;
        plotter->SetPageSettings( page_info );
        plotter->SetViewport( offset, IU_PER_MILS/10, scale, false );
    }
        break;
    }

    plotter->SetCreator( wxT( "PCBNEW" ) );
    plotter->SetDefaultLineWidth( 5 * IU_PER_MILS );
    plotter->SetColorMode( false );

    if( ! plotter->OpenFile( aFullFileName ) )
    {
        delete plotter;
        return false;
    }

    plotter->StartPlot();

    // Draw items on edge layer (not all, only items useful for drill map
    BRDITEMS_PLOTTER itemplotter( plotter, m_pcb, plot_opts );
    itemplotter.SetLayerSet( Edge_Cuts );

    for( auto PtStruct : m_pcb->Drawings() )
    {
        switch( PtStruct->Type() )
        {
        case PCB_LINE_T:
            itemplotter.PlotDrawSegment( (DRAWSEGMENT*) PtStruct );
            break;

        case PCB_TEXT_T:
            itemplotter.PlotTextePcb( (TEXTE_PCB*) PtStruct );
            break;

        case PCB_DIMENSION_T:
        case PCB_TARGET_T:
        case PCB_MARKER_T:     // do not draw
        default:
            break;
        }
    }

    int         x, y;
    int         plotX, plotY, TextWidth;
    int         intervalle = 0;
    char        line[1024];
    wxString    msg;
    int         textmarginaftersymbol = KiROUND( 2 * IU_PER_MM );

    // Set Drill Symbols width
    plotter->SetDefaultLineWidth( 0.2 * IU_PER_MM / scale );
    plotter->SetCurrentLineWidth( -1 );

    // Plot board outlines and drill map
    plotDrillMarks( plotter );

    // Print a list of symbols used.
    int     charSize    = 3 * IU_PER_MM;                    // text size in IUs
    double  charScale   = 1.0 / scale;                      // real scale will be 1/scale,
                                                            // because the global plot scale is scale
    TextWidth   = KiROUND( (charSize * charScale) / 10.0 );    // Set text width (thickness)
    intervalle  = KiROUND( charSize * charScale ) + TextWidth;

    // Trace information.
    plotX   = KiROUND( bbbox.GetX() + textmarginaftersymbol * charScale );
    plotY   = bbbox.GetBottom() + intervalle;

    // Plot title  "Info"
    wxString Text = wxT( "Drill Map:" );
    plotter->Text( wxPoint( plotX, plotY ), COLOR4D::UNSPECIFIED, Text, 0,
                   wxSize( KiROUND( charSize * charScale ),
                           KiROUND( charSize * charScale ) ),
                   GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_VJUSTIFY_CENTER,
                   TextWidth, false, false );

    for( unsigned ii = 0; ii < m_toolListBuffer.size(); ii++ )
    {
        DRILL_TOOL& tool = m_toolListBuffer[ii];

        if( tool.m_TotalCount == 0 )
            continue;

        plotY += intervalle;

        int plot_diam = KiROUND( tool.m_Diameter );
        x = KiROUND( plotX - textmarginaftersymbol * charScale - plot_diam / 2.0 );
        y = KiROUND( plotY + charSize * charScale );
        plotter->Marker( wxPoint( x, y ), plot_diam, ii );

        // List the diameter of each drill in mm and inches.
        sprintf( line, "%2.2fmm / %2.3f\" ",
                 diameter_in_mm( tool.m_Diameter ),
                 diameter_in_inches( tool.m_Diameter ) );

        msg = FROM_UTF8( line );

        // Now list how many holes and ovals are associated with each drill.
        if( ( tool.m_TotalCount == 1 )
            && ( tool.m_OvalCount == 0 ) )
            sprintf( line, "(1 hole)" );
        else if( tool.m_TotalCount == 1 ) // && ( toolm_OvalCount == 1 )
            sprintf( line, "(1 slot)" );
        else if( tool.m_OvalCount == 0 )
            sprintf( line, "(%d holes)", tool.m_TotalCount );
        else if( tool.m_OvalCount == 1 )
            sprintf( line, "(%d holes + 1 slot)", tool.m_TotalCount - 1 );
        else // if ( toolm_OvalCount > 1 )
            sprintf( line, "(%d holes + %d slots)",
                     tool.m_TotalCount - tool.m_OvalCount,
                     tool.m_OvalCount );

        msg += FROM_UTF8( line );

        if( tool.m_Hole_NotPlated )
            msg += wxT( " (not plated)" );

        plotter->Text( wxPoint( plotX, y ), COLOR4D::UNSPECIFIED, msg, 0,
                       wxSize( KiROUND( charSize * charScale ),
                               KiROUND( charSize * charScale ) ),
                       GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_VJUSTIFY_CENTER,
                       TextWidth, false, false );

        intervalle = KiROUND( ( ( charSize * charScale ) + TextWidth ) * 1.2 );

        if( intervalle < ( plot_diam + ( 1 * IU_PER_MM / scale ) + TextWidth ) )
            intervalle = plot_diam + ( 1 * IU_PER_MM / scale ) + TextWidth;
    }

    plotter->EndPlot();
    delete plotter;

    return true;
}
int ZONE_CONTAINER::FillZoneAreasWithSegments()
{
    int      ics, ice;
    int count = 0;
    std::vector <int> x_coordinates;
    bool error = false;

    int      istart, iend;      // index of the starting and the endif corner of one filled area in m_FilledPolysList

    int margin = m_ZoneMinThickness * 2 / 10;
    int minwidth = Mils2iu( 2 );
    margin = std::max ( minwidth, margin );
    int step = m_ZoneMinThickness - margin;
    step = std::max( step, minwidth );

    // Read all filled areas in m_FilledPolysList
    m_FillSegmList.clear();
    istart = 0;
    int end_list =  m_FilledPolysList.GetCornersCount()-1;

    for( int ic = 0; ic <= end_list; ic++ )
    {
        CPolyPt* corner = &m_FilledPolysList[ic];
        if ( corner->end_contour || (ic == end_list) )
        {
            iend = ic;
            EDA_RECT rect = CalculateSubAreaBoundaryBox( istart, iend );

            // Calculate the y limits of the zone
            int refy = rect.GetY();
            int endy = rect.GetBottom();

            for( ; refy < endy; refy += step )
            {
                // find all intersection points of an infinite line with polyline sides
                x_coordinates.clear();

                for( ics = istart, ice = iend; ics <= iend; ice = ics, ics++ )
                {
                    if ( m_FilledPolysList[ice].m_utility )
                        continue;

                    int seg_startX = m_FilledPolysList[ics].x;
                    int seg_startY = m_FilledPolysList[ics].y;
                    int seg_endX   = m_FilledPolysList[ice].x;
                    int seg_endY   = m_FilledPolysList[ice].y;


                    /* Trivial cases: skip if ref above or below the segment to test */
                    if( ( seg_startY > refy ) && (seg_endY > refy ) )
                        continue;

                    // segment below ref point, or its Y end pos on Y coordinate ref point: skip
                    if( ( seg_startY <= refy ) && (seg_endY <= refy ) )
                        continue;

                    /* at this point refy is between seg_startY and seg_endY
                     * see if an horizontal line at Y = refy is intersecting this segment
                    */
                    // calculate the x position of the intersection of this segment and the
                    // infinite line this is more easier if we move the X,Y axis origin to
                    // the segment start point:
                    seg_endX -= seg_startX;
                    seg_endY -= seg_startY;
                    double newrefy = (double) (refy - seg_startY);
                    double intersec_x;

                    if ( seg_endY == 0 )    // horizontal segment on the same line: skip
                        continue;

                    // Now calculate the x intersection coordinate of the horizontal line at
                    // y = newrefy and the segment from (0,0) to (seg_endX,seg_endY) with the
                    // horizontal line at the new refy position the line slope is:
                    // slope = seg_endY/seg_endX; and inv_slope = seg_endX/seg_endY
                    // and the x pos relative to the new origin is:
                    // intersec_x = refy/slope = refy * inv_slope
                    // Note: because horizontal segments are already tested and skipped, slope
                    // exists (seg_end_y not O)
                    double inv_slope      = (double)seg_endX / seg_endY;
                    intersec_x = newrefy * inv_slope;
                    x_coordinates.push_back((int) intersec_x + seg_startX);
                }

                // A line scan is finished: build list of segments

                // Sort intersection points by increasing x value:
                // So 2 consecutive points are the ends of a segment
                sort( x_coordinates.begin(), x_coordinates.end(), SortByXValues );

                // Create segments

                if ( !error && ( x_coordinates.size() & 1 ) != 0 )
                {   // An even number of coordinates is expected, because a segment has 2 ends.
                    // An if this algorithm always works, it must always find an even count.
                    wxString msg = wxT("Fill Zone: odd number of points at y = ");
                    msg << refy;
                    wxMessageBox(msg );
                    error = true;
                }

                if ( error )
                    break;

                int iimax = x_coordinates.size()-1;

                for (int ii = 0; ii < iimax; ii +=2 )
                {
                    wxPoint  seg_start, seg_end;
                    count++;
                    seg_start.x = x_coordinates[ii];
                    seg_start.y = refy;
                    seg_end.x = x_coordinates[ii+1];
                    seg_end.y = refy;
                    SEGMENT segment( seg_start, seg_end );
                    m_FillSegmList.push_back( segment );
                }
            }   //End examine segments in one area

            if ( error )
                break;

            istart = iend + 1;  // istart points the first corner of the next area
        }   // End find one end of outline

        if ( error )
            break;
    }   // End examine all areas

    return count;
}