/* 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 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; } }