129 bool aGroupBySheet,
int aComponentGap,
int aGroupGap )
131 using FpBBoxToFootprintsPair = std::pair<BOX2I, std::vector<FOOTPRINT*>>;
132 using SheetBBoxToFootprintsMapPair =
133 std::pair<BOX2I, std::map<VECTOR2I, FpBBoxToFootprintsPair>>;
135 std::map<wxString, SheetBBoxToFootprintsMapPair> sheetsMap;
138 for(
FOOTPRINT* footprint : *aFootprints )
141 aGroupBySheet ? footprint->GetPath().AsString().BeforeLast(
'/' ) : wxString( wxS(
"" ) );
143 VECTOR2I size = footprint->GetBoundingBox(
false ).GetSize();
144 size.
x += aComponentGap;
145 size.
y += aComponentGap;
147 sheetsMap[
path].second[size].second.push_back( footprint );
150 for(
auto& [sheetPath, sheetPair] : sheetsMap )
152 auto& [sheet_bbox, sizeToFpMap] = sheetPair;
154 for(
auto& [fpSize, fpPair] : sizeToFpMap )
156 auto& [block_bbox, footprints] = fpPair;
160 double blockEstimateArea = (double) fpSize.x * fpSize.y * footprints.size();
161 double initialSide = std::sqrt( blockEstimateArea );
162 bool vertical = fpSize.x >= fpSize.y;
164 int initialCountPerLine = footprints.size();
166 const int singleLineRatio = 5;
171 if( ( fpSize.y * footprints.size() / fpSize.x ) > singleLineRatio )
172 initialCountPerLine = initialSide / fpSize.y;
176 if( ( fpSize.x * footprints.size() / fpSize.y ) > singleLineRatio )
177 initialCountPerLine = initialSide / fpSize.x;
180 int optimalCountPerLine = initialCountPerLine;
181 int optimalRemainder = footprints.size() % optimalCountPerLine;
183 if( optimalRemainder != 0 )
185 for(
int i = std::max( 2, initialCountPerLine - 2 );
186 i <= std::min( (
int) footprints.size() - 2, initialCountPerLine + 2 ); i++ )
188 int r = footprints.size() % i;
190 if( r == 0 || r >= optimalRemainder )
192 optimalCountPerLine = i;
193 optimalRemainder = r;
201 for(
unsigned i = 0; i < footprints.size(); i++ )
209 position.
x += fpSize.x * ( i / optimalCountPerLine );
210 position.
y += fpSize.y * ( i % optimalCountPerLine );
214 position.
x += fpSize.x * ( i % optimalCountPerLine );
215 position.
y += fpSize.y * ( i / optimalCountPerLine );
222 new_fp_bbox.
Inflate( aComponentGap / 2 );
223 block_bbox.
Merge( new_fp_bbox );
228 long long blocksArea = 0;
231 for(
auto& [fpSize, fpPair] : sizeToFpMap )
233 auto& [block_bbox, footprints] = fpPair;
235 vecSubRects.emplace_back( 0, 0, block_bbox.GetWidth() /
scale,
236 block_bbox.GetHeight() /
scale,
false );
238 blocksArea += block_bbox.GetArea();
242 int areaSide = std::sqrt( blocksArea );
245 unsigned block_i = 0;
248 for(
auto& [fpSize, pair] : sizeToFpMap )
250 auto& [src_bbox, footprints] = pair;
259 if( (uint64_t) target_pos.
x + (uint64_t) target_size.
x > INT_MAX / 2 )
260 target_pos.
x -= INT_MAX / 2;
262 if( (uint64_t) target_pos.
y + (uint64_t) target_size.
y > INT_MAX / 2 )
263 target_pos.
y -= INT_MAX / 2;
267 footprint->Move( target_pos - src_bbox.GetPosition() );
268 sheet_bbox.Merge( footprint->GetBoundingBox(
false ) );
276 long long sheetsArea = 0;
279 for(
auto& [sheetPath, sheetPair] : sheetsMap )
281 auto& [sheet_bbox, sizeToFpMap] = sheetPair;
282 BOX2I rect = sheet_bbox;
289 sheetsArea += sheet_bbox.GetArea();
293 int areaSide = std::sqrt( sheetsArea );
296 unsigned srect_i = 0;
299 for(
auto& [sheetPath, sheetPair] : sheetsMap )
301 auto& [src_bbox, sizeToFpMap] = sheetPair;
306 srect.y *
scale + aTargetBoxPosition.
y );
311 if( (int64_t) target_pos.
x + (int64_t) target_size.
x > INT_MAX / 2 )
312 target_pos.
x -= INT_MAX / 2;
314 if( (int64_t) target_pos.
y + (int64_t) target_size.
y > INT_MAX / 2 )
315 target_pos.
y -= INT_MAX / 2;
317 for(
auto& [fpSize, fpPair] : sizeToFpMap )
319 auto& [block_bbox, footprints] = fpPair;
322 footprint->Move( target_pos - src_bbox.GetPosition() );
wxString result
Test unit parsing edge cases and error handling.