// Compute the access code for a pad. Returns -1 if there is no copper static int compute_pad_access_code( BOARD *aPcb, LAYER_MSK aLayerMask ) { // Non-copper is not interesting here aLayerMask &= ALL_CU_LAYERS; if( aLayerMask == 0 ) return -1; // Traditional TH pad if( (aLayerMask & LAYER_FRONT) && (aLayerMask & LAYER_BACK) ) return 0; // Front SMD pad if( (aLayerMask & LAYER_FRONT) ) return 1; // Back SMD pad if( (aLayerMask & LAYER_BACK) ) return aPcb->GetCopperLayerCount(); // OK, we have an inner-layer only pad (and I have no idea about // what could be used for); anyway, find the first copper layer // it's on for (LAYER_NUM scan_layer = LAYER_N_2; scan_layer < LAYER_N_BACK; ++scan_layer) { if( GetLayerMask( scan_layer ) & aLayerMask ) return scan_layer + 1; } // This shouldn't happen return -1; }
void BOARD_DESIGN_SETTINGS::SetLayerVisibility( LAYER_NUM aLayer, bool aNewState ) { if( aNewState && IsLayerEnabled( aLayer ) ) m_VisibleLayers |= GetLayerMask( aLayer ); else m_VisibleLayers &= ~GetLayerMask( aLayer ); }
void DIALOG_LAYERS_SETUP::showSelectedLayerCheckBoxes( LAYER_MSK enabledLayers ) { for( LAYER_NUM layer=FIRST_LAYER; layer<NB_PCB_LAYERS; ++layer ) { setLayerCheckBox( layer, GetLayerMask( layer ) & enabledLayers ); } }
LAYER_MSK DIALOG_LAYERS_SETUP::getUILayerMask() { LAYER_MSK layerMaskResult = NO_LAYERS; for( LAYER_NUM layer=FIRST_LAYER; layer<NB_PCB_LAYERS; ++layer ) { wxCheckBox* ctl = getCheckBox( layer ); if( ctl->GetValue() ) { layerMaskResult |= GetLayerMask( layer ); } } return layerMaskResult; }
void BOARD_DESIGN_SETTINGS::SetCopperLayerCount( int aNewLayerCount ) { // if( aNewLayerCount < 2 ) aNewLayerCount = 2; m_CopperLayerCount = aNewLayerCount; // ensure consistency with the m_EnabledLayers member m_EnabledLayers &= ~ALL_CU_LAYERS; m_EnabledLayers |= LAYER_BACK; if( m_CopperLayerCount > 1 ) m_EnabledLayers |= LAYER_FRONT; for( LAYER_NUM ii = LAYER_N_2; ii < aNewLayerCount - 1; ++ii ) m_EnabledLayers |= GetLayerMask( ii ); }
bool BOARD_PRINTOUT_CONTROLLER::OnPrintPage( int aPage ) { #ifdef PCBNEW LAYER_NUM layers_count = NB_PCB_LAYERS; #else LAYER_NUM layers_count = NB_LAYERS; #endif LAYER_MSK mask_layer = m_PrintParams.m_PrintMaskLayer; // compute layer mask from page number if we want one page per layer if( m_PrintParams.m_OptionPrintPage == 0 ) // One page per layer { int jj; LAYER_NUM ii; for( ii = FIRST_LAYER, jj = 0; ii < layers_count; ++ii ) { LAYER_MSK mask = GetLayerMask( ii ); if( mask_layer & mask ) jj++; if( jj == aPage ) { m_PrintParams.m_PrintMaskLayer = mask; break; } } } if( m_PrintParams.m_PrintMaskLayer == 0 ) return false; #ifdef PCBNEW // In Pcbnew we can want the layer EDGE always printed if( m_PrintParams.m_Flags == 1 ) m_PrintParams.m_PrintMaskLayer |= EDGE_LAYER; #endif DrawPage(); m_PrintParams.m_PrintMaskLayer = mask_layer; return true; }
int DIALOG_PRINT_USING_PRINTER::SetLayerMaskFromListSelection() /**************************************************************/ { int page_count = 0; s_Parameters.m_PrintMaskLayer = NO_LAYERS; for( LAYER_NUM ii = FIRST_LAYER; ii < NB_GERBER_LAYERS; ++ii ) { if( m_BoxSelectLayer[ii]->IsChecked() ) { page_count++; s_Parameters.m_PrintMaskLayer |= GetLayerMask( ii ); } } s_Parameters.m_PageCount = page_count; return page_count; }
// Reload the Layers void PCB_LAYER_BOX_SELECTOR::Resync() { Clear(); static DECLARE_LAYERS_ORDER_LIST( layertranscode ); static DECLARE_LAYERS_HOTKEY( layerhk ); // Tray to fix a minimum width fot the BitmapComboBox int minwidth = 80, h; wxClientDC dc( GetParent() ); // The DC for "this" is not always initialized #define BM_SIZE 14 for( LAYER_NUM i = FIRST_LAYER; i < NB_LAYERS; ++i ) { wxBitmap layerbmp( BM_SIZE, BM_SIZE ); wxString layername; LAYER_NUM layerid = i; if( m_layerorder ) layerid = layertranscode[i]; if( ! IsLayerEnabled( layerid ) ) continue; if( ( m_layerMaskDisable & GetLayerMask( layerid ) ) ) continue; SetBitmapLayer( layerbmp, layerid ); layername = GetLayerName( layerid ); if( m_layerhotkeys && m_hotkeys != NULL ) layername = AddHotkeyName( layername, m_hotkeys, layerhk[layerid], IS_COMMENT ); Append( layername, layerbmp, (void*)(intptr_t) layerid ); int w; dc.GetTextExtent ( layername, &w, &h ); minwidth = std::max( minwidth, w ); } minwidth += BM_SIZE + 35; // Take in account the bitmap size and margins SetMinSize( wxSize( minwidth, -1 ) ); }
void Scene::Render() { for ( Layer* pLayer : mLayerList ) { if ( pLayer->GetLayerDepth() & GetLayerMask() ) { glClear(GL_DEPTH_BUFFER_BIT); glLoadIdentity(); Vector3 cPos = GetCamera()->GetPosition(); Vector3 cTgt = GetCamera()->GetTargetPosition(); if ( pLayer->IsBackground() ) { Vector3 cDiff = cPos - cTgt; gluLookAt(cDiff.x, cDiff.y, cDiff.z, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); } else { gluLookAt(cPos.x, cPos.y, cPos.z, cTgt.x, cTgt.y, cTgt.z, 0.0f, 1.0f, 0.0f); } pLayer->Render(); } } for ( Layer* pLayerToDelete : mLayersToDelete ) { for ( LayerList::iterator it = mLayerList.begin(), itEnd = mLayerList.end(); it != itEnd; ) { if ( *it == pLayerToDelete ) { delete *it; it = mLayerList.erase( it ); } else it++; } } mLayersToDelete.clear(); }
void PCB_LAYER_WIDGET::OnLayerVisible( LAYER_NUM aLayer, bool isVisible, bool isFinal ) { BOARD* brd = myframe->GetBoard(); LAYER_MSK visibleLayers = brd->GetVisibleLayers(); if( isVisible ) visibleLayers |= GetLayerMask( aLayer ); else visibleLayers &= ~GetLayerMask( aLayer ); brd->SetVisibleLayers( visibleLayers ); EDA_DRAW_PANEL_GAL* galCanvas = myframe->GetGalCanvas(); if( galCanvas ) { KIGFX::VIEW* view = galCanvas->GetView(); view->SetLayerVisible( aLayer, isVisible ); } if( isFinal ) myframe->GetCanvas()->Refresh(); }
void DIALOG_SVG_PRINT::initDialog() { m_board = m_parent->GetBoard(); if( m_config ) { m_config->Read( PLOTSVGMODECOLOR_KEY, &m_printBW, false ); long ltmp; m_config->Read( PLOTSVGPAGESIZEOPT_KEY, <mp, 0 ); m_rbSvgPageSizeOpt->SetSelection( ltmp ); m_config->Read( PLOTSVGPLOT_BRD_EDGE_KEY, <mp, 1 ); m_PrintBoardEdgesCtrl->SetValue( ltmp ); } m_outputDirectory = m_parent->GetPlotSettings().GetOutputDirectory(); m_outputDirectoryName->SetValue( m_outputDirectory ); if( m_printBW ) m_ModeColorOption->SetSelection( 1 ); else m_ModeColorOption->SetSelection( 0 ); m_printMirrorOpt->SetValue( m_printMirror ); m_rbFileOpt->SetSelection( m_oneFileOnly ? 1 : 0 ); AddUnitSymbol( *m_TextPenWidth, g_UserUnit ); m_DialogDefaultPenSize->SetValue( ReturnStringFromValue( g_UserUnit, g_DrawDefaultLineThickness ) ); // Create layers list LAYER_NUM layer; for( layer = FIRST_LAYER; layer < NB_PCB_LAYERS; ++layer ) { if( !m_board->IsLayerEnabled( layer ) ) m_boxSelectLayer[layer] = NULL; else m_boxSelectLayer[layer] = new wxCheckBox( this, -1, m_board->GetLayerName( layer ) ); } // Add wxCheckBoxes in layers lists dialog // List layers in same order than in setup layers dialog // (Front or Top to Back or Bottom) DECLARE_LAYERS_ORDER_LIST( layersOrder ); for( LAYER_NUM layer_idx = FIRST_LAYER; layer_idx < NB_PCB_LAYERS; ++layer_idx ) { layer = layersOrder[layer_idx]; wxASSERT( layer < NB_PCB_LAYERS ); if( m_boxSelectLayer[layer] == NULL ) continue; LAYER_MSK mask = GetLayerMask( layer ); if( mask & s_SelectedLayers ) m_boxSelectLayer[layer]->SetValue( true ); if( layer <= LAST_COPPER_LAYER ) m_CopperLayersBoxSizer->Add( m_boxSelectLayer[layer], 0, wxGROW | wxALL, 1 ); else m_TechnicalBoxSizer->Add( m_boxSelectLayer[layer], 0, wxGROW | wxALL, 1 ); } if( m_config ) { wxString layerKey; for( LAYER_NUM layer = FIRST_LAYER; layer < NB_PCB_LAYERS; ++layer ) { bool option; if( m_boxSelectLayer[layer] == NULL ) continue; layerKey.Printf( OPTKEY_LAYERBASE, layer ); if( m_config->Read( layerKey, &option ) ) m_boxSelectLayer[layer]->SetValue( option ); } } }
void PCB_EDIT_FRAME::Block_SelectItems() { int layerMask; GetScreen()->m_BlockLocate.Normalize(); PICKED_ITEMS_LIST* itemsList = &GetScreen()->m_BlockLocate.m_ItemsSelection; ITEM_PICKER picker( NULL, UR_UNSPECIFIED ); // Add modules if( blockIncludeModules ) { for( MODULE* module = m_Pcb->m_Modules; module != NULL; module = module->Next() ) { int layer = module->GetLayer(); if( module->HitTest( GetScreen()->m_BlockLocate ) && ( !module->IsLocked() || blockIncludeLockedModules ) ) { if( blockIncludeItemsOnInvisibleLayers || m_Pcb->IsModuleLayerVisible( layer ) ) { picker.SetItem ( module ); itemsList->PushItem( picker ); } } } } // Add tracks and vias if( blockIncludeTracks ) { for( TRACK* pt_segm = m_Pcb->m_Track; pt_segm != NULL; pt_segm = pt_segm->Next() ) { if( pt_segm->HitTest( GetScreen()->m_BlockLocate ) ) { if( blockIncludeItemsOnInvisibleLayers || m_Pcb->IsLayerVisible( pt_segm->GetLayer() ) ) { picker.SetItem ( pt_segm ); itemsList->PushItem( picker ); } } } } // Add graphic items layerMask = EDGE_LAYER; if( blockIncludeItemsOnTechLayers ) layerMask = ALL_LAYERS; if( !blockIncludeBoardOutlineLayer ) layerMask &= ~EDGE_LAYER; for( BOARD_ITEM* PtStruct = m_Pcb->m_Drawings; PtStruct != NULL; PtStruct = PtStruct->Next() ) { if( !m_Pcb->IsLayerVisible( PtStruct->GetLayer() ) && ! blockIncludeItemsOnInvisibleLayers) continue; bool select_me = false; switch( PtStruct->Type() ) { case PCB_LINE_T: if( (GetLayerMask( PtStruct->GetLayer() ) & layerMask) == 0 ) break; if( !PtStruct->HitTest( GetScreen()->m_BlockLocate ) ) break; select_me = true; // This item is in bloc: select it break; case PCB_TEXT_T: if( !blockIncludePcbTexts ) break; if( !PtStruct->HitTest( GetScreen()->m_BlockLocate ) ) break; select_me = true; // This item is in bloc: select it break; case PCB_TARGET_T: if( ( GetLayerMask( PtStruct->GetLayer() ) & layerMask ) == 0 ) break; if( !PtStruct->HitTest( GetScreen()->m_BlockLocate ) ) break; select_me = true; // This item is in bloc: select it break; case PCB_DIMENSION_T: if( ( GetLayerMask( PtStruct->GetLayer() ) & layerMask ) == 0 ) break; if( !PtStruct->HitTest( GetScreen()->m_BlockLocate ) ) break; select_me = true; // This item is in bloc: select it break; default: break; } if( select_me ) { picker.SetItem ( PtStruct ); itemsList->PushItem( picker ); } } // Add zones if( blockIncludeZones ) { for( int ii = 0; ii < m_Pcb->GetAreaCount(); ii++ ) { ZONE_CONTAINER* area = m_Pcb->GetArea( ii ); if( area->HitTest( GetScreen()->m_BlockLocate ) ) { if( blockIncludeItemsOnInvisibleLayers || m_Pcb->IsLayerVisible( area->GetLayer() ) ) { BOARD_ITEM* zone_c = (BOARD_ITEM*) area; picker.SetItem ( zone_c ); itemsList->PushItem( picker ); } } } } }
/** * Function CreateKeepOutRectangle * builds the cost map: * Cells ( in Dist map ) inside the rect x0,y0 a x1,y1 are * incremented by value aKeepOut * Cell outside this rectangle, but inside the rectangle * x0,y0 -marge to x1,y1 + marge are incremented by a decreasing value * (aKeepOut ... 0). The decreasing value depends on the distance to the first rectangle * Therefore the cost is high in rect x0,y0 to x1,y1, and decrease outside this rectangle */ void CreateKeepOutRectangle( int ux0, int uy0, int ux1, int uy1, int marge, int aKeepOut, int aLayerMask ) { int row, col; int row_min, row_max, col_min, col_max, pmarge; int trace = 0; DIST_CELL data, LocalKeepOut; int lgain, cgain; if( aLayerMask & GetLayerMask( g_Route_Layer_BOTTOM ) ) trace = 1; // Trace on bottom layer. if( ( aLayerMask & GetLayerMask( g_Route_Layer_TOP ) ) && RoutingMatrix.m_RoutingLayersCount ) trace |= 2; // Trace on top layer. if( trace == 0 ) return; ux0 -= RoutingMatrix.m_BrdBox.GetX(); uy0 -= RoutingMatrix.m_BrdBox.GetY(); ux1 -= RoutingMatrix.m_BrdBox.GetX(); uy1 -= RoutingMatrix.m_BrdBox.GetY(); ux0 -= marge; ux1 += marge; uy0 -= marge; uy1 += marge; pmarge = marge / RoutingMatrix.m_GridRouting; if( pmarge < 1 ) pmarge = 1; // Calculate the coordinate limits of the rectangle. row_max = uy1 / RoutingMatrix.m_GridRouting; col_max = ux1 / RoutingMatrix.m_GridRouting; row_min = uy0 / RoutingMatrix.m_GridRouting; if( uy0 > row_min * RoutingMatrix.m_GridRouting ) row_min++; col_min = ux0 / RoutingMatrix.m_GridRouting; if( ux0 > col_min * RoutingMatrix.m_GridRouting ) col_min++; if( row_min < 0 ) row_min = 0; if( row_max >= (RoutingMatrix.m_Nrows - 1) ) row_max = RoutingMatrix.m_Nrows - 1; if( col_min < 0 ) col_min = 0; if( col_max >= (RoutingMatrix.m_Ncols - 1) ) col_max = RoutingMatrix.m_Ncols - 1; for( row = row_min; row <= row_max; row++ ) { lgain = 256; if( row < pmarge ) lgain = ( 256 * row ) / pmarge; else if( row > row_max - pmarge ) lgain = ( 256 * ( row_max - row ) ) / pmarge; for( col = col_min; col <= col_max; col++ ) { // RoutingMatrix Dist map containt the "cost" of the cell // at position (row, col) // in autoplace this is the cost of the cell, when // a footprint overlaps it, near a "master" footprint // this cost is hight near the "master" footprint // and decrease with the distance cgain = 256; LocalKeepOut = aKeepOut; if( col < pmarge ) cgain = ( 256 * col ) / pmarge; else if( col > col_max - pmarge ) cgain = ( 256 * ( col_max - col ) ) / pmarge; cgain = ( cgain * lgain ) / 256; if( cgain != 256 ) LocalKeepOut = ( LocalKeepOut * cgain ) / 256; if( trace & 1 ) { data = RoutingMatrix.GetDist( row, col, BOTTOM ) + LocalKeepOut; RoutingMatrix.SetDist( row, col, BOTTOM, data ); } if( trace & 2 ) { data = RoutingMatrix.GetDist( row, col, TOP ); data = std::max( data, LocalKeepOut ); RoutingMatrix.SetDist( row, col, TOP, data ); } } } }
/** * Function PlaceCells * Initialize the matrix routing by setting obstacles for each occupied cell * a cell set to HOLE is an obstacle for tracks and vias * a cell set to VIA_IMPOSSIBLE is an obstacle for vias only. * a cell set to CELL_is_EDGE is a frontier. * Tracks and vias having the same net code as net_code are skipped * (htey do not are obstacles) * * For single-sided Routing 1: * BOTTOM side is used, and Route_Layer_BOTTOM = Route_Layer_TOP * * If flag == FORCE_PADS: all pads will be put in matrix as obstacles. */ void PlaceCells( BOARD* aPcb, int net_code, int flag ) { int ux0 = 0, uy0 = 0, ux1, uy1, dx, dy; int marge, via_marge; LAYER_MSK layerMask; // use the default NETCLASS? NETCLASS* nc = aPcb->m_NetClasses.GetDefault(); int trackWidth = nc->GetTrackWidth(); int clearance = nc->GetClearance(); int viaSize = nc->GetViaDiameter(); marge = clearance + (trackWidth / 2); via_marge = clearance + (viaSize / 2); // Place PADS on matrix routing: for( unsigned i = 0; i < aPcb->GetPadCount(); ++i ) { D_PAD* pad = aPcb->GetPad( i ); if( net_code != pad->GetNet() || (flag & FORCE_PADS) ) { ::PlacePad( pad, HOLE, marge, WRITE_CELL ); } ::PlacePad( pad, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL ); } // Place outlines of modules on matrix routing, if they are on a copper layer // or on the edge layer TRACK tmpSegm( NULL ); // A dummy track used to create segments. for( MODULE* module = aPcb->m_Modules; module; module = module->Next() ) { for( BOARD_ITEM* item = module->GraphicalItems(); item; item = item->Next() ) { switch( item->Type() ) { case PCB_MODULE_EDGE_T: { EDGE_MODULE* edge = (EDGE_MODULE*) item; tmpSegm.SetLayer( edge->GetLayer() ); if( tmpSegm.GetLayer() == EDGE_N ) tmpSegm.SetLayer( UNDEFINED_LAYER ); tmpSegm.SetStart( edge->GetStart() ); tmpSegm.SetEnd( edge->GetEnd() ); tmpSegm.SetShape( edge->GetShape() ); tmpSegm.SetWidth( edge->GetWidth() ); tmpSegm.m_Param = edge->GetAngle(); tmpSegm.SetNet( -1 ); TraceSegmentPcb( &tmpSegm, HOLE, marge, WRITE_CELL ); TraceSegmentPcb( &tmpSegm, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL ); } break; default: break; } } } // Place board outlines and texts on copper layers: for( BOARD_ITEM* item = aPcb->m_Drawings; item; item = item->Next() ) { switch( item->Type() ) { case PCB_LINE_T: { DRAWSEGMENT* DrawSegm; int type_cell = HOLE; DrawSegm = (DRAWSEGMENT*) item; tmpSegm.SetLayer( DrawSegm->GetLayer() ); if( DrawSegm->GetLayer() == EDGE_N ) { tmpSegm.SetLayer( UNDEFINED_LAYER ); type_cell |= CELL_is_EDGE; } tmpSegm.SetStart( DrawSegm->GetStart() ); tmpSegm.SetEnd( DrawSegm->GetEnd() ); tmpSegm.SetShape( DrawSegm->GetShape() ); tmpSegm.SetWidth( DrawSegm->GetWidth() ); tmpSegm.m_Param = DrawSegm->GetAngle(); tmpSegm.SetNet( -1 ); TraceSegmentPcb( &tmpSegm, type_cell, marge, WRITE_CELL ); } break; case PCB_TEXT_T: { TEXTE_PCB* PtText; PtText = (TEXTE_PCB*) item; if( PtText->GetText().Length() == 0 ) break; EDA_RECT textbox = PtText->GetTextBox( -1 ); ux0 = textbox.GetX(); uy0 = textbox.GetY(); dx = textbox.GetWidth(); dy = textbox.GetHeight(); /* Put bounding box (rectangle) on matrix */ dx /= 2; dy /= 2; ux1 = ux0 + dx; uy1 = uy0 + dy; ux0 -= dx; uy0 -= dy; layerMask = GetLayerMask( PtText->GetLayer() ); TraceFilledRectangle( ux0 - marge, uy0 - marge, ux1 + marge, uy1 + marge, PtText->GetOrientation(), layerMask, HOLE, WRITE_CELL ); TraceFilledRectangle( ux0 - via_marge, uy0 - via_marge, ux1 + via_marge, uy1 + via_marge, PtText->GetOrientation(), layerMask, VIA_IMPOSSIBLE, WRITE_OR_CELL ); } break; default: break; } } /* Put tracks and vias on matrix */ for( TRACK* track = aPcb->m_Track; track; track = track->Next() ) { if( net_code == track->GetNet() ) continue; TraceSegmentPcb( track, HOLE, marge, WRITE_CELL ); TraceSegmentPcb( track, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL ); } }
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 PCB_LAYER_WIDGET::ReFill() { BOARD* brd = myframe->GetBoard(); int enabledLayers = brd->GetEnabledLayers(); ClearLayerRows(); // show all coppers first, with front on top, back on bottom, then technical layers for( LAYER_NUM layer = LAYER_N_FRONT; layer >= FIRST_LAYER; --layer ) { if( enabledLayers & GetLayerMask( layer ) ) { wxString dsc; switch( layer ) { case LAYER_N_FRONT: dsc = _("Front copper layer"); break; case LAYER_N_BACK: dsc = _("Back copper layer"); break; default: dsc = _("Inner copper layer"); break; } AppendLayerRow( LAYER_WIDGET::ROW( brd->GetLayerName( layer ), layer, brd->GetLayerColor( layer ), dsc, true ) ); } } // technical layers are shown in this order: // Because they are static, wxGetTranslation must be explicitely // called for tooltips. static const struct { LAYER_NUM layerId; wxString tooltip; } techLayerSeq[] = { { ADHESIVE_N_FRONT, _( "Adhesive on board's front" ) }, { ADHESIVE_N_BACK, _( "Adhesive on board's back" ) }, { SOLDERPASTE_N_FRONT, _( "Solder paste on board's front" )}, { SOLDERPASTE_N_BACK, _( "Solder paste on board's back" ) }, { SILKSCREEN_N_FRONT, _( "Silkscreen on board's front" ) }, { SILKSCREEN_N_BACK, _( "Silkscreen on board's back" ) }, { SOLDERMASK_N_FRONT, _( "Solder mask on board's front" ) }, { SOLDERMASK_N_BACK, _( "Solder mask on board's back" ) }, { DRAW_N, _( "Explanatory drawings" ) }, { COMMENT_N, _( "Explanatory comments" ) }, { ECO1_N, _( "User defined meaning" ) }, { ECO2_N, _( "User defined meaning" ) }, { EDGE_N, _( "Board's perimeter definition" ) }, }; for( unsigned i=0; i<DIM(techLayerSeq); ++i ) { LAYER_NUM layer = techLayerSeq[i].layerId; if( !(enabledLayers & GetLayerMask( layer )) ) continue; AppendLayerRow( LAYER_WIDGET::ROW( brd->GetLayerName( layer ), layer, brd->GetLayerColor( layer ), wxGetTranslation( techLayerSeq[i].tooltip ), true ) ); } installRightLayerClickHandler(); }
/* Route a trace on the BOARD. * Parameters: * 1 side / 2 sides (0 / 1) * Coord source (row, col) * Coord destination (row, col) * Net_code * Pointer to the ratsnest reference * * Returns: * SUCCESS if routed * TRIVIAL_SUCCESS if pads are connected by overlay (no track needed) * If failure NOSUCCESS * Escape STOP_FROM_ESC if demand * ERR_MEMORY if memory allocation failed. */ static int Autoroute_One_Track( PCB_EDIT_FRAME* pcbframe, wxDC* DC, int two_sides, int row_source, int col_source, int row_target, int col_target, RATSNEST_ITEM* pt_rat ) { int r, c, side, d, apx_dist, nr, nc; int result, skip; int i; long curcell, newcell, buddy, lastopen, lastclos, lastmove; int newdist, olddir, _self; int current_net_code; int marge; int padLayerMaskStart; /* Mask layers belonging to the starting pad. */ int padLayerMaskEnd; /* Mask layers belonging to the ending pad. */ int topLayerMask = GetLayerMask( g_Route_Layer_TOP ); int bottomLayerMask = GetLayerMask( g_Route_Layer_BOTTOM ); int routeLayerMask; /* Mask two layers for routing. */ int tab_mask[2]; /* Enables the calculation of the mask layer being * tested. (side = TOP or BOTTOM) */ int start_mask_layer = 0; wxString msg; wxBusyCursor dummy_cursor; // Set an hourglass cursor while routing a // track result = NOSUCCESS; marge = s_Clearance + ( pcbframe->GetDesignSettings().GetCurrentTrackWidth() / 2 ); /* clear direction flags */ i = RoutingMatrix.m_Nrows * RoutingMatrix.m_Ncols * sizeof(DIR_CELL); if( two_sides ) memset( RoutingMatrix.m_DirSide[TOP], FROM_NOWHERE, i ); memset( RoutingMatrix.m_DirSide[BOTTOM], FROM_NOWHERE, i ); lastopen = lastclos = lastmove = 0; /* Set tab_masque[side] for final test of routing. */ if( two_sides ) tab_mask[TOP] = topLayerMask; tab_mask[BOTTOM] = bottomLayerMask; /* Set active layers mask. */ routeLayerMask = topLayerMask | bottomLayerMask; pt_cur_ch = pt_rat; current_net_code = pt_rat->GetNet(); padLayerMaskStart = pt_cur_ch->m_PadStart->GetLayerMask(); padLayerMaskEnd = pt_cur_ch->m_PadEnd->GetLayerMask(); /* First Test if routing possible ie if the pads are accessible * on the routing layers. */ if( ( routeLayerMask & padLayerMaskStart ) == 0 ) goto end_of_route; if( ( routeLayerMask & padLayerMaskEnd ) == 0 ) goto end_of_route; /* Then test if routing possible ie if the pads are accessible * On the routing grid (1 grid point must be in the pad) */ { int cX = ( RoutingMatrix.m_GridRouting * col_source ) + pcbframe->GetBoard()->GetBoundingBox().GetX(); int cY = ( RoutingMatrix.m_GridRouting * row_source ) + pcbframe->GetBoard()->GetBoundingBox().GetY(); int dx = pt_cur_ch->m_PadStart->GetSize().x / 2; int dy = pt_cur_ch->m_PadStart->GetSize().y / 2; int px = pt_cur_ch->m_PadStart->GetPosition().x; int py = pt_cur_ch->m_PadStart->GetPosition().y; if( ( ( int( pt_cur_ch->m_PadStart->GetOrientation() ) / 900 ) & 1 ) != 0 ) EXCHG( dx, dy ); if( ( abs( cX - px ) > dx ) || ( abs( cY - py ) > dy ) ) goto end_of_route; cX = ( RoutingMatrix.m_GridRouting * col_target ) + pcbframe->GetBoard()->GetBoundingBox().GetX(); cY = ( RoutingMatrix.m_GridRouting * row_target ) + pcbframe->GetBoard()->GetBoundingBox().GetY(); dx = pt_cur_ch->m_PadEnd->GetSize().x / 2; dy = pt_cur_ch->m_PadEnd->GetSize().y / 2; px = pt_cur_ch->m_PadEnd->GetPosition().x; py = pt_cur_ch->m_PadEnd->GetPosition().y; if( ( ( int( pt_cur_ch->m_PadEnd->GetOrientation() ) / 900) & 1 ) != 0 ) EXCHG( dx, dy ); if( ( abs( cX - px ) > dx ) || ( abs( cY - py ) > dy ) ) goto end_of_route; } /* Test the trivial case: direct connection overlay pads. */ if( ( row_source == row_target ) && ( col_source == col_target ) && ( padLayerMaskEnd & padLayerMaskStart & g_TabAllCopperLayerMask[pcbframe->GetBoard()->GetCopperLayerCount() - 1] ) ) { result = TRIVIAL_SUCCESS; goto end_of_route; } /* Placing the bit to remove obstacles on 2 pads to a link. */ pcbframe->SetStatusText( wxT( "Gen Cells" ) ); PlacePad( pt_cur_ch->m_PadStart, CURRENT_PAD, marge, WRITE_OR_CELL ); PlacePad( pt_cur_ch->m_PadEnd, CURRENT_PAD, marge, WRITE_OR_CELL ); /* Regenerates the remaining barriers (which may encroach on the placement bits precedent) */ i = pcbframe->GetBoard()->GetPadCount(); for( unsigned ii = 0; ii < pcbframe->GetBoard()->GetPadCount(); ii++ ) { D_PAD* ptr = pcbframe->GetBoard()->GetPad( ii ); if( ( pt_cur_ch->m_PadStart != ptr ) && ( pt_cur_ch->m_PadEnd != ptr ) ) { PlacePad( ptr, ~CURRENT_PAD, marge, WRITE_AND_CELL ); } } InitQueue(); /* initialize the search queue */ apx_dist = RoutingMatrix.GetApxDist( row_source, col_source, row_target, col_target ); /* Initialize first search. */ if( two_sides ) /* Preferred orientation. */ { if( abs( row_target - row_source ) > abs( col_target - col_source ) ) { if( padLayerMaskStart & topLayerMask ) { start_mask_layer = 2; if( SetQueue( row_source, col_source, TOP, 0, apx_dist, row_target, col_target ) == 0 ) { return ERR_MEMORY; } } if( padLayerMaskStart & bottomLayerMask ) { start_mask_layer |= 1; if( SetQueue( row_source, col_source, BOTTOM, 0, apx_dist, row_target, col_target ) == 0 ) { return ERR_MEMORY; } } } else { if( padLayerMaskStart & bottomLayerMask ) { start_mask_layer = 1; if( SetQueue( row_source, col_source, BOTTOM, 0, apx_dist, row_target, col_target ) == 0 ) { return ERR_MEMORY; } } if( padLayerMaskStart & topLayerMask ) { start_mask_layer |= 2; if( SetQueue( row_source, col_source, TOP, 0, apx_dist, row_target, col_target ) == 0 ) { return ERR_MEMORY; } } } } else if( padLayerMaskStart & bottomLayerMask ) { start_mask_layer = 1; if( SetQueue( row_source, col_source, BOTTOM, 0, apx_dist, row_target, col_target ) == 0 ) { return ERR_MEMORY; } } /* search until success or we exhaust all possibilities */ GetQueue( &r, &c, &side, &d, &apx_dist ); for( ; r != ILLEGAL; GetQueue( &r, &c, &side, &d, &apx_dist ) ) { curcell = RoutingMatrix.GetCell( r, c, side ); if( curcell & CURRENT_PAD ) curcell &= ~HOLE; if( (r == row_target) && (c == col_target) /* success if layer OK */ && ( tab_mask[side] & padLayerMaskEnd) ) { /* Remove link. */ GRSetDrawMode( DC, GR_XOR ); GRLine( pcbframe->GetCanvas()->GetClipBox(), DC, segm_oX, segm_oY, segm_fX, segm_fY, 0, WHITE ); /* Generate trace. */ if( Retrace( pcbframe, DC, row_source, col_source, row_target, col_target, side, current_net_code ) ) { result = SUCCESS; /* Success : Route OK */ } break; /* Routing complete. */ } if( pcbframe->GetCanvas()->GetAbortRequest() ) { result = STOP_FROM_ESC; break; } /* report every COUNT new nodes or so */ #define COUNT 20000 if( ( OpenNodes - lastopen > COUNT ) || ( ClosNodes - lastclos > COUNT ) || ( MoveNodes - lastmove > COUNT ) ) { lastopen = OpenNodes; lastclos = ClosNodes; lastmove = MoveNodes; msg.Printf( wxT( "Activity: Open %d Closed %d Moved %d" ), OpenNodes, ClosNodes, MoveNodes ); pcbframe->SetStatusText( msg ); } _self = 0; if( curcell & HOLE ) { _self = 5; /* set 'present' bits */ for( i = 0; i < 8; i++ ) { selfok2[i].present = 0; if( curcell & selfok2[i].trace ) selfok2[i].present = 1; } } for( i = 0; i < 8; i++ ) /* consider neighbors */ { nr = r + delta[i][0]; nc = c + delta[i][1]; /* off the edge? */ if( nr < 0 || nr >= RoutingMatrix.m_Nrows || nc < 0 || nc >= RoutingMatrix.m_Ncols ) continue; /* off the edge */ if( _self == 5 && selfok2[i].present ) continue; newcell = RoutingMatrix.GetCell( nr, nc, side ); if( newcell & CURRENT_PAD ) newcell &= ~HOLE; /* check for non-target hole */ if( newcell & HOLE ) { if( nr != row_target || nc != col_target ) continue; } /* check for traces */ else if( newcell & HOLE & ~(newmask[i]) ) { continue; } /* check blocking on corner neighbors */ if( delta[i][0] && delta[i][1] ) { /* check first buddy */ buddy = RoutingMatrix.GetCell( r + blocking[i].r1, c + blocking[i].c1, side ); if( buddy & CURRENT_PAD ) buddy &= ~HOLE; if( buddy & HOLE ) continue; // if (buddy & (blocking[i].b1)) continue; /* check second buddy */ buddy = RoutingMatrix.GetCell( r + blocking[i].r2, c + blocking[i].c2, side ); if( buddy & CURRENT_PAD ) buddy &= ~HOLE; if( buddy & HOLE ) continue; // if (buddy & (blocking[i].b2)) continue; } olddir = RoutingMatrix.GetDir( r, c, side ); newdist = d + RoutingMatrix.CalcDist( ndir[i], olddir, ( olddir == FROM_OTHERSIDE ) ? RoutingMatrix.GetDir( r, c, 1 - side ) : 0, side ); /* if (a) not visited yet, or (b) we have */ /* found a better path, add it to queue */ if( !RoutingMatrix.GetDir( nr, nc, side ) ) { RoutingMatrix.SetDir( nr, nc, side, ndir[i] ); RoutingMatrix.SetDist( nr, nc, side, newdist ); if( SetQueue( nr, nc, side, newdist, RoutingMatrix.GetApxDist( nr, nc, row_target, col_target ), row_target, col_target ) == 0 ) { return ERR_MEMORY; } } else if( newdist < RoutingMatrix.GetDist( nr, nc, side ) ) { RoutingMatrix.SetDir( nr, nc, side, ndir[i] ); RoutingMatrix.SetDist( nr, nc, side, newdist ); ReSetQueue( nr, nc, side, newdist, RoutingMatrix.GetApxDist( nr, nc, row_target, col_target ), row_target, col_target ); } } /** Test the other layer. **/ if( two_sides ) { olddir = RoutingMatrix.GetDir( r, c, side ); if( olddir == FROM_OTHERSIDE ) continue; /* useless move, so don't bother */ if( curcell ) /* can't drill via if anything here */ continue; /* check for holes or traces on other side */ if( ( newcell = RoutingMatrix.GetCell( r, c, 1 - side ) ) != 0 ) continue; /* check for nearby holes or traces on both sides */ for( skip = 0, i = 0; i < 8; i++ ) { nr = r + delta[i][0]; nc = c + delta[i][1]; if( nr < 0 || nr >= RoutingMatrix.m_Nrows || nc < 0 || nc >= RoutingMatrix.m_Ncols ) continue; /* off the edge !! */ if( RoutingMatrix.GetCell( nr, nc, side ) /* & blocking2[i]*/ ) { skip = 1; /* can't drill via here */ break; } if( RoutingMatrix.GetCell( nr, nc, 1 - side ) /* & blocking2[i]*/ ) { skip = 1; /* can't drill via here */ break; } } if( skip ) /* neighboring hole or trace? */ continue; /* yes, can't drill via here */ newdist = d + RoutingMatrix.CalcDist( FROM_OTHERSIDE, olddir, 0, side ); /* if (a) not visited yet, * or (b) we have found a better path, * add it to queue */ if( !RoutingMatrix.GetDir( r, c, 1 - side ) ) { RoutingMatrix.SetDir( r, c, 1 - side, FROM_OTHERSIDE ); RoutingMatrix.SetDist( r, c, 1 - side, newdist ); if( SetQueue( r, c, 1 - side, newdist, apx_dist, row_target, col_target ) == 0 ) { return ERR_MEMORY; } } else if( newdist < RoutingMatrix.GetDist( r, c, 1 - side ) ) { RoutingMatrix.SetDir( r, c, 1 - side, FROM_OTHERSIDE ); RoutingMatrix.SetDist( r, c, 1 - side, newdist ); ReSetQueue( r, c, 1 - side, newdist, apx_dist, row_target, col_target ); } } /* Finished attempt to route on other layer. */ } end_of_route: PlacePad( pt_cur_ch->m_PadStart, ~CURRENT_PAD, marge, WRITE_AND_CELL ); PlacePad( pt_cur_ch->m_PadEnd, ~CURRENT_PAD, marge, WRITE_AND_CELL ); msg.Printf( wxT( "Activity: Open %d Closed %d Moved %d"), OpenNodes, ClosNodes, MoveNodes ); pcbframe->SetStatusText( msg ); return result; }
MODULE* PCB_EDIT_FRAME::Genere_Self( wxDC* DC ) { D_PAD* pad; int ll; wxString msg; m_canvas->CallMouseCapture( DC, wxDefaultPosition, false ); m_canvas->SetMouseCapture( NULL, NULL ); if( Self_On == 0 ) { DisplayError( this, wxT( "Starting point not init.." ) ); return NULL; } Self_On = 0; Mself.m_End = GetCrossHairPosition(); wxPoint pt = Mself.m_End - Mself.m_Start; int min_len = KiROUND( EuclideanNorm( pt ) ); Mself.lng = min_len; // Enter the desired length. msg = StringFromValue( g_UserUnit, Mself.lng ); wxTextEntryDialog dlg( this, _( "Length:" ), _( "Length" ), msg ); if( dlg.ShowModal() != wxID_OK ) return NULL; // canceled by user msg = dlg.GetValue(); Mself.lng = ValueFromString( g_UserUnit, msg ); // Control values (ii = minimum length) if( Mself.lng < min_len ) { DisplayError( this, _( "Requested length < minimum length" ) ); return NULL; } // Calculate the elements. Mself.m_Width = GetBoard()->GetCurrentTrackWidth(); std::vector <wxPoint> buffer; ll = BuildCornersList_S_Shape( buffer, Mself.m_Start, Mself.m_End, Mself.lng, Mself.m_Width ); if( !ll ) { DisplayError( this, _( "Requested length too large" ) ); return NULL; } // Generate module. MODULE* module; module = Create_1_Module( wxEmptyString ); if( module == NULL ) return NULL; // here the module is already in the BOARD, Create_1_Module() does that. module->SetFPID( FPID( std::string( "MuSelf" ) ) ); module->SetAttributes( MOD_VIRTUAL | MOD_CMS ); module->ClearFlags(); module->SetPosition( Mself.m_End ); // Generate segments for( unsigned jj = 1; jj < buffer.size(); jj++ ) { EDGE_MODULE* PtSegm; PtSegm = new EDGE_MODULE( module ); PtSegm->SetStart( buffer[jj - 1] ); PtSegm->SetEnd( buffer[jj] ); PtSegm->SetWidth( Mself.m_Width ); PtSegm->SetLayer( module->GetLayer() ); PtSegm->SetShape( S_SEGMENT ); PtSegm->SetStart0( PtSegm->GetStart() - module->GetPosition() ); PtSegm->SetEnd0( PtSegm->GetEnd() - module->GetPosition() ); module->GraphicalItems().PushBack( PtSegm ); } // Place a pad on each end of coil. pad = new D_PAD( module ); module->Pads().PushFront( pad ); pad->SetPadName( wxT( "1" ) ); pad->SetPosition( Mself.m_End ); pad->SetPos0( pad->GetPosition() - module->GetPosition() ); pad->SetSize( wxSize( Mself.m_Width, Mself.m_Width ) ); pad->SetLayerMask( GetLayerMask( module->GetLayer() ) ); pad->SetAttribute( PAD_SMD ); pad->SetShape( PAD_CIRCLE ); D_PAD* newpad = new D_PAD( *pad ); module->Pads().Insert( newpad, pad->Next() ); pad = newpad; pad->SetPadName( wxT( "2" ) ); pad->SetPosition( Mself.m_Start ); pad->SetPos0( pad->GetPosition() - module->GetPosition() ); // Modify text positions. SetMsgPanel( module ); wxPoint refPos( ( Mself.m_Start.x + Mself.m_End.x ) / 2, ( Mself.m_Start.y + Mself.m_End.y ) / 2 ); wxPoint valPos = refPos; refPos.y -= module->Reference().GetSize().y; module->Reference().SetTextPosition( refPos ); valPos.y += module->Value().GetSize().y; module->Value().SetTextPosition( valPos ); module->Reference().SetPos0( module->Reference().GetTextPosition() - module->GetPosition() ); module->Value().SetPos0( module->Value().GetTextPosition() - module->GetPosition() ); module->CalculateBoundingBox(); module->Draw( m_canvas, DC, GR_OR ); return module; }
void PlotOneBoardLayer( BOARD *aBoard, PLOTTER* aPlotter, LAYER_NUM aLayer, const PCB_PLOT_PARAMS& aPlotOpt ) { PCB_PLOT_PARAMS plotOpt = aPlotOpt; int soldermask_min_thickness = aBoard->GetDesignSettings().m_SolderMaskMinWidth; // Set a default color and the text mode for this layer aPlotter->SetColor( aPlotOpt.GetColor() ); aPlotter->SetTextMode( aPlotOpt.GetTextMode() ); // Specify that the contents of the "Edges Pcb" layer are to be plotted // in addition to the contents of the currently specified layer. LAYER_MSK layer_mask = GetLayerMask( aLayer ); if( !aPlotOpt.GetExcludeEdgeLayer() ) layer_mask |= EDGE_LAYER; switch( aLayer ) { case FIRST_COPPER_LAYER: case LAYER_N_2: case LAYER_N_3: case LAYER_N_4: case LAYER_N_5: case LAYER_N_6: case LAYER_N_7: case LAYER_N_8: case LAYER_N_9: case LAYER_N_10: case LAYER_N_11: case LAYER_N_12: case LAYER_N_13: case LAYER_N_14: case LAYER_N_15: case LAST_COPPER_LAYER: // Skip NPTH pads on copper layers ( only if hole size == pad size ): plotOpt.SetSkipPlotNPTH_Pads( true ); // Drill mark will be plotted, // if drill mark is SMALL_DRILL_SHAPE or FULL_DRILL_SHAPE PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt ); break; case SOLDERMASK_N_BACK: case SOLDERMASK_N_FRONT: plotOpt.SetSkipPlotNPTH_Pads( false ); // Disable plot pad holes plotOpt.SetDrillMarksType( PCB_PLOT_PARAMS::NO_DRILL_SHAPE ); // Plot solder mask: if( soldermask_min_thickness == 0 ) PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt ); else PlotSolderMaskLayer( aBoard, aPlotter, layer_mask, plotOpt, soldermask_min_thickness ); break; case SOLDERPASTE_N_BACK: case SOLDERPASTE_N_FRONT: plotOpt.SetSkipPlotNPTH_Pads( false ); // Disable plot pad holes plotOpt.SetDrillMarksType( PCB_PLOT_PARAMS::NO_DRILL_SHAPE ); PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt ); break; case SILKSCREEN_N_FRONT: case SILKSCREEN_N_BACK: PlotSilkScreen( aBoard, aPlotter, layer_mask, plotOpt ); // Gerber: Subtract soldermask from silkscreen if enabled if( aPlotter->GetPlotterType() == PLOT_FORMAT_GERBER && plotOpt.GetSubtractMaskFromSilk() ) { if( aLayer == SILKSCREEN_N_FRONT ) layer_mask = GetLayerMask( SOLDERMASK_N_FRONT ); else layer_mask = GetLayerMask( SOLDERMASK_N_BACK ); // Create the mask to subtract by creating a negative layer polarity aPlotter->SetLayerPolarity( false ); // Disable plot pad holes plotOpt.SetDrillMarksType( PCB_PLOT_PARAMS::NO_DRILL_SHAPE ); // Plot the mask PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt ); } break; default: PlotSilkScreen( aBoard, aPlotter, layer_mask, plotOpt ); break; } }
/* Creates the plot for silkscreen layers * Silkscreen layers have specific requirement for pads (not filled) and texts * (with option to remove them from some copper areas (pads...) */ void PlotSilkScreen( BOARD *aBoard, PLOTTER* aPlotter, LAYER_MSK aLayerMask, const PCB_PLOT_PARAMS& aPlotOpt ) { BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt ); itemplotter.SetLayerMask( aLayerMask ); // Plot edge layer and graphic items itemplotter.PlotBoardGraphicItems(); // Plot footprint outlines : itemplotter.Plot_Edges_Modules(); // Plot pads (creates pads outlines, for pads on silkscreen layers) int layersmask_plotpads = aLayerMask; // Calculate the mask layers of allowed layers for pads if( !aPlotOpt.GetPlotPadsOnSilkLayer() ) // Do not plot pads on silk screen layers layersmask_plotpads &= ~(SILKSCREEN_LAYER_BACK | SILKSCREEN_LAYER_FRONT ); if( layersmask_plotpads ) { for( MODULE* Module = aBoard->m_Modules; Module; Module = Module->Next() ) { for( D_PAD * pad = Module->Pads(); pad != NULL; pad = pad->Next() ) { // See if the pad is on this layer LAYER_MSK masklayer = pad->GetLayerMask(); if( (masklayer & layersmask_plotpads) == 0 ) continue; EDA_COLOR_T color = ColorFromInt(0); if( (layersmask_plotpads & SILKSCREEN_LAYER_BACK) ) color = aBoard->GetLayerColor( SILKSCREEN_N_BACK ); if((layersmask_plotpads & SILKSCREEN_LAYER_FRONT ) ) color = ColorFromInt( color | aBoard->GetLayerColor( SILKSCREEN_N_FRONT ) ); itemplotter.PlotPad( pad, color, LINE ); } } } // Plot footprints fields (ref, value ...) for( MODULE* module = aBoard->m_Modules; module; module = module->Next() ) { if( ! itemplotter.PlotAllTextsModule( module ) ) { wxLogMessage( _( "Your BOARD has a bad layer number for module %s" ), GetChars( module->GetReference() ) ); } } // Plot filled areas for( int ii = 0; ii < aBoard->GetAreaCount(); ii++ ) { ZONE_CONTAINER* edge_zone = aBoard->GetArea( ii ); if( ( GetLayerMask( edge_zone->GetLayer() ) & aLayerMask ) == 0 ) continue; itemplotter.PlotFilledAreas( edge_zone ); } // Plot segments used to fill zone areas (outdated, but here for old boards // compatibility): for( SEGZONE* seg = aBoard->m_Zone; seg != NULL; seg = seg->Next() ) { if( ( GetLayerMask( seg->GetLayer() ) & aLayerMask ) == 0 ) continue; aPlotter->ThickSegment( seg->GetStart(), seg->GetEnd(), seg->GetWidth(), itemplotter.GetMode() ); } }
/* Plot a copper layer or mask. * Silk screen layers are not plotted here. */ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter, LAYER_MSK aLayerMask, const PCB_PLOT_PARAMS& aPlotOpt ) { BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt ); itemplotter.SetLayerMask( aLayerMask ); EDA_DRAW_MODE_T plotMode = aPlotOpt.GetMode(); // Plot edge layer and graphic items itemplotter.PlotBoardGraphicItems(); // Draw footprint shapes without pads (pads will plotted later) // We plot here module texts, but they are usually on silkscreen layer, // so they are not plot here but plot by PlotSilkScreen() // Plot footprints fields (ref, value ...) for( MODULE* module = aBoard->m_Modules; module; module = module->Next() ) { if( ! itemplotter.PlotAllTextsModule( module ) ) { wxLogMessage( _( "Your BOARD has a bad layer number for module %s" ), GetChars( module->GetReference() ) ); } } for( MODULE* module = aBoard->m_Modules; module; module = module->Next() ) { for( BOARD_ITEM* item = module->GraphicalItems(); item; item = item->Next() ) { if( ! (aLayerMask & GetLayerMask( item->GetLayer() ) ) ) continue; switch( item->Type() ) { case PCB_MODULE_EDGE_T: itemplotter.Plot_1_EdgeModule( (EDGE_MODULE*) item ); break; default: break; } } } // Plot footprint pads for( MODULE* module = aBoard->m_Modules; module; module = module->Next() ) { for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() ) { if( (pad->GetLayerMask() & aLayerMask) == 0 ) continue; wxSize margin; double width_adj = 0; if( aLayerMask & ALL_CU_LAYERS ) width_adj = itemplotter.getFineWidthAdj(); switch( aLayerMask & ( SOLDERMASK_LAYER_BACK | SOLDERMASK_LAYER_FRONT | SOLDERPASTE_LAYER_BACK | SOLDERPASTE_LAYER_FRONT ) ) { case SOLDERMASK_LAYER_FRONT: case SOLDERMASK_LAYER_BACK: margin.x = margin.y = pad->GetSolderMaskMargin(); break; case SOLDERPASTE_LAYER_FRONT: case SOLDERPASTE_LAYER_BACK: margin = pad->GetSolderPasteMargin(); break; default: break; } wxSize padPlotsSize; padPlotsSize.x = pad->GetSize().x + ( 2 * margin.x ) + width_adj; padPlotsSize.y = pad->GetSize().y + ( 2 * margin.y ) + width_adj; // Don't draw a null size item : if( padPlotsSize.x <= 0 || padPlotsSize.y <= 0 ) continue; EDA_COLOR_T color = BLACK; if( (pad->GetLayerMask() & LAYER_BACK) ) color = aBoard->GetVisibleElementColor( PAD_BK_VISIBLE ); if((pad->GetLayerMask() & LAYER_FRONT ) ) color = ColorFromInt( color | aBoard->GetVisibleElementColor( PAD_FR_VISIBLE ) ); // Temporary set the pad size to the required plot size: wxSize tmppadsize = pad->GetSize(); pad->SetSize( padPlotsSize ); switch( pad->GetShape() ) { case PAD_CIRCLE: case PAD_OVAL: if( aPlotOpt.GetSkipPlotNPTH_Pads() && (pad->GetSize() == pad->GetDrillSize()) && (pad->GetAttribute() == PAD_HOLE_NOT_PLATED) ) break; // Fall through: case PAD_TRAPEZOID: case PAD_RECT: default: itemplotter.PlotPad( pad, color, plotMode ); break; } pad->SetSize( tmppadsize ); // Restore the pad size } } // Plot vias on copper layers, and if aPlotOpt.GetPlotViaOnMaskLayer() is true, // plot them on solder mask for( TRACK* track = aBoard->m_Track; track; track = track->Next() ) { const VIA* Via = dynamic_cast<const VIA*>( track ); if( !Via ) continue; // vias are not plotted if not on selected layer, but if layer // is SOLDERMASK_LAYER_BACK or SOLDERMASK_LAYER_FRONT,vias are drawn, // only if they are on the corresponding external copper layer int via_mask_layer = Via->GetLayerMask(); if( aPlotOpt.GetPlotViaOnMaskLayer() ) { if( via_mask_layer & LAYER_BACK ) via_mask_layer |= SOLDERMASK_LAYER_BACK; if( via_mask_layer & LAYER_FRONT ) via_mask_layer |= SOLDERMASK_LAYER_FRONT; } if( ( via_mask_layer & aLayerMask ) == 0 ) continue; int via_margin = 0; double width_adj = 0; // If the current layer is a solder mask, use the global mask // clearance for vias if( ( aLayerMask & ( SOLDERMASK_LAYER_BACK | SOLDERMASK_LAYER_FRONT ) ) ) via_margin = aBoard->GetDesignSettings().m_SolderMaskMargin; if( aLayerMask & ALL_CU_LAYERS ) width_adj = itemplotter.getFineWidthAdj(); int diameter = Via->GetWidth() + 2 * via_margin + width_adj; // Don't draw a null size item : if( diameter <= 0 ) continue; EDA_COLOR_T color = aBoard->GetVisibleElementColor(VIAS_VISIBLE + Via->GetViaType()); // Set plot color (change WHITE to LIGHTGRAY because // the white items are not seen on a white paper or screen aPlotter->SetColor( color != WHITE ? color : LIGHTGRAY); aPlotter->FlashPadCircle( Via->GetStart(), diameter, plotMode ); } // Plot tracks (not vias) : for( TRACK* track = aBoard->m_Track; track; track = track->Next() ) { if( track->Type() == PCB_VIA_T ) continue; if( (GetLayerMask( track->GetLayer() ) & aLayerMask) == 0 ) continue; int width = track->GetWidth() + itemplotter.getFineWidthAdj(); aPlotter->SetColor( itemplotter.getColor( track->GetLayer() ) ); aPlotter->ThickSegment( track->GetStart(), track->GetEnd(), width, plotMode ); } // Plot zones (outdated, for old boards compatibility): for( TRACK* track = aBoard->m_Zone; track; track = track->Next() ) { if( (GetLayerMask( track->GetLayer() ) & aLayerMask) == 0 ) continue; int width = track->GetWidth() + itemplotter.getFineWidthAdj(); aPlotter->SetColor( itemplotter.getColor( track->GetLayer() ) ); aPlotter->ThickSegment( track->GetStart(), track->GetEnd(), width, plotMode ); } // Plot filled ares for( int ii = 0; ii < aBoard->GetAreaCount(); ii++ ) { ZONE_CONTAINER* zone = aBoard->GetArea( ii ); if( ( GetLayerMask(zone->GetLayer() ) & aLayerMask ) == 0 ) continue; itemplotter.PlotFilledAreas( zone ); } // Adding drill marks, if required and if the plotter is able to plot them: if( aPlotOpt.GetDrillMarksType() != PCB_PLOT_PARAMS::NO_DRILL_SHAPE ) itemplotter.PlotDrillMarks(); }
void PlotLayerOutlines( BOARD *aBoard, PLOTTER* aPlotter, LAYER_MSK aLayerMask, const PCB_PLOT_PARAMS& aPlotOpt ) { BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt ); itemplotter.SetLayerMask( aLayerMask ); CPOLYGONS_LIST outlines; for( LAYER_NUM layer = FIRST_LAYER; layer < NB_PCB_LAYERS; layer++ ) { LAYER_MSK layer_mask = GetLayerMask( layer ); if( (aLayerMask & layer_mask ) == 0 ) continue; outlines.RemoveAllContours(); aBoard->ConvertBrdLayerToPolygonalContours( layer, outlines ); // Merge all overlapping polygons. KI_POLYGON_SET kpolygons; KI_POLYGON_SET ktmp; outlines.ExportTo( ktmp ); kpolygons += ktmp; // Plot outlines std::vector< wxPoint > cornerList; for( unsigned ii = 0; ii < kpolygons.size(); ii++ ) { KI_POLYGON polygon = kpolygons[ii]; // polygon contains only one polygon, but it can have holes linked by // overlapping segments. // To plot clean outlines, we have to break this polygon into more polygons with // no overlapping segments, using Clipper, because boost::polygon // does not allow that ClipperLib::Path raw_polygon; ClipperLib::Paths normalized_polygons; for( unsigned ic = 0; ic < polygon.size(); ic++ ) { KI_POLY_POINT corner = *(polygon.begin() + ic); raw_polygon.push_back( ClipperLib::IntPoint( corner.x(), corner.y() ) ); } ClipperLib::SimplifyPolygon( raw_polygon, normalized_polygons ); // Now we have one or more basic polygons: plot each polygon for( unsigned ii = 0; ii < normalized_polygons.size(); ii++ ) { ClipperLib::Path& polygon = normalized_polygons[ii]; cornerList.clear(); for( unsigned jj = 0; jj < polygon.size(); jj++ ) cornerList.push_back( wxPoint( polygon[jj].X , polygon[jj].Y ) ); // Ensure the polygon is closed if( cornerList[0] != cornerList[cornerList.size()-1] ) cornerList.push_back( cornerList[0] ); aPlotter->PlotPoly( cornerList, NO_FILL ); } } // Plot pad holes if( aPlotOpt.GetDrillMarksType() != PCB_PLOT_PARAMS::NO_DRILL_SHAPE ) { for( MODULE* module = aBoard->m_Modules; module; module = module->Next() ) { for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() ) { wxSize hole = pad->GetDrillSize(); if( hole.x == 0 || hole.y == 0 ) continue; if( hole.x == hole.y ) aPlotter->Circle( pad->GetPosition(), hole.x, NO_FILL ); else { wxPoint drl_start, drl_end; int width; pad->GetOblongDrillGeometry( drl_start, drl_end, width ); aPlotter->ThickSegment( pad->GetPosition() + drl_start, pad->GetPosition() + drl_end, width, SKETCH ); } } } } // Plot vias holes for( TRACK* track = aBoard->m_Track; track; track = track->Next() ) { const VIA* via = dyn_cast<const VIA*>( track ); if( via && via->IsOnLayer( layer ) ) // via holes can be not through holes { aPlotter->Circle( via->GetPosition(), via->GetDrillValue(), NO_FILL ); } } } }
void DIALOG_PRINT_USING_PRINTER::InitValues( ) /************************************************************************/ { SetFocus(); LAYER_NUM layer_max = NB_GERBER_LAYERS; wxString msg; if( g_pageSetupData == NULL ) { g_pageSetupData = new wxPageSetupDialogData; // Set initial page margins. // Margins are already set in Pcbnew, so we can use 0 g_pageSetupData->SetMarginTopLeft(wxPoint(0, 0)); g_pageSetupData->SetMarginBottomRight(wxPoint(0, 0)); } s_Parameters.m_PageSetupData = g_pageSetupData; layer_max = NB_LAYERS; // Create layer list for( LAYER_NUM ii = FIRST_LAYER; ii < layer_max; ++ii ) { LAYER_MSK mask = GetLayerMask( ii ); msg = _( "Layer" ); msg << wxT( " " ) << ii + 1; m_BoxSelectLayer[ii] = new wxCheckBox( this, -1, msg ); if( mask & s_SelectedLayers ) m_BoxSelectLayer[ii]->SetValue( true ); if( ii < 16 ) m_leftLayersBoxSizer->Add( m_BoxSelectLayer[ii], wxGROW | wxLEFT | wxRIGHT | wxTOP ); else m_rightLayersBoxSizer->Add( m_BoxSelectLayer[ii], wxGROW | wxLEFT | wxRIGHT | wxTOP ); } // Read the scale adjust option int scale_idx = 4; // default selected scale = ScaleList[4] = 1.000 if( m_Config ) { m_Config->Read( OPTKEY_PRINT_X_FINESCALE_ADJ, &s_Parameters.m_XScaleAdjust ); m_Config->Read( OPTKEY_PRINT_Y_FINESCALE_ADJ, &s_Parameters.m_YScaleAdjust ); m_Config->Read( OPTKEY_PRINT_SCALE, &scale_idx ); m_Config->Read( OPTKEY_PRINT_PAGE_FRAME, &s_Parameters.m_Print_Sheet_Ref, 1); m_Config->Read( OPTKEY_PRINT_MONOCHROME_MODE, &s_Parameters.m_Print_Black_and_White, 1); // Test for a reasonnable scale value. Set to 1 if problem if( s_Parameters.m_XScaleAdjust < MIN_SCALE || s_Parameters.m_YScaleAdjust < MIN_SCALE || s_Parameters.m_XScaleAdjust > MAX_SCALE || s_Parameters.m_YScaleAdjust > MAX_SCALE ) s_Parameters.m_XScaleAdjust = s_Parameters.m_YScaleAdjust = 1.0; s_SelectedLayers = 0; for( LAYER_NUM layer = FIRST_LAYER; layer < layer_max; ++layer ) { wxString layerKey; bool option; layerKey.Printf( OPTKEY_LAYERBASE, layer ); option = false; if( m_Config->Read( layerKey, &option ) ) { m_BoxSelectLayer[layer]->SetValue( option ); if( option ) s_SelectedLayers |= GetLayerMask( layer ); } } } m_ScaleOption->SetSelection( scale_idx ); scale_idx = m_ScaleOption->GetSelection(); s_Parameters.m_PrintScale = s_ScaleList[scale_idx]; m_Print_Mirror->SetValue(s_Parameters.m_PrintMirror); if( s_Parameters.m_Print_Black_and_White ) m_ModeColorOption->SetSelection( 1 ); else m_ModeColorOption->SetSelection( 0 ); s_Parameters.m_PenDefaultSize = 0; // Create scale adjust option msg.Printf( wxT( "%f" ), s_Parameters.m_XScaleAdjust ); m_FineAdjustXscaleOpt->SetValue( msg ); msg.Printf( wxT( "%f" ), s_Parameters.m_YScaleAdjust ); m_FineAdjustYscaleOpt->SetValue( msg ); bool enable = (s_Parameters.m_PrintScale == 1.0); if( m_FineAdjustXscaleOpt ) m_FineAdjustXscaleOpt->Enable(enable); if( m_FineAdjustYscaleOpt ) m_FineAdjustYscaleOpt->Enable(enable); }
void DIALOG_SVG_PRINT::ExportSVGFile( bool aOnlyOneFile ) { m_outputDirectory = m_outputDirectoryName->GetValue(); // Create output directory if it does not exist (also transform it in // absolute form). Bail if it fails wxFileName outputDir = wxFileName::DirName( m_outputDirectory ); wxString boardFilename = m_board->GetFileName(); WX_TEXT_CTRL_REPORTER reporter( m_messagesBox ); if( !EnsureOutputDirectory( &outputDir, boardFilename, &reporter ) ) { wxString msg; msg.Printf( _( "Could not write plot files to folder \"%s\"." ), GetChars( outputDir.GetPath() ) ); DisplayError( this, msg ); return; } m_printMirror = m_printMirrorOpt->GetValue(); m_printBW = m_ModeColorOption->GetSelection(); SetPenWidth(); // Build layers mask LAYER_MSK printMaskLayer = NO_LAYERS; for( LAYER_NUM layer = FIRST_LAYER; layer < NB_PCB_LAYERS; ++layer ) { if( m_boxSelectLayer[layer] && m_boxSelectLayer[layer]->GetValue() ) printMaskLayer |= GetLayerMask( layer ); } wxString msg; for( LAYER_NUM layer = FIRST_LAYER; layer < NB_PCB_LAYERS; ++layer ) { LAYER_MSK currlayer_mask = GetLayerMask( layer ); if( (printMaskLayer & currlayer_mask ) == 0 ) continue; wxString suffix = m_board->GetStandardLayerName( layer ); if( aOnlyOneFile ) { m_printMaskLayer = printMaskLayer; suffix = wxT( "brd" ); } else { m_printMaskLayer = currlayer_mask; suffix = m_board->GetStandardLayerName( layer ); } wxFileName fn(boardFilename); BuildPlotFileName( &fn, outputDir.GetPath(), suffix, SVGFileExtension ); if( m_PrintBoardEdgesCtrl->IsChecked() ) m_printMaskLayer |= EDGE_LAYER; if( CreateSVGFile( fn.GetFullPath() ) ) msg.Printf( _( "Plot: %s OK\n" ), GetChars( fn.GetFullPath() ) ); else // Error msg.Printf( _( "** Unable to create %s **\n" ), GetChars( fn.GetFullPath() ) ); m_messagesBox->AppendText( msg ); if( aOnlyOneFile ) break; } }
/* * This function starts a new track segment. * If a new track segment is in progress, ends this current new segment, * and created a new one. */ TRACK* PCB_EDIT_FRAME::Begin_Route( TRACK* aTrack, wxDC* aDC ) { TRACK* TrackOnStartPoint = NULL; int layerMask = GetLayerMask( GetScreen()->m_Active_Layer ); BOARD_CONNECTED_ITEM* LockPoint; wxPoint pos = GetScreen()->GetCrossHairPosition(); if( aTrack == NULL ) // Starting a new track segment { m_canvas->SetMouseCapture( ShowNewTrackWhenMovingCursor, Abort_Create_Track ); // Prepare the undo command info s_ItemsListPicker.ClearListAndDeleteItems(); // Should not be necessary, but... GetBoard()->PushHighLight(); // erase old highlight if( GetBoard()->IsHighLightNetON() ) HighLight( aDC ); g_CurrentTrackList.PushBack( new TRACK( GetBoard() ) ); g_CurrentTrackSegment->SetFlags( IS_NEW ); GetBoard()->SetHighLightNet( 0 ); // Search for a starting point of the new track, a track or pad LockPoint = GetBoard()->GetLockPoint( pos, layerMask ); D_PAD* pad = NULL; if( LockPoint ) // An item (pad or track) is found { if( LockPoint->Type() == PCB_PAD_T ) { pad = (D_PAD*) LockPoint; // A pad is found: put the starting point on pad center pos = pad->GetPosition(); GetBoard()->SetHighLightNet( pad->GetNet() ); } else // A track segment is found { TrackOnStartPoint = (TRACK*) LockPoint; GetBoard()->SetHighLightNet( TrackOnStartPoint->GetNet() ); GetBoard()->CreateLockPoint( pos, TrackOnStartPoint, &s_ItemsListPicker ); } } else { // Not a starting point, but a filled zone area can exist. This is also a // good starting point. ZONE_CONTAINER* zone; zone = GetBoard()->HitTestForAnyFilledArea( pos, GetScreen()-> m_Active_Layer ); if( zone ) GetBoard()->SetHighLightNet( zone->GetNet() ); } D( g_CurrentTrackList.VerifyListIntegrity() ); BuildAirWiresTargetsList( LockPoint, wxPoint( 0, 0 ), true ); D( g_CurrentTrackList.VerifyListIntegrity() ); GetBoard()->HighLightON(); GetBoard()->DrawHighLight( m_canvas, aDC, GetBoard()->GetHighLightNetCode() ); // Display info about track Net class, and init track and vias sizes: g_CurrentTrackSegment->SetNet( GetBoard()->GetHighLightNetCode() ); GetBoard()->SetCurrentNetClass( g_CurrentTrackSegment->GetNetClassName() ); g_CurrentTrackSegment->SetLayer( GetScreen()->m_Active_Layer ); g_CurrentTrackSegment->SetWidth( GetBoard()->GetCurrentTrackWidth() ); if( GetBoard()->GetDesignSettings().m_UseConnectedTrackWidth ) { if( TrackOnStartPoint && TrackOnStartPoint->Type() == PCB_TRACE_T ) g_CurrentTrackSegment->SetWidth( TrackOnStartPoint->GetWidth()); } g_CurrentTrackSegment->SetStart( pos ); g_CurrentTrackSegment->SetEnd( pos ); if( pad ) { g_CurrentTrackSegment->m_PadsConnected.push_back( pad ); // Useful to display track length, if the pad has a die length: g_CurrentTrackSegment->SetState( BEGIN_ONPAD, ON ); g_CurrentTrackSegment->start = pad; } if( g_TwoSegmentTrackBuild ) { // Create 2nd segment g_CurrentTrackList.PushBack( (TRACK*)g_CurrentTrackSegment->Clone() ); D( g_CurrentTrackList.VerifyListIntegrity(); ); g_CurrentTrackSegment->start = g_FirstTrackSegment; g_FirstTrackSegment->end = g_CurrentTrackSegment; g_FirstTrackSegment->SetState( BEGIN_ONPAD | END_ONPAD, OFF ); }
// Place a dragged (or moved) track segment or via bool PCB_EDIT_FRAME::PlaceDraggedOrMovedTrackSegment( TRACK* Track, wxDC* DC ) { int errdrc; if( Track == NULL ) return false; int current_net_code = Track->GetNetCode(); // DRC control: if( g_Drc_On ) { errdrc = m_drc->Drc( Track, GetBoard()->m_Track ); if( errdrc == BAD_DRC ) return false; // Redraw the dragged segments for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ ) { errdrc = m_drc->Drc( g_DragSegmentList[ii].m_Track, GetBoard()->m_Track ); if( errdrc == BAD_DRC ) return false; } } // DRC Ok: place track segments Track->ClearFlags(); Track->SetState( IN_EDIT, false ); // Draw dragged tracks for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ ) { Track = g_DragSegmentList[ii].m_Track; Track->SetState( IN_EDIT, false ); Track->ClearFlags(); /* Test the connections modified by the move * (only pad connection must be tested, track connection will be * tested by TestNetConnection() ) */ LAYER_MSK layerMask = GetLayerMask( Track->GetLayer() ); Track->start = GetBoard()->GetPadFast( Track->GetStart(), layerMask ); if( Track->start ) Track->SetState( BEGIN_ONPAD, true ); else Track->SetState( BEGIN_ONPAD, false ); Track->end = GetBoard()->GetPadFast( Track->GetEnd(), layerMask ); if( Track->end ) Track->SetState( END_ONPAD, true ); else Track->SetState( END_ONPAD, false ); } EraseDragList(); SaveCopyInUndoList( s_ItemsListPicker, UR_UNSPECIFIED ); s_ItemsListPicker.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items GetBoard()->PopHighLight(); OnModify(); m_canvas->SetMouseCapture( NULL, NULL ); if( current_net_code > 0 ) TestNetConnection( DC, current_net_code ); m_canvas->Refresh(); return true; }
/** * Function Magnetize * tests to see if there are any magnetic items within near reach of the given * "curpos". If yes, then curpos is adjusted appropriately according to that * near magnetic item and true is returned. * @param frame = the current frame * @param aCurrentTool = the current tool id (from vertical right toolbar) * @param aGridSize = the current grid size * @param on_grid = the on grid position near initial position ( often on_grid = curpos) * @param curpos The initial position, and what to adjust if a change is needed. * @return bool - true if the position was adjusted magnetically, else false. */ bool Magnetize( PCB_EDIT_FRAME* frame, int aCurrentTool, wxSize aGridSize, wxPoint on_grid, wxPoint* curpos ) { bool doCheckNet = g_MagneticPadOption != capture_always && g_Drc_On; bool doTrack = false; bool doPad = false; bool amMovingVia = false; BOARD* m_Pcb = frame->GetBoard(); TRACK* currTrack = g_CurrentTrackSegment; BOARD_ITEM* currItem = frame->GetCurItem(); PCB_SCREEN* screen = frame->GetScreen(); wxPoint pos = frame->RefPos( true ); // D( printf( "currTrack=%p currItem=%p currTrack->Type()=%d currItem->Type()=%d\n", currTrack, currItem, currTrack ? currTrack->Type() : 0, currItem ? currItem->Type() : 0 ); ) if( !currTrack && currItem && currItem->Type()==PCB_VIA_T && currItem->GetFlags() ) { // moving a VIA currTrack = (TRACK*) currItem; amMovingVia = true; return false; // comment this return out and play with it. } else if( currItem != currTrack ) { currTrack = NULL; } if( g_MagneticPadOption == capture_always ) doPad = true; if( g_MagneticTrackOption == capture_always ) doTrack = true; if( aCurrentTool == ID_TRACK_BUTT || amMovingVia ) { int q = capture_cursor_in_track_tool; if( g_MagneticPadOption == q ) doPad = true; if( g_MagneticTrackOption == q ) doTrack = true; } // D(printf("doPad=%d doTrack=%d aCurrentTool=%d amMovingVia=%d\n", doPad, doTrack, aCurrentTool, amMovingVia );) // The search precedence order is pads, then tracks/vias if( doPad ) { LAYER_MSK layer_mask = GetLayerMask( screen->m_Active_Layer ); D_PAD* pad = m_Pcb->GetPad( pos, layer_mask ); if( pad ) { if( doCheckNet && currTrack && currTrack->GetNetCode() != pad->GetNetCode() ) return false; *curpos = pad->GetPosition(); return true; } } // after pads, only track & via tests remain, skip them if not desired if( doTrack ) { LAYER_NUM layer = screen->m_Active_Layer; for( TRACK* via = m_Pcb->m_Track; via && (via = via->GetVia( *curpos, layer )) != NULL; via = via->Next() ) { if( via != currTrack ) // a via cannot influence itself { if( !doCheckNet || !currTrack || currTrack->GetNetCode() == via->GetNetCode() ) { *curpos = via->GetStart(); // D(printf("via hit\n");) return true; } } } if( !currTrack ) { LAYER_MSK layer_mask = GetLayerMask( layer ); TRACK* track = m_Pcb->GetTrack( m_Pcb->m_Track, pos, layer_mask ); if( !track || track->Type() != PCB_TRACE_T ) { // D(printf("!currTrack and track=%p not found, layer_mask=0x%X\n", track, layer_mask );) return false; } // D( printf( "Project\n" ); ) return Project( curpos, on_grid, track ); } /* * In two segment mode, ignore the final segment if it's inside a grid square. */ if( !amMovingVia && currTrack && g_TwoSegmentTrackBuild && currTrack->Back() && currTrack->GetStart().x - aGridSize.x < currTrack->GetEnd().x && currTrack->GetStart().x + aGridSize.x > currTrack->GetEnd().x && currTrack->GetStart().y - aGridSize.y < currTrack->GetEnd().y && currTrack->GetStart().y + aGridSize.y > currTrack->GetEnd().y ) { currTrack = currTrack->Back(); } for( TRACK* track = m_Pcb->m_Track; track; track = track->Next() ) { if( track->Type() != PCB_TRACE_T ) continue; if( doCheckNet && currTrack && currTrack->GetNetCode() != track->GetNetCode() ) continue; if( m_Pcb->IsLayerVisible( track->GetLayer() ) == false ) continue; // omit the layer check if moving a via if( !amMovingVia && !track->IsOnLayer( layer ) ) continue; if( !track->HitTest( *curpos ) ) continue; // D(printf( "have track prospect\n");) if( Join( curpos, track->GetStart(), track->GetEnd(), currTrack->GetStart(), currTrack->GetEnd() ) ) { // D(printf( "join currTrack->Type()=%d\n", currTrack->Type() );) return true; } if( aCurrentTool == ID_TRACK_BUTT || amMovingVia ) { // At this point we have a drawing mouse on a track, we are drawing // a new track and that new track is parallel to the track the // mouse is on. Find the nearest end point of the track under mouse // to the mouse and return that. double distStart = GetLineLength( *curpos, track->GetStart() ); double distEnd = GetLineLength( *curpos, track->GetEnd() ); // if track not via, or if its a via dragging but not with its adjacent track if( currTrack->Type() != PCB_VIA_T || ( currTrack->GetStart() != track->GetStart() && currTrack->GetStart() != track->GetEnd() )) { if( distStart <= currTrack->GetWidth()/2 ) { // D(printf("nearest end is start\n");) *curpos = track->GetStart(); return true; } if( distEnd <= currTrack->GetWidth()/2 ) { // D(printf("nearest end is end\n");) *curpos = track->GetEnd(); return true; } // @todo otherwise confine curpos such that it stays centered within "track" } } } } return false; }