void PNS_ROUTER::updateView( PNS_NODE* aNode, PNS_ITEMSET& aCurrent ) { PNS_NODE::ITEM_VECTOR removed, added; PNS_NODE::OBSTACLES obstacles; if( !aNode ) return; if( Settings().Mode() == RM_MarkObstacles ) markViolations( aNode, aCurrent, removed ); aNode->GetUpdatedItems( removed, added ); for( PNS_ITEM* item : added ) { DisplayItem( item ); } for( PNS_ITEM* item : removed ) { BOARD_CONNECTED_ITEM* parent = item->Parent(); if( parent ) { if( parent->ViewIsVisible() ) m_hiddenItems.insert( parent ); parent->ViewSetVisible( false ); parent->ViewUpdate( KIGFX::VIEW_ITEM::APPEARANCE ); } } }
int SELECTION_TOOL::selectConnection( const TOOL_EVENT& aEvent ) { BOARD_CONNECTED_ITEM* item = m_selection.Item<BOARD_CONNECTED_ITEM>( 0 ); int segmentCount; if( item->Type() != PCB_TRACE_T && item->Type() != PCB_VIA_T ) return 0; clearSelection(); TRACK* trackList = getModel<BOARD>()->MarkTrace( static_cast<TRACK*>( item ), &segmentCount, NULL, NULL, true ); if( segmentCount == 0 ) return 0; for( int i = 0; i < segmentCount; ++i ) { select( trackList ); trackList = trackList->Next(); } // Inform other potentially interested tools TOOL_EVENT selectEvent( SelectedEvent ); m_toolMgr->ProcessEvent( selectEvent ); return 0; }
int PNS_PCBNEW_CLEARANCE_RESOLVER::localPadClearance( const PNS_ITEM* aItem ) const { BOARD_CONNECTED_ITEM *parent = aItem->Parent<BOARD_CONNECTED_ITEM>(); if( !parent || parent->Type() != PCB_PAD_T ) return 0; const D_PAD* pad = static_cast<D_PAD*>( parent ); return pad->GetLocalClearance(); }
void PNS_KICAD_IFACE::AddItem( PNS::ITEM* aItem ) { BOARD_CONNECTED_ITEM* newBI = NULL; switch( aItem->Kind() ) { case PNS::ITEM::SEGMENT_T: { PNS::SEGMENT* seg = static_cast<PNS::SEGMENT*>( aItem ); TRACK* track = new TRACK( m_board ); const SEG& s = seg->Seg(); track->SetStart( wxPoint( s.A.x, s.A.y ) ); track->SetEnd( wxPoint( s.B.x, s.B.y ) ); track->SetWidth( seg->Width() ); track->SetLayer( ToLAYER_ID( seg->Layers().Start() ) ); track->SetNetCode( seg->Net() > 0 ? seg->Net() : 0 ); newBI = track; break; } case PNS::ITEM::VIA_T: { VIA* via_board = new VIA( m_board ); PNS::VIA* via = static_cast<PNS::VIA*>( aItem ); via_board->SetPosition( wxPoint( via->Pos().x, via->Pos().y ) ); via_board->SetWidth( via->Diameter() ); via_board->SetDrill( via->Drill() ); via_board->SetNetCode( via->Net() > 0 ? via->Net() : 0 ); via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair() via_board->SetLayerPair( ToLAYER_ID( via->Layers().Start() ), ToLAYER_ID( via->Layers().End() ) ); newBI = via_board; break; } default: break; } if( newBI ) { aItem->SetParent( newBI ); newBI->ClearFlags(); m_commit->Add( newBI ); } }
int SELECTION_TOOL::selectNet( const TOOL_EVENT& aEvent ) { std::list<BOARD_CONNECTED_ITEM*> itemsList; RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest(); BOARD_CONNECTED_ITEM* item = m_selection.Item<BOARD_CONNECTED_ITEM>( 0 ); int netCode = item->GetNetCode(); clearSelection(); ratsnest->GetNetItems( netCode, itemsList, (RN_ITEM_TYPE)( RN_TRACKS | RN_VIAS ) ); BOOST_FOREACH( BOARD_CONNECTED_ITEM* i, itemsList ) select( i ); // Inform other potentially interested tools if( itemsList.size() > 0 ) { TOOL_EVENT selectEvent( SelectedEvent ); m_toolMgr->ProcessEvent( selectEvent ); } return 0; }
/* * This function starts a new track segment. * If a new track segment is in progress, ends this current new segment, * and created a new one. */ TRACK* PCB_EDIT_FRAME::Begin_Route( TRACK* aTrack, wxDC* aDC ) { TRACK* TrackOnStartPoint = NULL; int layerMask = GetLayerMask( GetScreen()->m_Active_Layer ); BOARD_CONNECTED_ITEM* LockPoint; wxPoint pos = GetScreen()->GetCrossHairPosition(); if( aTrack == NULL ) // Starting a new track segment { m_canvas->SetMouseCapture( ShowNewTrackWhenMovingCursor, Abort_Create_Track ); // Prepare the undo command info s_ItemsListPicker.ClearListAndDeleteItems(); // Should not be necessary, but... GetBoard()->PushHighLight(); // erase old highlight if( GetBoard()->IsHighLightNetON() ) HighLight( aDC ); g_CurrentTrackList.PushBack( new TRACK( GetBoard() ) ); g_CurrentTrackSegment->SetFlags( IS_NEW ); GetBoard()->SetHighLightNet( 0 ); // Search for a starting point of the new track, a track or pad LockPoint = GetBoard()->GetLockPoint( pos, layerMask ); D_PAD* pad = NULL; if( LockPoint ) // An item (pad or track) is found { if( LockPoint->Type() == PCB_PAD_T ) { pad = (D_PAD*) LockPoint; // A pad is found: put the starting point on pad center pos = pad->GetPosition(); GetBoard()->SetHighLightNet( pad->GetNet() ); } else // A track segment is found { TrackOnStartPoint = (TRACK*) LockPoint; GetBoard()->SetHighLightNet( TrackOnStartPoint->GetNet() ); GetBoard()->CreateLockPoint( pos, TrackOnStartPoint, &s_ItemsListPicker ); } } else { // Not a starting point, but a filled zone area can exist. This is also a // good starting point. ZONE_CONTAINER* zone; zone = GetBoard()->HitTestForAnyFilledArea( pos, GetScreen()-> m_Active_Layer ); if( zone ) GetBoard()->SetHighLightNet( zone->GetNet() ); } D( g_CurrentTrackList.VerifyListIntegrity() ); BuildAirWiresTargetsList( LockPoint, wxPoint( 0, 0 ), true ); D( g_CurrentTrackList.VerifyListIntegrity() ); GetBoard()->HighLightON(); GetBoard()->DrawHighLight( m_canvas, aDC, GetBoard()->GetHighLightNetCode() ); // Display info about track Net class, and init track and vias sizes: g_CurrentTrackSegment->SetNet( GetBoard()->GetHighLightNetCode() ); GetBoard()->SetCurrentNetClass( g_CurrentTrackSegment->GetNetClassName() ); g_CurrentTrackSegment->SetLayer( GetScreen()->m_Active_Layer ); g_CurrentTrackSegment->SetWidth( GetBoard()->GetCurrentTrackWidth() ); if( GetBoard()->GetDesignSettings().m_UseConnectedTrackWidth ) { if( TrackOnStartPoint && TrackOnStartPoint->Type() == PCB_TRACE_T ) g_CurrentTrackSegment->SetWidth( TrackOnStartPoint->GetWidth()); } g_CurrentTrackSegment->SetStart( pos ); g_CurrentTrackSegment->SetEnd( pos ); if( pad ) { g_CurrentTrackSegment->m_PadsConnected.push_back( pad ); // Useful to display track length, if the pad has a die length: g_CurrentTrackSegment->SetState( BEGIN_ONPAD, ON ); g_CurrentTrackSegment->start = pad; } if( g_TwoSegmentTrackBuild ) { // Create 2nd segment g_CurrentTrackList.PushBack( (TRACK*)g_CurrentTrackSegment->Clone() ); D( g_CurrentTrackList.VerifyListIntegrity(); ); g_CurrentTrackSegment->start = g_FirstTrackSegment; g_FirstTrackSegment->end = g_CurrentTrackSegment; g_FirstTrackSegment->SetState( BEGIN_ONPAD | END_ONPAD, OFF ); }
void PNS_ROUTER::CommitRouting( PNS_NODE* aNode ) { PNS_NODE::ITEM_VECTOR removed, added; aNode->GetUpdatedItems( removed, added ); for( unsigned int i = 0; i < removed.size(); i++ ) { BOARD_CONNECTED_ITEM* parent = removed[i]->Parent(); if( parent ) { m_view->Remove( parent ); m_board->Remove( parent ); m_undoBuffer.PushItem( ITEM_PICKER( parent, UR_DELETED ) ); } } for( PNS_ITEM* item : added ) { BOARD_CONNECTED_ITEM* newBI = NULL; switch( item->Kind() ) { case PNS_ITEM::SEGMENT: { PNS_SEGMENT* seg = static_cast<PNS_SEGMENT*>( item ); TRACK* track = new TRACK( m_board ); const SEG& s = seg->Seg(); track->SetStart( wxPoint( s.A.x, s.A.y ) ); track->SetEnd( wxPoint( s.B.x, s.B.y ) ); track->SetWidth( seg->Width() ); track->SetLayer( ToLAYER_ID( seg->Layers().Start() ) ); track->SetNetCode( seg->Net() > 0 ? seg->Net() : 0 ); newBI = track; break; } case PNS_ITEM::VIA: { VIA* via_board = new VIA( m_board ); PNS_VIA* via = static_cast<PNS_VIA*>( item ); via_board->SetPosition( wxPoint( via->Pos().x, via->Pos().y ) ); via_board->SetWidth( via->Diameter() ); via_board->SetDrill( via->Drill() ); via_board->SetNetCode( via->Net() > 0 ? via->Net() : 0 ); via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair() via_board->SetLayerPair( ToLAYER_ID( via->Layers().Start() ), ToLAYER_ID( via->Layers().End() ) ); newBI = via_board; break; } default: break; } if( newBI ) { item->SetParent( newBI ); newBI->ClearFlags(); m_view->Add( newBI ); m_board->Add( newBI ); m_undoBuffer.PushItem( ITEM_PICKER( newBI, UR_NEW ) ); newBI->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } } m_board->GetRatsnest()->Recalculate(); m_world->Commit( aNode ); }
/* Test a list of track segments, to create or propagate a sub netcode to pads and * segments connected together. * The track list must be sorted by nets, and all segments * from m_firstTrack to m_lastTrack have the same net * When 2 items are connected (a track to a pad, or a track to an other track), * they are grouped in a cluster. * The .m_Subnet member is the cluster identifier (subnet id) * For a given net, if all tracks are created, there is only one cluster. * but if not all tracks are created, there are more than one cluster, * and some ratsnests will be left active. * A ratsnest is active when it "connect" 2 items having different subnet id */ void CONNECTIONS::Propagate_SubNets() { int sub_netcode = 1; TRACK* curr_track = (TRACK*)m_firstTrack; if( curr_track ) curr_track->SetSubNet( sub_netcode ); // Examine connections between tracks and pads for( ; curr_track != NULL; curr_track = curr_track->Next() ) { // First: handling connections to pads for( unsigned ii = 0; ii < curr_track->m_PadsConnected.size(); ii++ ) { D_PAD * pad = curr_track->m_PadsConnected[ii]; if( curr_track->GetSubNet() ) // the track segment is already a cluster member { if( pad->GetSubNet() > 0 ) { // The pad is already a cluster member, so we can merge the 2 clusters Merge_SubNets( pad->GetSubNet(), curr_track->GetSubNet() ); } else { /* The pad is not yet attached to a cluster , so we can add this pad to * the cluster */ pad->SetSubNet( curr_track->GetSubNet() ); } } else // the track segment is not attached to a cluster { if( pad->GetSubNet() > 0 ) { // it is connected to a pad in a cluster, merge this track curr_track->SetSubNet( pad->GetSubNet() ); } else { /* it is connected to a pad not in a cluster, so we must create a new * cluster (only with the 2 items: the track and the pad) */ sub_netcode++; curr_track->SetSubNet( sub_netcode ); pad->SetSubNet( curr_track->GetSubNet() ); } } } // Test connections between segments for( unsigned ii = 0; ii < curr_track->m_TracksConnected.size(); ii++ ) { BOARD_CONNECTED_ITEM* track = curr_track->m_TracksConnected[ii]; if( curr_track->GetSubNet() ) // The current track is already a cluster member { // The other track is already a cluster member, so we can merge the 2 clusters if( track->GetSubNet() ) { Merge_SubNets( track->GetSubNet(), curr_track->GetSubNet() ); } else { // The other track is not yet attached to a cluster , so we can add this // other track to the cluster track->SetSubNet( curr_track->GetSubNet() ); } } else // the current track segment is not yet attached to a cluster { if( track->GetSubNet() ) { // The other track is already a cluster member, so we can add // the current segment to the cluster curr_track->SetSubNet( track->GetSubNet() ); } else { // it is connected to an other segment not in a cluster, so we must // create a new cluster (only with the 2 track segments) sub_netcode++; curr_track->SetSubNet( sub_netcode ); track->SetSubNet( curr_track->GetSubNet() ); } } } if( curr_track == m_lastTrack ) break; } // Examine connections between intersecting pads, and propagate // sub_netcodes to intersecting pads for( unsigned ii = 0; ii < m_sortedPads.size(); ii++ ) { D_PAD* curr_pad = m_sortedPads[ii]; for( unsigned jj = 0; jj < curr_pad->m_PadsConnected.size(); jj++ ) { D_PAD* pad = curr_pad->m_PadsConnected[jj]; if( curr_pad->GetSubNet() ) // the current pad is already attached to a cluster { if( pad->GetSubNet() > 0 ) { // The pad is already a cluster member, so we can merge the 2 clusters // Store the initial subnets, which will be modified by Merge_PadsSubNets int subnet1 = pad->GetSubNet(); int subnet2 = curr_pad->GetSubNet(); // merge subnets of pads only, even those not connected by tracks Merge_PadsSubNets( subnet1, subnet2 ); // merge subnets of tracks (and pads, which are already merged) Merge_SubNets( subnet1, subnet2 ); } else { // The pad is not yet attached to a cluster, // so we can add this pad to the cluster pad->SetSubNet( curr_pad->GetSubNet() ); } } else // the current pad is not attached to a cluster { if( pad->GetSubNet() > 0 ) { // the connected pad is in a cluster, // so we can add the current pad to the cluster curr_pad->SetSubNet( pad->GetSubNet() ); } else { // the connected pad is not in a cluster, // so we must create a new cluster, with the 2 pads. sub_netcode++; curr_pad->SetSubNet( sub_netcode ); pad->SetSubNet( curr_pad->GetSubNet() ); } } } } }
/** * Function Test_Connection_To_Copper_Areas * init .m_ZoneSubnet parameter in tracks and pads according to the connections to areas found * @param aNetcode = netcode to analyse. if -1, analyse all nets */ void BOARD::Test_Connections_To_Copper_Areas( int aNetcode ) { // list of pads and tracks candidates on this layer and on this net. // It is static to avoid multiple memory realloc. static std::vector <BOARD_CONNECTED_ITEM*> candidates; // clear .m_ZoneSubnet parameter for pads for( MODULE* module = m_Modules; module; module = module->Next() ) { for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() ) if( aNetcode < 0 || aNetcode == pad->GetNetCode() ) pad->SetZoneSubNet( 0 ); } // clear .m_ZoneSubnet parameter for tracks and vias for( TRACK* track = m_Track; track; track = track->Next() ) { if( aNetcode < 0 || aNetcode == track->GetNetCode() ) track->SetZoneSubNet( 0 ); } // examine all zones, net by net: int subnet = 0; // Build zones candidates list std::vector<ZONE_CONTAINER*> zones_candidates; zones_candidates.reserve( GetAreaCount() ); for( int index = 0; index < GetAreaCount(); index++ ) { ZONE_CONTAINER* zone = GetArea( index ); if( !zone->IsOnCopperLayer() ) continue; if( aNetcode >= 0 && aNetcode != zone->GetNetCode() ) continue; if( zone->GetFilledPolysList().GetCornersCount() == 0 ) continue; zones_candidates.push_back( zone ); } // sort them by netcode then vertices count. // For a given net, examine the smaller zones first slightly speed up calculation // (25% faster) // this is only noticeable with very large boards and depends on board zones topology // This is due to the fact some items are connected by small zones ares, // before examining large zones areas and these items are not tested after a connection is found sort( zones_candidates.begin(), zones_candidates.end(), sort_areas ); int oldnetcode = -1; for( unsigned idx = 0; idx < zones_candidates.size(); idx++ ) { ZONE_CONTAINER* zone = zones_candidates[idx]; int netcode = zone->GetNetCode(); // Build a list of candidates connected to the net: // At this point, layers are not considered, because areas on different layers can // be connected by a via or a pad. // (because zones are sorted by netcode, there is made only once per net) NETINFO_ITEM* net = FindNet( netcode ); wxASSERT( net ); if( net == NULL ) continue; if( oldnetcode != netcode ) { oldnetcode = netcode; candidates.clear(); // Build the list of pads candidates connected to the net: candidates.reserve( net->m_PadInNetList.size() ); for( unsigned ii = 0; ii < net->m_PadInNetList.size(); ii++ ) candidates.push_back( net->m_PadInNetList[ii] ); // Build the list of track candidates connected to the net: TRACK* track = m_Track.GetFirst()->GetStartNetCode( netcode ); for( ; track; track = track->Next() ) { if( track->GetNetCode() != netcode ) break; candidates.push_back( track ); } } // test if a candidate is inside a filled area of this zone unsigned indexstart = 0, indexend; const CPOLYGONS_LIST& polysList = zone->GetFilledPolysList(); for( indexend = 0; indexend < polysList.GetCornersCount(); indexend++ ) { // end of a filled sub-area found if( polysList.IsEndContour( indexend ) ) { subnet++; EDA_RECT bbox = zone->CalculateSubAreaBoundaryBox( indexstart, indexend ); for( unsigned ic = 0; ic < candidates.size(); ic++ ) { // test if this area is connected to a board item: BOARD_CONNECTED_ITEM* item = candidates[ic]; if( item->GetZoneSubNet() == subnet ) // Already merged continue; if( !item->IsOnLayer( zone->GetLayer() ) ) continue; wxPoint pos1, pos2; if( item->Type() == PCB_PAD_T ) { // For pads we use the shape position instead of // the pad position, because the zones are connected // to the center of the shape, not the pad position // (this is important for pads with thermal relief) pos1 = pos2 = ( (D_PAD*) item )->ShapePos(); } else if( item->Type() == PCB_VIA_T ) { const VIA *via = static_cast<const VIA*>( item ); pos1 = via->GetStart(); pos2 = pos1; } else if( item->Type() == PCB_TRACE_T ) { const TRACK *trk = static_cast<const TRACK*>( item ); pos1 = trk->GetStart(); pos2 = trk->GetEnd(); } else { continue; } bool connected = false; if( bbox.Contains( pos1 ) ) { if( TestPointInsidePolygon( polysList, indexstart, indexend, pos1.x, pos1.y ) ) connected = true; } if( !connected && (pos1 != pos2 ) ) { if( bbox.Contains( pos2 ) ) { if( TestPointInsidePolygon( polysList, indexstart, indexend, pos2.x, pos2.y ) ) connected = true; } } if( connected ) { // Set ZoneSubnet to the current subnet value. // If the previous subnet is not 0, merge all items with old subnet // to the new one int old_subnet = item->GetZoneSubNet(); item->SetZoneSubNet( subnet ); // Merge previous subnet with the current if( (old_subnet > 0) && (old_subnet != subnet) ) { for( unsigned jj = 0; jj < candidates.size(); jj++ ) { BOARD_CONNECTED_ITEM* item_to_merge = candidates[jj]; if( old_subnet == item_to_merge->GetZoneSubNet() ) { item_to_merge->SetZoneSubNet( subnet ); } } } // End if ( old_subnet > 0 ) } // End if( connected ) } // End test candidates for the current filled area indexstart = indexend + 1; // prepare test next area, starting at indexend+1 // (if exists). End read one area in // zone->m_FilledPolysList } } // End read all segments in zone } // End read all zones candidates }
/** * Function Merge_SubNets_Connected_By_CopperAreas(BOARD* aPcb, int aNetcode) * Used after connections by tracks calculations * Merge subnets, in tracks ans pads when they are connected by a filled copper area * for pads, this is the .m_physical_connexion member which is tested and modified * for tracks, this is the .m_Subnet member which is tested and modified * these members are block numbers (or cluster numbers) for a given net, * calculated by Build_Pads_Info_Connections_By_Tracks() * The result is merging 2 blocks (or subnets) * @param aPcb = the current board * @param aNetcode = netcode to consider */ void Merge_SubNets_Connected_By_CopperAreas( BOARD* aPcb, int aNetcode ) { // Ensure a zone with the given netcode exists: examine all zones: bool found = false; for( int index = 0; index < aPcb->GetAreaCount(); index++ ) { ZONE_CONTAINER* zone = aPcb->GetArea( index ); if( aNetcode == zone->GetNetCode() ) { found = true; break; } } if( !found ) // No zone with this netcode, therefore no connection by zone return; // list of pads and tracks candidates to test: // It is static to avoid multiple memory realloc. static std::vector <BOARD_CONNECTED_ITEM*> Candidates; Candidates.clear(); // Build the list of pads candidates connected to the net: NETINFO_ITEM* net = aPcb->FindNet( aNetcode ); wxASSERT( net ); Candidates.reserve( net->m_PadInNetList.size() ); for( unsigned ii = 0; ii < net->m_PadInNetList.size(); ii++ ) Candidates.push_back( net->m_PadInNetList[ii] ); // Build the list of track candidates connected to the net: TRACK* track; track = aPcb->m_Track.GetFirst()->GetStartNetCode( aNetcode ); for( ; track; track = track->Next() ) { if( track->GetNetCode() != aNetcode ) break; Candidates.push_back( track ); } if( Candidates.size() == 0 ) return; int next_subnet_free_number = 0; for( unsigned ii = 0; ii < Candidates.size(); ii++ ) { int subnet = Candidates[ii]->GetSubNet(); next_subnet_free_number = std::max( next_subnet_free_number, subnet ); } next_subnet_free_number++; // This is a subnet we can use with not connected items // by tracks, but connected by zone. // Sort by zone_subnet: sort( Candidates.begin(), Candidates.end(), CmpZoneSubnetValue ); // Some items can be not connected, but they can be connected to a filled area: // give them a subnet common to these items connected only by the area, // and not already used. // a value like next_subnet_free_number+zone_subnet is right for( unsigned jj = 0; jj < Candidates.size(); jj++ ) { BOARD_CONNECTED_ITEM* item = Candidates[jj]; if ( item->GetSubNet() == 0 && (item->GetZoneSubNet() > 0) ) { item->SetSubNet( next_subnet_free_number + item->GetZoneSubNet() ); } } // Now, for each zone subnet, we search for 2 items with different subnets. // if found, the 2 subnet are merged in the whole candidate list. int old_subnet = 0; int old_zone_subnet = 0; for( unsigned ii = 0; ii < Candidates.size(); ii++ ) { BOARD_CONNECTED_ITEM* item = Candidates[ii]; int zone_subnet = item->GetZoneSubNet(); if( zone_subnet == 0 ) // Not connected by a filled area, skip it continue; int subnet = item->GetSubNet(); if( zone_subnet != old_zone_subnet ) // a new zone subnet is found { old_subnet = subnet; old_zone_subnet = zone_subnet; continue; } zone_subnet = old_zone_subnet; // 2 successive items already from the same cluster: nothing to do if( subnet == old_subnet ) continue; // Here we have 2 items connected by the same area have 2 differents subnets: merge subnets if( (subnet > old_subnet) || ( subnet <= 0) ) EXCHG( subnet, old_subnet ); for( unsigned jj = 0; jj < Candidates.size(); jj++ ) { BOARD_CONNECTED_ITEM * item_to_merge = Candidates[jj]; if( item_to_merge->GetSubNet() == old_subnet ) item_to_merge->SetSubNet( subnet ); } old_subnet = subnet; } }