|
|
|
@ -5,7 +5,7 @@ |
|
|
|
* Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> |
|
|
|
* Copyright (C) 2013 Wayne Stambaugh <stambaughw@verizon.net> |
|
|
|
* |
|
|
|
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors. |
|
|
|
* Copyright (C) 1992-2016 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 |
|
|
|
@ -35,6 +35,7 @@ |
|
|
|
*/ |
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <boost/foreach.hpp>
|
|
|
|
|
|
|
|
#include <fctsys.h>
|
|
|
|
#include <convert_to_biu.h>
|
|
|
|
@ -135,7 +136,8 @@ void spreadRectangles( CRectPlacement& aPlacementArea, |
|
|
|
|
|
|
|
|
|
|
|
void moveFootprintsInArea( CRectPlacement& aPlacementArea, |
|
|
|
std::vector <MODULE*>& aModuleList, EDA_RECT& aFreeArea, |
|
|
|
std::vector <MODULE*>& aModuleList, |
|
|
|
EDA_RECT& aFreeArea, |
|
|
|
bool aFindAreaOnly ) |
|
|
|
{ |
|
|
|
CSubRectArray vecSubRects; |
|
|
|
@ -163,83 +165,82 @@ void moveFootprintsInArea( CRectPlacement& aPlacementArea, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static bool sortModulesbySheetPath( MODULE* ref, MODULE* compare ); |
|
|
|
static bool sortFootprintsbySheetPath( 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 ) |
|
|
|
void PCB_EDIT_FRAME::SpreadFootprints( std::vector<MODULE*>* aFootprints, |
|
|
|
bool aMoveFootprintsOutsideBoardOnly, |
|
|
|
bool aCheckForBoardEdges ) |
|
|
|
{ |
|
|
|
EDA_RECT bbox = GetBoard()->ComputeBoundingBox( true ); |
|
|
|
bool edgesExist = ( bbox.GetWidth() || bbox.GetHeight() ); |
|
|
|
// if aFootprintsOutsideBoardOnly is true, and if board outline exists,
|
|
|
|
// wue have to filter footprints to move:
|
|
|
|
bool outsideBrdFilter = aMoveFootprintsOutsideBoardOnly && edgesExist; |
|
|
|
|
|
|
|
// no edges exist
|
|
|
|
if( aFootprintsOutsideBoardOnly && !edgesExist ) |
|
|
|
if( aMoveFootprintsOutsideBoardOnly && !edgesExist ) |
|
|
|
{ |
|
|
|
DisplayError( this, |
|
|
|
_( "Could not automatically place footprints. 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; |
|
|
|
std::vector <MODULE*> footprintList; |
|
|
|
|
|
|
|
for( ; module != NULL; module = module->Next() ) |
|
|
|
BOOST_FOREACH( MODULE* footprint, *aFootprints ) |
|
|
|
{ |
|
|
|
module->CalculateBoundingBox(); |
|
|
|
footprint->CalculateBoundingBox(); |
|
|
|
|
|
|
|
if( outsideBrdFilter ) |
|
|
|
{ |
|
|
|
if( bbox.Contains( module->GetPosition() ) ) |
|
|
|
if( bbox.Contains( footprint->GetPosition() ) ) |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
if( module->IsLocked() ) |
|
|
|
if( footprint->IsLocked() ) |
|
|
|
continue; |
|
|
|
|
|
|
|
moduleList.push_back(module); |
|
|
|
footprintList.push_back( footprint ); |
|
|
|
} |
|
|
|
|
|
|
|
if( moduleList.size() == 0 ) // Nothing to do
|
|
|
|
if( footprintList.empty() ) |
|
|
|
return; |
|
|
|
|
|
|
|
// sort footprints by sheet path. we group them later by sheet
|
|
|
|
sort( moduleList.begin(), moduleList.end(), sortModulesbySheetPath ); |
|
|
|
sort( footprintList.begin(), footprintList.end(), sortFootprintsbySheetPath ); |
|
|
|
|
|
|
|
// 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++ ) |
|
|
|
BOOST_FOREACH( MODULE* footprint, footprintList ) |
|
|
|
{ |
|
|
|
module = moduleList[ii]; |
|
|
|
|
|
|
|
// Undo: add copy of module to undo list
|
|
|
|
picker.SetItem( module ); |
|
|
|
picker.SetLink( module->Clone() ); |
|
|
|
// 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*> moduleListBySheet; |
|
|
|
std::vector <MODULE*> footprintListBySheet; |
|
|
|
std::vector <EDA_RECT> placementSheetAreas; |
|
|
|
double subsurface; |
|
|
|
double placementsurface = 0.0; |
|
|
|
|
|
|
|
wxPoint placementAreaPosition = GetCrossHairPosition(); |
|
|
|
|
|
|
|
// We do not want to move footprints inside an existing board.
|
|
|
|
// We sometimes 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( edgesExist && aCheckForBoardEdges ) |
|
|
|
{ |
|
|
|
if( placementAreaPosition.x < bbox.GetEnd().x && |
|
|
|
placementAreaPosition.y < bbox.GetEnd().y ) |
|
|
|
@ -253,24 +254,25 @@ void PCB_EDIT_FRAME::SpreadFootprints( bool aFootprintsOutsideBoardOnly ) |
|
|
|
// 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; |
|
|
|
moduleListBySheet.clear(); |
|
|
|
footprintListBySheet.clear(); |
|
|
|
subsurface = 0.0; |
|
|
|
|
|
|
|
for( unsigned ii = 0; ii < moduleList.size(); ii++ ) |
|
|
|
for( unsigned ii = 0; ii < footprintList.size(); ii++ ) |
|
|
|
{ |
|
|
|
module = moduleList[ii]; |
|
|
|
footprint = footprintList[ii]; |
|
|
|
bool islastItem = false; |
|
|
|
|
|
|
|
if( ii == moduleList.size() - 1 || |
|
|
|
( moduleList[ii]->GetPath().BeforeLast( '/' ) != |
|
|
|
moduleList[ii+1]->GetPath().BeforeLast( '/' ) ) ) |
|
|
|
if( ii == footprintList.size() - 1 || |
|
|
|
( footprintList[ii]->GetPath().BeforeLast( '/' ) != |
|
|
|
footprintList[ii+1]->GetPath().BeforeLast( '/' ) ) ) |
|
|
|
islastItem = true; |
|
|
|
|
|
|
|
moduleListBySheet.push_back( module ); |
|
|
|
subsurface += module->GetArea(); |
|
|
|
footprintListBySheet.push_back( footprint ); |
|
|
|
subsurface += footprint->GetArea(); |
|
|
|
|
|
|
|
if( islastItem ) |
|
|
|
{ |
|
|
|
@ -292,7 +294,7 @@ void PCB_EDIT_FRAME::SpreadFootprints( bool aFootprintsOutsideBoardOnly ) |
|
|
|
} |
|
|
|
|
|
|
|
bool findAreaOnly = pass == 0; |
|
|
|
moveFootprintsInArea( placementArea, moduleListBySheet, |
|
|
|
moveFootprintsInArea( placementArea, footprintListBySheet, |
|
|
|
freeArea, findAreaOnly ); |
|
|
|
|
|
|
|
if( pass == 0 ) |
|
|
|
@ -312,7 +314,7 @@ void PCB_EDIT_FRAME::SpreadFootprints( bool aFootprintsOutsideBoardOnly ) |
|
|
|
|
|
|
|
// Prepare buffers for next sheet
|
|
|
|
subsurface = 0.0; |
|
|
|
moduleListBySheet.clear(); |
|
|
|
footprintListBySheet.clear(); |
|
|
|
subareaIdx++; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -353,7 +355,7 @@ void PCB_EDIT_FRAME::SpreadFootprints( bool aFootprintsOutsideBoardOnly ) |
|
|
|
// Footprints are sorted by their sheet path.
|
|
|
|
// (the full sheet path restricted to the time stamp of the sheet itself,
|
|
|
|
// without the time stamp of the footprint ).
|
|
|
|
static bool sortModulesbySheetPath( MODULE* ref, MODULE* compare ) |
|
|
|
static bool sortFootprintsbySheetPath( MODULE* ref, MODULE* compare ) |
|
|
|
{ |
|
|
|
if( ref->GetPath().Length() == compare->GetPath().Length() ) |
|
|
|
return ref->GetPath().BeforeLast( '/' ).Cmp( compare->GetPath().BeforeLast( '/' ) ) < 0; |
|
|
|
|