KiCad PCB EDA Suite
spread_footprints.cpp File Reference

functions to spread footprints on free areas outside a board. More...

#include <algorithm>
#include <fctsys.h>
#include <convert_to_biu.h>
#include <confirm.h>
#include <pcbnew.h>
#include <pcb_edit_frame.h>
#include <class_board.h>
#include <class_module.h>
#include <rect_placement/rect_placement.h>

Go to the source code of this file.

Classes

struct  TSubRect
 

Typedefs

typedef std::vector< TSubRectCSubRectArray
 

Functions

void fillRectList (CSubRectArray &vecSubRects, std::vector< MODULE * > &aModuleList)
 
void fillRectList (CSubRectArray &vecSubRects, std::vector< EDA_RECT > &aRectList)
 
void spreadRectangles (CRectPlacement &aPlacementArea, CSubRectArray &vecSubRects, int areaSizeX, int areaSizeY)
 
void moveFootprintsInArea (CRectPlacement &aPlacementArea, std::vector< MODULE * > &aModuleList, EDA_RECT &aFreeArea, bool aFindAreaOnly)
 
static bool sortFootprintsbySheetPath (MODULE *ref, MODULE *compare)
 
void SpreadFootprints (std::vector< MODULE * > *aFootprints, wxPoint aSpreadAreaPosition)
 Footprints (after loaded by reading a netlist for instance) are moved to be in a small free area (outside the current board) without overlapping. More...
 

Variables

const int scale = (int)(0.01 * IU_PER_MM)
 
const int PADDING = (int)(1 * IU_PER_MM)
 

Detailed Description

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.

Definition in file spread_footprints.cpp.

Typedef Documentation

◆ CSubRectArray

typedef std::vector<TSubRect> CSubRectArray

Definition at line 60 of file spread_footprints.cpp.

Function Documentation

◆ fillRectList() [1/2]

void fillRectList ( CSubRectArray vecSubRects,
std::vector< MODULE * > &  aModuleList 
)

Definition at line 68 of file spread_footprints.cpp.

69 {
70  vecSubRects.clear();
71 
72  for( unsigned ii = 0; ii < aModuleList.size(); ii++ )
73  {
74  EDA_RECT fpBox = aModuleList[ii]->GetFootprintRect();
75  TSubRect fpRect( ( fpBox.GetWidth() + PADDING ) / scale,
76  ( fpBox.GetHeight() + PADDING ) / scale, ii );
77  vecSubRects.push_back( fpRect );
78  }
79 }
int GetWidth() const
Definition: eda_rect.h:119
const int PADDING
int GetHeight() const
Definition: eda_rect.h:120
const int scale
Class EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44

References EDA_RECT::GetHeight(), EDA_RECT::GetWidth(), PADDING, and scale.

Referenced by moveFootprintsInArea(), and SpreadFootprints().

◆ fillRectList() [2/2]

void fillRectList ( CSubRectArray vecSubRects,
std::vector< EDA_RECT > &  aRectList 
)

Definition at line 82 of file spread_footprints.cpp.

83 {
84  vecSubRects.clear();
85 
86  for( unsigned ii = 0; ii < aRectList.size(); ii++ )
87  {
88  EDA_RECT& rect = aRectList[ii];
89  TSubRect fpRect( rect.GetWidth()/scale, rect.GetHeight()/scale, ii );
90  vecSubRects.push_back( fpRect );
91  }
92 }
int GetWidth() const
Definition: eda_rect.h:119
int GetHeight() const
Definition: eda_rect.h:120
const int scale
Class EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44

References EDA_RECT::GetHeight(), EDA_RECT::GetWidth(), and scale.

◆ moveFootprintsInArea()

void moveFootprintsInArea ( CRectPlacement aPlacementArea,
std::vector< MODULE * > &  aModuleList,
EDA_RECT aFreeArea,
bool  aFindAreaOnly 
)

Definition at line 137 of file spread_footprints.cpp.

141 {
142  CSubRectArray vecSubRects;
143 
144  fillRectList( vecSubRects, aModuleList );
145  spreadRectangles( aPlacementArea, vecSubRects,
146  aFreeArea.GetWidth(), aFreeArea.GetHeight() );
147 
148  if( aFindAreaOnly )
149  return;
150 
151  for( unsigned it = 0; it < vecSubRects.size(); ++it )
152  {
153  wxPoint pos( vecSubRects[it].x, vecSubRects[it].y );
154  pos.x *= scale;
155  pos.y *= scale;
156 
157  MODULE * module = aModuleList[vecSubRects[it].n];
158 
159  EDA_RECT fpBBox = module->GetFootprintRect();
160  wxPoint mod_pos = pos + ( module->GetPosition() - fpBBox.GetOrigin() )
161  + aFreeArea.GetOrigin();
162 
163  module->Move( mod_pos - module->GetPosition() );
164  }
165 }
int GetWidth() const
Definition: eda_rect.h:119
EDA_RECT GetFootprintRect() const
Function GetFootprintRect() Returns the area of the module footprint excluding any text.
void fillRectList(CSubRectArray &vecSubRects, std::vector< MODULE * > &aModuleList)
const wxPoint GetOrigin() const
Definition: eda_rect.h:114
std::vector< TSubRect > CSubRectArray
int GetHeight() const
Definition: eda_rect.h:120
const int scale
void Move(const wxPoint &aMoveVector) override
Function Move move this object.
Class EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
const wxPoint GetPosition() const override
Definition: class_module.h:197
void spreadRectangles(CRectPlacement &aPlacementArea, CSubRectArray &vecSubRects, int areaSizeX, int areaSizeY)

References fillRectList(), MODULE::GetFootprintRect(), EDA_RECT::GetHeight(), EDA_RECT::GetOrigin(), MODULE::GetPosition(), EDA_RECT::GetWidth(), MODULE::Move(), scale, and spreadRectangles().

Referenced by SpreadFootprints().

◆ sortFootprintsbySheetPath()

static bool sortFootprintsbySheetPath ( MODULE ref,
MODULE compare 
)
static

Definition at line 304 of file spread_footprints.cpp.

305 {
306  if( ref->GetPath().Length() == compare->GetPath().Length() )
307  return ref->GetPath().BeforeLast( '/' ).Cmp( compare->GetPath().BeforeLast( '/' ) ) < 0;
308 
309  return ref->GetPath().Length() < compare->GetPath().Length();
310 }
const wxString & GetPath() const
Definition: class_module.h:215

References MODULE::GetPath().

Referenced by SpreadFootprints().

◆ SpreadFootprints()

void SpreadFootprints ( std::vector< MODULE * > *  aFootprints,
wxPoint  aSpreadAreaPosition 
)

Footprints (after loaded by reading a netlist for instance) are moved to be in a small free area (outside the current board) without overlapping.

Parameters
aBoardis the board to edit.
aFootprintsa list of footprints to be spread out.
aSpreadAreaPositionthe position of the upper left corner of the area allowed to spread footprints

Definition at line 178 of file spread_footprints.cpp.

180 {
181  // Build candidate list
182  // calculate also the area needed by these footprints
183  std::vector <MODULE*> footprintList;
184 
185  for( MODULE* footprint : *aFootprints )
186  {
187  if( footprint->IsLocked() )
188  continue;
189 
190  footprint->CalculateBoundingBox();
191  footprintList.push_back( footprint );
192  }
193 
194  if( footprintList.empty() )
195  return;
196 
197  // sort footprints by sheet path. we group them later by sheet
198  sort( footprintList.begin(), footprintList.end(), sortFootprintsbySheetPath );
199 
200  // Extract and place footprints by sheet
201  std::vector <MODULE*> footprintListBySheet;
202  std::vector <EDA_RECT> placementSheetAreas;
203  double subsurface;
204  double placementsurface = 0.0;
205 
206  // The placement uses 2 passes:
207  // the first pass creates the rectangular areas to place footprints
208  // each sheet in schematic creates one rectangular area.
209  // the second pass moves footprints inside these areas
210  for( int pass = 0; pass < 2; pass++ )
211  {
212  int subareaIdx = 0;
213  footprintListBySheet.clear();
214  subsurface = 0.0;
215 
216  for( unsigned ii = 0; ii < footprintList.size(); ii++ )
217  {
218  MODULE* footprint = footprintList[ii];
219  bool islastItem = false;
220 
221  if( ii == footprintList.size() - 1 ||
222  ( footprintList[ii]->GetPath().BeforeLast( '/' ) !=
223  footprintList[ii+1]->GetPath().BeforeLast( '/' ) ) )
224  islastItem = true;
225 
226  footprintListBySheet.push_back( footprint );
227  subsurface += footprint->GetArea( PADDING );
228 
229  if( islastItem )
230  {
231  // end of the footprint sublist relative to the same sheet path
232  // calculate placement of the current sublist
233  EDA_RECT freeArea;
234  int Xsize_allowed = (int) ( sqrt( subsurface ) * 4.0 / 3.0 );
235  int Ysize_allowed = (int) ( subsurface / Xsize_allowed );
236 
237  freeArea.SetWidth( Xsize_allowed );
238  freeArea.SetHeight( Ysize_allowed );
239  CRectPlacement placementArea;
240 
241  if( pass == 1 )
242  {
243  wxPoint areapos = placementSheetAreas[subareaIdx].GetOrigin()
244  + aSpreadAreaPosition;
245  freeArea.SetOrigin( areapos );
246  }
247 
248  bool findAreaOnly = pass == 0;
249  moveFootprintsInArea( placementArea, footprintListBySheet,
250  freeArea, findAreaOnly );
251 
252  if( pass == 0 )
253  {
254  // Populate sheet placement areas list
255  EDA_RECT sub_area;
256  sub_area.SetWidth( placementArea.GetW()*scale );
257  sub_area.SetHeight( placementArea.GetH()*scale );
258  // Add a margin around the sheet placement area:
259  sub_area.Inflate( Millimeter2iu( 1.5 ) );
260 
261  placementSheetAreas.push_back( sub_area );
262 
263  placementsurface += (double) sub_area.GetWidth()*
264  sub_area.GetHeight();
265  }
266 
267  // Prepare buffers for next sheet
268  subsurface = 0.0;
269  footprintListBySheet.clear();
270  subareaIdx++;
271  }
272  }
273 
274  // End of pass:
275  // At the end of the first pass, we have to find position of each sheet
276  // placement area
277  if( pass == 0 )
278  {
279  int Xsize_allowed = (int) ( sqrt( placementsurface ) * 4.0 / 3.0 );
280  int Ysize_allowed = (int) ( placementsurface / Xsize_allowed );
281  CRectPlacement placementArea;
282  CSubRectArray vecSubRects;
283 
284  fillRectList( vecSubRects, placementSheetAreas );
285  spreadRectangles( placementArea, vecSubRects, Xsize_allowed, Ysize_allowed );
286 
287  for( unsigned it = 0; it < vecSubRects.size(); ++it )
288  {
289  TSubRect& srect = vecSubRects[it];
290  wxPoint pos( srect.x*scale, srect.y*scale );
291  wxSize size( srect.w*scale, srect.h*scale );
292  placementSheetAreas[srect.n].SetOrigin( pos );
293  placementSheetAreas[srect.n].SetSize( size );
294  }
295  }
296  } // End pass
297 }
double GetArea(int aPadding=0) const
int GetWidth() const
Definition: eda_rect.h:119
void SetOrigin(const wxPoint &pos)
Definition: eda_rect.h:131
void fillRectList(CSubRectArray &vecSubRects, std::vector< MODULE * > &aModuleList)
const int PADDING
void SetHeight(int val)
Definition: eda_rect.h:186
int GetW() const
static bool sortFootprintsbySheetPath(MODULE *ref, MODULE *compare)
std::vector< TSubRect > CSubRectArray
void SetWidth(int val)
Definition: eda_rect.h:180
int GetHeight() const
Definition: eda_rect.h:120
const int scale
Class EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
void moveFootprintsInArea(CRectPlacement &aPlacementArea, std::vector< MODULE * > &aModuleList, EDA_RECT &aFreeArea, bool aFindAreaOnly)
void spreadRectangles(CRectPlacement &aPlacementArea, CSubRectArray &vecSubRects, int areaSizeX, int areaSizeY)
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
int GetH() const

References fillRectList(), MODULE::GetArea(), CRectPlacement::GetH(), EDA_RECT::GetHeight(), CRectPlacement::GetW(), EDA_RECT::GetWidth(), CRectPlacement::TRect::h, EDA_RECT::Inflate(), moveFootprintsInArea(), TSubRect::n, PADDING, scale, EDA_RECT::SetHeight(), EDA_RECT::SetOrigin(), EDA_RECT::SetWidth(), sortFootprintsbySheetPath(), spreadRectangles(), CRectPlacement::TRect::w, CRectPlacement::TPos::x, and CRectPlacement::TPos::y.

Referenced by PCB_EDIT_FRAME::OnNetlistChanged().

◆ spreadRectangles()

void spreadRectangles ( CRectPlacement aPlacementArea,
CSubRectArray vecSubRects,
int  areaSizeX,
int  areaSizeY 
)

Definition at line 97 of file spread_footprints.cpp.

100 {
101  areaSizeX/= scale;
102  areaSizeY/= scale;
103 
104  // Sort the subRects based on dimensions, larger dimension goes first.
105  std::sort( vecSubRects.begin(), vecSubRects.end(), CRectPlacement::TRect::Greater );
106 
107  // gives the initial size to the area
108  aPlacementArea.Init( areaSizeX, areaSizeY );
109 
110  // Add all subrects
111  CSubRectArray::iterator it;
112  for( it = vecSubRects.begin(); it != vecSubRects.end(); )
113  {
114  CRectPlacement::TRect r( 0, 0, it->w, it->h );
115 
116  bool bPlaced = aPlacementArea.AddAtEmptySpotAutoGrow( &r, areaSizeX, areaSizeY );
117 
118  if( !bPlaced ) // No room to place the rectangle: enlarge area and retry
119  {
120  areaSizeX = ceil(areaSizeX * 1.1);
121  areaSizeY = ceil(areaSizeY * 1.1);
122  aPlacementArea.Init( areaSizeX, areaSizeY );
123  it = vecSubRects.begin();
124  continue;
125  }
126 
127  // When correctly placed in a placement area, the coords are returned in r.x and r.y
128  // Store them.
129  it->x = r.x;
130  it->y = r.y;
131 
132  it++;
133  }
134 }
void Init(int w=1, int h=1)
static bool Greater(const TRect &a, const TRect &b)
const int scale
bool AddAtEmptySpotAutoGrow(TRect *pRect, int maxW, int maxH)

References CRectPlacement::AddAtEmptySpotAutoGrow(), CRectPlacement::TRect::Greater(), CRectPlacement::Init(), scale, CRectPlacement::TPos::x, and CRectPlacement::TPos::y.

Referenced by moveFootprintsInArea(), and SpreadFootprints().

Variable Documentation

◆ PADDING

const int PADDING = (int)(1 * IU_PER_MM)

Definition at line 65 of file spread_footprints.cpp.

Referenced by fillRectList(), and SpreadFootprints().

◆ scale

const int scale = (int)(0.01 * IU_PER_MM)

Definition at line 63 of file spread_footprints.cpp.

Referenced by Clamp_Text_PenSize(), KIGFX::CAIRO_PRINT_GAL::ComputeWorldScreenMatrix(), KIGFX::GAL::ComputeWorldScreenMatrix(), DIALOG_PLOT_SCHEMATIC::createPSFile(), COMMON_TOOLS::doZoomToPreset(), KIGFX::CAIRO_GAL_BASE::DrawBitmap(), KIGFX::OPENGL_GAL::DrawBitmap(), BITMAP_BASE::DrawBitmap(), SCH_EDIT_FRAME::DrawCurrentSheetToClipboard(), PCB_EDIT_FRAME::Export_IDF3(), fillRectList(), SYMBOL_PREVIEW_WIDGET::fitOnDrawArea(), formatSILabels(), GENDRILL_WRITER_BASE::genDrillMapFile(), C3D_RENDER_OGL_LEGACY::generate_new_3DGrid(), getEnviromentScale(), getKiCadConfiguredScale(), DIALOG_PRINT_GENERIC::getScaleValue(), idf_export_module(), idf_export_outline(), KiScaledBitmap(), KiScaledSeparator(), GERBVIEW_FRAME::Liste_D_Codes(), C3D_RENDER_RAYTRACING::load_3D_models(), moveFootprintsInArea(), nsvg__addShape(), PCB_EDIT_FRAME::OnExportVRML(), EDA_3D_CANVAS::OnPaint(), DIALOG_PAD_PRIMITIVE_POLY_PROPS::onPaintPolyPanel(), DIALOG_LIB_EDIT_PIN::OnPaintShowPanel(), DIALOG_PAD_PROPERTIES::OnPaintShowPanel(), DIALOG_IMAGE_EDITOR::OnRedrawPanel(), std::hash< SCALED_BITMAP_ID >::operator()(), DIALOG_PLOT_SCHEMATIC::plotOneSheetSVG(), SCENEGRAPH::Prepare(), PCB_EDIT_FRAME::PrepareLayerIndicator(), SCH_BASE_FRAME::RedrawScreen(), KIGFX::VERTEX_MANAGER::Scale(), ZOOM_TOOL::selectRegion(), DIALOG_PLOT_SCHEMATIC::setupPlotPagePDF(), SpreadFootprints(), spreadRectangles(), LIB_EDIT_FRAME::SVG_PlotComponent(), DIALOG_IMAGE_EDITOR::TransferToImage(), DIALOG_PAD_PRIMITIVES_TRANSFORM::Transform(), GERBVIEW_FRAME::updateDCodeSelectBox(), COMMON_TOOLS::ZoomFitScreen(), and SELECTION_TOOL::zoomFitSelection().