void PCB_EDIT_FRAME::Swap_Layers( wxCommandEvent& event ) { PCB_LAYER_ID new_layer[PCB_LAYER_ID_COUNT]; DIALOG_SWAP_LAYERS dlg( this, new_layer ); if( dlg.ShowModal() != wxID_OK ) return; BOARD_COMMIT commit( this ); bool hasChanges = false; // Change tracks. for( TRACK* segm = GetBoard()->m_Track; segm; segm = segm->Next() ) { if( segm->Type() == PCB_VIA_T ) { VIA* via = (VIA*) segm; PCB_LAYER_ID top_layer, bottom_layer; if( via->GetViaType() == VIA_THROUGH ) continue; via->LayerPair( &top_layer, &bottom_layer ); if( new_layer[bottom_layer] != bottom_layer || new_layer[top_layer] != top_layer ) { commit.Modify( via ); via->SetLayerPair( new_layer[top_layer], new_layer[bottom_layer] ); GetGalCanvas()->GetView()->Update( via, KIGFX::GEOMETRY ); hasChanges = true; } } else { hasChanges |= processBoardItem( this, commit, segm, new_layer ); } } for( BOARD_ITEM* zone : GetBoard()->Zones() ) { hasChanges |= processBoardItem( this, commit, zone, new_layer ); } for( BOARD_ITEM* drawing : GetBoard()->Drawings() ) { hasChanges |= processBoardItem( this, commit, drawing, new_layer ); } if( hasChanges ) { OnModify(); commit.Push( "Layers moved" ); GetCanvas()->Refresh(); } }
VIA* TRACK::GetVia( const wxPoint& aPosition, LAYER_NUM aLayer) { for( VIA *via = GetFirstVia( this ); via; via = GetFirstVia( via->Next() ) ) { if( via->HitTest( aPosition ) && !via->GetState( BUSY | IS_DELETED ) && ((aLayer == UNDEFINED_LAYER) || (via->IsOnLayer( aLayer ))) ) return via; } return NULL; }
VIA* TRACK::GetVia( TRACK* aEndTrace, const wxPoint& aPosition, LAYER_MSK aLayerMask ) { for( VIA *via = GetFirstVia( this, aEndTrace ); via; via = GetFirstVia( via->Next() ) ) { if( via->HitTest( aPosition ) && !via->GetState( BUSY | IS_DELETED ) && (aLayerMask & via->GetLayerMask()) ) return via; } return NULL; }
std::vector<LAYER_PAIR> EXCELLON_WRITER::getUniqueLayerPairs() const { wxASSERT( m_pcb ); static const KICAD_T interesting_stuff_to_collect[] = { PCB_VIA_T, EOT }; PCB_TYPE_COLLECTOR vias; vias.Collect( m_pcb, interesting_stuff_to_collect ); std::set< LAYER_PAIR > unique; LAYER_PAIR layer_pair; for( int i = 0; i < vias.GetCount(); ++i ) { VIA* v = (VIA*) vias[i]; v->LayerPair( &layer_pair.first, &layer_pair.second ); // only make note of blind buried. // thru hole is placed unconditionally as first in fetched list. if( layer_pair != LAYER_PAIR( F_Cu, B_Cu ) ) { unique.insert( layer_pair ); } } std::vector<LAYER_PAIR> ret; ret.push_back( LAYER_PAIR( F_Cu, B_Cu ) ); // always first in returned list for( std::set< LAYER_PAIR >::const_iterator it = unique.begin(); it != unique.end(); ++it ) ret.push_back( *it ); return ret; }
/** Utility: does the endpoint unconnected processed for one endpoint of one track * Returns true if the track must be deleted, false if not necessarily */ bool TRACKS_CLEANER::testTrackEndpointDangling( TRACK *aTrack, ENDPOINT_T aEndPoint ) { bool flag_erase = false; TRACK* other = aTrack->GetTrack( m_Brd->m_Track, NULL, aEndPoint, true, false ); if( (other == NULL) && (zoneForTrackEndpoint( aTrack, aEndPoint ) == NULL) ) flag_erase = true; // Start endpoint is neither on pad, zone or other track else // segment, via or zone connected to this end { // Fill connectivity informations if( aEndPoint == ENDPOINT_START ) aTrack->start = other; else aTrack->end = other; /* If a via is connected to this end, test if this via has a second item connected. * If not, remove the current segment (the via would then become * unconnected and remove on the following pass) */ VIA* via = dyn_cast<VIA*>( other ); if( via ) { // search for another segment following the via aTrack->SetState( BUSY, true ); other = via->GetTrack( m_Brd->m_Track, NULL, aEndPoint, true, false ); // There is a via on the start but it goes nowhere if( (other == NULL) && (zoneForTrackEndpoint( via, aEndPoint ) == NULL) ) flag_erase = true; aTrack->SetState( BUSY, false ); } } return flag_erase; }
bool TRACKS_CLEANER::clean_vias() { bool modified = false; for( VIA* via = GetFirstVia( m_Brd->m_Track ); via != NULL; via = GetFirstVia( via->Next() ) ) { // Correct via m_End defects (if any), should never happen if( via->GetStart() != via->GetEnd() ) { wxFAIL_MSG( wxT( "Via with mismatching ends" ) ); via->SetEnd( via->GetStart() ); } /* Important: these cleanups only do thru hole vias, they don't * (yet) handle high density interconnects */ if( via->GetViaType() != VIA_THROUGH ) { modified |= remove_duplicates_of_via( via ); /* To delete through Via on THT pads at same location * Examine the list of connected pads: * if one through pad is found, the via can be removed */ for( unsigned ii = 0; ii < via->m_PadsConnected.size(); ++ii ) { const D_PAD *pad = via->m_PadsConnected[ii]; const LSET all_cu = LSET::AllCuMask(); if( (pad->GetLayerSet() & all_cu) == all_cu ) { // redundant: delete the via m_Brd->GetRatsnest()->Remove( via ); via->ViewRelease(); via->DeleteStructure(); modified = true; break; } } } } return modified; }
/* Extract the D356 record from the vias */ static void build_via_testpoints( BOARD *aPcb, std::vector <D356_RECORD>& aRecords ) { wxPoint origin = aPcb->GetAuxOrigin(); // Enumerate all the track segments and keep the vias for( TRACK *track = aPcb->m_Track; track; track = track->Next() ) { if( track->Type() == PCB_VIA_T ) { VIA *via = (VIA*) track; NETINFO_ITEM *net = track->GetNet(); D356_RECORD rk; rk.smd = false; rk.hole = true; if( net ) rk.netname = net->GetNetname(); else rk.netname = wxEmptyString; rk.refdes = wxT("VIA"); rk.pin = wxT(""); rk.midpoint = true; // Vias are always midpoints rk.drill = via->GetDrillValue(); rk.mechanical = false; LAYER_ID top_layer, bottom_layer; via->LayerPair( &top_layer, &bottom_layer ); rk.access = via_access_code( aPcb, top_layer, bottom_layer ); rk.x_location = via->GetPosition().x - origin.x; rk.y_location = origin.y - via->GetPosition().y; rk.x_size = via->GetWidth(); rk.y_size = 0; // Round so height = 0 rk.rotation = 0; rk.soldermask = 3; // XXX always tented? aRecords.push_back( rk ); } } }
void EDA_3D_CANVAS::buildBoardThroughHolesPolygonList( SHAPE_POLY_SET& allBoardHoles, int aSegCountPerCircle, bool aOptimizeLargeCircles ) { // hole diameter value to change seg count by circle: int small_hole_limit = Millimeter2iu( 1.0 ); int copper_thickness = GetPrm3DVisu().GetCopperThicknessBIU(); BOARD* pcb = GetBoard(); // Build holes of through vias: for( TRACK* track = pcb->m_Track; track; track = track->Next() ) { if( track->Type() != PCB_VIA_T ) continue; VIA *via = static_cast<VIA*>( track ); if( via->GetViaType() != VIA_THROUGH ) continue; int holediameter = via->GetDrillValue(); int hole_outer_radius = (holediameter + copper_thickness) / 2; TransformCircleToPolygon( allBoardHoles, via->GetStart(), hole_outer_radius, aSegCountPerCircle ); } // Build holes of through pads: for( MODULE* footprint = pcb->m_Modules; footprint; footprint = footprint->Next() ) { for( D_PAD* pad = footprint->Pads(); pad; pad = pad->Next() ) { // Calculate a factor to apply to segcount for large holes ( > 1 mm) // (bigger pad drill size -> more segments) because holes in pads can have // very different sizes and optimizing this segcount gives a better look // Mainly mounting holes have a size bigger than small_hole_limit wxSize padHole = pad->GetDrillSize(); if( ! padHole.x ) // Not drilled pad like SMD pad continue; // we use the hole diameter to calculate the seg count. // for round holes, padHole.x == padHole.y // for oblong holes, the diameter is the smaller of (padHole.x, padHole.y) int diam = std::min( padHole.x, padHole.y ); int segcount = aSegCountPerCircle; if( diam > small_hole_limit ) { double segFactor = (double)diam / small_hole_limit; segcount = (int)(aSegCountPerCircle * segFactor); // limit segcount to 48. For a circle this is a very good approx. if( segcount > 48 ) segcount = 48; } // The hole in the body is inflated by copper thickness. int inflate = copper_thickness; // If not plated, no copper. if( pad->GetAttribute () == PAD_HOLE_NOT_PLATED ) inflate = 0; pad->BuildPadDrillShapePolygon( allBoardHoles, inflate, segcount ); } } allBoardHoles.Simplify(); }
void EDA_3D_CANVAS::buildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList, REPORTER* aErrorMessages, REPORTER* aActivity ) { BOARD* pcb = GetBoard(); // If FL_RENDER_SHOW_HOLES_IN_ZONES is true, holes are correctly removed from copper zones areas. // If FL_RENDER_SHOW_HOLES_IN_ZONES is false, holes are not removed from copper zones areas, // but the calculation time is twice shorter. bool remove_Holes = isEnabled( FL_RENDER_SHOW_HOLES_IN_ZONES ); bool realistic_mode = isRealisticMode(); bool useTextures = isRealisticMode() && isEnabled( FL_RENDER_TEXTURES ); // Number of segments to convert a circle to polygon // We use 2 values: the first gives a good shape (for instanes rond pads) // the second is used to speed up calculations, when a poor approximation is acceptable (holes) const int segcountforcircle = 18; double correctionFactor = 1.0 / cos( M_PI / (segcountforcircle * 2.0) ); const int segcountLowQuality = 12; // segments to draw a circle with low quality // to reduce time calculations // for holes and items which do not need // a fine representation double correctionFactorLQ = 1.0 / cos( M_PI / (segcountLowQuality * 2.0) ); SHAPE_POLY_SET bufferPolys; // copper areas: tracks, pads and filled zones areas // when holes are removed from zones SHAPE_POLY_SET bufferPcbOutlines; // stores the board main outlines SHAPE_POLY_SET bufferZonesPolys; // copper filled zones areas // when holes are not removed from zones SHAPE_POLY_SET currLayerHoles; // Contains holes for the current layer SHAPE_POLY_SET allLayerHoles; // Contains holes for all layers // Build a polygon from edge cut items wxString msg; if( !pcb->GetBoardPolygonOutlines( bufferPcbOutlines, allLayerHoles, &msg ) ) { if( aErrorMessages ) { msg << wxT("\n") << _("Unable to calculate the board outlines.\n" "Therefore use the board boundary box.") << wxT("\n\n"); aErrorMessages->Report( msg, REPORTER::RPT_WARNING ); } } // Build board holes, with optimization of large holes shape. buildBoardThroughHolesPolygonList( allLayerHoles, segcountLowQuality, true ); LSET cu_set = LSET::AllCuMask( GetPrm3DVisu().m_CopperLayersCount ); glNewList( aBoardList, GL_COMPILE ); for( LSEQ cu = cu_set.CuStack(); cu; ++cu ) { LAYER_ID layer = *cu; // Skip non enabled layers in normal mode, // and internal layers in realistic mode if( !is3DLayerEnabled( layer ) ) continue; if( aActivity ) aActivity->Report( wxString::Format( _( "Build layer %s" ), LSET::Name( layer ) ) ); bufferPolys.RemoveAllContours(); bufferZonesPolys.RemoveAllContours(); currLayerHoles.RemoveAllContours(); // Draw track shapes: for( TRACK* track = pcb->m_Track; track; track = track->Next() ) { if( !track->IsOnLayer( layer ) ) continue; track->TransformShapeWithClearanceToPolygon( bufferPolys, 0, segcountforcircle, correctionFactor ); // Add blind/buried via holes if( track->Type() == PCB_VIA_T ) { VIA *via = static_cast<VIA*>( track ); if( via->GetViaType() == VIA_THROUGH ) continue; // already done int holediameter = via->GetDrillValue(); int thickness = GetPrm3DVisu().GetCopperThicknessBIU(); int hole_outer_radius = (holediameter + thickness) / 2; TransformCircleToPolygon( currLayerHoles, via->GetStart(), hole_outer_radius, segcountLowQuality ); } } // draw pad shapes for( MODULE* module = pcb->m_Modules; module; module = module->Next() ) { // Note: NPTH pads are not drawn on copper layers when the pad // has same shape as its hole module->TransformPadsShapesWithClearanceToPolygon( layer, bufferPolys, 0, segcountforcircle, correctionFactor, true ); // Micro-wave modules may have items on copper layers module->TransformGraphicShapesWithClearanceToPolygonSet( layer, bufferPolys, 0, segcountforcircle, correctionFactor ); // pad holes are already in list. } // Draw copper zones. Note: // * if the holes are removed from copper zones // the polygons are stored in bufferPolys (which contains all other polygons) // * if the holes are NOT removed from copper zones // the polygons are stored in bufferZonesPolys if( isEnabled( FL_ZONE ) ) { for( int ii = 0; ii < pcb->GetAreaCount(); ii++ ) { ZONE_CONTAINER* zone = pcb->GetArea( ii ); LAYER_NUM zonelayer = zone->GetLayer(); if( zonelayer == layer ) { zone->TransformSolidAreasShapesToPolygonSet( remove_Holes ? bufferPolys : bufferZonesPolys, segcountLowQuality, correctionFactorLQ ); } } } // draw graphic items on copper layers (texts) for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() ) { if( !item->IsOnLayer( layer ) ) continue; switch( item->Type() ) { case PCB_LINE_T: // should not exist on copper layers ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon( bufferPolys, 0, segcountforcircle, correctionFactor ); break; case PCB_TEXT_T: ( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet( bufferPolys, 0, segcountLowQuality, correctionFactor ); break; default: break; } } // bufferPolys contains polygons to merge. Many overlaps . // Calculate merged polygons if( bufferPolys.IsEmpty() ) continue; // Use Clipper lib to subtract holes to copper areas if( currLayerHoles.OutlineCount() ) { currLayerHoles.Append(allLayerHoles); currLayerHoles.Simplify(); bufferPolys.BooleanSubtract( currLayerHoles ); } else bufferPolys.BooleanSubtract( allLayerHoles ); int thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer ); int zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer ); float zNormal = 1.0f; // When using thickness it will draw first the top and then botton (with z inverted) // If we are not using thickness, then the z-normal has to match the layer direction // because just one plane will be drawn if( !thickness ) zNormal = Get3DLayer_Z_Orientation( layer ); if( realistic_mode ) { setGLCopperColor(); } else { EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( layer ); SetGLColor( color ); } // If holes are removed from copper zones, bufferPolys contains all polygons // to draw (tracks+zones+texts). Draw3D_SolidHorizontalPolyPolygons( bufferPolys, zpos, thickness, GetPrm3DVisu().m_BiuTo3Dunits, useTextures, zNormal ); // If holes are not removed from copper zones (for calculation time reasons, // the zone polygons are stored in bufferZonesPolys and have to be drawn now: if( !bufferZonesPolys.IsEmpty() ) { Draw3D_SolidHorizontalPolyPolygons( bufferZonesPolys, zpos, thickness, GetPrm3DVisu().m_BiuTo3Dunits, useTextures, zNormal ); } } if( aActivity ) aActivity->Report( _( "Build board body" ) ); // Draw plated vertical holes inside the board, but not always. They are drawn: // - if the board body is not shown, to show the holes. // - or if the copper thickness is shown if( !isEnabled( FL_SHOW_BOARD_BODY ) || isEnabled( FL_USE_COPPER_THICKNESS ) ) { // Draw vias holes (vertical cylinders) for( const TRACK* track = pcb->m_Track; track; track = track->Next() ) { if( track->Type() == PCB_VIA_T ) { const VIA *via = static_cast<const VIA*>(track); draw3DViaHole( via ); } } // Draw pads holes (vertical cylinders) for( const MODULE* module = pcb->m_Modules; module; module = module->Next() ) { for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() ) if( pad->GetAttribute () != PAD_HOLE_NOT_PLATED ) draw3DPadHole( pad ); } } glEndList(); // Build the body board: glNewList( aBodyOnlyList, GL_COMPILE ); if( isRealisticMode() ) { setGLEpoxyColor( 1.00 ); } else { EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( Edge_Cuts ); SetGLColor( color, 0.7 ); } float copper_thickness = GetPrm3DVisu().GetCopperThicknessBIU(); // a small offset between substrate and external copper layer to avoid artifacts // when drawing copper items on board float epsilon = Millimeter2iu( 0.01 ); float zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Cu ); float board_thickness = GetPrm3DVisu().GetLayerZcoordBIU( F_Cu ) - GetPrm3DVisu().GetLayerZcoordBIU( B_Cu ); // items on copper layers and having a thickness = copper_thickness // are drawn from zpos - copper_thickness/2 to zpos + copper_thickness // therefore substrate position is copper_thickness/2 to // substrate_height - copper_thickness/2 zpos += (copper_thickness + epsilon) / 2.0f; board_thickness -= copper_thickness + epsilon; bufferPcbOutlines.BooleanSubtract( allLayerHoles ); if( !bufferPcbOutlines.IsEmpty() ) { Draw3D_SolidHorizontalPolyPolygons( bufferPcbOutlines, zpos + board_thickness / 2.0, board_thickness, GetPrm3DVisu().m_BiuTo3Dunits, useTextures, 1.0f ); } glEndList(); }
bool PCB_EDIT_FRAME::Other_Layer_Route( TRACK* aTrack, wxDC* DC ) { unsigned itmp; if( aTrack == NULL ) { if( GetActiveLayer() != GetScreen()->m_Route_Layer_TOP ) SetActiveLayer( GetScreen()->m_Route_Layer_TOP ); else SetActiveLayer( 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 VIA* via = new VIA( GetBoard() ); via->SetFlags( IS_NEW ); via->SetViaType( GetDesignSettings().m_CurrentViaType ); via->SetNetCode( GetBoard()->GetHighLightNetCode() ); via->SetPosition( g_CurrentTrackSegment->GetEnd() ); // for microvias, the size and hole will be changed later. via->SetWidth( GetDesignSettings().GetCurrentViaSize()); via->SetDrill( GetDesignSettings().GetCurrentViaDrill() ); // Usual via is from copper to component. // layer pair is B_Cu and F_Cu. via->SetLayerPair( B_Cu, F_Cu ); LAYER_ID first_layer = GetActiveLayer(); LAYER_ID 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->GetViaType() ) { case VIA_BLIND_BURIED: via->SetLayerPair( first_layer, last_layer ); break; case VIA_MICROVIA: // from external to the near neighbor inner layer { LAYER_ID last_inner_layer = ToLAYER_ID( ( GetBoard()->GetCopperLayerCount() - 2 ) ); if( first_layer == B_Cu ) last_layer = last_inner_layer; else if( first_layer == F_Cu ) last_layer = In1_Cu; else if( first_layer == last_inner_layer ) last_layer = B_Cu; else if( first_layer == In1_Cu ) last_layer = F_Cu; // else error: will be removed later via->SetLayerPair( first_layer, last_layer ); // Update diameter and hole size, which where set previously // for normal vias NETINFO_ITEM* net = via->GetNet(); via->SetWidth( net->GetMicroViaSize() ); via->SetDrill( net->GetMicroViaDrillSize() ); } 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; }
bool DIALOG_TRACK_VIA_PROPERTIES::Apply( COMMIT& aCommit ) { if( !check() ) return false; bool changeLock = m_lockedCbox->Get3StateValue() != wxCHK_UNDETERMINED; bool setLock = m_lockedCbox->Get3StateValue() == wxCHK_CHECKED; for( auto item : m_items ) { aCommit.Modify( item ); switch( item->Type() ) { case PCB_TRACE_T: { assert( m_tracks ); TRACK* t = static_cast<TRACK*>( item ); if( m_trackStartX.Valid() || m_trackStartY.Valid() ) { wxPoint start = t->GetStart(); if( m_trackStartX.Valid() ) start.x = m_trackStartX.GetValue(); if( m_trackStartY.Valid() ) start.y = m_trackStartY.GetValue(); t->SetStart( start ); } if( m_trackEndX.Valid() || m_trackEndY.Valid() ) { wxPoint end = t->GetEnd(); if( m_trackEndX.Valid() ) end.x = m_trackEndX.GetValue(); if( m_trackEndY.Valid() ) end.y = m_trackEndY.GetValue(); t->SetEnd( end ); } if( m_trackNetclass->IsChecked() ) { t->SetWidth( t->GetNetClass()->GetTrackWidth() ); } else if( m_trackWidth.Valid() ) { t->SetWidth( m_trackWidth.GetValue() ); } LAYER_NUM layer = m_TrackLayerCtrl->GetLayerSelection(); if( layer != UNDEFINED_LAYER ) t->SetLayer( (LAYER_ID) layer ); if( changeLock ) t->SetLocked( setLock ); break; } case PCB_VIA_T: { assert( m_vias ); VIA* v = static_cast<VIA*>( item ); if( m_viaX.Valid() || m_viaY.Valid() ) { wxPoint pos = v->GetPosition(); if( m_viaX.Valid() ) pos.x = m_viaX.GetValue(); if( m_viaY.Valid() ) pos.y = m_viaY.GetValue(); v->SetPosition( pos ); } if( m_viaNetclass->IsChecked() ) { switch( v->GetViaType() ) { default: wxFAIL_MSG("Unhandled via type"); // fall through case VIA_THROUGH: case VIA_BLIND_BURIED: v->SetWidth( v->GetNetClass()->GetViaDiameter() ); v->SetDrill( v->GetNetClass()->GetViaDrill() ); break; case VIA_MICROVIA: v->SetWidth( v->GetNetClass()->GetuViaDiameter() ); v->SetDrill( v->GetNetClass()->GetuViaDrill() ); break; } } else { if( m_viaDiameter.Valid() ) v->SetWidth( m_viaDiameter.GetValue() ); if( m_viaDrill.Valid() ) v->SetDrill( m_viaDrill.GetValue() ); } if( changeLock ) v->SetLocked( setLock ); break; } default: assert( false ); break; } } return true; }
/* This function is used by Retrace and read the autorouting matrix data cells to create * the real track on the physical board */ static void OrCell_Trace( BOARD* pcb, int col, int row, int side, int orient, int current_net_code ) { if( orient == HOLE ) // placement of a via { VIA *newVia = new VIA( pcb ); g_CurrentTrackList.PushBack( newVia ); g_CurrentTrackSegment->SetState( TRACK_AR, true ); g_CurrentTrackSegment->SetLayer( F_Cu ); g_CurrentTrackSegment->SetStart(wxPoint( pcb->GetBoundingBox().GetX() + ( RoutingMatrix.m_GridRouting * row ), pcb->GetBoundingBox().GetY() + ( RoutingMatrix.m_GridRouting * col ))); g_CurrentTrackSegment->SetEnd( g_CurrentTrackSegment->GetStart() ); g_CurrentTrackSegment->SetWidth( pcb->GetDesignSettings().GetCurrentViaSize() ); newVia->SetViaType( pcb->GetDesignSettings().m_CurrentViaType ); g_CurrentTrackSegment->SetNetCode( current_net_code ); } else // placement of a standard segment { TRACK *newTrack = new TRACK( pcb ); int dx0, dy0, dx1, dy1; g_CurrentTrackList.PushBack( newTrack ); g_CurrentTrackSegment->SetLayer( g_Route_Layer_BOTTOM ); if( side == TOP ) g_CurrentTrackSegment->SetLayer( g_Route_Layer_TOP ); g_CurrentTrackSegment->SetState( TRACK_AR, true ); g_CurrentTrackSegment->SetEnd( wxPoint( pcb->GetBoundingBox().GetX() + ( RoutingMatrix.m_GridRouting * row ), pcb->GetBoundingBox().GetY() + ( RoutingMatrix.m_GridRouting * col ))); g_CurrentTrackSegment->SetNetCode( current_net_code ); if( g_CurrentTrackSegment->Back() == NULL ) // Start trace. { g_CurrentTrackSegment->SetStart( wxPoint( segm_fX, segm_fY ) ); // Placement on the center of the pad if outside grid. dx1 = g_CurrentTrackSegment->GetEnd().x - g_CurrentTrackSegment->GetStart().x; dy1 = g_CurrentTrackSegment->GetEnd().y - g_CurrentTrackSegment->GetStart().y; dx0 = pt_cur_ch->m_PadEnd->GetPosition().x - g_CurrentTrackSegment->GetStart().x; dy0 = pt_cur_ch->m_PadEnd->GetPosition().y - g_CurrentTrackSegment->GetStart().y; // If aligned, change the origin point. if( abs( dx0 * dy1 ) == abs( dx1 * dy0 ) ) { g_CurrentTrackSegment->SetStart( pt_cur_ch->m_PadEnd->GetPosition() ); } else // Creation of a supplemental segment { g_CurrentTrackSegment->SetStart( pt_cur_ch->m_PadEnd->GetPosition() ); newTrack = (TRACK*)g_CurrentTrackSegment->Clone(); newTrack->SetStart( g_CurrentTrackSegment->GetEnd()); g_CurrentTrackList.PushBack( newTrack ); } } else { if( g_CurrentTrackSegment->Back() ) { g_CurrentTrackSegment->SetStart( g_CurrentTrackSegment->Back()->GetEnd() ); } } g_CurrentTrackSegment->SetWidth( pcb->GetDesignSettings().GetCurrentTrackWidth() ); if( g_CurrentTrackSegment->GetStart() != g_CurrentTrackSegment->GetEnd() ) { // Reduce aligned segments by one. TRACK* oldTrack = g_CurrentTrackSegment->Back(); if( oldTrack && oldTrack->Type() != PCB_VIA_T ) { dx1 = g_CurrentTrackSegment->GetEnd().x - g_CurrentTrackSegment->GetStart().x; dy1 = g_CurrentTrackSegment->GetEnd().y - g_CurrentTrackSegment->GetStart().y; dx0 = oldTrack->GetEnd().x - oldTrack->GetStart().x; dy0 = oldTrack->GetEnd().y - oldTrack->GetStart().y; if( abs( dx0 * dy1 ) == abs( dx1 * dy0 ) ) { oldTrack->SetEnd( g_CurrentTrackSegment->GetEnd() ); delete g_CurrentTrackList.PopBack(); } } } } }
// Emit PADS and PADSTACKS. They are sorted and emitted uniquely. // Via name is synthesized from their attributes, pads are numbered static void CreatePadsShapesSection( FILE* aFile, BOARD* aPcb ) { std::vector<D_PAD*> pads; std::vector<D_PAD*> padstacks; std::vector<VIA*> vias; std::vector<VIA*> viastacks; padstacks.resize( 1 ); // We count pads from 1 // The master layermask (i.e. the enabled layers) for padstack generation LSET master_layermask = aPcb->GetDesignSettings().GetEnabledLayers(); int cu_count = aPcb->GetCopperLayerCount(); fputs( "$PADS\n", aFile ); // Enumerate and sort the pads if( aPcb->GetPadCount() > 0 ) { pads = aPcb->GetPads(); qsort( &pads[0], aPcb->GetPadCount(), sizeof( D_PAD* ), PadListSortByShape ); } // The same for vias for( VIA* via = GetFirstVia( aPcb->m_Track ); via; via = GetFirstVia( via->Next() ) ) { vias.push_back( via ); } qsort( &vias[0], vias.size(), sizeof(VIA*), ViaSort ); // Emit vias pads TRACK* old_via = 0; for( unsigned i = 0; i < vias.size(); i++ ) { VIA* via = vias[i]; if( old_via && 0 == ViaSort( &old_via, &via ) ) continue; old_via = via; viastacks.push_back( via ); fprintf( aFile, "PAD V%d.%d.%s ROUND %g\nCIRCLE 0 0 %g\n", via->GetWidth(), via->GetDrillValue(), fmt_mask( via->GetLayerSet() ).c_str(), via->GetDrillValue() / SCALE_FACTOR, via->GetWidth() / (SCALE_FACTOR * 2) ); } // Emit component pads D_PAD* old_pad = 0; int pad_name_number = 0; for( unsigned i = 0; i<pads.size(); ++i ) { D_PAD* pad = pads[i]; pad->SetSubRatsnest( pad_name_number ); if( old_pad && 0==D_PAD::Compare( old_pad, pad ) ) continue; // already created old_pad = pad; pad_name_number++; pad->SetSubRatsnest( pad_name_number ); fprintf( aFile, "PAD P%d", pad->GetSubRatsnest() ); padstacks.push_back( pad ); // Will have its own padstack later int dx = pad->GetSize().x / 2; int dy = pad->GetSize().y / 2; switch( pad->GetShape() ) { default: case PAD_SHAPE_CIRCLE: fprintf( aFile, " ROUND %g\n", pad->GetDrillSize().x / SCALE_FACTOR ); /* Circle is center, radius */ fprintf( aFile, "CIRCLE %g %g %g\n", pad->GetOffset().x / SCALE_FACTOR, -pad->GetOffset().y / SCALE_FACTOR, pad->GetSize().x / (SCALE_FACTOR * 2) ); break; case PAD_SHAPE_RECT: fprintf( aFile, " RECTANGULAR %g\n", pad->GetDrillSize().x / SCALE_FACTOR ); // Rectangle is begin, size *not* begin, end! fprintf( aFile, "RECTANGLE %g %g %g %g\n", (-dx + pad->GetOffset().x ) / SCALE_FACTOR, (-dy - pad->GetOffset().y ) / SCALE_FACTOR, dx / (SCALE_FACTOR / 2), dy / (SCALE_FACTOR / 2) ); break; case PAD_SHAPE_OVAL: // Create outline by 2 lines and 2 arcs { // OrCAD Layout call them OVAL or OBLONG - GenCAD call them FINGERs fprintf( aFile, " FINGER %g\n", pad->GetDrillSize().x / SCALE_FACTOR ); int dr = dx - dy; if( dr >= 0 ) // Horizontal oval { int radius = dy; fprintf( aFile, "LINE %g %g %g %g\n", (-dr + pad->GetOffset().x) / SCALE_FACTOR, (-pad->GetOffset().y - radius) / SCALE_FACTOR, (dr + pad->GetOffset().x ) / SCALE_FACTOR, (-pad->GetOffset().y - radius) / SCALE_FACTOR ); // GenCAD arcs are (start, end, center) fprintf( aFile, "ARC %g %g %g %g %g %g\n", (dr + pad->GetOffset().x) / SCALE_FACTOR, (-pad->GetOffset().y - radius) / SCALE_FACTOR, (dr + pad->GetOffset().x) / SCALE_FACTOR, (-pad->GetOffset().y + radius) / SCALE_FACTOR, (dr + pad->GetOffset().x) / SCALE_FACTOR, -pad->GetOffset().y / SCALE_FACTOR ); fprintf( aFile, "LINE %g %g %g %g\n", (dr + pad->GetOffset().x) / SCALE_FACTOR, (-pad->GetOffset().y + radius) / SCALE_FACTOR, (-dr + pad->GetOffset().x) / SCALE_FACTOR, (-pad->GetOffset().y + radius) / SCALE_FACTOR ); fprintf( aFile, "ARC %g %g %g %g %g %g\n", (-dr + pad->GetOffset().x) / SCALE_FACTOR, (-pad->GetOffset().y + radius) / SCALE_FACTOR, (-dr + pad->GetOffset().x) / SCALE_FACTOR, (-pad->GetOffset().y - radius) / SCALE_FACTOR, (-dr + pad->GetOffset().x) / SCALE_FACTOR, -pad->GetOffset().y / SCALE_FACTOR ); } else // Vertical oval { dr = -dr; int radius = dx; fprintf( aFile, "LINE %g %g %g %g\n", (-radius + pad->GetOffset().x) / SCALE_FACTOR, (-pad->GetOffset().y - dr) / SCALE_FACTOR, (-radius + pad->GetOffset().x ) / SCALE_FACTOR, (-pad->GetOffset().y + dr) / SCALE_FACTOR ); fprintf( aFile, "ARC %g %g %g %g %g %g\n", (-radius + pad->GetOffset().x ) / SCALE_FACTOR, (-pad->GetOffset().y + dr) / SCALE_FACTOR, (radius + pad->GetOffset().x ) / SCALE_FACTOR, (-pad->GetOffset().y + dr) / SCALE_FACTOR, pad->GetOffset().x / SCALE_FACTOR, (-pad->GetOffset().y + dr) / SCALE_FACTOR ); fprintf( aFile, "LINE %g %g %g %g\n", (radius + pad->GetOffset().x) / SCALE_FACTOR, (-pad->GetOffset().y + dr) / SCALE_FACTOR, (radius + pad->GetOffset().x) / SCALE_FACTOR, (-pad->GetOffset().y - dr) / SCALE_FACTOR ); fprintf( aFile, "ARC %g %g %g %g %g %g\n", (radius + pad->GetOffset().x) / SCALE_FACTOR, (-pad->GetOffset().y - dr) / SCALE_FACTOR, (-radius + pad->GetOffset().x) / SCALE_FACTOR, (-pad->GetOffset().y - dr) / SCALE_FACTOR, pad->GetOffset().x / SCALE_FACTOR, (-pad->GetOffset().y - dr) / SCALE_FACTOR ); } } break; case PAD_SHAPE_TRAPEZOID: fprintf( aFile, " POLYGON %g\n", pad->GetDrillSize().x / SCALE_FACTOR ); // XXX TO BE IMPLEMENTED! and I don't know if it could be actually imported by something break; } } fputs( "\n$ENDPADS\n\n", aFile ); // Now emit the padstacks definitions, using the combined layer masks fputs( "$PADSTACKS\n", aFile ); // Via padstacks for( unsigned i = 0; i < viastacks.size(); i++ ) { VIA* via = viastacks[i]; LSET mask = via->GetLayerSet() & master_layermask; fprintf( aFile, "PADSTACK VIA%d.%d.%s %g\n", via->GetWidth(), via->GetDrillValue(), fmt_mask( mask ).c_str(), via->GetDrillValue() / SCALE_FACTOR ); for( LSEQ seq = mask.Seq( gc_seq, DIM( gc_seq ) ); seq; ++seq ) { LAYER_ID layer = *seq; fprintf( aFile, "PAD V%d.%d.%s %s 0 0\n", via->GetWidth(), via->GetDrillValue(), fmt_mask( mask ).c_str(), GenCADLayerName( cu_count, layer ).c_str() ); } } /* Component padstacks * CAM350 don't apply correctly the FLIP semantics for padstacks, i.e. doesn't * swap the top and bottom layers... so I need to define the shape as MIRRORX * and define a separate 'flipped' padstack... until it appears yet another * noncompliant importer */ for( unsigned i = 1; i < padstacks.size(); i++ ) { D_PAD* pad = padstacks[i]; // Straight padstack fprintf( aFile, "PADSTACK PAD%u %g\n", i, pad->GetDrillSize().x / SCALE_FACTOR ); LSET pad_set = pad->GetLayerSet() & master_layermask; // the special gc_seq for( LSEQ seq = pad_set.Seq( gc_seq, DIM( gc_seq ) ); seq; ++seq ) { LAYER_ID layer = *seq; fprintf( aFile, "PAD P%u %s 0 0\n", i, GenCADLayerName( cu_count, layer ).c_str() ); } // Flipped padstack fprintf( aFile, "PADSTACK PAD%uF %g\n", i, pad->GetDrillSize().x / SCALE_FACTOR ); // the normal LAYER_ID sequence is inverted from gc_seq[] for( LSEQ seq = pad_set.Seq(); seq; ++seq ) { LAYER_ID layer = *seq; fprintf( aFile, "PAD P%u %s 0 0\n", i, GenCADLayerNameFlipped( cu_count, layer ).c_str() ); } } fputs( "$ENDPADSTACKS\n\n", aFile ); }
void EXCELLON_WRITER::BuildHolesList( LAYER_PAIR aLayerPair, bool aGenerateNPTH_list ) { HOLE_INFO new_hole; m_holeListBuffer.clear(); m_toolListBuffer.clear(); wxASSERT( aLayerPair.first < aLayerPair.second ); // fix the caller // build hole list for vias if( ! aGenerateNPTH_list ) // vias are always plated ! { for( VIA* via = GetFirstVia( m_pcb->m_Track ); via; via = GetFirstVia( via->Next() ) ) { int hole_sz = via->GetDrillValue(); if( hole_sz == 0 ) // Should not occur. continue; new_hole.m_Tool_Reference = -1; // Flag value for Not initialized new_hole.m_Hole_Orient = 0; new_hole.m_Hole_Diameter = hole_sz; new_hole.m_Hole_NotPlated = false; 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() returns params with m_Hole_Bottom_Layer > m_Hole_Top_Layer // Remember: top layer = 0 and bottom layer = 31 for through hole vias // Any captured via should be from aLayerPair.first to aLayerPair.second exactly. if( new_hole.m_Hole_Top_Layer != aLayerPair.first || new_hole.m_Hole_Bottom_Layer != aLayerPair.second ) continue; m_holeListBuffer.push_back( new_hole ); } } if( aLayerPair == LAYER_PAIR( F_Cu, B_Cu ) ) { // add holes for thru hole pads for( MODULE* module = m_pcb->m_Modules; module; module = module->Next() ) { for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() ) { if( !m_merge_PTH_NPTH ) { if( !aGenerateNPTH_list && pad->GetAttribute() == PAD_ATTRIB_HOLE_NOT_PLATED ) continue; if( aGenerateNPTH_list && pad->GetAttribute() != PAD_ATTRIB_HOLE_NOT_PLATED ) continue; } if( pad->GetDrillSize().x == 0 ) continue; new_hole.m_Hole_NotPlated = (pad->GetAttribute() == PAD_ATTRIB_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_SHAPE_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 = B_Cu; new_hole.m_Hole_Top_Layer = F_Cu; // pad holes are through holes m_holeListBuffer.push_back( new_hole ); } } } // Sort holes per increasing diameter value sort( m_holeListBuffer.begin(), m_holeListBuffer.end(), CmpHoleSettings ); // build the tool list int last_hole = -1; // Set to not initialized (this is a value not used // for m_holeListBuffer[ii].m_Hole_Diameter) bool last_notplated_opt = false; DRILL_TOOL new_tool( 0, false ); unsigned jj; for( unsigned ii = 0; ii < m_holeListBuffer.size(); ii++ ) { if( m_holeListBuffer[ii].m_Hole_Diameter != last_hole || m_holeListBuffer[ii].m_Hole_NotPlated != last_notplated_opt ) { new_tool.m_Diameter = m_holeListBuffer[ii].m_Hole_Diameter; new_tool.m_Hole_NotPlated = m_holeListBuffer[ii].m_Hole_NotPlated; m_toolListBuffer.push_back( new_tool ); last_hole = new_tool.m_Diameter; last_notplated_opt = new_tool.m_Hole_NotPlated; } 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++; } }
bool PCB_EDIT_FRAME::SetTrackSegmentWidth( TRACK* aTrackItem, PICKED_ITEMS_LIST* aItemsListPicker, bool aUseNetclassValue ) { /* Modify one track segment width or one via diameter and drill (using DRC control). * Basic function used by other routines when editing tracks or vias * aTrackItem = the track segment or via to modify * aItemsListPicker = the list picker to use for an undo command (can be NULL) * aUseNetclassValue = true to use NetClass value, false to use BOARD::m_designSettings value * return true if done, false if no not change (due to DRC error) */ int initial_width, new_width; int initial_drill = -1,new_drill = -1; bool change_ok = false; NETINFO_ITEM* net = NULL; if( aUseNetclassValue ) net = aTrackItem->GetNet(); initial_width = aTrackItem->GetWidth(); if( net ) new_width = net->GetTrackWidth(); else new_width = GetDesignSettings().GetCurrentTrackWidth(); if( aTrackItem->Type() == PCB_VIA_T ) { const VIA *via = static_cast<const VIA *>( aTrackItem ); // Micro vias have a size only defined in their netclass // (no specific values defined by a table of specific value) // Ensure the netclass is accessible: if( via->GetViaType() == VIA_MICROVIA && net == NULL ) net = aTrackItem->GetNet(); // Get the draill value, regardless it is default or specific initial_drill = via->GetDrillValue(); if( net ) { new_width = net->GetViaSize(); new_drill = net->GetViaDrillSize(); } else { new_width = GetDesignSettings().GetCurrentViaSize(); new_drill = GetDesignSettings().GetCurrentViaDrill(); } if( via->GetViaType() == VIA_MICROVIA ) { if( net ) { new_width = net->GetMicroViaSize(); new_drill = net->GetMicroViaDrillSize(); } else { // Should not occur } } // Old versions set a drill value <= 0, when the default netclass it used // but it could be better to set the drill value to the actual value // to avoid issues for existing vias, if the default drill value is modified // in the netclass, and not in current vias. if( via->GetDrill() <= 0 ) // means default netclass drill value used { initial_drill = -1; // Force drill vias re-initialization } } aTrackItem->SetWidth( new_width ); // make a DRC test because the new size is bigger than the old size if( initial_width < new_width ) { int diagdrc = OK_DRC; if( g_Drc_On ) diagdrc = m_drc->Drc( aTrackItem, GetBoard()->m_Track ); if( diagdrc == OK_DRC ) change_ok = true; } else if( initial_width > new_width ) { change_ok = true; } else if( (aTrackItem->Type() == PCB_VIA_T) ) { // if a via has its drill value changed, force change if( initial_drill != new_drill ) change_ok = true; } if( change_ok ) { OnModify(); if( aItemsListPicker ) { aTrackItem->SetWidth( initial_width ); ITEM_PICKER picker( aTrackItem, UR_CHANGED ); picker.SetLink( aTrackItem->Clone() ); aItemsListPicker->PushItem( picker ); aTrackItem->SetWidth( new_width ); if( aTrackItem->Type() == PCB_VIA_T ) { // Set new drill value. Note: currently microvias have only a default drill value VIA *via = static_cast<VIA *>( aTrackItem ); if( new_drill > 0 ) via->SetDrill( new_drill ); else via->SetDrillDefault(); } } } else { aTrackItem->SetWidth( initial_width ); } return change_ok; }
// Sort vias for uniqueness static int ViaSort( const void* aRefptr, const void* aObjptr ) { VIA* padref = *(VIA**) aRefptr; VIA* padcmp = *(VIA**) aObjptr; if( padref->GetWidth() != padcmp->GetWidth() ) return padref->GetWidth() - padcmp->GetWidth(); if( padref->GetDrillValue() != padcmp->GetDrillValue() ) return padref->GetDrillValue() - padcmp->GetDrillValue(); if( padref->GetLayerSet() != padcmp->GetLayerSet() ) return padref->GetLayerSet().FmtBin().compare( padcmp->GetLayerSet().FmtBin() ); return 0; }
void BOARD_ITEM::SwapData( BOARD_ITEM* aImage ) { if( aImage == NULL ) return; // Remark: to create images of edited items to undo, we are using Clone method // which can duplication of items foe copy, but does not clone all members // mainly pointers in chain and time stamp, which is set to new, unique value. // So we have to use the current values of these parameters. EDA_ITEM * pnext = Next(); EDA_ITEM * pback = Back(); DHEAD* mylist = m_List; time_t timestamp = GetTimeStamp(); switch( Type() ) { case PCB_MODULE_T: { MODULE* tmp = (MODULE*) aImage->Clone(); ( (MODULE*) aImage )->Copy( (MODULE*) this ); ( (MODULE*) this )->Copy( tmp ); delete tmp; } break; case PCB_ZONE_AREA_T: { ZONE_CONTAINER* tmp = (ZONE_CONTAINER*) aImage->Clone(); ( (ZONE_CONTAINER*) aImage )->Copy( (ZONE_CONTAINER*) this ); ( (ZONE_CONTAINER*) this )->Copy( tmp ); delete tmp; } break; case PCB_LINE_T: std::swap( *((DRAWSEGMENT*)this), *((DRAWSEGMENT*)aImage) ); break; case PCB_TRACE_T: case PCB_VIA_T: { TRACK* track = (TRACK*) this; TRACK* image = (TRACK*) aImage; std::swap(track->m_Layer, image->m_Layer ); // swap start, end, width and shape for track and image. wxPoint exchp = track->GetStart(); track->SetStart( image->GetStart() ); image->SetStart( exchp ); exchp = track->GetEnd(); track->SetEnd( image->GetEnd() ); image->SetEnd( exchp ); int atmp = track->GetWidth(); track->SetWidth( image->GetWidth() ); image->SetWidth( atmp ); if( Type() == PCB_VIA_T ) { VIA *via = static_cast<VIA*>( this ); VIA *viaimage = static_cast<VIA*>( aImage ); VIATYPE_T viatmp = via->GetViaType(); via->SetViaType( viaimage->GetViaType() ); viaimage->SetViaType( viatmp ); int drilltmp = via->GetDrillValue(); if( via->IsDrillDefault() ) drilltmp = -1; int itmp = viaimage->GetDrillValue(); if( viaimage->IsDrillDefault() ) itmp = -1; std::swap(itmp, drilltmp ); if( drilltmp > 0 ) via->SetDrill( drilltmp ); else via->SetDrillDefault(); if( itmp > 0 ) viaimage->SetDrill( itmp ); else viaimage->SetDrillDefault(); } } break; case PCB_TEXT_T: std::swap( *((TEXTE_PCB*)this), *((TEXTE_PCB*)aImage) ); break; case PCB_TARGET_T: std::swap( *((PCB_TARGET*)this), *((PCB_TARGET*)aImage) ); break; case PCB_DIMENSION_T: std::swap( *((DIMENSION*)this), *((DIMENSION*)aImage) ); break; case PCB_ZONE_T: default: wxLogMessage( wxT( "SwapData() error: unexpected type %d" ), Type() ); break; } // Restore pointers and time stamp, to be sure they are not broken Pnext = pnext; Pback = pback; m_List = mylist; SetTimeStamp( timestamp ); }
bool DIALOG_TRACK_VIA_PROPERTIES::TransferDataFromWindow() { auto connectivity = m_frame->GetBoard()->GetConnectivity(); int newNetCode = m_netSelector->GetSelectedNetcode(); std::vector<D_PAD*> changingPads; if ( !m_netSelector->IsIndeterminate() ) { std::set<D_PAD*> connectedPads; for( auto& item : m_items ) { const KICAD_T ourTypes[] = { PCB_TRACE_T, PCB_PAD_T, PCB_VIA_T, PCB_MODULE_T, EOT }; auto connectedItems = connectivity->GetConnectedItems( static_cast<BOARD_CONNECTED_ITEM*>( item ), ourTypes, true ); for ( auto citem : connectedItems ) { if( citem->Type() == PCB_PAD_T ) { connectedPads.insert( static_cast<D_PAD*>( citem ) ); } } } for( D_PAD* pad : connectedPads ) { if( pad->GetNetCode() != newNetCode ) changingPads.push_back( pad ); } } // Run validations: if( changingPads.size() ) { if( !confirmPadChange( changingPads ) ) return false; } if( m_vias ) { if( !m_viaDiameter.Validate( GEOMETRY_MIN_SIZE, INT_MAX ) || !m_viaDrill.Validate( GEOMETRY_MIN_SIZE, INT_MAX ) ) return false; if( m_ViaDiameterCtrl->IsEnabled() && !m_viaDiameter.IsIndeterminate() && m_ViaDrillCtrl->IsEnabled() && !m_viaDrill.IsIndeterminate() && m_viaDiameter.GetValue() <= m_viaDrill.GetValue() ) { DisplayError( GetParent(), _( "Via drill size must be smaller than via diameter" ) ); m_ViaDrillCtrl->SelectAll(); m_ViaDrillCtrl->SetFocus(); return false; } if( m_ViaStartLayer->GetLayerSelection() != UNDEFINED_LAYER && m_ViaStartLayer->GetLayerSelection() == m_ViaEndLayer->GetLayerSelection() ) { DisplayError( GetParent(), _( "Via start layer and end layer cannot be the same" ) ); return false; } } if( m_tracks ) { if( !m_trackWidth.Validate( GEOMETRY_MIN_SIZE, INT_MAX ) ) return false; } // If we survived that, then save the changes: bool changeLock = m_lockedCbox->Get3StateValue() != wxCHK_UNDETERMINED; bool setLock = m_lockedCbox->Get3StateValue() == wxCHK_CHECKED; for( auto item : m_items ) { m_commit.Modify( item ); switch( item->Type() ) { case PCB_TRACE_T: { wxASSERT( m_tracks ); TRACK* t = static_cast<TRACK*>( item ); if( !m_trackStartX.IsIndeterminate() ) t->SetStart( wxPoint( m_trackStartX.GetValue(), t->GetStart().y ) ); if( !m_trackStartY.IsIndeterminate() ) t->SetStart( wxPoint( t->GetStart().x, m_trackStartY.GetValue() ) ); if( !m_trackEndX.IsIndeterminate() ) t->SetEnd( wxPoint( m_trackEndX.GetValue(), t->GetEnd().y ) ); if( !m_trackEndY.IsIndeterminate() ) t->SetEnd( wxPoint( t->GetEnd().x, m_trackEndY.GetValue() ) ); if( m_trackNetclass->IsChecked() ) t->SetWidth( t->GetNetClass()->GetTrackWidth() ); else if( !m_trackWidth.IsIndeterminate() ) t->SetWidth( m_trackWidth.GetValue() ); LAYER_NUM layer = m_TrackLayerCtrl->GetLayerSelection(); if( layer != UNDEFINED_LAYER ) t->SetLayer( (PCB_LAYER_ID) layer ); if( changeLock ) t->SetLocked( setLock ); if ( !m_netSelector->IsIndeterminate() ) t->SetNetCode( m_netSelector->GetSelectedNetcode() ); break; } case PCB_VIA_T: { wxASSERT( m_vias ); VIA* v = static_cast<VIA*>( item ); if( !m_viaX.IsIndeterminate() ) v->SetPosition( wxPoint( m_viaX.GetValue(), v->GetPosition().y ) ); if( !m_viaY.IsIndeterminate() ) v->SetPosition( wxPoint( v->GetPosition().x, m_viaY.GetValue() ) ); if( m_ViaTypeChoice->GetSelection() != 3) { switch( m_ViaTypeChoice->GetSelection() ) { default: case 0: v->SetViaType( VIA_THROUGH ); v->SanitizeLayers(); break; case 1: v->SetViaType( VIA_MICROVIA ); break; case 2: v->SetViaType( VIA_BLIND_BURIED ); break; } } auto startLayer = static_cast<PCB_LAYER_ID>( m_ViaStartLayer->GetLayerSelection() ); auto endLayer = static_cast<PCB_LAYER_ID>( m_ViaEndLayer->GetLayerSelection() ); if (startLayer != UNDEFINED_LAYER ) v->SetTopLayer( startLayer ); if (endLayer != UNDEFINED_LAYER ) v->SetBottomLayer( endLayer ); v->SanitizeLayers(); if( m_viaNetclass->IsChecked() ) { switch( v->GetViaType() ) { default: wxFAIL_MSG("Unhandled via type"); // fall through case VIA_THROUGH: case VIA_BLIND_BURIED: v->SetWidth( v->GetNetClass()->GetViaDiameter() ); v->SetDrill( v->GetNetClass()->GetViaDrill() ); break; case VIA_MICROVIA: v->SetWidth( v->GetNetClass()->GetuViaDiameter() ); v->SetDrill( v->GetNetClass()->GetuViaDrill() ); break; } } else { if( !m_viaDiameter.IsIndeterminate() ) v->SetWidth( m_viaDiameter.GetValue() ); if( !m_viaDrill.IsIndeterminate() ) v->SetDrill( m_viaDrill.GetValue() ); } if ( !m_netSelector->IsIndeterminate() ) v->SetNetCode( m_netSelector->GetSelectedNetcode() ); if( changeLock ) v->SetLocked( setLock ); break; } default: wxASSERT( false ); break; } } if ( !m_netSelector->IsIndeterminate() ) { // Commit::Push() will rebuild connectivitiy propagating nets from connected pads // outwards. We therefore have to update the connected pads in order for the net // change to "stick". for( D_PAD* pad : changingPads ) { m_commit.Modify( pad ); pad->SetNetCode( m_netSelector->GetSelectedNetcode() ); } } m_commit.Push( _( "Edit track/via properties" ) ); return true; }
bool DIALOG_TRACK_VIA_PROPERTIES::Apply() { if( !check() ) return false; for( int i = 0; i < m_items.Size(); ++i ) { BOARD_ITEM* item = m_items.Item<BOARD_ITEM>( i ); switch( item->Type() ) { case PCB_TRACE_T: { assert( m_tracks ); TRACK* t = static_cast<TRACK*>( item ); if( m_trackStartX.Valid() || m_trackStartY.Valid() ) { wxPoint start = t->GetStart(); if( m_trackStartX.Valid() ) start.x = m_trackStartX.GetValue(); if( m_trackStartY.Valid() ) start.y = m_trackStartY.GetValue(); t->SetStart( start ); } if( m_trackEndX.Valid() || m_trackEndY.Valid() ) { wxPoint end = t->GetEnd(); if( m_trackEndX.Valid() ) end.x = m_trackEndX.GetValue(); if( m_trackEndY.Valid() ) end.y = m_trackEndY.GetValue(); t->SetEnd( end ); } if( m_trackNetclass->IsChecked() ) { t->SetWidth( t->GetNetClass()->GetTrackWidth() ); } else if( m_trackWidth.Valid() ) { t->SetWidth( m_trackWidth.GetValue() ); } LAYER_NUM layer = m_TrackLayerCtrl->GetLayerSelection(); if( layer != UNDEFINED_LAYER ) t->SetLayer( (LAYER_ID) layer ); break; } case PCB_VIA_T: { assert( m_vias ); VIA* v = static_cast<VIA*>( item ); if( m_viaX.Valid() || m_viaY.Valid() ) { wxPoint pos = v->GetPosition(); if( m_viaX.Valid() ) pos.x = m_viaX.GetValue(); if( m_viaY.Valid() ) pos.y = m_viaY.GetValue(); v->SetPosition( pos ); } if( m_viaNetclass->IsChecked() ) { v->SetWidth( v->GetNetClass()->GetViaDiameter() ); v->SetDrill( v->GetNetClass()->GetViaDrill() ); } else { if( m_viaDiameter.Valid() ) v->SetWidth( m_viaDiameter.GetValue() ); if( m_viaDrill.Valid() ) v->SetDrill( m_viaDrill.GetValue() ); } break; } default: assert( false ); break; } } return true; }
/** * Function SetTrackSegmentWidth * Modify one track segment width or one via diameter and drill (using DRC control). * Basic routine used by other routines when editing tracks or vias * @param aTrackItem = the track segment or via to modify * @param aItemsListPicker = the list picker to use for an undo command (can be NULL) * @param aUseNetclassValue = true to use NetClass value, false to use BOARD::m_designSettings value * @return true if done, false if no not change (because DRC error) */ bool PCB_EDIT_FRAME::SetTrackSegmentWidth( TRACK* aTrackItem, PICKED_ITEMS_LIST* aItemsListPicker, bool aUseNetclassValue ) { int initial_width, new_width; int initial_drill = -1,new_drill = -1; bool change_ok = false; NETINFO_ITEM* net = NULL; if( aUseNetclassValue ) net = aTrackItem->GetNet(); initial_width = aTrackItem->GetWidth(); if( net ) new_width = net->GetTrackWidth(); else new_width = GetDesignSettings().GetCurrentTrackWidth(); if( aTrackItem->Type() == PCB_VIA_T ) { const VIA *via = static_cast<const VIA *>( aTrackItem ); if( !via->IsDrillDefault() ) initial_drill = via->GetDrillValue(); if( net ) { new_width = net->GetViaSize(); } else { new_width = GetDesignSettings().GetCurrentViaSize(); new_drill = GetDesignSettings().GetCurrentViaDrill(); } if( via->GetViaType() == VIA_MICROVIA ) { if( net ) new_width = net->GetMicroViaSize(); else new_width = GetDesignSettings().GetCurrentMicroViaSize(); } } aTrackItem->SetWidth( new_width ); // make a DRC test because the new size is bigger than the old size if( initial_width < new_width ) { int diagdrc = OK_DRC; if( g_Drc_On ) diagdrc = m_drc->Drc( aTrackItem, GetBoard()->m_Track ); if( diagdrc == OK_DRC ) change_ok = true; } else if( initial_width > new_width ) { change_ok = true; } else if( (aTrackItem->Type() == PCB_VIA_T) && (initial_drill != new_drill) ) { // if new width == initial_width: do nothing, unless a via has its drill value changed change_ok = true; } if( change_ok ) { OnModify(); if( aItemsListPicker ) { aTrackItem->SetWidth( initial_width ); ITEM_PICKER picker( aTrackItem, UR_CHANGED ); picker.SetLink( aTrackItem->Clone() ); aItemsListPicker->PushItem( picker ); aTrackItem->SetWidth( new_width ); if( aTrackItem->Type() == PCB_VIA_T ) { // Set new drill value. Note: currently microvias have only a default drill value VIA *via = static_cast<VIA *>( aTrackItem ); if( new_drill > 0 ) via->SetDrill( new_drill ); else via->SetDrillDefault(); } } } else { aTrackItem->SetWidth( initial_width ); } return change_ok; }
void EXCELLON_WRITER::BuildHolesList( int aFirstLayer, int aLastLayer, bool aExcludeThroughHoles, bool aGenerateNPTH_list, bool aMerge_PTH_NPTH ) { HOLE_INFO new_hole; int hole_value; m_holeListBuffer.clear(); m_toolListBuffer.clear(); if( (aFirstLayer >= 0) && (aLastLayer >= 0) ) { if( aFirstLayer > aLastLayer ) std::swap( aFirstLayer, aLastLayer ); } if ( aGenerateNPTH_list && aMerge_PTH_NPTH ) { return; } // build hole list for vias if( ! aGenerateNPTH_list ) // vias are always plated ! { for( VIA* via = GetFirstVia( m_pcb->m_Track ); via; via = GetFirstVia( via->Next() ) ) { hole_value = via->GetDrillValue(); if( hole_value == 0 ) // Should not occur. 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 // Remember: top layer = 0 and bottom layer = 31 for through hole vias // the via should be at least from aFirstLayer to aLastLayer if( (new_hole.m_Hole_Top_Layer > aFirstLayer) && (aFirstLayer >= 0) ) continue; // via above the first layer if( (new_hole.m_Hole_Bottom_Layer < aLastLayer) && (aLastLayer >= 0) ) continue; // via below the last layer if( aExcludeThroughHoles && (new_hole.m_Hole_Bottom_Layer == B_Cu) && (new_hole.m_Hole_Top_Layer == F_Cu) ) 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 && ! aMerge_PTH_NPTH ) 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 = B_Cu; new_hole.m_Hole_Top_Layer = F_Cu;// 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++; } }
void PCB_PAD::AddToBoard() { PCB_PAD_SHAPE* padShape; int i; int width = 0; int height = 0; if( m_objType == wxT( 'V' ) ) // via { // choose one of the shapes for( i = 0; i < (int) m_shapes.GetCount(); i++ ) { padShape = m_shapes[i]; if( padShape->m_width > 0 && padShape->m_height > 0 ) { if( padShape->m_KiCadLayer == F_Cu || padShape->m_KiCadLayer == B_Cu ) { width = padShape->m_width; height = padShape->m_height; break; } } } if( width == 0 || height == 0 ) THROW_IO_ERROR( wxT( "pad or via with zero size" ) ); if( IsCopperLayer( m_KiCadLayer ) ) { VIA* via = new VIA( m_board ); m_board->m_Track.Append( via ); via->SetTimeStamp( 0 ); via->SetPosition( wxPoint( m_positionX, m_positionY ) ); via->SetEnd( wxPoint( m_positionX, m_positionY ) ); via->SetWidth( height ); via->SetViaType( VIA_THROUGH ); via->SetLayerPair( F_Cu, B_Cu ); via->SetDrill( m_hole ); via->SetLayer( m_KiCadLayer ); via->SetNetCode( m_netCode ); } } else // pad { MODULE* module = new MODULE( m_board ); m_board->Add( module, ADD_APPEND ); m_name.text = m_defaultPinDes; module->SetPosition( wxPoint( m_positionX, m_positionY ) ); AddToModule( module, 0, true ); } }
void BOARD_ITEM::SwapData( BOARD_ITEM* aImage ) { if( aImage == NULL ) { return; } EDA_ITEM * pnext = Next(); EDA_ITEM * pback = Back(); switch( Type() ) { case PCB_MODULE_T: { MODULE* tmp = (MODULE*) aImage->Clone(); ( (MODULE*) aImage )->Copy( (MODULE*) this ); ( (MODULE*) this )->Copy( tmp ); delete tmp; } break; case PCB_ZONE_AREA_T: { ZONE_CONTAINER* tmp = (ZONE_CONTAINER*) aImage->Clone(); ( (ZONE_CONTAINER*) aImage )->Copy( (ZONE_CONTAINER*) this ); ( (ZONE_CONTAINER*) this )->Copy( tmp ); delete tmp; } break; case PCB_LINE_T: std::swap( *((DRAWSEGMENT*)this), *((DRAWSEGMENT*)aImage) ); break; case PCB_TRACE_T: case PCB_VIA_T: { TRACK* track = (TRACK*) this; TRACK* image = (TRACK*) aImage; EXCHG(track->m_Layer, image->m_Layer ); // swap start, end, width and shape for track and image. wxPoint exchp = track->GetStart(); track->SetStart( image->GetStart() ); image->SetStart( exchp ); exchp = track->GetEnd(); track->SetEnd( image->GetEnd() ); image->SetEnd( exchp ); int atmp = track->GetWidth(); track->SetWidth( image->GetWidth() ); image->SetWidth( atmp ); if( Type() == PCB_VIA_T ) { VIA *via = static_cast<VIA*>( this ); VIA *viaimage = static_cast<VIA*>( aImage ); VIATYPE_T viatmp = via->GetViaType(); via->SetViaType( viaimage->GetViaType() ); viaimage->SetViaType( viatmp ); int drilltmp = via->GetDrillValue(); if( via->IsDrillDefault() ) drilltmp = -1; int itmp = viaimage->GetDrillValue(); if( viaimage->IsDrillDefault() ) itmp = -1; EXCHG(itmp, drilltmp ); if( drilltmp > 0 ) via->SetDrill( drilltmp ); else via->SetDrillDefault(); if( itmp > 0 ) viaimage->SetDrill( itmp ); else viaimage->SetDrillDefault(); } } break; case PCB_TEXT_T: std::swap( *((TEXTE_PCB*)this), *((TEXTE_PCB*)aImage) ); break; case PCB_TARGET_T: std::swap( *((PCB_TARGET*)this), *((PCB_TARGET*)aImage) ); break; case PCB_DIMENSION_T: std::swap( *((DIMENSION*)this), *((DIMENSION*)aImage) ); break; case PCB_ZONE_T: default: wxLogMessage( wxT( "SwapData() error: unexpected type %d" ), Type() ); break; } if( pnext != Next() || pback != Back() ) { Pnext = pnext; Pback = pback; #ifdef DEBUG wxLogMessage( wxT( "SwapData Error: %s Pnext or Pback pointers modified" ), GetClass().GetData() ); #endif } }
int PCB_EDIT_FRAME::SetTrackSegmentWidth( TRACK* aTrackItem, PICKED_ITEMS_LIST* aItemsListPicker, bool aUseNetclassValue ) { int return_code = TRACK_ACTION_NONE; int initial_width; int new_width; int initial_drill = -1; int new_drill = -1; NETINFO_ITEM* net = NULL; if( aUseNetclassValue ) net = aTrackItem->GetNet(); initial_width = aTrackItem->GetWidth(); if( net ) new_width = net->GetTrackWidth(); else new_width = GetDesignSettings().GetCurrentTrackWidth(); if( aTrackItem->Type() == PCB_VIA_T ) { const VIA *via = static_cast<const VIA *>( aTrackItem ); // Micro vias have a size only defined in their netclass // (no specific values defined by a table of specific value) // Ensure the netclass is accessible: if( via->GetViaType() == VIA_MICROVIA && net == NULL ) net = aTrackItem->GetNet(); // Get the draill value, regardless it is default or specific initial_drill = via->GetDrillValue(); if( net ) { new_width = net->GetViaSize(); new_drill = net->GetViaDrillSize(); } else { new_width = GetDesignSettings().GetCurrentViaSize(); new_drill = GetDesignSettings().GetCurrentViaDrill(); } if( via->GetViaType() == VIA_MICROVIA ) { if( net ) { new_width = net->GetMicroViaSize(); new_drill = net->GetMicroViaDrillSize(); } else { // Should not occur } } // Old versions set a drill value <= 0, when the default netclass it used // but it could be better to set the drill value to the actual value // to avoid issues for existing vias, if the default drill value is modified // in the netclass, and not in current vias. if( via->GetDrill() <= 0 ) // means default netclass drill value used { initial_drill = -1; // Force drill vias re-initialization } } aTrackItem->SetWidth( new_width ); // make a DRC test because the new size is bigger than the old size if( initial_width < new_width ) { int diagdrc = OK_DRC; return_code = TRACK_ACTION_SUCCESS; if( Settings().m_legacyDrcOn ) diagdrc = m_drc->DrcOnCreatingTrack( aTrackItem, GetBoard()->m_Track ); if( diagdrc != OK_DRC ) return_code = TRACK_ACTION_DRC_ERROR; } else if( initial_width > new_width ) { return_code = TRACK_ACTION_SUCCESS; } else if( (aTrackItem->Type() == PCB_VIA_T) ) { // if a via has its drill value changed, force change if( initial_drill != new_drill ) return_code = TRACK_ACTION_SUCCESS; } if( return_code == TRACK_ACTION_SUCCESS ) { OnModify(); if( aItemsListPicker ) { aTrackItem->SetWidth( initial_width ); ITEM_PICKER picker( aTrackItem, UR_CHANGED ); picker.SetLink( aTrackItem->Clone() ); aItemsListPicker->PushItem( picker ); aTrackItem->SetWidth( new_width ); if( aTrackItem->Type() == PCB_VIA_T ) { // Set new drill value. Note: currently microvias have only a default drill value VIA *via = static_cast<VIA *>( aTrackItem ); if( new_drill > 0 ) via->SetDrill( new_drill ); else via->SetDrillDefault(); } } } else { aTrackItem->SetWidth( initial_width ); } return return_code; }