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

References fillRectList(), FOOTPRINT::GetArea(), FOOTPRINT::GetBoundingBox(), 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().