Commit 18616d77 authored by jean-pierre charras's avatar jean-pierre charras
Browse files

Fix bugs in autoplac.cpp

parent 1b58582e
Loading
Loading
Loading
Loading
+69 −56
Original line number Diff line number Diff line
/**
 * @file autoplac.cpp
 * @brief Routiness to automatically place MODULES on a board.
 * @brief Functions to automatically place Footprints on a board.
 */

/*
@@ -57,9 +57,8 @@
#define KEEP_OUT_MARGIN 500


/* Penalty for guidance given by CntRot90 and CntRot180:
 * graduated from 0 (rotation allowed) to 10 (rotation not allowed)
 * the count is increased.
/* Penalty (cost) for CntRot90 and CntRot180:
 * CntRot90 and CntRot180 are from 0 (rotation allowed) to 10 (rotation not allowed)
 */
static const double OrientPenality[11] =
{
@@ -79,6 +78,7 @@ static const double OrientPenality[11] =
// Cell states.
#define OUT_OF_BOARD        -2
#define OCCUPED_By_MODULE   -1
#define FREE_CELL   0


static wxPoint  CurrPosition; // Current position of the current module placement
@@ -114,8 +114,11 @@ static double compute_Ratsnest_PlaceModule( BOARD* aBrd );
/* Place a footprint on the Routing matrix.
 */
void            genModuleOnRoutingMatrix( MODULE* Module );
/*
 * Displays the Placement/Routing matrix on the screen
 */
static void     drawPlacementRoutingMatrix( BOARD* aBrd, wxDC* DC );

static void     drawInfoPlace( BOARD* aBrd, wxDC* DC );
static int      TstModuleOnBoard( BOARD* Pcb, MODULE* Module, bool TstOtherSide );

static void     CreateKeepOutRectangle( int ux0, int uy0, int ux1, int uy1,
@@ -180,8 +183,8 @@ void PCB_EDIT_FRAME::AutoPlaceModule( MODULE* Module, int place_mode, wxDC* DC )
    RoutingMatrix.m_GridRouting = (int) GetScreen()->GetGridSize().x;

    // Ensure Board.m_GridRouting has a reasonable value:
    if( RoutingMatrix.m_GridRouting < 10 * IU_PER_MILS )
        RoutingMatrix.m_GridRouting = 10 * IU_PER_MILS; // Min value = 1/100 inch
    if( RoutingMatrix.m_GridRouting < Millimeter2iu( 0.25 ) )
        RoutingMatrix.m_GridRouting = Millimeter2iu( 0.25 );

    // Compute module parameters used in auto place
    if( genPlacementRoutingMatrix( GetBoard(), m_messagePanel ) == 0 )
@@ -255,7 +258,6 @@ void PCB_EDIT_FRAME::AutoPlaceModule( MODULE* Module, int place_mode, wxDC* DC )
            break;
        }


        if( Module->NeedsPlaced() )    // Erase from screen
        {
            moduleCount++;
@@ -267,12 +269,11 @@ void PCB_EDIT_FRAME::AutoPlaceModule( MODULE* Module, int place_mode, wxDC* DC )
        }
    }

    // Undo command: commit list
    // Undo command: prepare list
    if( newList.GetCount() )
        SaveCopyInUndoList( newList, UR_CHANGED );

    int         cnt = 0;
    int         ii;
    wxString    msg;

    while( ( Module = PickModule( this, DC ) ) != NULL )
@@ -281,36 +282,37 @@ void PCB_EDIT_FRAME::AutoPlaceModule( MODULE* Module, int place_mode, wxDC* DC )
        msg.Printf( _( "Place module %d of %d" ), cnt, moduleCount );
        SetStatusText( msg );

        double initialOrient = Module->GetOrientation();
        // Display fill area of interest, barriers, penalties.
        drawInfoPlace( GetBoard(), DC );
        drawPlacementRoutingMatrix( GetBoard(), DC );

        error = getOptimalModulePlacement( this, Module, DC );
        double BestScore = MinCout;
        double bestScore = MinCout;
        double bestRotation = 0.0;
        int rotAllowed;
        PosOK = CurrPosition;

        if( error == ESC )
            goto end_of_tst;

        // Determine if the best orientation of a module is 180.
        ii = Module->GetPlacementCost180() & 0x0F;
        // Try orientations 90, 180, 270 degrees from initial orientation
        rotAllowed = Module->GetPlacementCost180();

        if( ii != 0 )
        if( rotAllowed != 0 )
        {
            int Angle_Rot_Module = 1800;
            Rotate_Module( DC, Module, Angle_Rot_Module, false );
            Module->CalculateBoundingBox();
            Rotate_Module( DC, Module, 1800.0, true );
            error   = getOptimalModulePlacement( this, Module, DC );
            MinCout *= OrientPenality[ii];
            MinCout *= OrientPenality[rotAllowed];

            if( BestScore > MinCout )    // This orientation is best.
            if( bestScore > MinCout )    // This orientation is better.
            {
                PosOK       = CurrPosition;
                BestScore   = MinCout;
                bestScore   = MinCout;
                bestRotation = 1800.0;
            }
            else
            {
                Angle_Rot_Module = -1800;
                Rotate_Module( DC, Module, Angle_Rot_Module, false );
                Rotate_Module( DC, Module, initialOrient, false );
            }

            if( error == ESC )
@@ -318,49 +320,45 @@ void PCB_EDIT_FRAME::AutoPlaceModule( MODULE* Module, int place_mode, wxDC* DC )
        }

        // Determine if the best orientation of a module is 90.
        ii = Module->GetPlacementCost90() & 0x0F;
        rotAllowed = Module->GetPlacementCost90();

        if( ii != 0 )
        if( rotAllowed != 0 )
        {
            int Angle_Rot_Module = 900;
            Rotate_Module( DC, Module, Angle_Rot_Module, false );
            Rotate_Module( DC, Module, 900.0, true );
            error   = getOptimalModulePlacement( this, Module, DC );
            MinCout *= OrientPenality[ii];
            MinCout *= OrientPenality[rotAllowed];

            if( BestScore > MinCout )    // This orientation is best.
            if( bestScore > MinCout )    // This orientation is better.
            {
                PosOK       = CurrPosition;
                BestScore   = MinCout;
                bestScore   = MinCout;
                bestRotation = 900.0;
            }
            else
            {
                Angle_Rot_Module = -900;
                Rotate_Module( DC, Module, Angle_Rot_Module, false );
                Rotate_Module( DC, Module, initialOrient, false );
            }

            if( error == ESC )
                goto end_of_tst;
        }

        // Determine if the best orientation of a module is 270.
        ii = (Module->GetPlacementCost90() >> 4 ) & 0x0F;

        if( ii != 0 )
        // Determine if the best orientation of a module is -90.
        if( rotAllowed != 0 )
        {
            int Angle_Rot_Module = 2700;
            Rotate_Module( DC, Module, Angle_Rot_Module, false );
            Rotate_Module( DC, Module, 2700.0, true );
            error   = getOptimalModulePlacement( this, Module, DC );
            MinCout *= OrientPenality[ii];
            MinCout *= OrientPenality[rotAllowed];

            if( BestScore > MinCout )    // This orientation is best.
            if( bestScore > MinCout )    // This orientation is better.
            {
                PosOK       = CurrPosition;
                BestScore   = MinCout;
                bestScore   = MinCout;
                bestRotation = 2700.0;
            }
            else
            {
                Angle_Rot_Module = -2700;
                Rotate_Module( DC, Module, Angle_Rot_Module, false );
                Rotate_Module( DC, Module, initialOrient, false );
            }

            if( error == ESC )
@@ -375,7 +373,14 @@ end_of_tst:
        // Place module.
        CurrPosition = GetCrossHairPosition();
        SetCrossHairPosition( PosOK );

        PlaceModule( Module, DC );

        bestRotation += initialOrient;

        if( bestRotation != Module->GetOrientation() )
            Rotate_Module( DC, Module, bestRotation, false );

        SetCrossHairPosition( CurrPosition );

        Module->CalculateBoundingBox();
@@ -405,7 +410,7 @@ end_of_tst:
}


void drawInfoPlace( BOARD* aBrd, wxDC* DC )
void drawPlacementRoutingMatrix( BOARD* aBrd, wxDC* DC )
{
    int         ii, jj;
    EDA_COLOR_T color;
@@ -608,6 +613,13 @@ void genModuleOnRoutingMatrix( MODULE* Module )
    CreateKeepOutRectangle( ox, oy, fx, fy, margin, KEEP_OUT_MARGIN, layerMask );
}

// A minor helper function to draw a bounding box:
inline void draw_FootprintRect(EDA_RECT * aClipBox, wxDC* aDC, EDA_RECT& fpBBox, EDA_COLOR_T aColor)
{
#ifndef USE_WX_OVERLAY
    GRRect( aClipBox, aDC, fpBBox, 0, aColor );
#endif
}

int getOptimalModulePlacement( PCB_EDIT_FRAME* aFrame, MODULE* aModule, wxDC* aDC )
{
@@ -618,6 +630,8 @@ int getOptimalModulePlacement( PCB_EDIT_FRAME* aFrame, MODULE* aModule, wxDC* aD
    bool    showRats = g_Show_Module_Ratsnest;
    BOARD*  brd = aFrame->GetBoard();

    aModule->CalculateBoundingBox();

    g_Show_Module_Ratsnest = false;

    brd->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK;
@@ -674,8 +688,9 @@ int getOptimalModulePlacement( PCB_EDIT_FRAME* aFrame, MODULE* aModule, wxDC* aD
    }

    // Draw the initial bounding box position
    EDA_COLOR_T color = BROWN;
    fpBBox.SetOrigin( fpBBoxOrg + CurrPosition );
    GRRect( aFrame->GetCanvas()->GetClipBox(), aDC, fpBBox, 0, BROWN );
    draw_FootprintRect(aFrame->GetCanvas()->GetClipBox(), aDC, fpBBox, color);

    min_cost = -1.0;
    aFrame->SetStatusText( wxT( "Score ??, pos ??" ) );
@@ -696,19 +711,17 @@ int getOptimalModulePlacement( PCB_EDIT_FRAME* aFrame, MODULE* aModule, wxDC* aD

        for( ; CurrPosition.y < xylimit.y; CurrPosition.y += RoutingMatrix.m_GridRouting )
        {
#ifndef USE_WX_OVERLAY
            // Erase traces.
            GRRect( aFrame->GetCanvas()->GetClipBox(), aDC, fpBBox, 0, BROWN );
#endif
            draw_FootprintRect( aFrame->GetCanvas()->GetClipBox(), aDC, fpBBox, color );

            fpBBox.SetOrigin( fpBBoxOrg + CurrPosition );
            g_Offset_Module = mod_pos - CurrPosition;
#ifndef USE_WX_OVERLAY
            // Draw at new place
            GRRect( aFrame->GetCanvas()->GetClipBox(), aDC, fpBBox, 0, BROWN );
#endif
            int keepOutCost = TstModuleOnBoard( brd, aModule, TstOtherSide );

            // Draw at new place
            color = keepOutCost >= 0 ? BROWN : RED;
            draw_FootprintRect( aFrame->GetCanvas()->GetClipBox(), aDC, fpBBox, color );

            if( keepOutCost >= 0 )    // i.e. if the module can be put here
            {
                error = 0;
@@ -750,7 +763,7 @@ int getOptimalModulePlacement( PCB_EDIT_FRAME* aFrame, MODULE* aModule, wxDC* aD
 * - is a free zone (except OCCUPED_By_MODULE returns)
 * - is on the working surface of the board (otherwise returns OUT_OF_BOARD)
 *
 * Returns OUT_OF_BOARD, or, OCCUPED_By_MODULE or 0 if OK
 * Returns OUT_OF_BOARD, or OCCUPED_By_MODULE or FREE_CELL if OK
 */
int TstRectangle( BOARD* Pcb, const EDA_RECT& aRect, int side )
{
@@ -801,7 +814,7 @@ int TstRectangle( BOARD* Pcb, const EDA_RECT& aRect, int side )
        }
    }

    return 0;
    return FREE_CELL;
}


@@ -877,14 +890,14 @@ int TstModuleOnBoard( BOARD* Pcb, MODULE* aModule, bool TstOtherSide )

    int         diag = TstRectangle( Pcb, fpBBox, side );

    if( diag < 0 )
    if( diag != FREE_CELL )
        return diag;

    if( TstOtherSide )
    {
        diag = TstRectangle( Pcb, fpBBox, otherside );

        if( diag < 0 )
        if( diag != FREE_CELL )
            return diag;
    }