KiCad PCB EDA Suite
spread_footprints.cpp File Reference

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

#include <algorithm>
#include <convert_to_biu.h>
#include <confirm.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 58 of file spread_footprints.cpp.

Function Documentation

◆ fillRectList() [1/2]

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

Definition at line 66 of file spread_footprints.cpp.

67 {
68  vecSubRects.clear();
69 
70  for( unsigned ii = 0; ii < aModuleList.size(); ii++ )
71  {
72  EDA_RECT fpBox = aModuleList[ii]->GetFootprintRect();
73  TSubRect fpRect( ( fpBox.GetWidth() + PADDING ) / scale,
74  ( fpBox.GetHeight() + PADDING ) / scale, ii );
75  vecSubRects.push_back( fpRect );
76  }
77 }
int GetWidth() const
Definition: eda_rect.h:119
const int PADDING
int GetHeight() const
Definition: eda_rect.h:120
const int scale
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 80 of file spread_footprints.cpp.

81 {
82  vecSubRects.clear();
83 
84  for( unsigned ii = 0; ii < aRectList.size(); ii++ )
85  {
86  EDA_RECT& rect = aRectList[ii];
87  TSubRect fpRect( rect.GetWidth()/scale, rect.GetHeight()/scale, ii );
88  vecSubRects.push_back( fpRect );
89  }
90 }
int GetWidth() const
Definition: eda_rect.h:119
int GetHeight() const
Definition: eda_rect.h:120
const int scale
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 151 of file spread_footprints.cpp.

155 {
156  CSubRectArray vecSubRects;
157 
158  fillRectList( vecSubRects, aModuleList );
159  spreadRectangles( aPlacementArea, vecSubRects,
160  aFreeArea.GetWidth(), aFreeArea.GetHeight() );
161 
162  if( aFindAreaOnly )
163  return;
164 
165  for( unsigned it = 0; it < vecSubRects.size(); ++it )
166  {
167  wxPoint pos( vecSubRects[it].x, vecSubRects[it].y );
168  pos.x *= scale;
169  pos.y *= scale;
170 
171  MODULE * module = aModuleList[vecSubRects[it].n];
172 
173  EDA_RECT fpBBox = module->GetFootprintRect();
174  wxPoint mod_pos = pos + ( module->GetPosition() - fpBBox.GetOrigin() )
175  + aFreeArea.GetOrigin();
176 
177  module->Move( mod_pos - module->GetPosition() );
178  }
179 }
int GetWidth() const
Definition: eda_rect.h:119
EDA_RECT GetFootprintRect() const
Function GetFootprintRect() Build and returns the boundary box of the module footprint excluding any ...
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.
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
wxPoint GetPosition() const override
Definition: class_module.h:201
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, spreadRectangles(), wxPoint::x, and wxPoint::y.

Referenced by SpreadFootprints().

◆ sortFootprintsbySheetPath()

static bool sortFootprintsbySheetPath ( MODULE ref,
MODULE compare 
)
static

Definition at line 345 of file spread_footprints.cpp.

346 {
347  return ref->GetPath() < compare->GetPath();
348 }
const KIID_PATH & GetPath() const
Definition: class_module.h:219

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 192 of file spread_footprints.cpp.

194 {
195  // Build candidate list
196  // calculate also the area needed by these footprints
197  std::vector <MODULE*> footprintList;
198 
199  for( MODULE* footprint : *aFootprints )
200  {
201  if( footprint->IsLocked() )
202  continue;
203 
204  footprint->CalculateBoundingBox();
205  footprintList.push_back( footprint );
206  }
207 
208  if( footprintList.empty() )
209  return;
210 
211  // sort footprints by sheet path. we group them later by sheet
212  sort( footprintList.begin(), footprintList.end(), sortFootprintsbySheetPath );
213 
214  // Extract and place footprints by sheet
215  std::vector <MODULE*> footprintListBySheet;
216  std::vector <EDA_RECT> placementSheetAreas;
217  double subsurface;
218  double placementsurface = 0.0;
219 
220  // The placement uses 2 passes:
221  // the first pass creates the rectangular areas to place footprints
222  // each sheet in schematic creates one rectangular area.
223  // the second pass moves footprints inside these areas
224  for( int pass = 0; pass < 2; pass++ )
225  {
226  int subareaIdx = 0;
227  footprintListBySheet.clear();
228  subsurface = 0.0;
229 
230  int fp_max_width = 0;
231  int fp_max_height = 0;
232 
233  for( unsigned ii = 0; ii < footprintList.size(); ii++ )
234  {
235  MODULE* footprint = footprintList[ii];
236  bool islastItem = false;
237 
238  if( ii == footprintList.size() - 1 ||
239  ( footprintList[ii]->GetPath().AsString().BeforeLast( '/' ) !=
240  footprintList[ii+1]->GetPath().AsString().BeforeLast( '/' ) ) )
241  islastItem = true;
242 
243  footprintListBySheet.push_back( footprint );
244  subsurface += footprint->GetArea( PADDING );
245 
246  // Calculate min size of placement area:
247  EDA_RECT bbox = footprint->GetFootprintRect();
248  fp_max_width = std::max( fp_max_width, bbox.GetWidth() );
249  fp_max_height = std::max( fp_max_height, bbox.GetHeight() );
250 
251  if( islastItem )
252  {
253  // end of the footprint sublist relative to the same sheet path
254  // calculate placement of the current sublist
255  EDA_RECT freeArea;
256  int Xsize_allowed = (int) ( sqrt( subsurface ) * 4.0 / 3.0 );
257  Xsize_allowed = std::max( fp_max_width, Xsize_allowed );
258 
259  int Ysize_allowed = (int) ( subsurface / Xsize_allowed );
260  Ysize_allowed = std::max( fp_max_height, Ysize_allowed );
261 
262  freeArea.SetWidth( Xsize_allowed );
263  freeArea.SetHeight( Ysize_allowed );
264  CRectPlacement placementArea;
265 
266  if( pass == 1 )
267  {
268  wxPoint areapos = placementSheetAreas[subareaIdx].GetOrigin()
269  + aSpreadAreaPosition;
270  freeArea.SetOrigin( areapos );
271  }
272 
273  bool findAreaOnly = pass == 0;
274  moveFootprintsInArea( placementArea, footprintListBySheet,
275  freeArea, findAreaOnly );
276 
277  if( pass == 0 )
278  {
279  // Populate sheet placement areas list
280  EDA_RECT sub_area;
281  sub_area.SetWidth( placementArea.GetW()*scale );
282  sub_area.SetHeight( placementArea.GetH()*scale );
283  // Add a margin around the sheet placement area:
284  sub_area.Inflate( Millimeter2iu( 1.5 ) );
285 
286  placementSheetAreas.push_back( sub_area );
287 
288  placementsurface += (double) sub_area.GetWidth()*
289  sub_area.GetHeight();
290  }
291 
292  // Prepare buffers for next sheet
293  subsurface = 0.0;
294  footprintListBySheet.clear();
295  subareaIdx++;
296  }
297  }
298 
299  // End of pass:
300  // At the end of the first pass, we have to find position of each sheet
301  // placement area
302  if( pass == 0 )
303  {
304  int Xsize_allowed = (int) ( sqrt( placementsurface ) * 4.0 / 3.0 );
305 
306  if( Xsize_allowed < 0 || Xsize_allowed > INT_MAX/2 )
307  Xsize_allowed = INT_MAX/2;
308 
309  int Ysize_allowed = (int) ( placementsurface / Xsize_allowed );
310 
311  if( Ysize_allowed < 0 || Ysize_allowed > INT_MAX/2 )
312  Ysize_allowed = INT_MAX/2;
313 
314  CRectPlacement placementArea;
315  CSubRectArray vecSubRects;
316  fillRectList( vecSubRects, placementSheetAreas );
317  spreadRectangles( placementArea, vecSubRects, Xsize_allowed, Ysize_allowed );
318 
319  for( unsigned it = 0; it < vecSubRects.size(); ++it )
320  {
321  TSubRect& srect = vecSubRects[it];
322  wxPoint pos( srect.x*scale, srect.y*scale );
323  wxSize size( srect.w*scale, srect.h*scale );
324 
325  // Avoid too large coordinates: Overlapping components
326  // are better than out of screen components
327  if( (uint64_t)pos.x + (uint64_t)size.x > INT_MAX/2 )
328  pos.x = 0;
329 
330  if( (uint64_t)pos.y + (uint64_t)size.y > INT_MAX/2 )
331  pos.y = 0;
332 
333  placementSheetAreas[srect.n].SetOrigin( pos );
334  placementSheetAreas[srect.n].SetSize( size );
335  }
336  }
337  } // End pass
338 }
double GetArea(int aPadding=0) const
int GetWidth() const
Definition: eda_rect.h:119
void SetOrigin(const wxPoint &pos)
Definition: eda_rect.h:131
EDA_RECT GetFootprintRect() const
Function GetFootprintRect() Build and returns the boundary box of the module footprint excluding any ...
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
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
static constexpr int Millimeter2iu(double mm)
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.
Definition: eda_rect.cpp:363
int GetH() const

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

Referenced by PCB_EDIT_FRAME::OnNetlistChanged().

◆ spreadRectangles()

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

Definition at line 95 of file spread_footprints.cpp.

98 {
99  areaSizeX/= scale;
100  areaSizeY/= scale;
101 
102  // Sort the subRects based on dimensions, larger dimension goes first.
103  std::sort( vecSubRects.begin(), vecSubRects.end(), CRectPlacement::TRect::Greater );
104 
105  // gives the initial size to the area
106  aPlacementArea.Init( areaSizeX, areaSizeY );
107 
108  // Add all subrects
109  CSubRectArray::iterator it;
110 
111  for( it = vecSubRects.begin(); it != vecSubRects.end(); )
112  {
113  CRectPlacement::TRect r( 0, 0, it->w, it->h );
114 
115  bool bPlaced = aPlacementArea.AddAtEmptySpotAutoGrow( &r, areaSizeX, areaSizeY );
116 
117  if( !bPlaced ) // No room to place the rectangle: enlarge area and retry
118  {
119  bool retry = false;
120 
121  if( areaSizeX < INT_MAX/2 )
122  {
123  retry = true;
124  areaSizeX = areaSizeX * 1.2;
125  }
126 
127  if( areaSizeX < INT_MAX/2 )
128  {
129  retry = true;
130  areaSizeY = areaSizeY * 1.2;
131  }
132 
133  if( retry )
134  {
135  aPlacementArea.Init( areaSizeX, areaSizeY );
136  it = vecSubRects.begin();
137  continue;
138  }
139  }
140 
141  // When correctly placed in a placement area, the coords are returned in r.x and r.y
142  // Store them.
143  it->x = r.x;
144  it->y = r.y;
145 
146  it++;
147  }
148 }
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 63 of file spread_footprints.cpp.

Referenced by fillRectList(), and SpreadFootprints().

◆ scale

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

Definition at line 61 of file spread_footprints.cpp.

Referenced by ACTION_TOOLBAR::AddScaledSeparator(), Clamp_Text_PenSize(), KIGFX::CAIRO_PRINT_GAL::ComputeWorldScreenMatrix(), KIGFX::GAL::ComputeWorldScreenMatrix(), DIALOG_PLOT_SCHEMATIC::createPSFile(), EDA_3D_CANVAS::DoRePaint(), COMMON_TOOLS::doZoomFit(), 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(), WRL1STATUS::Init(), KiScaledBitmap(), C3D_RENDER_RAYTRACING::load_3D_models(), KIGFX::WX_VIEW_CONTROLS::LoadSettings(), moveFootprintsInArea(), PCB_EDIT_FRAME::OnExportVRML(), KIGFX::WX_VIEW_CONTROLS::onMotion(), DIALOG_PAD_PRIMITIVE_POLY_PROPS::onPaintPolyPanel(), DIALOG_PIN_PROPERTIES::OnPaintShowPanel(), DIALOG_IMAGE_EDITOR::OnRedrawPanel(), std::hash< SCALED_BITMAP_ID >::operator()(), DIALOG_PLOT_SCHEMATIC::plotOneSheetSVG(), PlotStandardLayer(), SCENEGRAPH::Prepare(), PCB_EDIT_FRAME::PrepareLayerIndicator(), C3D_RENDER_OGL_LEGACY::render_3D_module(), KIGFX::VERTEX_MANAGER::Scale(), ZOOM_TOOL::selectRegion(), DIALOG_PLOT_SCHEMATIC::setupPlotPagePDF(), GERBVIEW_INSPECTION_TOOL::ShowDCodes(), SpreadFootprints(), spreadRectangles(), LIB_EDIT_FRAME::SVG_PlotComponent(), DIALOG_IMAGE_EDITOR::TransferToImage(), DIALOG_PAD_PRIMITIVES_TRANSFORM::Transform(), WRL1TRANSFORM::TranslateToSG(), PCB_CALCULATOR_FRAME::TWCalculateCurrent(), PCB_CALCULATOR_FRAME::TWCalculateWidth(), GERBVIEW_FRAME::updateDCodeSelectBox(), PANEL_PCBNEW_COLOR_SETTINGS::zoomFitPreview(), PANEL_EESCHEMA_COLOR_SETTINGS::zoomFitPreview(), and SELECTION_TOOL::zoomFitSelection().