125 bool aGroupBySheet,
int aComponentGap,
int aGroupGap )
127 using FpBBoxToFootprintsPair = std::pair<BOX2I, std::vector<FOOTPRINT*>>;
128 using SheetBBoxToFootprintsMapPair =
129 std::pair<BOX2I, std::map<VECTOR2I, FpBBoxToFootprintsPair>>;
131 std::map<wxString, SheetBBoxToFootprintsMapPair> sheetsMap;
134 for(
FOOTPRINT* footprint : *aFootprints )
137 aGroupBySheet ? footprint->GetPath().AsString().BeforeLast(
'/' ) : wxString( wxS(
"" ) );
139 VECTOR2I size = footprint->GetBoundingBox(
false ).GetSize();
140 size.
x += aComponentGap;
141 size.
y += aComponentGap;
143 sheetsMap[
path].second[size].second.push_back( footprint );
146 for(
auto& [sheetPath, sheetPair] : sheetsMap )
148 auto& [sheet_bbox, sizeToFpMap] = sheetPair;
150 for(
auto& [fpSize, fpPair] : sizeToFpMap )
152 auto& [block_bbox, footprints] = fpPair;
156 double blockEstimateArea = (double) fpSize.x * fpSize.y * footprints.size();
157 double initialSide = std::sqrt( blockEstimateArea );
158 bool vertical = fpSize.x >= fpSize.y;
160 int initialCountPerLine = footprints.size();
162 const int singleLineRatio = 5;
167 if( ( fpSize.y * footprints.size() / fpSize.x ) > singleLineRatio )
168 initialCountPerLine = initialSide / fpSize.y;
172 if( ( fpSize.x * footprints.size() / fpSize.y ) > singleLineRatio )
173 initialCountPerLine = initialSide / fpSize.x;
176 int optimalCountPerLine = initialCountPerLine;
177 int optimalRemainder = footprints.size() % optimalCountPerLine;
179 if( optimalRemainder != 0 )
181 for(
int i = std::max( 2, initialCountPerLine - 2 );
182 i <= std::min( (
int) footprints.size() - 2, initialCountPerLine + 2 ); i++ )
184 int r = footprints.size() % i;
186 if( r == 0 || r >= optimalRemainder )
188 optimalCountPerLine = i;
189 optimalRemainder = r;
197 for(
unsigned i = 0; i < footprints.size(); i++ )
205 position.
x += fpSize.x * ( i / optimalCountPerLine );
206 position.
y += fpSize.y * ( i % optimalCountPerLine );
210 position.
x += fpSize.x * ( i % optimalCountPerLine );
211 position.
y += fpSize.y * ( i / optimalCountPerLine );
218 new_fp_bbox.
Inflate( aComponentGap / 2 );
219 block_bbox.
Merge( new_fp_bbox );
224 long long blocksArea = 0;
227 for(
auto& [fpSize, fpPair] : sizeToFpMap )
229 auto& [block_bbox, footprints] = fpPair;
231 vecSubRects.emplace_back( 0, 0, block_bbox.GetWidth() /
scale,
232 block_bbox.GetHeight() /
scale,
false );
234 blocksArea += block_bbox.GetArea();
238 int areaSide = std::sqrt( blocksArea );
241 unsigned block_i = 0;
244 for(
auto& [fpSize, pair] : sizeToFpMap )
246 auto& [src_bbox, footprints] = pair;
255 if( (uint64_t) target_pos.
x + (uint64_t) target_size.
x > INT_MAX / 2 )
256 target_pos.
x -= INT_MAX / 2;
258 if( (uint64_t) target_pos.
y + (uint64_t) target_size.
y > INT_MAX / 2 )
259 target_pos.
y -= INT_MAX / 2;
263 footprint->Move( target_pos - src_bbox.GetPosition() );
264 sheet_bbox.Merge( footprint->GetBoundingBox(
false ) );
272 long long sheetsArea = 0;
275 for(
auto& [sheetPath, sheetPair] : sheetsMap )
277 auto& [sheet_bbox, sizeToFpMap] = sheetPair;
278 BOX2I rect = sheet_bbox;
285 sheetsArea += sheet_bbox.GetArea();
289 int areaSide = std::sqrt( sheetsArea );
292 unsigned srect_i = 0;
295 for(
auto& [sheetPath, sheetPair] : sheetsMap )
297 auto& [src_bbox, sizeToFpMap] = sheetPair;
302 srect.y *
scale + aTargetBoxPosition.
y );
307 if( (int64_t) target_pos.
x + (int64_t) target_size.
x > INT_MAX / 2 )
308 target_pos.
x -= INT_MAX / 2;
310 if( (int64_t) target_pos.
y + (int64_t) target_size.
y > INT_MAX / 2 )
311 target_pos.
y -= INT_MAX / 2;
313 for(
auto& [fpSize, fpPair] : sizeToFpMap )
315 auto& [block_bbox, footprints] = fpPair;
318 footprint->Move( target_pos - src_bbox.GetPosition() );
wxString result
Test unit parsing edge cases and error handling.