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( (int64_t) target_pos.
x + (int64_t) target_size.
x > INT_MAX / 2 )
309 target_pos.
x -= INT_MAX / 2;
311 if( (int64_t) target_pos.
y + (int64_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() );
wxString result
Test unit parsing edge cases and error handling.