Pcbnew: Autoplace functions: renamed spread footprint functions. Rewritten.
Now footprints, after loaded by reading a netlist are grouped by sheets by the footprints spread function, and the grouping is better. Rename 2 files. Fix minor issues. Clean code
This commit is contained in:
parent
251f0c7f9b
commit
f068c0d94f
|
@ -228,8 +228,6 @@ void EDA_3D_CANVAS::SetView3D( int keycode )
|
|||
|
||||
void EDA_3D_CANVAS::OnMouseWheel( wxMouseEvent& event )
|
||||
{
|
||||
wxSize size( GetClientSize() );
|
||||
|
||||
if( event.ShiftDown() )
|
||||
{
|
||||
if( event.GetWheelRotation() < 0 )
|
||||
|
|
|
@ -906,11 +906,22 @@ void EDA_DRAW_PANEL::OnMouseWheel( wxMouseEvent& event )
|
|||
bool offCenterReq = event.ControlDown() && event.ShiftDown();
|
||||
offCenterReq = offCenterReq || m_enableZoomNoCenter;
|
||||
|
||||
#if wxMAJOR_VERSION >= 2 && wxMINOR_VERSION >= 9
|
||||
int axis = event.GetWheelAxis();
|
||||
#else
|
||||
const int axis = 0;
|
||||
#endif
|
||||
|
||||
// This is a zoom in or out command
|
||||
if( event.GetWheelRotation() > 0 )
|
||||
{
|
||||
if( event.ShiftDown() && !event.ControlDown() )
|
||||
cmd.SetId( ID_PAN_UP );
|
||||
{
|
||||
if( axis == 0 )
|
||||
cmd.SetId( ID_PAN_UP );
|
||||
else
|
||||
cmd.SetId( ID_PAN_RIGHT );
|
||||
}
|
||||
else if( event.ControlDown() && !event.ShiftDown() )
|
||||
cmd.SetId( ID_PAN_LEFT );
|
||||
else if( offCenterReq )
|
||||
|
@ -921,7 +932,12 @@ void EDA_DRAW_PANEL::OnMouseWheel( wxMouseEvent& event )
|
|||
else if( event.GetWheelRotation() < 0 )
|
||||
{
|
||||
if( event.ShiftDown() && !event.ControlDown() )
|
||||
cmd.SetId( ID_PAN_DOWN );
|
||||
{
|
||||
if( axis == 0 )
|
||||
cmd.SetId( ID_PAN_DOWN );
|
||||
else
|
||||
cmd.SetId( ID_PAN_LEFT );
|
||||
}
|
||||
else if( event.ControlDown() && !event.ShiftDown() )
|
||||
cmd.SetId( ID_PAN_RIGHT );
|
||||
else if( offCenterReq )
|
||||
|
|
|
@ -1494,7 +1494,7 @@ public:
|
|||
|
||||
|
||||
// Autoplacement:
|
||||
void AutoPlace( wxCommandEvent& event );
|
||||
void OnPlaceOrRouteFootprints( wxCommandEvent& event );
|
||||
|
||||
/**
|
||||
* Function ScriptingConsoleEnableDisable
|
||||
|
@ -1520,7 +1520,17 @@ public:
|
|||
*/
|
||||
bool ReOrientModules( const wxString& ModuleMask, double Orient, bool include_fixe );
|
||||
void LockModule( MODULE* aModule, bool aLocked );
|
||||
void AutoMoveModulesOnPcb( bool PlaceModulesHorsPcb );
|
||||
|
||||
/**
|
||||
* Function SpreadFootprints
|
||||
* Footprints (after loaded by reading a netlist for instance) are moved
|
||||
* to be in a small free area (outside the current board) without overlapping.
|
||||
* @param aFootprintsOutsideBoardOnly: true to move only
|
||||
* footprints outside the board outlines
|
||||
* (they are outside if the position of a footprint is outside
|
||||
* the board outlines bounding box
|
||||
*/
|
||||
void SpreadFootprints( bool aFootprintsOutsideBoardOnly );
|
||||
|
||||
/**
|
||||
* Function AutoPlaceModule
|
||||
|
|
|
@ -124,12 +124,14 @@ set( PCBNEW_IMPORT_DXF
|
|||
)
|
||||
|
||||
set( PCBNEW_AUTOROUTER_SRCS
|
||||
autorouter/automove.cpp
|
||||
autorouter/autoplac.cpp
|
||||
autorouter/rect_placement/rect_placement.cpp
|
||||
autorouter/move_and_route_event_functions.cpp
|
||||
autorouter/auto_place_footprints.cpp
|
||||
autorouter/autorout.cpp
|
||||
autorouter/routing_matrix.cpp
|
||||
autorouter/dist.cpp
|
||||
autorouter/queue.cpp
|
||||
autorouter/spread_footprints.cpp
|
||||
autorouter/solve.cpp
|
||||
autorouter/graphpcb.cpp
|
||||
autorouter/work.cpp
|
||||
|
|
|
@ -1085,7 +1085,7 @@ static bool Tri_PlaceModules( MODULE* ref, MODULE* compare )
|
|||
}
|
||||
|
||||
|
||||
static bool Tri_RatsModules( MODULE* ref, MODULE* compare )
|
||||
static bool sortFootprintsByRatsnestSize( MODULE* ref, MODULE* compare )
|
||||
{
|
||||
double ff1, ff2;
|
||||
|
||||
|
@ -1141,7 +1141,7 @@ static MODULE* PickModule( PCB_EDIT_FRAME* pcbframe, wxDC* DC )
|
|||
|
||||
pcbframe->GetBoard()->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK;
|
||||
|
||||
sort( moduleList.begin(), moduleList.end(), Tri_RatsModules );
|
||||
sort( moduleList.begin(), moduleList.end(), sortFootprintsByRatsnestSize );
|
||||
|
||||
// Search for "best" module.
|
||||
MODULE* bestModule = NULL;
|
|
@ -55,15 +55,13 @@ typedef enum {
|
|||
} SelectFixeFct;
|
||||
|
||||
|
||||
static bool sortModulesbySize( MODULE* ref, MODULE* compare );
|
||||
|
||||
|
||||
wxString ModulesMaskSelection = wxT( "*" );
|
||||
|
||||
|
||||
/* Called on events (popup menus) relative to automove and autoplace footprints
|
||||
*/
|
||||
void PCB_EDIT_FRAME::AutoPlace( wxCommandEvent& event )
|
||||
void PCB_EDIT_FRAME::OnPlaceOrRouteFootprints( wxCommandEvent& event )
|
||||
{
|
||||
int id = event.GetId();
|
||||
|
||||
|
@ -130,12 +128,19 @@ void PCB_EDIT_FRAME::AutoPlace( wxCommandEvent& event )
|
|||
AutoPlaceModule( NULL, PLACE_INCREMENTAL, &dc );
|
||||
break;
|
||||
|
||||
case ID_POPUP_PCB_AUTOMOVE_ALL_MODULES:
|
||||
AutoMoveModulesOnPcb( false );
|
||||
break;
|
||||
case ID_POPUP_PCB_SPREAD_ALL_MODULES:
|
||||
if( !IsOK( this,
|
||||
_("Not locked footprints inside the board will be moved. OK?") ) )
|
||||
break;
|
||||
// Fall through
|
||||
case ID_POPUP_PCB_SPREAD_NEW_MODULES:
|
||||
if( GetBoard()->m_Modules == NULL )
|
||||
{
|
||||
DisplayError( this, _( "No modules found!" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
case ID_POPUP_PCB_AUTOMOVE_NEW_MODULES:
|
||||
AutoMoveModulesOnPcb( true );
|
||||
SpreadFootprints( id == ID_POPUP_PCB_SPREAD_NEW_MODULES );
|
||||
break;
|
||||
|
||||
case ID_POPUP_PCB_AUTOROUTE_ALL_MODULES:
|
||||
|
@ -159,7 +164,7 @@ void PCB_EDIT_FRAME::AutoPlace( wxCommandEvent& event )
|
|||
break;
|
||||
|
||||
default:
|
||||
wxMessageBox( wxT( "AutoPlace command error" ) );
|
||||
wxMessageBox( wxT( "OnPlaceOrRouteFootprints command error" ) );
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -168,135 +173,6 @@ void PCB_EDIT_FRAME::AutoPlace( wxCommandEvent& event )
|
|||
}
|
||||
|
||||
|
||||
/* Function to move components in a rectangular area format 4 / 3,
|
||||
* starting from the mouse cursor
|
||||
* The components with the FIXED status set are not moved
|
||||
*/
|
||||
void PCB_EDIT_FRAME::AutoMoveModulesOnPcb( bool PlaceModulesHorsPcb )
|
||||
{
|
||||
std::vector <MODULE*> moduleList;
|
||||
wxPoint start, current;
|
||||
int Ymax_size, Xsize_allowed;
|
||||
int pas_grille = (int) GetScreen()->GetGridSize().x;
|
||||
double surface;
|
||||
|
||||
// Undo: init list
|
||||
PICKED_ITEMS_LIST newList;
|
||||
newList.m_Status = UR_CHANGED;
|
||||
ITEM_PICKER picker( NULL, UR_CHANGED );
|
||||
|
||||
if( GetBoard()->m_Modules == NULL )
|
||||
{
|
||||
DisplayError( this, _( "No modules found!" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
// Confirmation
|
||||
if( !IsOK( this, _( "Move modules?" ) ) )
|
||||
return;
|
||||
|
||||
EDA_RECT bbbox = GetBoard()->ComputeBoundingBox( true );
|
||||
|
||||
bool edgesExist = ( bbbox.GetWidth() || bbbox.GetHeight() );
|
||||
|
||||
// no edges exist
|
||||
if( PlaceModulesHorsPcb && !edgesExist )
|
||||
{
|
||||
DisplayError( this,
|
||||
_( "Could not automatically place modules. No board outlines detected." ) );
|
||||
return;
|
||||
}
|
||||
|
||||
// Build sorted footprints list (sort by decreasing size )
|
||||
MODULE* Module = GetBoard()->m_Modules;
|
||||
|
||||
for( ; Module != NULL; Module = Module->Next() )
|
||||
{
|
||||
Module->CalculateBoundingBox();
|
||||
moduleList.push_back(Module);
|
||||
}
|
||||
|
||||
sort( moduleList.begin(), moduleList.end(), sortModulesbySize );
|
||||
|
||||
/* to move modules outside the board, the cursor is placed below
|
||||
* the current board, to avoid placing components in board area.
|
||||
*/
|
||||
if( PlaceModulesHorsPcb && edgesExist )
|
||||
{
|
||||
if( GetCrossHairPosition().y < (bbbox.GetBottom() + 2000) )
|
||||
{
|
||||
wxPoint pos = GetCrossHairPosition();
|
||||
pos.y = bbbox.GetBottom() + 2000;
|
||||
SetCrossHairPosition( pos );
|
||||
}
|
||||
}
|
||||
|
||||
// calculate the area needed by footprints
|
||||
surface = 0.0;
|
||||
|
||||
for( unsigned ii = 0; ii < moduleList.size(); ii++ )
|
||||
{
|
||||
Module = moduleList[ii];
|
||||
|
||||
if( PlaceModulesHorsPcb && edgesExist )
|
||||
{
|
||||
if( bbbox.Contains( Module->GetPosition() ) )
|
||||
continue;
|
||||
}
|
||||
|
||||
surface += Module->GetArea();
|
||||
}
|
||||
|
||||
Xsize_allowed = (int) ( sqrt( surface ) * 4.0 / 3.0 );
|
||||
|
||||
start = current = GetCrossHairPosition();
|
||||
Ymax_size = 0;
|
||||
|
||||
for( unsigned ii = 0; ii < moduleList.size(); ii++ )
|
||||
{
|
||||
Module = moduleList[ii];
|
||||
|
||||
if( Module->IsLocked() )
|
||||
continue;
|
||||
|
||||
if( PlaceModulesHorsPcb && edgesExist )
|
||||
{
|
||||
if( bbbox.Contains( Module->GetPosition() ) )
|
||||
continue;
|
||||
}
|
||||
|
||||
// Undo: add copy of old Module to undo
|
||||
picker.SetItem( Module );
|
||||
picker.SetLink( Module->Clone() );
|
||||
|
||||
if( current.x > (Xsize_allowed + start.x) )
|
||||
{
|
||||
current.x = start.x;
|
||||
current.y += Ymax_size + pas_grille;
|
||||
Ymax_size = 0;
|
||||
}
|
||||
|
||||
SetCrossHairPosition( current + Module->GetPosition() -
|
||||
Module->GetBoundingBox().GetPosition() );
|
||||
|
||||
Ymax_size = std::max( Ymax_size, Module->GetBoundingBox().GetHeight() );
|
||||
|
||||
PlaceModule( Module, NULL, true );
|
||||
|
||||
// Undo: add new Module to undo
|
||||
newList.PushItem( picker );
|
||||
|
||||
current.x += Module->GetBoundingBox().GetWidth() + pas_grille;
|
||||
}
|
||||
|
||||
// Undo: commit
|
||||
if( newList.GetCount() )
|
||||
SaveCopyInUndoList( newList, UR_CHANGED );
|
||||
|
||||
m_canvas->Refresh();
|
||||
}
|
||||
|
||||
|
||||
/* Set or reset (true or false) Lock attribute of aModule or all modules if aModule == NULL
|
||||
*/
|
||||
void PCB_EDIT_FRAME::LockModule( MODULE* aModule, bool aLocked )
|
||||
|
@ -322,8 +198,3 @@ void PCB_EDIT_FRAME::LockModule( MODULE* aModule, bool aLocked )
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static bool sortModulesbySize( MODULE* ref, MODULE* compare )
|
||||
{
|
||||
return compare->GetArea() < ref->GetArea();
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
A class that fits subrectangles into a power-of-2 rectangle
|
||||
|
||||
(C) Copyright 2000-2002 by Javier Arevalo
|
||||
This code is free to use and modify for all purposes
|
||||
|
||||
You have a bunch of rectangular pieces. You need to arrange them in a
|
||||
rectangular surface so that they don't overlap, keeping the total area of the
|
||||
rectangle as small as possible. This is fairly common when arranging characters
|
||||
in a bitmapped font, lightmaps for a 3D engine, and I guess other situations as
|
||||
well.
|
||||
|
||||
The idea of this algorithm is that, as we add rectangles, we can pre-select
|
||||
"interesting" places where we can try to add the next rectangles. For optimal
|
||||
results, the rectangles should be added in order. I initially tried using area
|
||||
as a sorting criteria, but it didn't work well with very tall or very flat
|
||||
rectangles. I then tried using the longest dimension as a selector, and it
|
||||
worked much better. So much for intuition...
|
||||
|
||||
These "interesting" places are just to the right and just below the currently
|
||||
added rectangle. The first rectangle, obviously, goes at the top left, the next
|
||||
one would go either to the right or below this one, and so on. It is a weird way
|
||||
to do it, but it seems to work very nicely.
|
||||
|
||||
The way we search here is fairly brute-force, the fact being that for most off-
|
||||
line purposes the performance seems more than adequate. I have generated a
|
||||
japanese font with around 8500 characters and all the time was spent generating
|
||||
the bitmaps.
|
||||
|
||||
Also, for all we care, we could grow the parent rectangle in a different way
|
||||
than power of two. It just happens that power of 2 is very convenient for
|
||||
graphics hardware textures.
|
||||
|
||||
I'd be interested in hearing of other approaches to this problem. Make sure
|
||||
to post them on http://www.flipcode.com
|
||||
|
||||
See also
|
||||
http://www.flipcode.com/archives/Rectangle_Placement.shtml
|
||||
http://kossovsky.net/index.php/2009/07/cshar-rectangle-packing
|
|
@ -0,0 +1,259 @@
|
|||
// ----------------------------------------------------------------------------------------
|
||||
// Name : rect_placement.cpp
|
||||
// Description : A class that fits subrectangles into a power-of-2 rectangle
|
||||
// (C) Copyright 2000-2002 by Javier Arevalo
|
||||
// This code is free to use and modify for all purposes
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* You have a bunch of rectangular pieces. You need to arrange them in a
|
||||
* rectangular surface so that they don't overlap, keeping the total area of the
|
||||
* rectangle as small as possible. This is fairly common when arranging characters
|
||||
* in a bitmapped font, lightmaps for a 3D engine, and I guess other situations as
|
||||
* well.
|
||||
*
|
||||
* The idea of this algorithm is that, as we add rectangles, we can pre-select
|
||||
* "interesting" places where we can try to add the next rectangles. For optimal
|
||||
* results, the rectangles should be added in order. I initially tried using area
|
||||
* as a sorting criteria, but it didn't work well with very tall or very flat
|
||||
* rectangles. I then tried using the longest dimension as a selector, and it
|
||||
* worked much better. So much for intuition...
|
||||
*
|
||||
* These "interesting" places are just to the right and just below the currently
|
||||
* added rectangle. The first rectangle, obviously, goes at the top left, the next
|
||||
* one would go either to the right or below this one, and so on. It is a weird way
|
||||
* to do it, but it seems to work very nicely.
|
||||
*
|
||||
* The way we search here is fairly brute-force, the fact being that for most off-
|
||||
* line purposes the performance seems more than adequate. I have generated a
|
||||
* japanese font with around 8500 characters and all the time was spent generating
|
||||
* the bitmaps.
|
||||
*
|
||||
* Also, for all we care, we could grow the parent rectangle.
|
||||
*
|
||||
* I'd be interested in hearing of other approaches to this problem. Make sure
|
||||
* to post them on http://www.flipcode.com
|
||||
*/
|
||||
|
||||
#include "rect_placement.h"
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Name :
|
||||
// Description :
|
||||
// --------------------------------------------------------------------------------
|
||||
void CRectPlacement::Init( int w, int h )
|
||||
{
|
||||
End();
|
||||
m_size = TRect( 0, 0, w, h );
|
||||
m_vPositions.push_back( TPos( 0, 0 ) );
|
||||
m_area = 0;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Name :
|
||||
// Description :
|
||||
// --------------------------------------------------------------------------------
|
||||
void CRectPlacement::End()
|
||||
{
|
||||
m_vPositions.clear();
|
||||
m_vRects.clear();
|
||||
m_size.w = 0;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Name : IsFree
|
||||
// Description : Check if the given rectangle is partially or totally used
|
||||
// --------------------------------------------------------------------------------
|
||||
bool CRectPlacement::IsFree( const TRect& r ) const
|
||||
{
|
||||
if( !m_size.Contains( r ) )
|
||||
return false;
|
||||
|
||||
for( CRectArray::const_iterator it = m_vRects.begin();
|
||||
it != m_vRects.end(); ++it )
|
||||
{
|
||||
if( it->Intersects( r ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Name : AddPosition
|
||||
// Description : Add new anchor point
|
||||
// --------------------------------------------------------------------------------
|
||||
void CRectPlacement::AddPosition( const TPos& p )
|
||||
{
|
||||
// Try to insert anchor as close as possible to the top left corner
|
||||
// So it will be tried first
|
||||
bool bFound = false;
|
||||
CPosArray::iterator it;
|
||||
|
||||
for( it = m_vPositions.begin();
|
||||
!bFound && it != m_vPositions.end();
|
||||
++it )
|
||||
{
|
||||
if( p.x + p.y < it->x + it->y )
|
||||
bFound = true;
|
||||
}
|
||||
|
||||
if( bFound )
|
||||
m_vPositions.insert( it, p );
|
||||
else
|
||||
m_vPositions.push_back( p );
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Name : AddRect
|
||||
// Description : Add the given rect and updates anchor points
|
||||
// --------------------------------------------------------------------------------
|
||||
void CRectPlacement::AddRect( const TRect& r )
|
||||
{
|
||||
m_vRects.push_back( r );
|
||||
m_area += r.w * r.h;
|
||||
|
||||
// Add two new anchor points
|
||||
AddPosition( TPos( r.x, r.y + r.h ) );
|
||||
AddPosition( TPos( r.x + r.w, r.y ) );
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Name : AddAtEmptySpot
|
||||
// Description : Add the given rectangle
|
||||
// --------------------------------------------------------------------------------
|
||||
bool CRectPlacement::AddAtEmptySpot( TRect& r )
|
||||
{
|
||||
// Find a valid spot among available anchors.
|
||||
bool bFound = false;
|
||||
CPosArray::iterator it;
|
||||
|
||||
for( it = m_vPositions.begin();
|
||||
!bFound && it != m_vPositions.end();
|
||||
++it )
|
||||
{
|
||||
TRect Rect( it->x, it->y, r.w, r.h );
|
||||
|
||||
if( IsFree( Rect ) )
|
||||
{
|
||||
r = Rect;
|
||||
bFound = true;
|
||||
break; // Don't let the loop increase the iterator.
|
||||
}
|
||||
}
|
||||
|
||||
if( bFound )
|
||||
{
|
||||
int x, y;
|
||||
|
||||
// Remove the used anchor point
|
||||
m_vPositions.erase( it );
|
||||
|
||||
// Sometimes, anchors end up displaced from the optimal position
|
||||
// due to irregular sizes of the subrects.
|
||||
// So, try to adjut it up & left as much as possible.
|
||||
for( x = 1; x <= r.x; x++ )
|
||||
{
|
||||
if( !IsFree( TRect( r.x - x, r.y, r.w, r.h ) ) )
|
||||
break;
|
||||
}
|
||||
|
||||
for( y = 1; y <= r.y; y++ )
|
||||
{
|
||||
if( !IsFree( TRect( r.x, r.y - y, r.w, r.h ) ) )
|
||||
break;
|
||||
}
|
||||
|
||||
if( y > x )
|
||||
r.y -= y - 1;
|
||||
else
|
||||
r.x -= x - 1;
|
||||
|
||||
AddRect( r );
|
||||
}
|
||||
|
||||
return bFound;
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
// --------------------------------------------------------------------------------
|
||||
// Name : AddAtEmptySpotAutoGrow
|
||||
// Description : Add a rectangle of the given size, growing our area if needed
|
||||
// Area grows only until the max given.
|
||||
// Returns the placement of the rect in the rect's x,y coords
|
||||
// --------------------------------------------------------------------------------
|
||||
bool CRectPlacement::AddAtEmptySpotAutoGrow( TRect* pRect, int maxW, int maxH )
|
||||
{
|
||||
double growing_factor = 1.2; // Must be > 1.0, and event > 1.1 for fast optimization
|
||||
|
||||
#define GROW(x) ((x * growing_factor) + 1)
|
||||
|
||||
if( pRect->w <= 0 )
|
||||
return true;
|
||||
|
||||
int orgW = m_size.w;
|
||||
int orgH = m_size.h;
|
||||
|
||||
// Try to add it in the existing space
|
||||
while( !AddAtEmptySpot( *pRect ) )
|
||||
{
|
||||
int pw = m_size.w;
|
||||
int ph = m_size.h;
|
||||
|
||||
// Sanity check - if area is complete.
|
||||
if( pw >= maxW && ph >= maxH )
|
||||
{
|
||||
m_size.w = orgW;
|
||||
m_size.h = orgH;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try growing the smallest dim
|
||||
if( pw < maxW && ( pw < ph || ( (pw == ph) && (pRect->w >= pRect->h) ) ) )
|
||||
m_size.w = GROW( pw );
|
||||
else
|
||||
m_size.h = GROW( ph );
|
||||
|
||||
if( AddAtEmptySpot( *pRect ) )
|
||||
break;
|
||||
|
||||
// Try growing the other dim instead
|
||||
if( pw != m_size.w )
|
||||
{
|
||||
m_size.w = pw;
|
||||
|
||||
if( ph < maxW )
|
||||
m_size.h = GROW( ph );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_size.h = ph;
|
||||
|
||||
if( pw < maxW )
|
||||
m_size.w = GROW( pw );
|
||||
}
|
||||
|
||||
if( pw != m_size.w || ph != m_size.h )
|
||||
if( AddAtEmptySpot( *pRect ) )
|
||||
break;
|
||||
|
||||
|
||||
|
||||
// Grow both if possible, and reloop.
|
||||
m_size.w = pw;
|
||||
m_size.h = ph;
|
||||
|
||||
if( pw < maxW )
|
||||
m_size.w = GROW( pw );
|
||||
|
||||
if( ph < maxH )
|
||||
m_size.h = GROW( ph );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
// --------------------------------------------------------------------------------
|
||||
// Name : rect_placement.h
|
||||
// Description : A class that allocates subrectangles into power-of-2 rectangles
|
||||
// (C) Copyright 2000-2002 by Javier Arevalo
|
||||
// This code is free to use and modify for all purposes
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @file rect_placement.h
|
||||
*/
|
||||
|
||||
#ifndef _RECT_PLACEMENT_H_
|
||||
#define _RECT_PLACEMENT_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
class CRectPlacement
|
||||
{
|
||||
public:
|
||||
|
||||
// Helper classes
|
||||
struct TPos
|
||||
{
|
||||
int x, y;
|
||||
|
||||
TPos() { }
|
||||
TPos( int _x, int _y ) : x( _x ), y( _y ) { }
|
||||
|
||||
bool operator ==( const TPos& p ) const { return x == p.x && y == p.y; }
|
||||
};
|
||||
|
||||
struct TRect : public TPos
|
||||
{
|
||||
int w, h;
|
||||
|
||||
TRect() { }
|
||||
TRect( int _x, int _y, int _w, int _h ) : TPos( _x, _y ), w( _w > 0 ? _w : 0 ), h(
|
||||
_h > 0 ? _h : 0 ) { }
|
||||
|
||||
bool Contains( const TPos& p ) const
|
||||
{
|
||||
return p.x >= x && p.y >= y && p.x < (x + w) && p.y < (y + h);
|
||||
}
|
||||
bool Contains( const TRect& r ) const
|
||||
{
|
||||
return r.x >= x && r.y >= y &&
|
||||
(r.x + r.w) <= (x + w) && (r.y + r.h) <= (y + h);
|
||||
}
|
||||
bool Intersects( const TRect& r ) const
|
||||
{
|
||||
return w > 0 && h > 0 && r.w > 0 && r.h > 0
|
||||
&& ( (r.x + r.w) > x && r.x < (x + w) && (r.y + r.h) > y && r.y < (y + h) );
|
||||
}
|
||||
|
||||
// static bool Greater(const TRect &a, const TRect &b)
|
||||
// { return a.w*a.h > b.w*b.h; }
|
||||
// Greater rect area. Not as good as the next heuristic:
|
||||
// Greater size in at least one dim.
|
||||
static bool Greater( const TRect& a, const TRect& b )
|
||||
{
|
||||
return (a.w > b.w && a.w > b.h) || (a.h > b.w && a.h > b.h);
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------
|
||||
|
||||
typedef std::vector<TPos> CPosArray;
|
||||
typedef std::vector<TRect> CRectArray;
|
||||
|
||||
// ---------------------
|
||||
|
||||
CRectPlacement() { Init(); }
|
||||
~CRectPlacement() { End(); }
|
||||
|
||||
void Init( int w = 1, int h = 1 );
|
||||
void End();
|
||||
|
||||
bool IsOk() const { return m_size.w > 0; }
|
||||
|
||||
int GetW() const { return m_size.w; }
|
||||
int GetH() const { return m_size.h; }
|
||||
double GetArea() const { return m_area; }
|
||||
double GetTotalArea() const { return (double)m_size.w * m_size.h; }
|
||||
|
||||
bool AddAtEmptySpotAutoGrow( TRect* pRect, int maxW, int maxH );
|
||||
|
||||
private:
|
||||
TRect m_size;
|
||||
CRectArray m_vRects;
|
||||
CPosArray m_vPositions;
|
||||
double m_area;
|
||||
|
||||
// ---------------------
|
||||
|
||||
bool IsFree( const TRect& r ) const;
|
||||
void AddPosition( const TPos& p );
|
||||
void AddRect( const TRect& r );
|
||||
bool AddAtEmptySpot( TRect& r );
|
||||
};
|
||||
|
||||
#endif // _RECT_PLACEMENT_H_
|
|
@ -324,7 +324,6 @@ int PCB_EDIT_FRAME::Solve( wxDC* DC, int aLayersCount )
|
|||
AppendMsgPanel( wxT( "Activity" ), msg, BROWN );
|
||||
}
|
||||
|
||||
pt_cur_ch = pt_cur_ch;
|
||||
segm_oX = GetBoard()->GetBoundingBox().GetX() + (RoutingMatrix.m_GridRouting * col_source);
|
||||
segm_oY = GetBoard()->GetBoundingBox().GetY() + (RoutingMatrix.m_GridRouting * row_source);
|
||||
segm_fX = GetBoard()->GetBoundingBox().GetX() + (RoutingMatrix.m_GridRouting * col_target);
|
||||
|
|
|
@ -0,0 +1,356 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2013 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
|
||||
* Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 2013 Wayne Stambaugh <stambaughw@verizon.net>
|
||||
*
|
||||
* Copyright (C) 1992-2013 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file spread_footprints.cpp
|
||||
* @brief functions to spread footprints on free areas outside a board.
|
||||
* this is usefull after reading a netlist, when new footprints are loaded
|
||||
* and stacked at 0,0 coordinate.
|
||||
* Often, spread them on a free area near the board being edited make more easy
|
||||
* their selection.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <fctsys.h>
|
||||
#include <convert_to_biu.h>
|
||||
#include <class_drawpanel.h>
|
||||
#include <confirm.h>
|
||||
#include <pcbnew.h>
|
||||
#include <wxPcbStruct.h>
|
||||
#include <class_board.h>
|
||||
#include <class_module.h>
|
||||
|
||||
#include <rect_placement/rect_placement.h>
|
||||
|
||||
struct TSubRect : public CRectPlacement::TRect
|
||||
{
|
||||
int n; // Original index of this subrect, before sorting
|
||||
|
||||
TSubRect() { }
|
||||
TSubRect( int _w, int _h, int _n ) :
|
||||
TRect( 0, 0, _w, _h ), n( _n ) { }
|
||||
};
|
||||
|
||||
typedef std::vector<TSubRect> CSubRectArray;
|
||||
|
||||
// Use 0.01 mm units to calculate placement, to avoid long calculation time
|
||||
const int scale = (int)(0.01 * IU_PER_MM);
|
||||
|
||||
// Populates a list of rectangles, from a list of modules
|
||||
void fillRectList( CSubRectArray& vecSubRects, std::vector <MODULE*>& aModuleList )
|
||||
{
|
||||
vecSubRects.clear();
|
||||
|
||||
for( unsigned ii = 0; ii < aModuleList.size(); ii++ )
|
||||
{
|
||||
EDA_RECT fpBox = aModuleList[ii]->GetBoundingBox();
|
||||
TSubRect fpRect( fpBox.GetWidth()/scale, fpBox.GetHeight()/scale, ii );
|
||||
vecSubRects.push_back( fpRect );
|
||||
}
|
||||
}
|
||||
|
||||
// Populates a list of rectangles, from a list of EDA_RECT
|
||||
void fillRectList( CSubRectArray& vecSubRects, std::vector <EDA_RECT>& aRectList )
|
||||
{
|
||||
vecSubRects.clear();
|
||||
|
||||
for( unsigned ii = 0; ii < aRectList.size(); ii++ )
|
||||
{
|
||||
EDA_RECT& rect = aRectList[ii];
|
||||
TSubRect fpRect( rect.GetWidth()/scale, rect.GetHeight()/scale, ii );
|
||||
vecSubRects.push_back( fpRect );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Spread a list of rectangles inside a placement area
|
||||
void spreadRectangles( CRectPlacement& aPlacementArea,
|
||||
CSubRectArray& vecSubRects,
|
||||
int areaSizeX, int areaSizeY )
|
||||
{
|
||||
areaSizeX/= scale;
|
||||
areaSizeY/= scale;
|
||||
|
||||
// Sort the subRects based on dimensions, larger dimension goes first.
|
||||
std::sort( vecSubRects.begin(), vecSubRects.end(), CRectPlacement::TRect::Greater );
|
||||
|
||||
// gives the initial size to the area
|
||||
aPlacementArea.Init( areaSizeX, areaSizeY );
|
||||
|
||||
// Add all subrects
|
||||
CSubRectArray::iterator it;
|
||||
for( it = vecSubRects.begin(); it != vecSubRects.end(); )
|
||||
{
|
||||
CRectPlacement::TRect r( 0, 0, it->w, it->h );
|
||||
|
||||
bool bPlaced = aPlacementArea.AddAtEmptySpotAutoGrow( &r, areaSizeX, areaSizeY );
|
||||
|
||||
if( !bPlaced ) // No room to place the rectangle: enlarge area and retry
|
||||
{
|
||||
areaSizeX = ceil(areaSizeX * 1.1);
|
||||
areaSizeY = ceil(areaSizeY * 1.1);
|
||||
aPlacementArea.Init( areaSizeX, areaSizeY );
|
||||
it = vecSubRects.begin();
|
||||
continue;
|
||||
}
|
||||
|
||||
// When correctly placed in a placement area, the coords are returned in r.x and r.y
|
||||
// Store them.
|
||||
it->x = r.x;
|
||||
it->y = r.y;
|
||||
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void moveFootprintsInArea( CRectPlacement& aPlacementArea,
|
||||
std::vector <MODULE*>& aModuleList, EDA_RECT& aFreeArea,
|
||||
bool aFindAreaOnly )
|
||||
{
|
||||
CSubRectArray vecSubRects;
|
||||
|
||||
fillRectList( vecSubRects, aModuleList );
|
||||
spreadRectangles( aPlacementArea, vecSubRects,
|
||||
aFreeArea.GetWidth(), aFreeArea.GetHeight() );
|
||||
|
||||
if( aFindAreaOnly )
|
||||
return;
|
||||
|
||||
for( unsigned it = 0; it < vecSubRects.size(); ++it )
|
||||
{
|
||||
wxPoint pos( vecSubRects[it].x, vecSubRects[it].y );
|
||||
pos.x *= scale;
|
||||
pos.y *= scale;
|
||||
|
||||
MODULE * module = aModuleList[vecSubRects[it].n];
|
||||
|
||||
EDA_RECT fpBBox = module->GetBoundingBox();
|
||||
wxPoint mod_pos = pos + ( module->GetPosition() - fpBBox.GetOrigin() )
|
||||
+ aFreeArea.GetOrigin();
|
||||
|
||||
module->Move( mod_pos - module->GetPosition() );
|
||||
}
|
||||
}
|
||||
|
||||
static bool sortModulesbySheetPath( MODULE* ref, MODULE* compare );
|
||||
|
||||
/* Function to move components in a rectangular area format 4 / 3,
|
||||
* starting from the mouse cursor
|
||||
* The components with the FIXED status set are not moved
|
||||
*/
|
||||
void PCB_EDIT_FRAME::SpreadFootprints( bool aFootprintsOutsideBoardOnly )
|
||||
{
|
||||
EDA_RECT bbox = GetBoard()->ComputeBoundingBox( true );
|
||||
bool edgesExist = ( bbox.GetWidth() || bbox.GetHeight() );
|
||||
|
||||
// no edges exist
|
||||
if( aFootprintsOutsideBoardOnly && !edgesExist )
|
||||
{
|
||||
DisplayError( this,
|
||||
_( "Could not automatically place modules. No board outlines detected." ) );
|
||||
return;
|
||||
}
|
||||
|
||||
// if aFootprintsOutsideBoardOnly is true, and if board outline exists,
|
||||
// wue have to filter footprints to move:
|
||||
bool outsideBrdFilter = aFootprintsOutsideBoardOnly && edgesExist;
|
||||
|
||||
// Build candidate list
|
||||
// calculate also the area needed by these footprints
|
||||
MODULE* Module = GetBoard()->m_Modules;
|
||||
std::vector <MODULE*> moduleList;
|
||||
|
||||
for( ; Module != NULL; Module = Module->Next() )
|
||||
{
|
||||
Module->CalculateBoundingBox();
|
||||
|
||||
if( outsideBrdFilter )
|
||||
{
|
||||
if( bbox.Contains( Module->GetPosition() ) )
|
||||
continue;
|
||||
}
|
||||
|
||||
if( Module->IsLocked() )
|
||||
continue;
|
||||
|
||||
moduleList.push_back(Module);
|
||||
}
|
||||
|
||||
if( moduleList.size() == 0 ) // Nothing to do
|
||||
return;
|
||||
|
||||
// sort footprints by sheet path. we group them later by sheet
|
||||
sort( moduleList.begin(), moduleList.end(), sortModulesbySheetPath );
|
||||
|
||||
// Undo command: init undo list
|
||||
PICKED_ITEMS_LIST undoList;
|
||||
undoList.m_Status = UR_CHANGED;
|
||||
ITEM_PICKER picker( NULL, UR_CHANGED );
|
||||
|
||||
for( unsigned ii = 0; ii < moduleList.size(); ii++ )
|
||||
{
|
||||
Module = moduleList[ii];
|
||||
|
||||
// Undo: add copy of module to undo list
|
||||
picker.SetItem( Module );
|
||||
picker.SetLink( Module->Clone() );
|
||||
undoList.PushItem( picker );
|
||||
}
|
||||
|
||||
// Extract and place footprints by sheet
|
||||
std::vector <MODULE*> moduleListBySheet;
|
||||
std::vector <EDA_RECT> placementSheetAreas;
|
||||
wxString curr_sheetPath ;
|
||||
double subsurface;
|
||||
double placementsurface = 0.0;
|
||||
|
||||
wxPoint placementAreaPosition = GetCrossHairPosition();
|
||||
|
||||
// We do not want to move footprints inside an existing board.
|
||||
// move the placement area position outside the board bounding box
|
||||
// to the left of the board
|
||||
if( edgesExist )
|
||||
{
|
||||
if( placementAreaPosition.x < bbox.GetEnd().x &&
|
||||
placementAreaPosition.y < bbox.GetEnd().y )
|
||||
{
|
||||
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
|
||||
for( int pass = 0; pass < 2; pass++ )
|
||||
{
|
||||
int subareaIdx = 0;
|
||||
curr_sheetPath = moduleList[0]->GetPath().BeforeLast( '/' );
|
||||
moduleListBySheet.clear();
|
||||
subsurface = 0.0;
|
||||
|
||||
for( unsigned ii = 0; ii < moduleList.size(); ii++ )
|
||||
{
|
||||
Module = moduleList[ii];
|
||||
bool iscurrPath = curr_sheetPath == moduleList[ii]->GetPath().BeforeLast( '/' );
|
||||
|
||||
if( iscurrPath )
|
||||
{
|
||||
moduleListBySheet.push_back( Module );
|
||||
subsurface += Module->GetArea();
|
||||
}
|
||||
|
||||
if( !iscurrPath || (ii == moduleList.size()-1) )
|
||||
{
|
||||
// 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, moduleListBySheet,
|
||||
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();
|
||||
}
|
||||
|
||||
curr_sheetPath = moduleList[ii]->GetPath().BeforeLast( '/' );
|
||||
subsurface = 0.0;
|
||||
moduleListBySheet.clear();
|
||||
|
||||
// Enter first module of next sheet
|
||||
moduleListBySheet.push_back( Module );
|
||||
subsurface += Module->GetArea();
|
||||
|
||||
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
|
||||
SaveCopyInUndoList( undoList, UR_CHANGED );
|
||||
OnModify();
|
||||
|
||||
m_canvas->Refresh();
|
||||
}
|
||||
|
||||
|
||||
static bool sortModulesbySheetPath( MODULE* ref, MODULE* compare )
|
||||
{
|
||||
return compare->GetPath().Cmp( ref->GetPath() ) < 0;
|
||||
}
|
|
@ -386,25 +386,26 @@ bool PCB_EDIT_FRAME::OnRightClick( const wxPoint& aMousePos, wxMenu* aPopMenu )
|
|||
{
|
||||
wxMenu* commands = new wxMenu;
|
||||
AddMenuItem( aPopMenu, commands, ID_POPUP_PCB_AUTOPLACE_COMMANDS,
|
||||
_( "Global Move and Place" ), KiBitmap( move_xpm ) );
|
||||
_( "Global Spread and Place" ), KiBitmap( move_xpm ) );
|
||||
AddMenuItem( commands, ID_POPUP_PCB_AUTOPLACE_FREE_ALL_MODULES,
|
||||
_( "Unlock All Modules" ), KiBitmap( unlocked_xpm ) );
|
||||
_( "Unlock All Footprints" ), KiBitmap( unlocked_xpm ) );
|
||||
AddMenuItem( commands, ID_POPUP_PCB_AUTOPLACE_FIXE_ALL_MODULES,
|
||||
_( "Lock All Modules" ), KiBitmap( locked_xpm ) );
|
||||
_( "Lock All Footprints" ), KiBitmap( locked_xpm ) );
|
||||
commands->AppendSeparator();
|
||||
AddMenuItem( commands, ID_POPUP_PCB_AUTOMOVE_ALL_MODULES,
|
||||
_( "Move All Modules" ), KiBitmap( move_xpm ) );
|
||||
commands->Append( ID_POPUP_PCB_AUTOMOVE_NEW_MODULES, _( "Move New Modules" ) );
|
||||
AddMenuItem( commands, ID_POPUP_PCB_SPREAD_ALL_MODULES,
|
||||
_( "Spread out All Footprints" ), KiBitmap( move_xpm ) );
|
||||
commands->Append( ID_POPUP_PCB_SPREAD_NEW_MODULES,
|
||||
_( "Spread out Footprints not Already on Board" ) );
|
||||
commands->AppendSeparator();
|
||||
commands->Append( ID_POPUP_PCB_AUTOPLACE_ALL_MODULES,
|
||||
_( "Automatically Place All Modules" ) );
|
||||
_( "Automatically Place All Footprints" ) );
|
||||
commands->Append( ID_POPUP_PCB_AUTOPLACE_NEW_MODULES,
|
||||
_( "Automatically Place New Modules" ) );
|
||||
_( "Automatically Place New Footprints" ) );
|
||||
commands->Append( ID_POPUP_PCB_AUTOPLACE_NEXT_MODULE,
|
||||
_( "Automatically Place Next Module" ) );
|
||||
_( "Automatically Place Next Footprints" ) );
|
||||
commands->AppendSeparator();
|
||||
AddMenuItem( commands, ID_POPUP_PCB_REORIENT_ALL_MODULES,
|
||||
_( "Orient All Modules" ), KiBitmap( rotate_module_pos_xpm ) );
|
||||
_( "Orient All Footprints" ), KiBitmap( rotate_module_pos_xpm ) );
|
||||
aPopMenu->AppendSeparator();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2004-2010 Jean-Pierre Charras, jean-pierre.charras@gpisa-lab.inpg.fr
|
||||
* Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
|
||||
* Copyright (C) 2010 KiCad Developers, see change_log.txt for contributors.
|
||||
* Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 2013 Wayne Stambaugh <stambaughw@verizon.net>
|
||||
* Copyright (C) 2013 KiCad Developers, see change_log.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -237,7 +237,7 @@ BEGIN_EVENT_TABLE( PCB_EDIT_FRAME, PCB_BASE_FRAME )
|
|||
PCB_EDIT_FRAME::ProcessMuWaveFunctions )
|
||||
|
||||
EVT_MENU_RANGE( ID_POPUP_PCB_AUTOPLACE_START_RANGE, ID_POPUP_PCB_AUTOPLACE_END_RANGE,
|
||||
PCB_EDIT_FRAME::AutoPlace )
|
||||
PCB_EDIT_FRAME::OnPlaceOrRouteFootprints )
|
||||
|
||||
EVT_MENU( ID_POPUP_PCB_REORIENT_ALL_MODULES, PCB_EDIT_FRAME::OnOrientFootprints )
|
||||
|
||||
|
|
|
@ -216,8 +216,8 @@ enum pcbnew_ids
|
|||
ID_POPUP_PCB_AUTOPLACE_FREE_ALL_MODULES,
|
||||
ID_POPUP_PCB_AUTOPLACE_FIXE_ALL_MODULES,
|
||||
ID_POPUP_PCB_AUTOPLACE_CURRENT_MODULE,
|
||||
ID_POPUP_PCB_AUTOMOVE_ALL_MODULES,
|
||||
ID_POPUP_PCB_AUTOMOVE_NEW_MODULES,
|
||||
ID_POPUP_PCB_SPREAD_ALL_MODULES,
|
||||
ID_POPUP_PCB_SPREAD_NEW_MODULES,
|
||||
ID_POPUP_PCB_AUTOPLACE_COMMANDS,
|
||||
ID_POPUP_PCB_AUTOPLACE_ALL_MODULES,
|
||||
ID_POPUP_PCB_AUTOPLACE_NEW_MODULES,
|
||||
|
|
Loading…
Reference in New Issue