KiCad PCB EDA Suite
pcbnew/netlist_reader/netlist.cpp File Reference
#include <functional>
#include <kiway.h>
#include <pcb_edit_frame.h>
#include <netlist_reader/pcb_netlist.h>
#include <netlist_reader/netlist_reader.h>
#include <reporter.h>
#include <lib_id.h>
#include <fp_lib_table.h>
#include <board.h>
#include <footprint.h>
#include <ratsnest/ratsnest_data.h>
#include <io_mgr.h>
#include "board_netlist_updater.h"
#include <tool/tool_manager.h>
#include <tools/pcb_actions.h>
#include <tools/selection_tool.h>
#include <project/project_file.h>

Go to the source code of this file.

Functions

void SpreadFootprints (std::vector< FOOTPRINT * > *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...
 

Function Documentation

◆ SpreadFootprints()

void SpreadFootprints ( std::vector< FOOTPRINT * > *  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 189 of file spread_footprints.cpp.

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

Referenced by PCB_EDIT_FRAME::OnNetlistChanged().