Example #1
0
const EDA_RECT PCB_TARGET::GetBoundingBox() const
{
    EDA_RECT bBox;
    bBox.SetX( m_Pos.x - m_Size/2 );
    bBox.SetY( m_Pos.y - m_Size/2 );
    bBox.SetWidth( m_Size );
    bBox.SetHeight( m_Size );

    return bBox;
}
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;
}
/* Function to move components in a rectangular area format 4 / 3,
 * starting from the mouse cursor.
 * Footprints are grouped by sheet.
 * Components with the LOCKED status set are not moved
 */
void PCB_EDIT_FRAME::SpreadFootprints( std::vector<MODULE*>* aFootprints,
                                       bool aMoveFootprintsOutsideBoardOnly,
                                       bool aCheckForBoardEdges,
                                       wxPoint aSpreadAreaPosition,
                                       bool aPrepareUndoCommand )
{
    EDA_RECT bbox = GetBoard()->GetBoardEdgesBoundingBox();
    bool     edgesExist = bbox.GetWidth() || bbox.GetHeight();
    // if aFootprintsOutsideBoardOnly is true, and if board outline exists,
    // we have to filter footprints to move:
    bool outsideBrdFilter = aMoveFootprintsOutsideBoardOnly && edgesExist;

    // no edges exist
    if( aMoveFootprintsOutsideBoardOnly && !edgesExist )
    {
        DisplayError( this,
                      _( "Could not automatically place footprints. No board outlines detected." ) );
        return;
    }


    // Build candidate list
    // calculate also the area needed by these footprints
    std::vector <MODULE*> footprintList;

    for( MODULE* footprint : *aFootprints )
    {
        footprint->CalculateBoundingBox();

        if( outsideBrdFilter )
        {
            if( bbox.Contains( footprint->GetPosition() ) )
                continue;
        }

        if( footprint->IsLocked() )
            continue;

        footprintList.push_back( footprint );
    }

    if( footprintList.empty() )
        return;

    // sort footprints by sheet path. we group them later by sheet
    sort( footprintList.begin(), footprintList.end(), sortFootprintsbySheetPath );

    // Undo command: init undo list. If aPrepareUndoCommand == false
    // no undo command will be initialized.
    // Useful when a undo command is already initialized by the caller
    PICKED_ITEMS_LIST  undoList;

    if( aPrepareUndoCommand )
    {
        undoList.m_Status = UR_CHANGED;
        ITEM_PICKER        picker( NULL, UR_CHANGED );

        for( MODULE* footprint : footprintList )
        {
            // Undo: add copy of the footprint to undo list
            picker.SetItem( footprint );
            picker.SetLink( footprint->Clone() );
            undoList.PushItem( picker );
        }
    }

    // Extract and place footprints by sheet
    std::vector <MODULE*> footprintListBySheet;
    std::vector <EDA_RECT> placementSheetAreas;
    double subsurface;
    double placementsurface = 0.0;

    // put the placement area position on mouse cursor.
    // this position will be adjusted later
    wxPoint placementAreaPosition = aSpreadAreaPosition;

    // We sometimes do not want to move footprints inside an existing board.
    // Therefore, move the placement area position outside the board bounding box
    // to the left of the board
    if( aCheckForBoardEdges && edgesExist )
    {
        if( placementAreaPosition.x < bbox.GetEnd().x &&
            placementAreaPosition.y < bbox.GetEnd().y )
        {
            // the placement area could overlap the board
            // move its position to a safe location
            placementAreaPosition.x = bbox.GetEnd().x;
            placementAreaPosition.y = bbox.GetOrigin().y;
        }
    }

    // The placement uses 2 passes:
    // the first pass creates the rectangular areas to place footprints
    // each sheet in schematic creates one rectangular area.
    // the second pass moves footprints inside these areas
    MODULE* footprint;
    for( int pass = 0; pass < 2; pass++ )
    {
        int subareaIdx = 0;
        footprintListBySheet.clear();
        subsurface = 0.0;

        for( unsigned ii = 0; ii < footprintList.size(); ii++ )
        {
            footprint = footprintList[ii];
            bool islastItem = false;

            if( ii == footprintList.size() - 1 ||
                ( footprintList[ii]->GetPath().BeforeLast( '/' ) !=
                  footprintList[ii+1]->GetPath().BeforeLast( '/' ) ) )
                islastItem = true;

            footprintListBySheet.push_back( footprint );
            subsurface += footprint->GetArea( PADDING );

            if( islastItem )
            {
                // end of the footprint sublist relative to the same sheet path
                // calculate placement of the current sublist
                EDA_RECT freeArea;
                int Xsize_allowed = (int) ( sqrt( subsurface ) * 4.0 / 3.0 );
                int Ysize_allowed = (int) ( subsurface / Xsize_allowed );

                freeArea.SetWidth( Xsize_allowed );
                freeArea.SetHeight( Ysize_allowed );
                CRectPlacement placementArea;

                if( pass == 1 )
                {
                    wxPoint areapos = placementSheetAreas[subareaIdx].GetOrigin()
                                      + placementAreaPosition;
                    freeArea.SetOrigin( areapos );
                }

                bool findAreaOnly = pass == 0;
                moveFootprintsInArea( placementArea, footprintListBySheet,
                                      freeArea, findAreaOnly );

                if( pass == 0 )
                {
                    // Populate sheet placement areas list
                    EDA_RECT sub_area;
                    sub_area.SetWidth( placementArea.GetW()*scale );
                    sub_area.SetHeight( placementArea.GetH()*scale );
                    // Add a margin around the sheet placement area:
                    sub_area.Inflate( Millimeter2iu( 1.5 ) );

                    placementSheetAreas.push_back( sub_area );

                    placementsurface += (double) sub_area.GetWidth()*
                                        sub_area.GetHeight();
                }

                // Prepare buffers for next sheet
                subsurface  = 0.0;
                footprintListBySheet.clear();
                subareaIdx++;
            }
        }

        // End of pass:
        // At the end of the first pass, we have to find position of each sheet
        // placement area
        if( pass == 0 )
        {
            int Xsize_allowed = (int) ( sqrt( placementsurface ) * 4.0 / 3.0 );
            int Ysize_allowed = (int) ( placementsurface / Xsize_allowed );
            CRectPlacement placementArea;
            CSubRectArray  vecSubRects;

            fillRectList( vecSubRects, placementSheetAreas );
            spreadRectangles( placementArea, vecSubRects, Xsize_allowed, Ysize_allowed );

            for( unsigned it = 0; it < vecSubRects.size(); ++it )
            {
                TSubRect& srect = vecSubRects[it];
                wxPoint pos( srect.x*scale, srect.y*scale );
                wxSize size( srect.w*scale, srect.h*scale );
                placementSheetAreas[srect.n].SetOrigin( pos );
                placementSheetAreas[srect.n].SetSize( size );
            }
        }
    }   // End pass

    // Undo: commit list
    if( aPrepareUndoCommand )
        SaveCopyInUndoList( undoList, UR_CHANGED );

    OnModify();

    m_canvas->Refresh();
}