void DIALOG_DRC_CONTROL::doSelectionMenu( const DRC_ITEM* aItem ) { // popup menu to go to either of the items listed in the DRC_ITEM. BOARD_ITEM* first = aItem->GetMainItem( m_brdEditor->GetBoard() ); BOARD_ITEM* second = nullptr; GENERAL_COLLECTOR items; items.Append( first ); if( aItem->HasSecondItem() ) { second = aItem->GetAuxiliaryItem( m_brdEditor->GetBoard() ); items.Append( second ); } WINDOW_THAWER thawer( m_brdEditor ); m_brdEditor->GetToolManager()->VetoContextMenuMouseWarp(); m_brdEditor->GetToolManager()->RunAction( PCB_ACTIONS::selectionMenu, true, &items ); // If we got an item, focus on it BOARD_ITEM* selection = m_brdEditor->GetCurItem(); if( selection && ( selection == first || selection == second ) ) m_brdEditor->GetToolManager()->GetView()->SetCenter( selection->GetPosition() ); m_brdEditor->GetCanvas()->Refresh(); }
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 ); }
void DIALOG_CLEANUP_TRACKS_AND_VIAS::OnRightUpItem( wxMouseEvent& event ) { // popup menu to go to either of the items listed in the DRC_ITEM. int selection = m_ItemsListBox->GetSelection(); if( selection != wxNOT_FOUND ) { // popup menu to go to either of the items listed in the DRC_ITEM. const DRC_ITEM* item = m_ItemsListBox->GetItem( selection ); GENERAL_COLLECTOR items; items.Append( item->GetMainItem( m_parentFrame->GetBoard() ) ); if( item->HasSecondItem() ) items.Append( item->GetAuxiliaryItem( m_parentFrame->GetBoard() ) ); WINDOW_THAWER thawer( m_parentFrame ); m_parentFrame->GetToolManager()->RunAction( PCB_ACTIONS::selectionMenu, true, &items ); m_parentFrame->GetCanvas()->Refresh(); } }
// 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 ); }
// 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 ); } } }