void EXCELLON_WRITER::BuildHolesList( int aFirstLayer, int aLastLayer, bool aExcludeThroughHoles, bool aGenerateNPTH_list, bool aMergePTHNPTH ) { HOLE_INFO new_hole; int hole_value; m_holeListBuffer.clear(); m_toolListBuffer.clear(); if( (aFirstLayer >= 0) && (aLastLayer >= 0) ) { if( aFirstLayer > aLastLayer ) EXCHG( aFirstLayer, aLastLayer ); } if ( aGenerateNPTH_list && aMergePTHNPTH ) { return; } // build hole list for vias if( ! aGenerateNPTH_list ) // vias are always plated ! { for( TRACK* track = m_pcb->m_Track; track; track = track->Next() ) { if( track->Type() != PCB_VIA_T ) continue; SEGVIA* via = (SEGVIA*) track; hole_value = via->GetDrillValue(); if( hole_value == 0 ) continue; new_hole.m_Tool_Reference = -1; // Flag value for Not initialized new_hole.m_Hole_Orient = 0; new_hole.m_Hole_Diameter = hole_value; new_hole.m_Hole_Size.x = new_hole.m_Hole_Size.y = new_hole.m_Hole_Diameter; new_hole.m_Hole_Shape = 0; // hole shape: round new_hole.m_Hole_Pos = via->GetStart(); via->LayerPair( &new_hole.m_Hole_Top_Layer, &new_hole.m_Hole_Bottom_Layer ); // LayerPair return params with m_Hole_Bottom_Layer < m_Hole_Top_Layer if( (new_hole.m_Hole_Bottom_Layer > aFirstLayer) && (aFirstLayer >= 0) ) continue; if( (new_hole.m_Hole_Top_Layer < aLastLayer) && (aLastLayer >= 0) ) continue; if( aExcludeThroughHoles && (new_hole.m_Hole_Bottom_Layer == LAYER_N_BACK) && (new_hole.m_Hole_Top_Layer == LAYER_N_FRONT) ) continue; m_holeListBuffer.push_back( new_hole ); } } // build hole list for pads (assumed always through holes) if( !aExcludeThroughHoles || aGenerateNPTH_list ) { for( MODULE* module = m_pcb->m_Modules; module; module = module->Next() ) { // Read and analyse pads for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() ) { if( ! aGenerateNPTH_list && pad->GetAttribute() == PAD_HOLE_NOT_PLATED && ! aMergePTHNPTH ) continue; if( aGenerateNPTH_list && pad->GetAttribute() != PAD_HOLE_NOT_PLATED ) continue; if( pad->GetDrillSize().x == 0 ) continue; new_hole.m_Hole_NotPlated = (pad->GetAttribute() == PAD_HOLE_NOT_PLATED); new_hole.m_Tool_Reference = -1; // Flag is: Not initialized new_hole.m_Hole_Orient = pad->GetOrientation(); new_hole.m_Hole_Shape = 0; // hole shape: round new_hole.m_Hole_Diameter = std::min( pad->GetDrillSize().x, pad->GetDrillSize().y ); new_hole.m_Hole_Size.x = new_hole.m_Hole_Size.y = new_hole.m_Hole_Diameter; if( pad->GetDrillShape() != PAD_DRILL_CIRCLE ) new_hole.m_Hole_Shape = 1; // oval flag set new_hole.m_Hole_Size = pad->GetDrillSize(); new_hole.m_Hole_Pos = pad->GetPosition(); // hole position new_hole.m_Hole_Bottom_Layer = LAYER_N_BACK; new_hole.m_Hole_Top_Layer = LAYER_N_FRONT;// pad holes are through holes m_holeListBuffer.push_back( new_hole ); } } } // Sort holes per increasing diameter value sort( m_holeListBuffer.begin(), m_holeListBuffer.end(), CmpHoleDiameterValue ); // build the tool list int LastHole = -1; /* Set to not initialized (this is a value not used * for m_holeListBuffer[ii].m_Hole_Diameter) */ DRILL_TOOL new_tool( 0 ); unsigned jj; for( unsigned ii = 0; ii < m_holeListBuffer.size(); ii++ ) { if( m_holeListBuffer[ii].m_Hole_Diameter != LastHole ) { new_tool.m_Diameter = ( m_holeListBuffer[ii].m_Hole_Diameter ); m_toolListBuffer.push_back( new_tool ); LastHole = new_tool.m_Diameter; } jj = m_toolListBuffer.size(); if( jj == 0 ) continue; // Should not occurs m_holeListBuffer[ii].m_Tool_Reference = jj; // Tool value Initialized (value >= 1) m_toolListBuffer.back().m_TotalCount++; if( m_holeListBuffer[ii].m_Hole_Shape ) m_toolListBuffer.back().m_OvalCount++; } }
/* * 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; }
bool PCB_EDIT_FRAME::Other_Layer_Route( TRACK* aTrack, wxDC* DC ) { unsigned itmp; if( aTrack == NULL ) { if( getActiveLayer() != ((PCB_SCREEN*)GetScreen())->m_Route_Layer_TOP ) setActiveLayer( ((PCB_SCREEN*)GetScreen())->m_Route_Layer_TOP ); else setActiveLayer(((PCB_SCREEN*)GetScreen())->m_Route_Layer_BOTTOM ); UpdateStatusBar(); return true; } // Avoid more than one via on the current location: if( GetBoard()->GetViaByPosition( g_CurrentTrackSegment->GetEnd(), g_CurrentTrackSegment->GetLayer() ) ) return false; for( TRACK* segm = g_FirstTrackSegment; segm; segm = segm->Next() ) { if( segm->Type() == PCB_VIA_T && g_CurrentTrackSegment->GetEnd() == segm->GetStart() ) return false; } // Is the current segment Ok (no DRC error) ? if( g_Drc_On ) { if( BAD_DRC==m_drc->Drc( g_CurrentTrackSegment, GetBoard()->m_Track ) ) // DRC error, the change layer is not made return false; // Handle 2 segments. if( g_TwoSegmentTrackBuild && g_CurrentTrackSegment->Back() ) { if( BAD_DRC == m_drc->Drc( g_CurrentTrackSegment->Back(), GetBoard()->m_Track ) ) return false; } } /* Save current state before placing a via. * If the via cannot be placed this current state will be reused */ itmp = g_CurrentTrackList.GetCount(); Begin_Route( g_CurrentTrackSegment, DC ); m_canvas->CallMouseCapture( DC, wxDefaultPosition, false ); // create the via SEGVIA* via = new SEGVIA( GetBoard() ); via->SetFlags( IS_NEW ); via->SetShape( GetDesignSettings().m_CurrentViaType ); via->SetWidth( GetBoard()->GetCurrentViaSize()); via->SetNet( GetBoard()->GetHighLightNetCode() ); via->SetEnd( g_CurrentTrackSegment->GetEnd() ); via->SetStart( g_CurrentTrackSegment->GetEnd() ); // Usual via is from copper to component. // layer pair is LAYER_N_BACK and LAYER_N_FRONT. via->SetLayerPair( LAYER_N_BACK, LAYER_N_FRONT ); via->SetDrill( GetBoard()->GetCurrentViaDrill() ); LAYER_NUM first_layer = getActiveLayer(); LAYER_NUM last_layer; // prepare switch to new active layer: if( first_layer != GetScreen()->m_Route_Layer_TOP ) last_layer = GetScreen()->m_Route_Layer_TOP; else last_layer = GetScreen()->m_Route_Layer_BOTTOM; // Adjust the actual via layer pair switch ( via->GetShape() ) { case VIA_BLIND_BURIED: via->SetLayerPair( first_layer, last_layer ); break; case VIA_MICROVIA: // from external to the near neighbor inner layer { LAYER_NUM last_inner_layer = FIRST_LAYER + (GetBoard()->GetCopperLayerCount() - 2); if ( first_layer == LAYER_N_BACK ) last_layer = LAYER_N_2; else if ( first_layer == LAYER_N_FRONT ) last_layer = last_inner_layer; else if ( first_layer == LAYER_N_2 ) last_layer = LAYER_N_BACK; else if ( first_layer == last_inner_layer ) last_layer = LAYER_N_FRONT; // else error: will be removed later via->SetLayerPair( first_layer, last_layer ); { NETINFO_ITEM* net = GetBoard()->FindNet( via->GetNet() ); via->SetWidth( net->GetMicroViaSize() ); } } break; default: break; } if( g_Drc_On && BAD_DRC == m_drc->Drc( via, GetBoard()->m_Track ) ) { // DRC fault: the Via cannot be placed here ... delete via; m_canvas->CallMouseCapture( DC, wxDefaultPosition, false ); // delete the track(s) added in Begin_Route() while( g_CurrentTrackList.GetCount() > itmp ) { Delete_Segment( DC, g_CurrentTrackSegment ); } SetCurItem( g_CurrentTrackSegment, false ); // Refresh DRC diag, erased by previous calls if( m_drc->GetCurrentMarker() ) SetMsgPanel( m_drc->GetCurrentMarker() ); return false; } setActiveLayer( last_layer ); TRACK* lastNonVia = g_CurrentTrackSegment; /* A new via was created. It was Ok. */ g_CurrentTrackList.PushBack( via ); /* The via is now in linked list and we need a new track segment * after the via, starting at via location. * it will become the new current segment (from via to the mouse cursor) */ TRACK* track = (TRACK*)lastNonVia->Clone(); /* the above creates a new segment from the last entered segment, with the * current width, flags, netcode, etc... values. * layer, start and end point are not correct, * and will be modified next */ // set the layer to the new value track->SetLayer( getActiveLayer() ); /* the start point is the via position and the end point is the cursor * which also is on the via (will change when moving mouse) */ track->SetEnd( via->GetStart() ); track->SetStart( via->GetStart() ); g_CurrentTrackList.PushBack( track ); if( g_TwoSegmentTrackBuild ) { // Create a second segment (we must have 2 track segments to adjust) g_CurrentTrackList.PushBack( (TRACK*)g_CurrentTrackSegment->Clone() ); } m_canvas->CallMouseCapture( DC, wxDefaultPosition, false ); SetMsgPanel( via ); UpdateStatusBar(); return true; }