/* Function to move components in a rectangular area format 4 / 3, * starting from the mouse cursor * The components with the FIXED status set are not moved */ void PCB_EDIT_FRAME::SpreadFootprints( bool aFootprintsOutsideBoardOnly ) { EDA_RECT bbox = GetBoard()->ComputeBoundingBox( true ); bool edgesExist = ( bbox.GetWidth() || bbox.GetHeight() ); // no edges exist if( aFootprintsOutsideBoardOnly && !edgesExist ) { DisplayError( this, _( "Could not automatically place footprints. No board outlines detected." ) ); return; } // if aFootprintsOutsideBoardOnly is true, and if board outline exists, // wue have to filter footprints to move: bool outsideBrdFilter = aFootprintsOutsideBoardOnly && edgesExist; // Build candidate list // calculate also the area needed by these footprints MODULE* module = GetBoard()->m_Modules; std::vector <MODULE*> moduleList; for( ; module != NULL; module = module->Next() ) { module->CalculateBoundingBox(); if( outsideBrdFilter ) { if( bbox.Contains( module->GetPosition() ) ) continue; } if( module->IsLocked() ) continue; moduleList.push_back(module); } if( moduleList.size() == 0 ) // Nothing to do return; // sort footprints by sheet path. we group them later by sheet sort( moduleList.begin(), moduleList.end(), sortModulesbySheetPath ); // Undo command: init undo list PICKED_ITEMS_LIST undoList; undoList.m_Status = UR_CHANGED; ITEM_PICKER picker( NULL, UR_CHANGED ); for( unsigned ii = 0; ii < moduleList.size(); ii++ ) { module = moduleList[ii]; // Undo: add copy of module to undo list picker.SetItem( module ); picker.SetLink( module->Clone() ); undoList.PushItem( picker ); } // Extract and place footprints by sheet std::vector <MODULE*> moduleListBySheet; std::vector <EDA_RECT> placementSheetAreas; double subsurface; double placementsurface = 0.0; wxPoint placementAreaPosition = GetCrossHairPosition(); // We do not want to move footprints inside an existing board. // move the placement area position outside the board bounding box // to the left of the board if( edgesExist ) { if( placementAreaPosition.x < bbox.GetEnd().x && placementAreaPosition.y < bbox.GetEnd().y ) { placementAreaPosition.x = bbox.GetEnd().x; placementAreaPosition.y = bbox.GetOrigin().y; } } // The placement uses 2 passes: // the first pass creates the rectangular areas to place footprints // each sheet in schematic creates one rectangular area. // the second pass moves footprints inside these areas for( int pass = 0; pass < 2; pass++ ) { int subareaIdx = 0; moduleListBySheet.clear(); subsurface = 0.0; for( unsigned ii = 0; ii < moduleList.size(); ii++ ) { module = moduleList[ii]; bool islastItem = false; if( ii == moduleList.size() - 1 || ( moduleList[ii]->GetPath().BeforeLast( '/' ) != moduleList[ii+1]->GetPath().BeforeLast( '/' ) ) ) islastItem = true; moduleListBySheet.push_back( module ); subsurface += module->GetArea(); if( islastItem ) { // end of the footprint sublist relative to the same sheet path // calculate placement of the current sublist EDA_RECT freeArea; int Xsize_allowed = (int) ( sqrt( subsurface ) * 4.0 / 3.0 ); int Ysize_allowed = (int) ( subsurface / Xsize_allowed ); freeArea.SetWidth( Xsize_allowed ); freeArea.SetHeight( Ysize_allowed ); CRectPlacement placementArea; if( pass == 1 ) { wxPoint areapos = placementSheetAreas[subareaIdx].GetOrigin() + placementAreaPosition; freeArea.SetOrigin( areapos ); } bool findAreaOnly = pass == 0; moveFootprintsInArea( placementArea, moduleListBySheet, freeArea, findAreaOnly ); if( pass == 0 ) { // Populate sheet placement areas list EDA_RECT sub_area; sub_area.SetWidth( placementArea.GetW()*scale ); sub_area.SetHeight( placementArea.GetH()*scale ); // Add a margin around the sheet placement area: sub_area.Inflate( Millimeter2iu( 1.5 ) ); placementSheetAreas.push_back( sub_area ); placementsurface += (double) sub_area.GetWidth()* sub_area.GetHeight(); } // Prepare buffers for next sheet subsurface = 0.0; moduleListBySheet.clear(); subareaIdx++; } } // End of pass: // At the end of the first pass, we have to find position of each sheet // placement area if( pass == 0 ) { int Xsize_allowed = (int) ( sqrt( placementsurface ) * 4.0 / 3.0 ); int Ysize_allowed = (int) ( placementsurface / Xsize_allowed ); CRectPlacement placementArea; CSubRectArray vecSubRects; fillRectList( vecSubRects, placementSheetAreas ); spreadRectangles( placementArea, vecSubRects, Xsize_allowed, Ysize_allowed ); for( unsigned it = 0; it < vecSubRects.size(); ++it ) { TSubRect& srect = vecSubRects[it]; wxPoint pos( srect.x*scale, srect.y*scale ); wxSize size( srect.w*scale, srect.h*scale ); placementSheetAreas[srect.n].SetOrigin( pos ); placementSheetAreas[srect.n].SetSize( size ); } } } // End pass // Undo: commit list SaveCopyInUndoList( undoList, UR_CHANGED ); OnModify(); m_canvas->Refresh(); }