void ROUTER_TOOL::NeighboringSegmentFilter( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector ) { /* * If the collection contains a trivial line corner (two connected segments) * or a non-fanout-via (a via with no more than two connected segments), then * trim the collection down to a single item (which one won't matter since * they're all connected). */ // First make sure we've got something that *might* match. int vias = aCollector.CountType( PCB_VIA_T ); int traces = aCollector.CountType( PCB_TRACE_T ); if( vias > 1 || traces > 2 || vias + traces < 1 ) return; // Fetch first TRACK (via or trace) as our reference TRACK* reference = nullptr; for( int i = 0; !reference && i < aCollector.GetCount(); i++ ) reference = dynamic_cast<TRACK*>( aCollector[i] ); int refNet = reference->GetNetCode(); wxPoint refPoint( aPt.x, aPt.y ); STATUS_FLAGS flags = reference->IsPointOnEnds( refPoint, -1 ); if( flags & STARTPOINT ) refPoint = reference->GetStart(); else if( flags & ENDPOINT ) refPoint = reference->GetEnd(); // Check all items to ensure that any TRACKs are co-terminus with the reference and on // the same net. for( int i = 0; i < aCollector.GetCount(); i++ ) { TRACK* neighbor = dynamic_cast<TRACK*>( aCollector[i] ); if( neighbor && neighbor != reference ) { if( neighbor->GetNetCode() != refNet ) return; if( neighbor->GetStart() != refPoint && neighbor->GetEnd() != refPoint ) return; } } // Selection meets criteria; trim it to the reference item. aCollector.Empty(); aCollector.Append( reference ); }
/** * Function highlightNet() * Looks for a BOARD_CONNECTED_ITEM in a given spot, and if one is found - it enables * highlight for its net. * @param aPoint is the point where an item is expected (world coordinates). */ static bool highlightNet( TOOL_MANAGER* aToolMgr, const VECTOR2D& aPosition ) { KIGFX::RENDER_SETTINGS* render = aToolMgr->GetView()->GetPainter()->GetSettings(); GENERAL_COLLECTORS_GUIDE guide = static_cast<PCB_BASE_FRAME*>( aToolMgr->GetEditFrame() )->GetCollectorsGuide(); BOARD* board = static_cast<BOARD*>( aToolMgr->GetModel() ); GENERAL_COLLECTOR collector; int net = -1; // Find a connected item for which we are going to highlight a net collector.Collect( board, GENERAL_COLLECTOR::PadsTracksOrZones, wxPoint( aPosition.x, aPosition.y ), guide ); bool enableHighlight = ( collector.GetCount() > 0 ); // Obtain net code for the clicked item if( enableHighlight ) net = static_cast<BOARD_CONNECTED_ITEM*>( collector[0] )->GetNetCode(); // Toggle highlight when the same net was picked if( net > 0 && net == render->GetHighlightNetCode() ) enableHighlight = !render->IsHighlightEnabled(); if( enableHighlight != render->IsHighlightEnabled() || net != render->GetHighlightNetCode() ) { render->SetHighlight( enableHighlight, net ); aToolMgr->GetView()->UpdateAllLayersColor(); } return true; }
static double calcMinArea( GENERAL_COLLECTOR& aCollector, KICAD_T aType ) { double best = std::numeric_limits<double>::max(); if( !aCollector.GetCount() ) return 0.0; for( int i = 0; i < aCollector.GetCount(); i++ ) { BOARD_ITEM* item = aCollector[i]; if( item->Type() == aType ) best = std::min( best, calcArea( item ) ); } return best; }
/** * Function highlightNet() * Looks for a BOARD_CONNECTED_ITEM in a given spot, and if one is found - it enables * highlight for its net. * @param aPoint is the point where an item is expected (world coordinates). */ static bool highlightNet( TOOL_MANAGER* aToolMgr, const VECTOR2D& aPosition ) { auto render = aToolMgr->GetView()->GetPainter()->GetSettings(); auto frame = static_cast<PCB_EDIT_FRAME*>( aToolMgr->GetEditFrame() ); auto guide = frame->GetCollectorsGuide(); BOARD* board = static_cast<BOARD*>( aToolMgr->GetModel() ); GENERAL_COLLECTOR collector; int net = -1; // Find a connected item for which we are going to highlight a net collector.Collect( board, GENERAL_COLLECTOR::PadsTracksOrZones, wxPoint( aPosition.x, aPosition.y ), guide ); for( int i = 0; i < collector.GetCount(); i++ ) { if( collector[i]->Type() == PCB_PAD_T ) { frame->SendMessageToEESCHEMA( static_cast<BOARD_CONNECTED_ITEM*>( collector[i] ) ); break; } } bool enableHighlight = ( collector.GetCount() > 0 ); // Obtain net code for the clicked item if( enableHighlight ) net = static_cast<BOARD_CONNECTED_ITEM*>( collector[0] )->GetNetCode(); // Toggle highlight when the same net was picked if( net > 0 && net == render->GetHighlightNetCode() ) enableHighlight = !render->IsHighlightEnabled(); if( enableHighlight != render->IsHighlightEnabled() || net != render->GetHighlightNetCode() ) { render->SetHighlight( enableHighlight, net ); aToolMgr->GetView()->UpdateAllLayersColor(); } // Store the highlighted netcode in the current board (for dialogs for instance) if( enableHighlight && net >= 0 ) board->SetHighLightNet( net ); else board->ResetHighLight(); return true; }
void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere ) { BOARD* pcb = getModel<BOARD>( PCB_T ); BOARD_ITEM* item; GENERAL_COLLECTORS_GUIDE guide = getEditFrame<PCB_EDIT_FRAME>()->GetCollectorsGuide(); GENERAL_COLLECTOR collector; collector.Collect( pcb, GENERAL_COLLECTOR::AllBoardItems, wxPoint( aWhere.x, aWhere.y ), guide ); switch( collector.GetCount() ) { case 0: if( !m_additive ) clearSelection(); break; case 1: toggleSelection( collector[0] ); break; default: // Remove unselectable items for( int i = collector.GetCount() - 1; i >= 0 ; --i ) { if( !selectable( collector[i] ) ) collector.Remove( i ); } // Let's see if there is still disambiguation in selection.. if( collector.GetCount() == 1 ) { toggleSelection( collector[0] ); } else if( collector.GetCount() > 1 ) { item = disambiguationMenu( &collector ); if( item ) toggleSelection( item ); } break; } }
static double calcMaxArea( GENERAL_COLLECTOR& aCollector, KICAD_T aType ) { double best = 0.0; for( int i = 0; i < aCollector.GetCount(); i++ ) { BOARD_ITEM* item = aCollector[i]; if( item->Type() == aType ) best = std::max( best, calcArea( item ) ); } return best; }
void SELECTION_TOOL::highlightNet( const VECTOR2I& aPoint ) { KIGFX::RENDER_SETTINGS* render = getView()->GetPainter()->GetSettings(); GENERAL_COLLECTORS_GUIDE guide = m_frame->GetCollectorsGuide(); GENERAL_COLLECTOR collector; int net = -1; // Find a connected item for which we are going to highlight a net collector.Collect( getModel<BOARD>(), GENERAL_COLLECTOR::PadsTracksOrZones, wxPoint( aPoint.x, aPoint.y ), guide ); bool enableHighlight = ( collector.GetCount() > 0 ); // Obtain net code for the clicked item if( enableHighlight ) net = static_cast<BOARD_CONNECTED_ITEM*>( collector[0] )->GetNetCode(); if( enableHighlight != render->GetHighlight() || net != render->GetHighlightNetCode() ) { render->SetHighlight( enableHighlight, net ); getView()->UpdateAllLayersColor(); } }
bool SELECTION_TOOL::selectCursor( const VECTOR2I& aWhere, bool aOnDrag ) { BOARD_ITEM* item; GENERAL_COLLECTORS_GUIDE guide = m_frame->GetCollectorsGuide(); GENERAL_COLLECTOR collector; if( m_editModules ) collector.Collect( getModel<BOARD>(), GENERAL_COLLECTOR::ModuleItems, wxPoint( aWhere.x, aWhere.y ), guide ); else collector.Collect( getModel<BOARD>(), GENERAL_COLLECTOR::AllBoardItems, wxPoint( aWhere.x, aWhere.y ), guide ); bool anyCollected = collector.GetCount() != 0; // Remove unselectable items for( int i = collector.GetCount() - 1; i >= 0; --i ) { if( !selectable( collector[i] ) || ( aOnDrag && collector[i]->IsLocked() ) ) collector.Remove( i ); } switch( collector.GetCount() ) { case 0: if( !m_additive && anyCollected ) clearSelection(); return false; case 1: toggleSelection( collector[0] ); return true; default: // Apply some ugly heuristics to avoid disambiguation menus whenever possible guessSelectionCandidates( collector ); // Let's see if there is still disambiguation in selection.. if( collector.GetCount() == 1 ) { toggleSelection( collector[0] ); return true; } else if( collector.GetCount() > 1 ) { if( aOnDrag ) Wait( TOOL_EVENT( TC_ANY, TA_MOUSE_UP, BUT_LEFT ) ); item = disambiguationMenu( &collector ); if( item ) { toggleSelection( item ); return true; } } break; } return false; }
// todo: explain the selection heuristics void SELECTION_TOOL::guessSelectionCandidates( GENERAL_COLLECTOR& aCollector ) const { std::set<BOARD_ITEM*> rejected; const double footprintAreaRatio = 0.2; const double modulePadMinCoverRatio = 0.45; const double padViaAreaRatio = 0.5; const double trackViaLengthRatio = 2.0; const double trackTrackLengthRatio = 0.3; const double textToFeatureMinRatio = 0.2; const double textToFootprintMinRatio = 0.4; LAYER_ID actLayer = m_frame->GetActiveLayer(); LSET silkLayers( 2, B_SilkS, F_SilkS ); if( silkLayers[actLayer] ) { std::set<BOARD_ITEM*> preferred; for( int i = 0; i < aCollector.GetCount(); ++i ) { BOARD_ITEM* item = aCollector[i]; if ( item->Type() == PCB_MODULE_TEXT_T || item->Type() == PCB_TEXT_T || item->Type() == PCB_LINE_T ) if ( silkLayers[item->GetLayer()] ) preferred.insert ( item ); } if( preferred.size() != 0 ) { aCollector.Empty(); BOOST_FOREACH( BOARD_ITEM* item, preferred ) aCollector.Append( item ); return; } } if( aCollector.CountType( PCB_MODULE_TEXT_T ) > 0 ) { for( int i = 0; i < aCollector.GetCount(); ++i ) if( TEXTE_MODULE* txt = dyn_cast<TEXTE_MODULE*>( aCollector[i] ) ) { double textArea = calcArea( txt ); for( int j = 0; j < aCollector.GetCount(); ++j ) { BOARD_ITEM* item = aCollector[j]; double areaRatio = calcRatio( textArea, calcArea( item ) ); if( item->Type() == PCB_MODULE_T && areaRatio < textToFootprintMinRatio ) { //printf("rejectModuleN\n"); rejected.insert( item ); } switch( item->Type() ) { case PCB_TRACE_T: case PCB_PAD_T: case PCB_LINE_T: case PCB_VIA_T: case PCB_MODULE_T: if( areaRatio > textToFeatureMinRatio ) { //printf("t after moduleRejected\n"); rejected.insert( txt ); } break; default: break; } } } } if( aCollector.CountType( PCB_MODULE_T ) > 0 ) { double minArea = calcMinArea( aCollector, PCB_MODULE_T ); double maxArea = calcMaxArea( aCollector, PCB_MODULE_T ); if( calcRatio( minArea, maxArea ) <= footprintAreaRatio ) { for( int i = 0; i < aCollector.GetCount(); ++i ) if( MODULE* mod = dyn_cast<MODULE*>( aCollector[i] ) ) { double normalizedArea = calcRatio( calcArea(mod), maxArea ); if( normalizedArea > footprintAreaRatio ) { //printf("rejectModule1\n"); rejected.insert( mod ); } } } } if( aCollector.CountType ( PCB_PAD_T ) > 0 ) { for( int i = 0; i < aCollector.GetCount(); ++i ) { if ( D_PAD* pad = dyn_cast<D_PAD*>( aCollector[i] ) ) { double ratio = pad->GetParent()->PadCoverageRatio(); if( ratio < modulePadMinCoverRatio ) rejected.insert( pad->GetParent() ); } } } if( aCollector.CountType( PCB_VIA_T ) > 0 ) { for( int i = 0; i < aCollector.GetCount(); ++i ) { if( VIA* via = dyn_cast<VIA*>( aCollector[i] ) ) { double viaArea = calcArea( via ); for( int j = 0; j < aCollector.GetCount(); ++j ) { BOARD_ITEM* item = aCollector[j]; double areaRatio = calcRatio ( viaArea, calcArea( item ) ); if( item->Type() == PCB_MODULE_T && areaRatio < modulePadMinCoverRatio ) rejected.insert( item ); if( item->Type() == PCB_PAD_T && areaRatio < padViaAreaRatio ) rejected.insert( item ); if( TRACK* track = dyn_cast<TRACK*>( item ) ) { if( track->GetNetCode() != via->GetNetCode() ) continue; double lenRatio = (double) ( track->GetLength() + track->GetWidth() ) / (double) via->GetWidth(); if( lenRatio > trackViaLengthRatio ) rejected.insert( track ); } } } } } int nTracks = aCollector.CountType ( PCB_TRACE_T ); if( nTracks > 0 ) { double maxLength = 0.0; double minLength = std::numeric_limits<double>::max(); double maxArea = 0.0; for( int i = 0; i < aCollector.GetCount(); ++i ) if ( TRACK *track = dyn_cast<TRACK*> ( aCollector[i] ) ) { maxLength = std::max( track->GetLength(), maxLength ); maxLength = std::max( (double)track->GetWidth(), maxLength ); minLength = std::min( std::max ( track->GetLength(), (double)track->GetWidth() ), minLength ); double area = ( track->GetLength() + track->GetWidth() * track->GetWidth() ); maxArea = std::max(area, maxArea); } if( maxLength > 0.0 && minLength/maxLength < trackTrackLengthRatio && nTracks > 1 ) { for( int i = 0; i < aCollector.GetCount(); ++i ) { if( TRACK* track = dyn_cast<TRACK*>( aCollector[i] ) ) { double ratio = std::max( (double) track->GetWidth(), track->GetLength()) / maxLength; if( ratio > trackTrackLengthRatio ) rejected.insert( track) ; } } } for( int j = 0; j < aCollector.GetCount(); ++j ) { if( MODULE* mod = dyn_cast<MODULE*>( aCollector[j] ) ) { double ratio = maxArea / mod->GetFootprintRect().GetArea(); if( ratio < modulePadMinCoverRatio ) { //printf("rejectModule\n"); rejected.insert( mod ); } } } } BOOST_FOREACH( BOARD_ITEM* item, rejected ) { aCollector.Remove( item ); }
int MODULE_TOOLS::EnumeratePads( const TOOL_EVENT& aEvent ) { std::list<D_PAD*> pads; std::set<D_PAD*> allPads; if( !m_board->m_Modules || !m_board->m_Modules->Pads() ) return 0; GENERAL_COLLECTOR collector; const KICAD_T types[] = { PCB_PAD_T, EOT }; GENERAL_COLLECTORS_GUIDE guide = m_frame->GetCollectorsGuide(); guide.SetIgnoreMTextsMarkedNoShow( true ); guide.SetIgnoreMTextsOnBack( true ); guide.SetIgnoreMTextsOnFront( true ); guide.SetIgnoreModulesVals( true ); guide.SetIgnoreModulesRefs( true ); // Create a set containing all pads (to avoid double adding to the list) for( D_PAD* p = m_board->m_Modules->Pads(); p; p = p->Next() ) allPads.insert( p ); DIALOG_ENUM_PADS settingsDlg( m_frame ); if( settingsDlg.ShowModal() == wxID_CANCEL ) return 0; int padNumber = settingsDlg.GetStartNumber(); wxString padPrefix = settingsDlg.GetPrefix(); m_frame->DisplayToolMsg( _( "Hold left mouse button and move cursor over pads to enumerate them" ) ); Activate(); m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); m_controls->ShowCursor( true ); VECTOR2I oldCursorPos = m_controls->GetCursorPosition(); std::list<D_PAD*> selectedPads; while( OPT_TOOL_EVENT evt = Wait() ) { if( evt->IsDrag( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) { selectedPads.clear(); VECTOR2I cursorPos = m_controls->GetCursorPosition(); if( evt->IsClick( BUT_LEFT ) ) { oldCursorPos = m_controls->GetCursorPosition(); collector.Empty(); collector.Collect( m_board, types, wxPoint( cursorPos.x, cursorPos.y ), guide ); for( int i = 0; i < collector.GetCount(); ++i ) { if( collector[i]->Type() == PCB_PAD_T ) selectedPads.push_back( static_cast<D_PAD*>( collector[i] ) ); } } else //evt->IsDrag( BUT_LEFT ) { // wxWidgets deliver mouse move events not frequently enough, resulting in skipping // pads if the user moves cursor too fast. To solve it, create a line that approximates // the mouse move and select items intersecting with the line. int distance = ( cursorPos - oldCursorPos ).EuclideanNorm(); int segments = distance / 100000 + 1; const wxPoint LINE_STEP( ( cursorPos - oldCursorPos ).x / segments, ( cursorPos - oldCursorPos ).y / segments ); collector.Empty(); for( int j = 0; j < segments; ++j ) { collector.Collect( m_board, types, wxPoint( oldCursorPos.x, oldCursorPos.y ) + j * LINE_STEP, guide ); for( int i = 0; i < collector.GetCount(); ++i ) { if( collector[i]->Type() == PCB_PAD_T ) selectedPads.push_back( static_cast<D_PAD*>( collector[i] ) ); } } selectedPads.unique(); } for( D_PAD* pad : selectedPads ) { std::set<D_PAD*>::iterator it = allPads.find( pad ); // Add the pad to the list, if it was not selected previously.. if( it != allPads.end() ) { allPads.erase( it ); pads.push_back( pad ); pad->SetSelected(); } // ..or remove it from the list if it was clicked else if( evt->IsClick( BUT_LEFT ) ) { allPads.insert( pad ); pads.remove( pad ); pad->ClearSelected(); } } oldCursorPos = cursorPos; } else if( ( evt->IsKeyPressed() && evt->KeyCode() == WXK_RETURN ) || evt->IsDblClick( BUT_LEFT ) ) { // Accept changes BOARD_COMMIT commit( m_frame ); m_frame->OnModify(); for( D_PAD* pad : pads ) { commit.Modify( pad ); pad->SetPadName( wxString::Format( wxT( "%s%d" ), padPrefix.c_str(), padNumber++ ) ); } commit.Push( _( "Enumerate pads" ) ); break; } else if( evt->IsCancel() || evt->IsActivate() ) { break; } } for( D_PAD* pad : pads ) pad->ClearSelected(); m_frame->DisplayToolMsg( wxEmptyString ); m_controls->ShowCursor( false ); return 0; }
bool SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere, bool aAllowDisambiguation ) { BOARD_ITEM* item; GENERAL_COLLECTORS_GUIDE guide = m_frame->GetCollectorsGuide(); GENERAL_COLLECTOR collector; // Preferred types (they have the priority when if they are covered by a bigger item) const KICAD_T types[] = { PCB_TRACE_T, PCB_VIA_T, PCB_LINE_T, PCB_MODULE_TEXT_T, EOT }; if( m_editModules ) collector.Collect( getModel<BOARD>(), GENERAL_COLLECTOR::ModuleItems, wxPoint( aWhere.x, aWhere.y ), guide ); else collector.Collect( getModel<BOARD>(), GENERAL_COLLECTOR::AllBoardItems, wxPoint( aWhere.x, aWhere.y ), guide ); switch( collector.GetCount() ) { case 0: if( !m_additive ) clearSelection(); return false; case 1: toggleSelection( collector[0] ); return true; default: // Remove unselectable items for( int i = collector.GetCount() - 1; i >= 0; --i ) { if( !selectable( collector[i] ) ) collector.Remove( i ); } // Check if among the selection candidates there is only one instance of preferred type item = prefer( collector, types ); if( item ) { toggleSelection( item ); return true; } // Let's see if there is still disambiguation in selection.. if( collector.GetCount() == 1 ) { toggleSelection( collector[0] ); return true; } else if( aAllowDisambiguation && collector.GetCount() > 1 ) { item = disambiguationMenu( &collector ); if( item ) { toggleSelection( item ); return true; } } break; } return false; }
// todo: explain the selection heuristics void SELECTION_TOOL::guessSelectionCandidates( GENERAL_COLLECTOR& aCollector ) const { std::set<BOARD_ITEM*> rejected; const double footprintAreaRatio = 0.2; const double modulePadMinCoverRatio = 0.45; const double padViaAreaRatio = 0.5; const double trackViaLengthRatio = 2.0; const double trackTrackLengthRatio = 0.3; const double textToFeatureMinRatio = 0.2; const double textToFootprintMinRatio = 0.4; // If the common area of two compared items is above the following threshold, they cannot // be rejected (it means they overlap and it might be hard to pick one by selecting // its unique area). const double commonAreaRatio = 0.6; LAYER_ID actLayer = m_frame->GetActiveLayer(); LSET silkLayers( 2, B_SilkS, F_SilkS ); if( silkLayers[actLayer] ) { std::set<BOARD_ITEM*> preferred; for( int i = 0; i < aCollector.GetCount(); ++i ) { BOARD_ITEM* item = aCollector[i]; KICAD_T type = item->Type(); if( ( type == PCB_MODULE_TEXT_T || type == PCB_TEXT_T || type == PCB_LINE_T ) && silkLayers[item->GetLayer()] ) { preferred.insert( item ); } } if( preferred.size() != 0 ) { aCollector.Empty(); for( BOARD_ITEM* item : preferred ) aCollector.Append( item ); return; } } if( aCollector.CountType( PCB_MODULE_TEXT_T ) > 0 ) { for( int i = 0; i < aCollector.GetCount(); ++i ) { if( TEXTE_MODULE* txt = dyn_cast<TEXTE_MODULE*>( aCollector[i] ) ) { double textArea = calcArea( txt ); for( int j = 0; j < aCollector.GetCount(); ++j ) { if( i == j ) continue; BOARD_ITEM* item = aCollector[j]; double itemArea = calcArea( item ); double areaRatio = calcRatio( textArea, itemArea ); double commonArea = calcCommonArea( txt, item ); double itemCommonRatio = calcRatio( commonArea, itemArea ); double txtCommonRatio = calcRatio( commonArea, textArea ); if( item->Type() == PCB_MODULE_T && areaRatio < textToFootprintMinRatio && itemCommonRatio < commonAreaRatio ) rejected.insert( item ); switch( item->Type() ) { case PCB_TRACE_T: case PCB_PAD_T: case PCB_LINE_T: case PCB_VIA_T: case PCB_MODULE_T: if( areaRatio > textToFeatureMinRatio && txtCommonRatio < commonAreaRatio ) rejected.insert( txt ); break; default: break; } } } } } if( aCollector.CountType( PCB_MODULE_T ) > 0 ) { double minArea = calcMinArea( aCollector, PCB_MODULE_T ); double maxArea = calcMaxArea( aCollector, PCB_MODULE_T ); if( calcRatio( minArea, maxArea ) <= footprintAreaRatio ) { for( int i = 0; i < aCollector.GetCount(); ++i ) { if( MODULE* mod = dyn_cast<MODULE*>( aCollector[i] ) ) { double normalizedArea = calcRatio( calcArea( mod ), maxArea ); if( normalizedArea > footprintAreaRatio ) rejected.insert( mod ); } } } } if( aCollector.CountType( PCB_PAD_T ) > 0 ) { for( int i = 0; i < aCollector.GetCount(); ++i ) { if( D_PAD* pad = dyn_cast<D_PAD*>( aCollector[i] ) ) { double ratio = pad->GetParent()->PadCoverageRatio(); if( ratio < modulePadMinCoverRatio ) rejected.insert( pad->GetParent() ); } } } if( aCollector.CountType( PCB_VIA_T ) > 0 ) { for( int i = 0; i < aCollector.GetCount(); ++i ) { if( VIA* via = dyn_cast<VIA*>( aCollector[i] ) ) { double viaArea = calcArea( via ); for( int j = 0; j < aCollector.GetCount(); ++j ) { if( i == j ) continue; BOARD_ITEM* item = aCollector[j]; double areaRatio = calcRatio( viaArea, calcArea( item ) ); if( item->Type() == PCB_MODULE_T && areaRatio < modulePadMinCoverRatio ) rejected.insert( item ); if( item->Type() == PCB_PAD_T && areaRatio < padViaAreaRatio ) rejected.insert( item ); if( TRACK* track = dyn_cast<TRACK*>( item ) ) { if( track->GetNetCode() != via->GetNetCode() ) continue; double lenRatio = (double) ( track->GetLength() + track->GetWidth() ) / (double) via->GetWidth(); if( lenRatio > trackViaLengthRatio ) rejected.insert( track ); } } } } } int nTracks = aCollector.CountType( PCB_TRACE_T ); if( nTracks > 0 ) { double maxLength = 0.0; double minLength = std::numeric_limits<double>::max(); double maxArea = 0.0; const TRACK* maxTrack = nullptr; for( int i = 0; i < aCollector.GetCount(); ++i ) { if( TRACK* track = dyn_cast<TRACK*> ( aCollector[i] ) ) { maxLength = std::max( track->GetLength(), maxLength ); maxLength = std::max( (double) track->GetWidth(), maxLength ); minLength = std::min( std::max( track->GetLength(), (double) track->GetWidth() ), minLength ); double area = track->GetLength() * track->GetWidth(); if( area > maxArea ) { maxArea = area; maxTrack = track; } } } if( maxLength > 0.0 && minLength / maxLength < trackTrackLengthRatio && nTracks > 1 ) { for( int i = 0; i < aCollector.GetCount(); ++i ) { if( TRACK* track = dyn_cast<TRACK*>( aCollector[i] ) ) { double ratio = std::max( (double) track->GetWidth(), track->GetLength() ) / maxLength; if( ratio > trackTrackLengthRatio ) rejected.insert( track ); } } } for( int j = 0; j < aCollector.GetCount(); ++j ) { if( MODULE* mod = dyn_cast<MODULE*>( aCollector[j] ) ) { double ratio = calcRatio( maxArea, mod->GetFootprintRect().GetArea() ); if( ratio < modulePadMinCoverRatio && calcCommonArea( maxTrack, mod ) < commonAreaRatio ) rejected.insert( mod ); } } } if( (unsigned) aCollector.GetCount() > rejected.size() ) // do not remove everything { for( BOARD_ITEM* item : rejected ) { aCollector.Remove( item ); } } }