bool TRACKS_CLEANER::remove_duplicates_of_track( const TRACK *aTrack ) { bool modified = false; TRACK *nextsegment; for( TRACK *other = aTrack->Next(); other; other = nextsegment ) { nextsegment = other->Next(); // New netcode, break out (can't be there any other) if( aTrack->GetNetCode() != other->GetNetCode() ) break; // Must be of the same type, on the same layer and the endpoints // must be the same (maybe swapped) if( (aTrack->Type() != other->Type()) && (aTrack->GetLayer() != other->GetLayer()) ) { if( ((aTrack->GetStart() == other->GetStart()) && (aTrack->GetEnd() == other->GetEnd())) || ((aTrack->GetStart() == other->GetEnd()) && (aTrack->GetEnd() == other->GetStart()))) { m_Brd->GetRatsnest()->Remove( other ); other->ViewRelease(); other->DeleteStructure(); modified = true; } } } return modified; }
bool TRACKS_CLEANER::merge_collinear_of_track( TRACK *aSegment ) { bool merged_this = false; // *WHY* doesn't C++ have prec and succ (or ++ --) like PASCAL? for( ENDPOINT_T endpoint = ENDPOINT_START; endpoint <= ENDPOINT_END; endpoint = ENDPOINT_T( endpoint + 1 ) ) { // search for a possible segment connected to the current endpoint of the current one TRACK *other = aSegment->Next(); if( other ) { other = aSegment->GetTrack( other, NULL, endpoint, true, false ); if( other ) { // the two segments must have the same width and the other // cannot be a via if( (aSegment->GetWidth() == other->GetWidth()) && (other->Type() == PCB_TRACE_T) ) { // There can be only one segment connected other->SetState( BUSY, true ); TRACK *yet_another = aSegment->GetTrack( m_Brd->m_Track, NULL, endpoint, true, false ); other->SetState( BUSY, false ); if( !yet_another ) { // Try to merge them TRACK *segDelete = mergeCollinearSegmentIfPossible( aSegment, other, endpoint ); // Merge succesful, the other one has to go away if( segDelete ) { m_Brd->GetRatsnest()->Remove( segDelete ); segDelete->ViewRelease(); segDelete->DeleteStructure(); merged_this = true; } } } } } } return merged_this; }
/* * 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; }
// Delete null length track segments bool TRACKS_CLEANER::delete_null_segments() { TRACK *nextsegment; bool modified = false; // Delete null segments for( TRACK *segment = m_Brd->m_Track; segment; segment = nextsegment ) { nextsegment = segment->Next(); if( segment->IsNull() ) // Length segment = 0; delete it { m_Brd->GetRatsnest()->Remove( segment ); segment->ViewRelease(); segment->DeleteStructure(); modified = true; } } return modified; }
// Delete null length segments, and intermediate points .. bool TRACKS_CLEANER::clean_segments() { bool modified = false; TRACK* segment, * nextsegment; TRACK* other; int flag, no_inc; // Delete null segments for( segment = m_Brd->m_Track; segment; segment = nextsegment ) { nextsegment = segment->Next(); if( segment->IsNull() ) // Length segment = 0; delete it segment->DeleteStructure(); } // Delete redundant segments, i.e. segments having the same end points // and layers for( segment = m_Brd->m_Track; segment; segment = segment->Next() ) { for( other = segment->Next(); other; other = nextsegment ) { nextsegment = other->Next(); bool erase = false; if( segment->Type() != other->Type() ) continue; if( segment->GetLayer() != other->GetLayer() ) continue; if( segment->GetNetCode() != other->GetNetCode() ) break; if( ( segment->GetStart() == other->GetStart() ) && ( segment->GetEnd() == other->GetEnd() ) ) erase = true; if( ( segment->GetStart() == other->GetEnd() ) && ( segment->GetEnd() == other->GetStart() ) ) erase = true; // Delete redundant point if( erase ) { other->DeleteStructure(); modified = true; } } } // merge collinear segments: for( segment = m_Brd->m_Track; segment; segment = nextsegment ) { TRACK* segStart; TRACK* segEnd; TRACK* segDelete; nextsegment = segment->Next(); if( segment->Type() != PCB_TRACE_T ) continue; flag = no_inc = 0; // search for a possible point connected to the START point of the current segment for( segStart = segment->Next(); ; ) { segStart = segment->GetTrace( segStart, NULL, FLG_START ); if( segStart ) { // the two segments must have the same width if( segment->GetWidth() != segStart->GetWidth() ) break; // it cannot be a via if( segStart->Type() != PCB_TRACE_T ) break; // We must have only one segment connected segStart->SetState( BUSY, true ); other = segment->GetTrace( m_Brd->m_Track, NULL, FLG_START ); segStart->SetState( BUSY, false ); if( other == NULL ) flag = 1; // OK break; } break; } if( flag ) // We have the starting point of the segment is connected to an other segment { segDelete = mergeCollinearSegmentIfPossible( segment, segStart, FLG_START ); if( segDelete ) { no_inc = 1; segDelete->DeleteStructure(); modified = true; } } // search for a possible point connected to the END point of the current segment: for( segEnd = segment->Next(); ; ) { segEnd = segment->GetTrace( segEnd, NULL, FLG_END ); if( segEnd ) { if( segment->GetWidth() != segEnd->GetWidth() ) break; if( segEnd->Type() != PCB_TRACE_T ) break; // We must have only one segment connected segEnd->SetState( BUSY, true ); other = segment->GetTrace( m_Brd->m_Track, NULL, FLG_END ); segEnd->SetState( BUSY, false ); if( other == NULL ) flag |= 2; // Ok break; } else { break; } } if( flag & 2 ) // We have the ending point of the segment is connected to an other segment { segDelete = mergeCollinearSegmentIfPossible( segment, segEnd, FLG_END ); if( segDelete ) { no_inc = 1; segDelete->DeleteStructure(); modified = true; } } if( no_inc ) // The current segment was modified, retry to merge it nextsegment = segment->Next(); } return modified; }
/* * 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; }