45#include <rectpack2d/finders_interface.h>
50using spaces_type = rectpack2D::empty_spaces<allow_flip, rectpack2D::default_empty_spaces>;
51using rect_type = rectpack2D::output_rect_t<spaces_type>;
64 if( refPrefix != cmpPrefix )
66 return refPrefix < cmpPrefix;
73 return refInt < cmpInt;
87 std::optional<rectpack2D::rect_wh> result;
89 int max_side = std::max( areaSizeX, areaSizeY );
91 for(
int i = 0; i < 2000; i++ )
93 bool anyUnsuccessful =
false;
94 const int discard_step = 1;
96 auto report_successful = [&](
rect_type& )
98 return rectpack2D::callback_result::CONTINUE_PACKING;
101 auto report_unsuccessful = [&](
rect_type& r )
103 anyUnsuccessful =
true;
104 return rectpack2D::callback_result::ABORT_PACKING;
107 result = rectpack2D::find_best_packing<spaces_type>(
109 make_finder_input( max_side, discard_step, report_successful, report_unsuccessful,
110 rectpack2D::flipping_option::DISABLED ) );
112 if( !result || anyUnsuccessful )
114 max_side = (int) ( max_side * 1.2 );
126 bool aGroupBySheet,
int aComponentGap,
int aGroupGap )
128 using FpBBoxToFootprintsPair = std::pair<BOX2I, std::vector<FOOTPRINT*>>;
129 using SheetBBoxToFootprintsMapPair =
130 std::pair<BOX2I, std::map<VECTOR2I, FpBBoxToFootprintsPair>>;
132 std::map<wxString, SheetBBoxToFootprintsMapPair> sheetsMap;
135 for(
FOOTPRINT* footprint : *aFootprints )
138 aGroupBySheet ? footprint->GetPath().AsString().BeforeLast(
'/' ) : wxString( wxS(
"" ) );
140 VECTOR2I size = footprint->GetBoundingBox(
false ).GetSize();
141 size.
x += aComponentGap;
142 size.
y += aComponentGap;
144 sheetsMap[
path].second[size].second.push_back( footprint );
147 for(
auto& [sheetPath, sheetPair] : sheetsMap )
149 auto& [sheet_bbox, sizeToFpMap] = sheetPair;
151 for(
auto& [fpSize, fpPair] : sizeToFpMap )
153 auto& [block_bbox, footprints] = fpPair;
157 double blockEstimateArea = (double) fpSize.x * fpSize.y * footprints.size();
158 double initialSide = std::sqrt( blockEstimateArea );
159 bool vertical = fpSize.x >= fpSize.y;
161 int initialCountPerLine = footprints.size();
163 const int singleLineRatio = 5;
168 if( ( fpSize.y * footprints.size() / fpSize.x ) > singleLineRatio )
169 initialCountPerLine = initialSide / fpSize.y;
173 if( ( fpSize.x * footprints.size() / fpSize.y ) > singleLineRatio )
174 initialCountPerLine = initialSide / fpSize.x;
177 int optimalCountPerLine = initialCountPerLine;
178 int optimalRemainder = footprints.size() % optimalCountPerLine;
180 if( optimalRemainder != 0 )
182 for(
int i = std::max( 2, initialCountPerLine - 2 );
183 i <= std::min( (
int) footprints.size() - 2, initialCountPerLine + 2 ); i++ )
185 int r = footprints.size() % i;
187 if( r == 0 || r >= optimalRemainder )
189 optimalCountPerLine = i;
190 optimalRemainder = r;
198 for(
unsigned i = 0; i < footprints.size(); i++ )
206 position.
x += fpSize.x * ( i / optimalCountPerLine );
207 position.
y += fpSize.y * ( i % optimalCountPerLine );
211 position.
x += fpSize.x * ( i % optimalCountPerLine );
212 position.
y += fpSize.y * ( i / optimalCountPerLine );
219 new_fp_bbox.
Inflate( aComponentGap / 2 );
220 block_bbox.
Merge( new_fp_bbox );
225 long long blocksArea = 0;
228 for(
auto& [fpSize, fpPair] : sizeToFpMap )
230 auto& [block_bbox, footprints] = fpPair;
232 vecSubRects.emplace_back( 0, 0, block_bbox.GetWidth() /
scale,
233 block_bbox.GetHeight() /
scale, false );
235 blocksArea += block_bbox.
GetArea();
239 int areaSide = std::sqrt( blocksArea );
242 unsigned block_i = 0;
245 for(
auto& [fpSize, pair] : sizeToFpMap )
247 auto& [src_bbox, footprints] = pair;
256 if( (uint64_t) target_pos.
x + (uint64_t) target_size.
x > INT_MAX / 2 )
257 target_pos.
x -= INT_MAX / 2;
259 if( (uint64_t) target_pos.
y + (uint64_t) target_size.
y > INT_MAX / 2 )
260 target_pos.
y -= INT_MAX / 2;
264 footprint->Move( target_pos - src_bbox.GetPosition() );
265 sheet_bbox.Merge( footprint->GetBoundingBox(
false ) );
273 long long sheetsArea = 0;
276 for(
auto& [sheetPath, sheetPair] : sheetsMap )
278 auto& [sheet_bbox, sizeToFpMap] = sheetPair;
279 BOX2I rect = sheet_bbox;
286 sheetsArea += sheet_bbox.
GetArea();
290 int areaSide = std::sqrt( sheetsArea );
293 unsigned srect_i = 0;
296 for(
auto& [sheetPath, sheetPair] : sheetsMap )
298 auto& [src_bbox, sizeToFpMap] = sheetPair;
303 srect.y *
scale + aTargetBoxPosition.
y );
308 if( (uint64_t) target_pos.
x + (uint64_t) target_size.
x > INT_MAX / 2 )
309 target_pos.
x -= INT_MAX / 2;
311 if( (uint64_t) target_pos.
y + (uint64_t) target_size.
y > INT_MAX / 2 )
312 target_pos.
y -= INT_MAX / 2;
314 for(
auto& [fpSize, fpPair] : sizeToFpMap )
316 auto& [block_bbox, footprints] = fpPair;
319 footprint->Move( target_pos - src_bbox.GetPosition() );
constexpr EDA_IU_SCALE pcbIUScale
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
constexpr size_type GetWidth() const
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
constexpr ecoord_type GetArea() const
Return the area of the rectangle.
constexpr size_type GetHeight() const
constexpr const Vec & GetOrigin() const
This file is part of the common library.
wxString GetRefDesPrefix(const wxString &aRefDes)
Get the (non-numeric) prefix from a refdes - e.g.
Collection of utility functions for component reference designators (refdes)
int GetTrailingInt(const wxString &aStr)
Gets the trailing int, if any, from a string.