/* * Delete dangling tracks * Vias: * If a via is only connected to a dangling track, it also will be removed */ bool TRACKS_CLEANER::deleteUnconnectedTracks() { if( m_Brd->m_Track == NULL ) return false; bool modified = false; bool item_erased; do // Iterate when at least one track is deleted { item_erased = false; TRACK* next_track; for( TRACK *track = m_Brd->m_Track; track != NULL; track = next_track ) { next_track = track->Next(); bool flag_erase = false; // Start without a good reason to erase it /* if a track endpoint is not connected to a pad, test if * the endpoint is connected to another track or to a zone. * For via test, an enhancement could be to test if * connected to 2 items on different layers. Currently * a via must be connected to 2 items, that can be on the * same layer */ // Check if there is nothing attached on the start if( !(track->GetState( START_ON_PAD )) ) flag_erase |= testTrackEndpointDangling( track, ENDPOINT_START ); // Check if there is nothing attached on the end if( !(track->GetState( END_ON_PAD )) ) flag_erase |= testTrackEndpointDangling( track, ENDPOINT_END ); if( flag_erase ) { // remove segment from board m_Brd->GetRatsnest()->Remove( track ); track->ViewRelease(); track->DeleteStructure(); /* keep iterating, because a track connected to the deleted track * now perhaps is not connected and should be deleted */ item_erased = true; modified = true; } } } while( item_erased ); return modified; }
TRACK* GetTrack( TRACK* aStartTrace, const TRACK* aEndTrace, const wxPoint& aPosition, LAYER_MSK aLayerMask ) { for( TRACK *PtSegm = aStartTrace; PtSegm != NULL; PtSegm = PtSegm->Next() ) { if( PtSegm->GetState( IS_DELETED | BUSY ) == 0 ) { if( aPosition == PtSegm->GetStart() ) { if( aLayerMask & PtSegm->GetLayerMask() ) return PtSegm; } if( aPosition == PtSegm->GetEnd() ) { if( aLayerMask & PtSegm->GetLayerMask() ) return PtSegm; } } if( PtSegm == aEndTrace ) break; } return NULL; }
TRACK* GetTrack( TRACK* aStartTrace, const TRACK* aEndTrace, const wxPoint& aPosition, LSET aLayerMask ) { for( TRACK* seg = aStartTrace; seg; seg = seg->Next() ) { if( seg->GetState( IS_DELETED | BUSY ) == 0 ) { if( aPosition == seg->GetStart() ) { if( ( aLayerMask & seg->GetLayerSet() ).any() ) return seg; } if( aPosition == seg->GetEnd() ) { if( ( aLayerMask & seg->GetLayerSet() ).any() ) return seg; } } if( seg == aEndTrace ) break; } return NULL; }
TRACK * Locate_Pistes(TRACK * start_adresse, wxPoint ref, int Layer) { TRACK * Track; /* pointeur sur les pistes */ int l_piste ; /* demi-largeur de la piste */ for( Track = start_adresse; Track != NULL; Track = (TRACK*) Track->Pnext) { if( Track->GetState(BUSY|DELETED) ) continue; /* calcul des coordonnees du segment teste */ l_piste = Track->m_Width >> 1; /* l_piste = demi largeur piste */ ux0 = Track->m_Start.x ; uy0 = Track->m_Start.y ; /* coord de depart */ dx = Track->m_End.x ; dy = Track->m_End.y ; /* coord d'arrivee */ /* recalcul des coordonnees avec ux0, uy0 = origine des coordonnees */ dx -= ux0 ; dy -= uy0 ; spot_cX = ref.x - ux0 ; spot_cY = ref.y - uy0 ; if ( Track->m_StructType == TYPEVIA ) /* VIA rencontree */ { if ((abs(spot_cX) <= l_piste ) && (abs(spot_cY) <=l_piste)) { return(Track) ; } continue ; } if(Layer >= 0) if( Track->m_Layer != Layer ) continue; /* Segments sur couches differentes */ if( distance(l_piste) ) return(Track) ; } return(NULL) ; }
/* * This function try to remove an old track, when a new track is created, * and the old track is no more needed */ int PCB_EDIT_FRAME::EraseRedundantTrack( wxDC* aDC, TRACK* aNewTrack, int aNewTrackSegmentsCount, PICKED_ITEMS_LIST* aItemsListPicker ) { TRACK* StartTrack, * EndTrack; TRACK* pt_segm; TRACK* pt_del; int ii, jj, nb_segm, nbconnect; wxPoint start; wxPoint end; int startmasklayer, endmasklayer; int netcode = aNewTrack->GetNet(); /* Reconstruct the complete track (the new track has to start on a segment of track). */ ListSetState( aNewTrack, aNewTrackSegmentsCount, BUSY, OFF ); /* If the new track begins with a via, complete the track segment using * the following segment as a reference because a via is often a hub of * segments, and does not characterize track. */ if( aNewTrack->Type() == PCB_VIA_T && ( aNewTrackSegmentsCount > 1 ) ) aNewTrack = aNewTrack->Next(); aNewTrack = GetBoard()->MarkTrace( aNewTrack, &aNewTrackSegmentsCount, NULL, NULL, true ); wxASSERT( aNewTrack ); #if 0 && defined(DEBUG) TRACK* EndNewTrack; // The last segment of the list chained to the track EndNewTrack = aNewTrack; for( ii = 1; ii < aNewTrackSegmentsCount; ii++ ) { wxASSERT( EndNewTrack->GetState( -1 ) != 0 ); D( printf( "track %p is newly part of net %d\n", EndNewTrack, netcode ); ) EndNewTrack = EndNewTrack->Next(); }
bool PCB_EDIT_FRAME::RemoveMisConnectedTracks() { /* finds all track segments which are mis-connected (to more than one net). * When such a bad segment is found, it is flagged to be removed. * All tracks having at least one flagged segment are removed. */ TRACK* segment; TRACK* other; TRACK* next; int net_code_s, net_code_e; bool isModified = false; for( segment = GetBoard()->m_Track; segment; segment = (TRACK*) segment->Next() ) { segment->SetState( FLAG0, false ); // find the netcode for segment using anything connected to the "start" of "segment" net_code_s = -1; if( segment->start && segment->start->Type()==PCB_PAD_T ) { // get the netcode of the pad to propagate. net_code_s = ((D_PAD*)(segment->start))->GetNetCode(); } else { other = segment->GetTrace( GetBoard()->m_Track, NULL, FLG_START ); if( other ) net_code_s = other->GetNetCode(); } if( net_code_s < 0 ) continue; // the "start" of segment is not connected // find the netcode for segment using anything connected to the "end" of "segment" net_code_e = -1; if( segment->end && segment->end->Type()==PCB_PAD_T ) { net_code_e = ((D_PAD*)(segment->end))->GetNetCode(); } else { other = segment->GetTrace( GetBoard()->m_Track, NULL, FLG_END ); if( other ) net_code_e = other->GetNetCode(); } if( net_code_e < 0 ) continue; // the "end" of segment is not connected // Netcodes do not agree, so mark the segment as "to be removed" if( net_code_s != net_code_e ) { segment->SetState( FLAG0, true ); } } // Remove tracks having a flagged segment for( segment = GetBoard()->m_Track; segment; segment = next ) { next = (TRACK*) segment->Next(); if( segment->GetState( FLAG0 ) ) // Segment is flagged to be removed { segment->SetState( FLAG0, false ); isModified = true; GetBoard()->m_Status_Pcb = 0; Remove_One_Track( NULL, segment ); // the current segment is deleted, // we do not know the next "not yet tested" segment, // so restart to the beginning next = GetBoard()->m_Track; } } return isModified; }
/* * Delete dangling tracks * Vias: * If a via is only connected to a dangling track, it also will be removed */ bool TRACKS_CLEANER::deleteUnconnectedTracks() { if( m_Brd->m_Track == NULL ) return false; bool modified = false; bool item_erased = true; while( item_erased ) // Iterate when at least one track is deleted { item_erased = false; TRACK* next_track; for( TRACK * track = m_Brd->m_Track; track ; track = next_track ) { next_track = track->Next(); int flag_erase = 0; //Not connected indicator int type_end = 0; if( track->GetState( START_ON_PAD ) ) type_end |= START_ON_PAD; if( track->GetState( END_ON_PAD ) ) type_end |= END_ON_PAD; // if the track start point is not connected to a pad, // test if this track start point is connected to another track // For via test, an enhancement could be to test if connected // to 2 items on different layers. // Currently a via must be connected to 2 items, that can be on the same layer LAYER_NUM top_layer, bottom_layer; ZONE_CONTAINER* zone; if( (type_end & START_ON_PAD ) == 0 ) { TRACK* other = track->GetTrace( m_Brd->m_Track, NULL, FLG_START ); if( other == NULL ) // Test a connection to zones { if( track->Type() != PCB_VIA_T ) { zone = m_Brd->HitTestForAnyFilledArea( track->GetStart(), track->GetLayer(), track->GetLayer(), track->GetNetCode() ); } else { ((SEGVIA*)track)->LayerPair( &top_layer, &bottom_layer ); zone = m_Brd->HitTestForAnyFilledArea( track->GetStart(), top_layer, bottom_layer, track->GetNetCode() ); } } if( (other == NULL) && (zone == NULL) ) { flag_erase |= 1; } else // segment, via or zone connected to this end { track->start = other; // If a via is connected to this end, // test if this via has a second item connected. // If no, remove it with the current segment if( other && other->Type() == PCB_VIA_T ) { // search for another segment following the via track->SetState( BUSY, true ); SEGVIA* via = (SEGVIA*) other; other = via->GetTrace( m_Brd->m_Track, NULL, FLG_START ); if( other == NULL ) { via->LayerPair( &top_layer, &bottom_layer ); zone = m_Brd->HitTestForAnyFilledArea( via->GetStart(), bottom_layer, top_layer, via->GetNetCode() ); } if( (other == NULL) && (zone == NULL) ) flag_erase |= 2; track->SetState( BUSY, false ); } } } // if track end point is not connected to a pad, // test if this track end point is connected to an other track if( (type_end & END_ON_PAD ) == 0 ) { TRACK* other = track->GetTrace( m_Brd->m_Track, NULL, FLG_END ); if( other == NULL ) // Test a connection to zones { if( track->Type() != PCB_VIA_T ) { zone = m_Brd->HitTestForAnyFilledArea( track->GetEnd(), track->GetLayer(), track->GetLayer(), track->GetNetCode() ); } else { ((SEGVIA*)track)->LayerPair( &top_layer, &bottom_layer ); zone = m_Brd->HitTestForAnyFilledArea( track->GetEnd(), top_layer, bottom_layer, track->GetNetCode() ); } } if ( (other == NULL) && (zone == NULL) ) { flag_erase |= 0x10; } else // segment, via or zone connected to this end { track->end = other; // If a via is connected to this end, test if this via has a second item connected // if no, remove it with the current segment if( other && other->Type() == PCB_VIA_T ) { // search for another segment following the via track->SetState( BUSY, true ); SEGVIA* via = (SEGVIA*) other; other = via->GetTrace( m_Brd->m_Track, NULL, FLG_END ); if( other == NULL ) { via->LayerPair( &top_layer, &bottom_layer ); zone = m_Brd->HitTestForAnyFilledArea( via->GetEnd(), bottom_layer, top_layer, via->GetNetCode() ); } if( (other == NULL) && (zone == NULL) ) flag_erase |= 0x20; track->SetState( BUSY, false ); } } } if( flag_erase ) { // remove segment from board track->DeleteStructure(); // iterate, because a track connected to the deleted track // is now perhaps now not connected and should be deleted item_erased = true; modified = true; } } } return modified; }
TRACK* TRACK::GetTrack( TRACK* aStartTrace, TRACK* aEndTrace, ENDPOINT_T aEndPoint, bool aSameNetOnly, bool aSequential ) { const wxPoint &position = GetEndPoint( aEndPoint ); LAYER_MSK refLayers = GetLayerMask(); TRACK *previousSegment; TRACK *nextSegment; if( aSequential ) { // Simple sequential search: from aStartTrace forward to aEndTrace previousSegment = NULL; nextSegment = aStartTrace; } else { /* Local bidirectional search: from this backward to aStartTrace * AND forward to aEndTrace. The idea is that nearest segments * are found (on average) faster in this way. In fact same-net * segments are almost guaranteed to be found faster, in a global * search, since they are grouped together in the track list */ previousSegment = this; nextSegment = this; } while( nextSegment || previousSegment ) { // Terminate the search in the direction if the netcode mismatches if( aSameNetOnly ) { if( nextSegment && (nextSegment->GetNetCode() != GetNetCode()) ) nextSegment = NULL; if( previousSegment && (previousSegment->GetNetCode() != GetNetCode()) ) previousSegment = NULL; } if( nextSegment ) { if ( (nextSegment != this) && !nextSegment->GetState( BUSY | IS_DELETED ) && (refLayers & nextSegment->GetLayerMask()) ) { if( (position == nextSegment->m_Start) || (position == nextSegment->m_End) ) return nextSegment; } // Keep looking forward if( nextSegment == aEndTrace ) nextSegment = NULL; else nextSegment = nextSegment->Next(); } // Same as above, looking back. During sequential search this branch is inactive if( previousSegment ) { if ( (previousSegment != this) && !previousSegment->GetState( BUSY | IS_DELETED ) && (refLayers & previousSegment->GetLayerMask()) ) { if( (position == previousSegment->m_Start) || (position == previousSegment->m_End) ) return previousSegment; } if( previousSegment == aStartTrace ) previousSegment = NULL; else previousSegment = previousSegment->Back(); } } return NULL; }
void DIALOG_GLOBAL_DELETION::AcceptPcbDelete( ) { bool gen_rastnest = false; m_Parent->SetCurItem( NULL ); if( m_DelAlls->GetValue() ) { m_Parent->Clear_Pcb( true ); } else { if( !IsOK( this, _( "Are you sure you want to delete the selected items?" ) ) ) return; BOARD* pcb = m_Parent->GetBoard(); PICKED_ITEMS_LIST pickersList; ITEM_PICKER itemPicker( NULL, UR_DELETED ); BOARD_ITEM* item; BOARD_ITEM* nextitem; RN_DATA* ratsnest = pcb->GetRatsnest(); LSET layers_filter = LSET().set(); if( m_rbLayersOption->GetSelection() != 0 ) // Use current layer only layers_filter = LSET( ToLAYER_ID( m_currentLayer ) ); if( m_DelZones->GetValue() ) { int area_index = 0; item = pcb->GetArea( area_index ); while( item ) { if( layers_filter[item->GetLayer()] ) { itemPicker.SetItem( item ); pickersList.PushItem( itemPicker ); pcb->Remove( item ); item->ViewRelease(); ratsnest->Remove( item ); gen_rastnest = true; } else { area_index++; } item = pcb->GetArea( area_index ); } } if( m_DelDrawings->GetValue() || m_DelBoardEdges->GetValue() ) { LSET masque_layer; if( m_DelDrawings->GetValue() ) masque_layer = LSET::AllNonCuMask().set( Edge_Cuts, false ); if( m_DelBoardEdges->GetValue() ) masque_layer.set( Edge_Cuts ); masque_layer &= layers_filter; for( item = pcb->m_Drawings; item; item = nextitem ) { nextitem = item->Next(); if( item->Type() == PCB_LINE_T && masque_layer[item->GetLayer()] ) { itemPicker.SetItem( item ); pickersList.PushItem( itemPicker ); item->ViewRelease(); item->UnLink(); } } } if( m_DelTexts->GetValue() ) { LSET del_text_layers = layers_filter; for( item = pcb->m_Drawings; item; item = nextitem ) { nextitem = item->Next(); if( item->Type() == PCB_TEXT_T && del_text_layers[item->GetLayer()] ) { itemPicker.SetItem( item ); pickersList.PushItem( itemPicker ); item->ViewRelease(); item->UnLink(); } } } if( m_DelModules->GetValue() ) { for( item = pcb->m_Modules; item; item = nextitem ) { nextitem = item->Next(); if( layers_filter[item->GetLayer()] && ( ( m_ModuleFilterNormal->GetValue() && !item->IsLocked() ) || ( m_ModuleFilterLocked->GetValue() && item->IsLocked() ) ) ) { itemPicker.SetItem( item ); pickersList.PushItem( itemPicker ); static_cast<MODULE*>( item )->RunOnChildren( boost::bind( &KIGFX::VIEW_ITEM::ViewRelease, _1 ) ); ratsnest->Remove( item ); item->ViewRelease(); item->UnLink(); gen_rastnest = true; } } } if( m_DelTracks->GetValue() ) { STATUS_FLAGS track_mask_filter = 0; if( !m_TrackFilterLocked->GetValue() ) track_mask_filter |= TRACK_LOCKED; if( !m_TrackFilterAR->GetValue() ) track_mask_filter |= TRACK_AR; TRACK* nexttrack; for( TRACK *track = pcb->m_Track; track; track = nexttrack ) { nexttrack = track->Next(); if( ( track->GetState( TRACK_LOCKED | TRACK_AR ) & track_mask_filter ) != 0 ) continue; if( ( track->GetState( TRACK_LOCKED | TRACK_AR ) == 0 ) && !m_TrackFilterNormal->GetValue() ) continue; if( ( track->Type() == PCB_VIA_T ) && !m_TrackFilterVias->GetValue() ) continue; if( ( track->GetLayerSet() & layers_filter ) == 0 ) continue; itemPicker.SetItem( track ); pickersList.PushItem( itemPicker ); track->ViewRelease(); ratsnest->Remove( track ); track->UnLink(); gen_rastnest = true; } } if( pickersList.GetCount() ) m_Parent->SaveCopyInUndoList( pickersList, UR_DELETED ); if( m_DelMarkers->GetValue() ) pcb->DeleteMARKERs(); if( gen_rastnest ) m_Parent->Compile_Ratsnest( NULL, true ); if( m_Parent->IsGalCanvasActive() ) pcb->GetRatsnest()->Recalculate(); } m_Parent->GetCanvas()->Refresh(); m_Parent->OnModify(); EndModal( 1 ); }
static void calcule_connexite_1_net(TRACK* pt_start_conn,TRACK* pt_end_conn) /***************************************************************************/ /* calcule la connexite d'un net constitue de segments de piste consecutifs. Entree: pt_start_conn = adresse du 1er segment ( debut du net ) pt_end_conn = adr de fin (dernier segment) Les connexions relatives aux pads doivent etre deja calculees, car elles ne sont pas ici recalculees ( pour des raisons de temps de calcul, et du fait que lors des modif de pistes, les pads ne sont pas touches */ { TRACK * Track; /* Les pointeurs .start et .end sont mis a jour, si la connexion est du type segment a segment. la connexion sur pads est supposee etre deja calculee */ /* Raz des pointeurs sur pistes */ for( Track = pt_start_conn; Track != NULL; Track = (TRACK*) Track->Pnext) { Track->m_Sous_Netcode = 0; if( Track->GetState(BEGIN_ONPAD) == 0 ) Track->start = NULL; if( Track->GetState(END_ONPAD) == 0 ) Track->end = NULL; if (Track == pt_end_conn) break; } /* calcul des connexions */ for( Track = pt_start_conn; Track != NULL; Track = (TRACK*) Track->Pnext) { if(Track->m_StructType == TYPEVIA) { TRACK* pt_segm; int layermask = Track->ReturnMaskLayer(); for( pt_segm = pt_start_conn; pt_segm != NULL; pt_segm = (TRACK*) pt_segm->Pnext) { int curlayermask = pt_segm->ReturnMaskLayer(); if( (pt_segm->m_Start.x == Track->m_Start.x) && (pt_segm->m_Start.y == Track->m_Start.y) && ( layermask & curlayermask ) ) { pt_segm->start = Track; } if( (pt_segm->m_End.x == Track->m_Start.x) && (pt_segm->m_End.y == Track->m_Start.y) && (layermask & curlayermask) ) { pt_segm->end = Track; } if( pt_segm == pt_end_conn ) break; } } if( Track->start == NULL ) { Track->start = Locate_Piste_Connectee(Track, Track,pt_end_conn,START); } if( Track->end == NULL ) { Track->end = Locate_Piste_Connectee(Track, Track,pt_end_conn,END); } if (Track == pt_end_conn) break; } /* Generation des sous equipots du net */ propage_equipot(pt_start_conn,pt_end_conn); }