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 <board.h>
#include <footprint.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< FOOTPRINT * > &aFootprintList)
 
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< FOOTPRINT * > &aFootprintList, EDA_RECT &aFreeArea, bool aFindAreaOnly)
 
static bool sortFootprintsbySheetPath (FOOTPRINT *ref, FOOTPRINT *compare)
 
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...
 

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 useful 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< FOOTPRINT * > &  aFootprintList 
)

Definition at line 66 of file spread_footprints.cpp.

67 {
68  vecSubRects.clear();
69 
70  for( unsigned ii = 0; ii < aFootprintList.size(); ii++ )
71  {
72  EDA_RECT fpBox = aFootprintList[ii]->GetBoundingBox( false, false );
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:109
const int PADDING
int GetHeight() const
Definition: eda_rect.h:110
const int scale
Handle the component boundary box.
Definition: eda_rect.h:42

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:109
int GetHeight() const
Definition: eda_rect.h:110
const int scale
Handle the component boundary box.
Definition: eda_rect.h:42

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

◆ moveFootprintsInArea()

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

Definition at line 151 of file spread_footprints.cpp.

153 {
154  CSubRectArray vecSubRects;
155 
156  fillRectList( vecSubRects, aFootprintList );
157  spreadRectangles( aPlacementArea, vecSubRects, aFreeArea.GetWidth(), aFreeArea.GetHeight() );
158 
159  if( aFindAreaOnly )
160  return;
161 
162  for( unsigned it = 0; it < vecSubRects.size(); ++it )
163  {
164  wxPoint pos( vecSubRects[it].x, vecSubRects[it].y );
165  pos.x *= scale;
166  pos.y *= scale;
167 
168  FOOTPRINT* footprint = aFootprintList[vecSubRects[it].n];
169 
170  EDA_RECT fpBBox = footprint->GetBoundingBox( false, false );
171  wxPoint mod_pos = pos + ( footprint->GetPosition() - fpBBox.GetOrigin() )
172  + aFreeArea.GetOrigin();
173 
174  footprint->Move( mod_pos - footprint->GetPosition() );
175  }
176 }
void fillRectList(CSubRectArray &vecSubRects, std::vector< FOOTPRINT * > &aFootprintList)
int GetWidth() const
Definition: eda_rect.h:109
const wxPoint GetOrigin() const
Definition: eda_rect.h:101
void Move(const wxPoint &aMoveVector) override
Move this object.
Definition: footprint.cpp:1440
std::vector< TSubRect > CSubRectArray
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:718
Handle the component boundary box.
Definition: eda_rect.h:42
wxPoint GetPosition() const override
Definition: footprint.h:186
void spreadRectangles(CRectPlacement &aPlacementArea, CSubRectArray &vecSubRects, int areaSizeX, int areaSizeY)

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

Referenced by SpreadFootprints().

◆ sortFootprintsbySheetPath()

static bool sortFootprintsbySheetPath ( FOOTPRINT ref,
FOOTPRINT compare 
)
static

Definition at line 339 of file spread_footprints.cpp.

340 {
341  return ref->GetPath() < compare->GetPath();
342 }
const KIID_PATH & GetPath() const
Definition: footprint.h:203

References FOOTPRINT::GetPath().

Referenced by SpreadFootprints().

◆ 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:718
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().

◆ 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)
E_SERIE r
Definition: eserie.cpp:41
const int scale
bool AddAtEmptySpotAutoGrow(TRect *pRect, int maxW, int maxH)

References CRectPlacement::AddAtEmptySpotAutoGrow(), CRectPlacement::TRect::Greater(), CRectPlacement::Init(), r, and scale.

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::createPSFiles(), EDA_3D_CANVAS::DoRePaint(), COMMON_TOOLS::doZoomFit(), COMMON_TOOLS::doZoomToPreset(), KIGFX::CAIRO_GAL_BASE::DrawBitmap(), BITMAP_BASE::DrawBitmap(), KIGFX::OPENGL_GAL::DrawBitmap(), SCH_EDIT_FRAME::DrawCurrentSheetToClipboard(), PCB_EDIT_FRAME::Export_IDF3(), fillRectList(), SYMBOL_PREVIEW_WIDGET::fitOnDrawArea(), GENDRILL_WRITER_BASE::genDrillMapFile(), RENDER_3D_OPENGL::generate3dGrid(), DXF_IMPORT_PLUGIN::getCurrentUnitScale(), getEnvironmentScale(), getKiCadConfiguredScale(), DIALOG_PRINT_GENERIC::getScaleValue(), KIUI::GetStatusFont(), idf_export_footprint(), idf_export_outline(), WRL1STATUS::Init(), KiScaledBitmap(), RENDER_3D_RAYTRACE::load3DModels(), 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(), SCENEGRAPH::Prepare(), PCB_EDIT_FRAME::PrepareLayerIndicator(), RENDER_3D_OPENGL::renderFootprint(), KIGFX::VERTEX_MANAGER::Scale(), ZOOM_TOOL::selectRegion(), UNIT_BINDER::setPrecision(), DIALOG_PLOT_SCHEMATIC::setupPlotPagePDF(), GERBVIEW_INSPECTION_TOOL::ShowDCodes(), SpreadFootprints(), spreadRectangles(), SYMBOL_EDIT_FRAME::SVGPlotSymbol(), DIALOG_IMAGE_EDITOR::TransferToImage(), DIALOG_PAD_PRIMITIVES_TRANSFORM::Transform(), WRL1TRANSFORM::TranslateToSG(), PANEL_TRACK_WIDTH::TWCalculateCurrent(), PANEL_TRACK_WIDTH::TWCalculateWidth(), GERBVIEW_FRAME::updateDCodeSelectBox(), DIALOG_PAGES_SETTINGS::UpdateDrawingSheetExample(), PANEL_PCBNEW_COLOR_SETTINGS::zoomFitPreview(), PANEL_EESCHEMA_COLOR_SETTINGS::zoomFitPreview(), and PCB_SELECTION_TOOL::zoomFitSelection().