bool BOARD_PRINTOUT_CONTROLLER::OnPrintPage( int aPage ) { LSET lset = 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 { // This sequence is TBD, call a different // sequencer if needed, such as Seq(). Could not find documentation on // page order. LSEQ seq = lset.UIOrder(); // aPage starts at 1, not 0 if( unsigned( aPage-1 ) < seq.size() ) m_PrintParams.m_PrintMaskLayer = LSET( seq[aPage-1] ); } if( !m_PrintParams.m_PrintMaskLayer.any() ) return false; // In Pcbnew we can want the layer EDGE always printed if( m_PrintParams.m_Flags == 1 ) m_PrintParams.m_PrintMaskLayer.set( Edge_Cuts ); DrawPage(); m_PrintParams.m_PrintMaskLayer = lset; return true; }
bool DIALOG_SWAP_LAYERS::TransferDataToWindow() { LSET enabledCopperLayers = LSET::AllCuMask( m_parent->GetBoard()->GetCopperLayerCount() ); int row = 0; for( size_t layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer ) { if( enabledCopperLayers.test( layer ) ) { auto attr = new wxGridCellAttr; attr->SetRenderer( new GRID_CELL_LAYER_RENDERER( m_parent ) ); attr->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_MENU ) ); attr->SetReadOnly(); m_grid->SetAttr( row, 0, attr ); attr = new wxGridCellAttr; attr->SetRenderer( new GRID_CELL_LAYER_RENDERER( m_parent ) ); attr->SetEditor( new GRID_CELL_LAYER_SELECTOR( m_parent, LSET::AllNonCuMask() ) ); m_grid->SetAttr( row, 1, attr ); m_grid->GetTable()->SetValueAsLong( row, 0, (long) layer ); m_grid->GetTable()->SetValueAsLong( row, 1, (long) layer ); ++row; } } return true; }
/* Place module on Routing matrix. */ void genModuleOnRoutingMatrix( MODULE* Module ) { int ox, oy, fx, fy; LSET layerMask; D_PAD* Pad; EDA_RECT fpBBox = Module->GetBoundingBox(); fpBBox.Inflate( RoutingMatrix.m_GridRouting / 2 ); ox = fpBBox.GetX(); fx = fpBBox.GetRight(); oy = fpBBox.GetY(); fy = fpBBox.GetBottom(); if( ox < RoutingMatrix.m_BrdBox.GetX() ) ox = RoutingMatrix.m_BrdBox.GetX(); if( ox > RoutingMatrix.m_BrdBox.GetRight() ) ox = RoutingMatrix.m_BrdBox.GetRight(); if( fx < RoutingMatrix.m_BrdBox.GetX() ) fx = RoutingMatrix.m_BrdBox.GetX(); if( fx > RoutingMatrix.m_BrdBox.GetRight() ) fx = RoutingMatrix.m_BrdBox.GetRight(); if( oy < RoutingMatrix.m_BrdBox.GetY() ) oy = RoutingMatrix.m_BrdBox.GetY(); if( oy > RoutingMatrix.m_BrdBox.GetBottom() ) oy = RoutingMatrix.m_BrdBox.GetBottom(); if( fy < RoutingMatrix.m_BrdBox.GetY() ) fy = RoutingMatrix.m_BrdBox.GetY(); if( fy > RoutingMatrix.m_BrdBox.GetBottom() ) fy = RoutingMatrix.m_BrdBox.GetBottom(); if( Module->GetLayer() == F_Cu ) layerMask.set( F_Cu ); if( Module->GetLayer() == B_Cu ) layerMask.set( B_Cu ); TraceFilledRectangle( ox, oy, fx, fy, layerMask, CELL_is_MODULE, WRITE_OR_CELL ); // Trace pads + clearance areas. for( Pad = Module->Pads(); Pad != NULL; Pad = Pad->Next() ) { int margin = (RoutingMatrix.m_GridRouting / 2) + Pad->GetClearance(); ::PlacePad( Pad, CELL_is_MODULE, margin, WRITE_OR_CELL ); } // Trace clearance. int margin = ( RoutingMatrix.m_GridRouting * Module->GetPadCount() ) / GAIN; CreateKeepOutRectangle( ox, oy, fx, fy, margin, KEEP_OUT_MARGIN, layerMask ); }
// Reload the Layers void PCB_LAYER_BOX_SELECTOR::Resync() { Clear(); // Tray to fix a minimum width fot the BitmapComboBox int minwidth = 80; wxClientDC dc( GetParent() ); // The DC for "this" is not always initialized const int BM_SIZE = 14; LSET show = LSET::AllLayersMask() & ~m_layerMaskDisable; LSET activated = getEnabledLayers() & ~m_layerMaskDisable; wxString layerstatus; for( LSEQ seq = show.UIOrder(); seq; ++seq ) { LAYER_ID layerid = *seq; if( !m_showNotEnabledBrdlayers && !activated[layerid] ) continue; else if( !activated[layerid] ) layerstatus = wxT( " " ) + _( "(not activated)" ); else layerstatus.Empty(); wxBitmap layerbmp( BM_SIZE, BM_SIZE ); SetBitmapLayer( layerbmp, layerid ); wxString layername = GetLayerName( layerid ) + layerstatus; if( m_layerhotkeys && m_hotkeys ) { int id = layer2hotkey_id( layerid ); if( id != -1 ) layername = AddHotkeyName( layername, m_hotkeys, id, IS_COMMENT ); } Append( layername, layerbmp, (void*)(intptr_t) layerid ); int w, h; 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 ) ); }
wxString LayerMaskDescribe( const BOARD *aBoard, LSET aMask ) { // Try to be smart and useful. Check all copper first. if( aMask[F_Cu] && aMask[B_Cu] ) return _( "All copper layers" ); // Check for copper. auto layer = aBoard->GetEnabledLayers().AllCuMask() & aMask; for( int i = 0; i < 2; i++ ) { for( int bit = PCBNEW_LAYER_ID_START; bit < PCB_LAYER_ID_COUNT; ++bit ) { if( layer[ bit ] ) { wxString layerInfo = aBoard->GetLayerName( static_cast<PCB_LAYER_ID>( bit ) ); if( aMask.count() > 1 ) layerInfo << _( " and others" ); return layerInfo; } } // No copper; check for technicals. layer = aBoard->GetEnabledLayers().AllTechMask() & aMask; } // No copper, no technicals: no layer return _( "no layers" ); }
// Compute the access code for a pad. Returns -1 if there is no copper static int compute_pad_access_code( BOARD *aPcb, LSET aLayerMask ) { // Non-copper is not interesting here aLayerMask &= LSET::AllCuMask(); if( !aLayerMask.any() ) return -1; // Traditional TH pad if( aLayerMask[F_Cu] && aLayerMask[B_Cu] ) return 0; // Front SMD pad if( aLayerMask[F_Cu] ) return 1; // Back SMD pad if( aLayerMask[B_Cu] ) 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 layer = In1_Cu; layer < B_Cu; ++layer ) { if( aLayerMask[layer] ) return layer + 1; } // This shouldn't happen return -1; }
wxString LayerMaskDescribe( const BOARD *aBoard, LSET aMask ) { // Try the single or no- layer case (easy) PCB_LAYER_ID layer = aMask.ExtractLayer(); switch( (int) layer ) { case UNSELECTED_LAYER: return _( "No layers" ); case UNDEFINED_LAYER: break; default: return aBoard->GetLayerName( layer ); } // Try to be smart and useful, starting with outer copper // (which are more important than internal ones) wxString layerInfo; if( aMask[F_Cu] ) AccumulateDescription( layerInfo, aBoard->GetLayerName( F_Cu ) ); if( aMask[B_Cu] ) AccumulateDescription( layerInfo, aBoard->GetLayerName( B_Cu ) ); if( ( aMask & LSET::InternalCuMask() ).any() ) AccumulateDescription( layerInfo, _("Internal" ) ); if( ( aMask & LSET::AllNonCuMask() ).any() ) AccumulateDescription( layerInfo, _("Non-copper" ) ); return layerInfo; }
LSET DIALOG_LAYERS_SETUP::getUILayerMask() { LSET layerMaskResult; for( LSEQ seq = dlg_layers(); seq; ++seq ) { LAYER_ID layer = *seq; wxCheckBox* ctl = getCheckBox( layer ); if( ctl->GetValue() ) { layerMaskResult.set( layer ); } } return layerMaskResult; }
static std::string fmt_mask( LSET aSet ) { #if 0 return aSet.FmtHex(); #else return StrPrintf( "%08x", (unsigned) ( aSet & LSET::AllCuMask() ).to_ulong() ); #endif }
bool PCB_SELECTION_CONDITIONS::sameLayerFunc( const SELECTION& aSelection ) { if( aSelection.Empty() ) return false; LSET layerSet; layerSet.set(); for( const auto& i : aSelection ) { auto item = static_cast<BOARD_ITEM*>( i ); layerSet &= item->GetLayerSet(); if( !layerSet.any() ) // there are no common layers left return false; } return true; }
bool DIALOG_SWAP_LAYERS::TransferDataFromWindow() { if( !m_grid->CommitPendingChanges() ) return false; LSET enabledCopperLayers = LSET::AllCuMask( m_parent->GetBoard()->GetCopperLayerCount() ); wxGridTableBase* table = m_grid->GetTable(); int row = 0; for( size_t layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer ) { if( enabledCopperLayers.test( layer ) ) m_layerDestinations[ layer ] = (PCB_LAYER_ID) table->GetValueAsLong( row++, 1 ); else m_layerDestinations[ layer ] = (PCB_LAYER_ID) layer; } return true; }
LSET VIA::GetLayerSet() const { if( GetViaType() == VIA_THROUGH ) return LSET::AllCuMask(); // VIA_BLIND_BURIED or VIA_MICRVIA: LSET layermask; wxASSERT( m_Layer <= m_BottomLayer ); // LAYER_IDs are numbered from front to back, this is top to bottom. for( LAYER_NUM id = m_Layer; id <= m_BottomLayer; ++id ) { layermask.set( id ); } return layermask; }
void ReadParam( wxConfigBase* aConfig ) const override { if( !m_Pt_param || !aConfig ) return; BOARD* board = m_Pt_param; BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings(); LSET enabledLayers = bds.GetEnabledLayers(); wxString oldPath = aConfig->GetPath(); wxString layerKeyPrefix = LayerKeyPrefix; bds.SetCopperLayerCount( aConfig->Read( CopperLayerCountKey, 2 ) ); double thickness = aConfig->ReadDouble( BoardThicknessKey, DEFAULT_BOARD_THICKNESS_MM ); bds.SetBoardThickness( Millimeter2iu( thickness ) ); for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq ) { PCB_LAYER_ID layer = *seq; wxString path = layerKeyPrefix + wxT( "." ) + board->GetStandardLayerName( layer ); wxString layerName; int layerType; bool layerEnabled; aConfig->SetPath( oldPath ); aConfig->SetPath( path ); if( aConfig->Read( LayerNameKey, &layerName ) ) board->SetLayerName( layer, layerName ); if( aConfig->Read( LayerTypeKey, &layerType ) ) board->SetLayerType( layer, (LAYER_T) layerType ); if( aConfig->Read( LayerEnabledKey, &layerEnabled ) ) enabledLayers.set( layer, layerEnabled ); } board->SetEnabledLayers( enabledLayers ); aConfig->SetPath( oldPath ); }
void PCB_LAYER_WIDGET::OnLayerVisible( int aLayer, bool isVisible, bool isFinal ) { BOARD* brd = myframe->GetBoard(); LSET visibleLayers = brd->GetVisibleLayers(); visibleLayers.set( aLayer, isVisible ); brd->SetVisibleLayers( visibleLayers ); EDA_DRAW_PANEL_GAL* galCanvas = myframe->GetGalCanvas(); if( galCanvas ) { KIGFX::VIEW* view = galCanvas->GetView(); view->SetLayerVisible( aLayer, isVisible ); view->RecacheAllItems( true ); } if( isFinal ) myframe->GetCanvas()->Refresh(); }
bool BOARD_PRINTOUT_CONTROLLER::OnPrintPage( int aPage ) { LSET lset = m_PrintParams.m_PrintMaskLayer; int pageCount = lset.count(); wxString layer; LAYER_ID extractLayer; // compute layer mask from page number if we want one page per layer if( m_PrintParams.m_OptionPrintPage == 0 ) // One page per layer { // This sequence is TBD, call a different // sequencer if needed, such as Seq(). Could not find documentation on // page order. LSEQ seq = lset.UIOrder(); // aPage starts at 1, not 0 if( unsigned( aPage-1 ) < seq.size() ) m_PrintParams.m_PrintMaskLayer = LSET( seq[aPage-1] ); } if( !m_PrintParams.m_PrintMaskLayer.any() ) return false; extractLayer = m_PrintParams.m_PrintMaskLayer.ExtractLayer(); if( extractLayer == UNDEFINED_LAYER ) layer = _( "Multiple Layers" ); else layer = LSET::Name( extractLayer ); // In Pcbnew we can want the layer EDGE always printed if( m_PrintParams.m_Flags == 1 ) m_PrintParams.m_PrintMaskLayer.set( Edge_Cuts ); DrawPage( layer, aPage, pageCount ); m_PrintParams.m_PrintMaskLayer = lset; return true; }
void BOARD_DESIGN_SETTINGS::SetEnabledLayers( LSET aMask ) { // Back and front layers are always enabled. aMask.set( B_Cu ).set( F_Cu ); m_enabledLayers = aMask; // A disabled layer cannot be visible m_visibleLayers &= aMask; // update m_CopperLayerCount to ensure its consistency with m_EnabledLayers m_copperLayerCount = ( aMask & LSET::AllCuMask() ).count(); }
void PCB_LAYER_WIDGET::OnLayerVisible( int aLayer, bool isVisible, bool isFinal ) { BOARD* brd = myframe->GetBoard(); LSET visibleLayers = brd->GetVisibleLayers(); if( visibleLayers.test( aLayer ) != isVisible ) { visibleLayers.set( aLayer, isVisible ); brd->SetVisibleLayers( visibleLayers ); myframe->OnModify(); EDA_DRAW_PANEL_GAL* galCanvas = myframe->GetGalCanvas(); if( galCanvas ) galCanvas->GetView()->SetLayerVisible( aLayer, isVisible ); } if( isFinal ) myframe->GetCanvas()->Refresh(); }
bool SELECTION_CONDITIONS::sameLayerFunc( const SELECTION& aSelection ) { if( aSelection.Empty() ) return false; LSET layerSet; layerSet.set(); for( int i = 0; i < aSelection.Size(); ++i ) { const BOARD_ITEM* item = dynamic_cast<const BOARD_ITEM*>( aSelection.Item<EDA_ITEM>( i ) ); if( !item ) return false; layerSet &= item->GetLayerSet(); if( !layerSet.any() ) // there are no common layers left return false; } return true; }
void DIALOG_LAYERS_SETUP::OnPresetsChoice( wxCommandEvent& event ) { unsigned presetNdx = m_PresetsChoice->GetCurrentSelection(); if( presetNdx == 0 ) // the Custom setting controls nothing. return; if( presetNdx < DIM(presets) ) { m_EnabledLayers = presets[ presetNdx ]; LSET copperSet = m_EnabledLayers & LSET::AllCuMask(); int copperCount = copperSet.count(); m_CopperLayerCount = copperCount; showCopperChoice( m_CopperLayerCount ); showSelectedLayerCheckBoxes( m_EnabledLayers ); setCopperLayerCheckBoxes( m_CopperLayerCount ); } }
void PCB_LAYER_WIDGET::ReFill() { BOARD* brd = myframe->GetBoard(); LSET enabled = brd->GetEnabledLayers(); ClearLayerRows(); wxString dsc; // show all coppers first, with front on top, back on bottom, then technical layers for( LSEQ cu_stack = enabled.CuStack(); cu_stack; ++cu_stack ) { LAYER_ID layer = *cu_stack; switch( layer ) { case F_Cu: dsc = _("Front copper layer"); break; case B_Cu: 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_ID layerId; wxString tooltip; } non_cu_seq[] = { { F_Adhes, _( "Adhesive on board's front" ) }, { B_Adhes, _( "Adhesive on board's back" ) }, { F_Paste, _( "Solder paste on board's front" ) }, { B_Paste, _( "Solder paste on board's back" ) }, { F_SilkS, _( "Silkscreen on board's front" ) }, { B_SilkS, _( "Silkscreen on board's back" ) }, { F_Mask, _( "Solder mask on board's front" ) }, { B_Mask, _( "Solder mask on board's back" ) }, { Dwgs_User, _( "Explanatory drawings" ) }, { Cmts_User, _( "Explanatory comments" ) }, { Eco1_User, _( "User defined meaning" ) }, { Eco2_User, _( "User defined meaning" ) }, { Edge_Cuts, _( "Board's perimeter definition" ) }, { Margin, _( "Board's edge setback outline" ) }, { F_CrtYd, _( "Footprint courtyards on board's front" ) }, { B_CrtYd, _( "Footprint courtyards on board's back" ) }, { F_Fab, _( "Footprint assembly on board's front" ) }, { B_Fab, _( "Footprint assembly on board's back" ) } }; for( unsigned i=0; i<DIM(non_cu_seq); ++i ) { LAYER_ID layer = non_cu_seq[i].layerId; if( !enabled[layer] ) continue; AppendLayerRow( LAYER_WIDGET::ROW( brd->GetLayerName( layer ), layer, brd->GetLayerColor( layer ), wxGetTranslation( non_cu_seq[i].tooltip ), true ) ); } installRightLayerClickHandler(); }
void DIALOG_PLOT::applyPlotSettings() { REPORTER& reporter = m_messagesPanel->Reporter(); PCB_PLOT_PARAMS tempOptions; tempOptions.SetExcludeEdgeLayer( m_excludeEdgeLayerOpt->GetValue() ); tempOptions.SetSubtractMaskFromSilk( m_subtractMaskFromSilk->GetValue() ); tempOptions.SetPlotFrameRef( m_plotSheetRef->GetValue() ); tempOptions.SetPlotPadsOnSilkLayer( m_plotPads_on_Silkscreen->GetValue() ); tempOptions.SetUseAuxOrigin( m_useAuxOriginCheckBox->GetValue() ); tempOptions.SetPlotValue( m_plotModuleValueOpt->GetValue() ); tempOptions.SetPlotReference( m_plotModuleRefOpt->GetValue() ); tempOptions.SetPlotInvisibleText( m_plotInvisibleText->GetValue() ); tempOptions.SetScaleSelection( m_scaleOpt->GetSelection() ); tempOptions.SetDrillMarksType( static_cast<PCB_PLOT_PARAMS::DrillMarksType> ( m_drillShapeOpt->GetSelection() ) ); tempOptions.SetMirror( m_plotMirrorOpt->GetValue() ); tempOptions.SetPlotMode( m_plotModeOpt->GetSelection() == 1 ? SKETCH : FILLED ); tempOptions.SetDXFPlotPolygonMode( m_DXF_plotModeOpt->GetValue() ); tempOptions.SetPlotViaOnMaskLayer( m_plotNoViaOnMaskOpt->GetValue() ); if( !m_DXF_plotTextStrokeFontOpt->IsEnabled() ) // Currently, only DXF supports this option tempOptions.SetTextMode( PLOTTEXTMODE_DEFAULT ); else tempOptions.SetTextMode( m_DXF_plotTextStrokeFontOpt->GetValue() ? PLOTTEXTMODE_DEFAULT : PLOTTEXTMODE_NATIVE ); // Update settings from text fields. Rewrite values back to the fields, // since the values may have been constrained by the setters. // read HPLG pen size (this param is stored in mils) wxString msg = m_HPGLPenSizeOpt->GetValue(); int tmp = ValueFromString( g_UserUnit, msg ) / IU_PER_MILS; if( !tempOptions.SetHPGLPenDiameter( tmp ) ) { msg = StringFromValue( g_UserUnit, tempOptions.GetHPGLPenDiameter() * IU_PER_MILS ); m_HPGLPenSizeOpt->SetValue( msg ); msg.Printf( _( "HPGL pen size constrained." ) ); reporter.Report( msg, REPORTER::RPT_INFO ); } // Default linewidth msg = m_linesWidth->GetValue(); tmp = ValueFromString( g_UserUnit, msg ); if( !tempOptions.SetLineWidth( tmp ) ) { msg = StringFromValue( g_UserUnit, tempOptions.GetLineWidth() ); m_linesWidth->SetValue( msg ); msg.Printf( _( "Default line width constrained." ) ); reporter.Report( msg, REPORTER::RPT_INFO ); } // X scale double tmpDouble; msg = m_fineAdjustXscaleOpt->GetValue(); msg.ToDouble( &tmpDouble ); if( !setDouble( &m_XScaleAdjust, tmpDouble, PLOT_MIN_SCALE, PLOT_MAX_SCALE ) ) { msg.Printf( wxT( "%f" ), m_XScaleAdjust ); m_fineAdjustXscaleOpt->SetValue( msg ); msg.Printf( _( "X scale constrained." ) ); reporter.Report( msg, REPORTER::RPT_INFO ); } ConfigBaseWriteDouble( m_config, OPTKEY_PLOT_X_FINESCALE_ADJ, m_XScaleAdjust ); // Y scale msg = m_fineAdjustYscaleOpt->GetValue(); msg.ToDouble( &tmpDouble ); if( !setDouble( &m_YScaleAdjust, tmpDouble, PLOT_MIN_SCALE, PLOT_MAX_SCALE ) ) { msg.Printf( wxT( "%f" ), m_YScaleAdjust ); m_fineAdjustYscaleOpt->SetValue( msg ); msg.Printf( _( "Y scale constrained." ) ); reporter.Report( msg, REPORTER::RPT_INFO ); } ConfigBaseWriteDouble( m_config, OPTKEY_PLOT_Y_FINESCALE_ADJ, m_YScaleAdjust ); // PS Width correction msg = m_PSFineAdjustWidthOpt->GetValue(); int itmp = ValueFromString( g_UserUnit, msg ); if( !setInt( &m_PSWidthAdjust, itmp, m_widthAdjustMinValue, m_widthAdjustMaxValue ) ) { msg = StringFromValue( g_UserUnit, m_PSWidthAdjust ); m_PSFineAdjustWidthOpt->SetValue( msg ); msg.Printf( _( "Width correction constrained. " "The reasonable width correction value must be in a range of " " [%+f; %+f] (%s) for current design rules. " ), To_User_Unit( g_UserUnit, m_widthAdjustMinValue ), To_User_Unit( g_UserUnit, m_widthAdjustMaxValue ), ( g_UserUnit == INCHES ) ? wxT( "\"" ) : wxT( "mm" ) ); reporter.Report( msg, REPORTER::RPT_WARNING ); } // Store m_PSWidthAdjust in mm in user config ConfigBaseWriteDouble( m_config, CONFIG_PS_FINEWIDTH_ADJ, (double)m_PSWidthAdjust / IU_PER_MM ); tempOptions.SetFormat( getPlotFormat() ); tempOptions.SetUseGerberProtelExtensions( m_useGerberExtensions->GetValue() ); tempOptions.SetUseGerberAttributes( m_useGerberX2Attributes->GetValue() ); tempOptions.SetIncludeGerberNetlistInfo( m_useGerberNetAttributes->GetValue() ); tempOptions.SetCreateGerberJobFile( m_generateGerberJobFile->GetValue() ); tempOptions.SetGerberPrecision( m_rbGerberFormat->GetSelection() == 0 ? 5 : 6 ); LSET selectedLayers; for( unsigned i = 0; i < m_layerList.size(); i++ ) { if( m_layerCheckListBox->IsChecked( i ) ) selectedLayers.set( m_layerList[i] ); } // Get a list of copper layers that aren't being used by inverting enabled layers. LSET disabledCopperLayers = LSET::AllCuMask() & ~m_board->GetEnabledLayers(); // Enable all of the disabled copper layers. // If someone enables more copper layers they will be selected by default. selectedLayers = selectedLayers | disabledCopperLayers; tempOptions.SetLayerSelection( selectedLayers ); tempOptions.SetNegative( m_plotPSNegativeOpt->GetValue() ); tempOptions.SetA4Output( m_forcePSA4OutputOpt->GetValue() ); // Set output directory and replace backslashes with forward ones wxString dirStr; dirStr = m_outputDirectoryName->GetValue(); dirStr.Replace( wxT( "\\" ), wxT( "/" ) ); tempOptions.SetOutputDirectory( dirStr ); if( !m_plotOpts.IsSameAs( tempOptions, false ) ) { // First, mark board as modified only for parameters saved in file if( !m_plotOpts.IsSameAs( tempOptions, true ) ) m_parent->OnModify(); // Now, save any change, for the session m_parent->SetPlotSettings( tempOptions ); m_plotOpts = tempOptions; } }
bool DIALOG_PAD_PROPERTIES::transferDataToPad( D_PAD* aPad ) { wxString msg; int x, y; if( !Validate() ) return true; if( !m_panelGeneral->Validate() ) return true; if( !m_localSettingsPanel->Validate() ) return true; m_OrientValidator.TransferFromWindow(); aPad->SetAttribute( code_type[m_PadType->GetSelection()] ); aPad->SetShape( code_shape[m_PadShape->GetSelection()] ); // Read pad clearances values: aPad->SetLocalClearance( ValueFromTextCtrl( *m_NetClearanceValueCtrl ) ); aPad->SetLocalSolderMaskMargin( ValueFromTextCtrl( *m_SolderMaskMarginCtrl ) ); aPad->SetLocalSolderPasteMargin( ValueFromTextCtrl( *m_SolderPasteMarginCtrl ) ); aPad->SetThermalWidth( ValueFromTextCtrl( *m_ThermalWidthCtrl ) ); aPad->SetThermalGap( ValueFromTextCtrl( *m_ThermalGapCtrl ) ); double dtmp = 0.0; msg = m_SolderPasteMarginRatioCtrl->GetValue(); msg.ToDouble( &dtmp ); // A -50% margin ratio means no paste on a pad, the ratio must be >= -50% if( dtmp < -50.0 ) dtmp = -50.0; // A margin ratio is always <= 0 // 0 means use full pad copper area if( dtmp > 0.0 ) dtmp = 0.0; aPad->SetLocalSolderPasteMarginRatio( dtmp / 100 ); switch( m_ZoneConnectionChoice->GetSelection() ) { default: case 0: aPad->SetZoneConnection( PAD_ZONE_CONN_INHERITED ); break; case 1: aPad->SetZoneConnection( PAD_ZONE_CONN_FULL ); break; case 2: aPad->SetZoneConnection( PAD_ZONE_CONN_THERMAL ); break; case 3: aPad->SetZoneConnection( PAD_ZONE_CONN_NONE ); break; } // Read pad position: x = ValueFromTextCtrl( *m_PadPosition_X_Ctrl ); y = ValueFromTextCtrl( *m_PadPosition_Y_Ctrl ); aPad->SetPosition( wxPoint( x, y ) ); aPad->SetPos0( wxPoint( x, y ) ); // Read pad drill: x = ValueFromTextCtrl( *m_PadDrill_X_Ctrl ); y = ValueFromTextCtrl( *m_PadDrill_Y_Ctrl ); if( m_DrillShapeCtrl->GetSelection() == 0 ) { aPad->SetDrillShape( PAD_DRILL_SHAPE_CIRCLE ); y = x; } else aPad->SetDrillShape( PAD_DRILL_SHAPE_OBLONG ); aPad->SetDrillSize( wxSize( x, y ) ); // Read pad shape size: x = ValueFromTextCtrl( *m_ShapeSize_X_Ctrl ); y = ValueFromTextCtrl( *m_ShapeSize_Y_Ctrl ); if( aPad->GetShape() == PAD_SHAPE_CIRCLE ) y = x; aPad->SetSize( wxSize( x, y ) ); // Read pad length die aPad->SetPadToDieLength( ValueFromTextCtrl( *m_LengthPadToDieCtrl ) ); // For a trapezoid, test delta value (be sure delta is not too large for pad size) // remember DeltaSize.x is the Y size variation bool error = false; if( aPad->GetShape() == PAD_SHAPE_TRAPEZOID ) { wxSize delta; // For a trapezoid, only one of delta.x or delta.y is not 0, depending on // the direction. if( m_trapDeltaDirChoice->GetSelection() == 0 ) delta.x = ValueFromTextCtrl( *m_ShapeDelta_Ctrl ); else delta.y = ValueFromTextCtrl( *m_ShapeDelta_Ctrl ); if( delta.x < 0 && delta.x <= -aPad->GetSize().y ) { delta.x = -aPad->GetSize().y + 2; error = true; } if( delta.x > 0 && delta.x >= aPad->GetSize().y ) { delta.x = aPad->GetSize().y - 2; error = true; } if( delta.y < 0 && delta.y <= -aPad->GetSize().x ) { delta.y = -aPad->GetSize().x + 2; error = true; } if( delta.y > 0 && delta.y >= aPad->GetSize().x ) { delta.y = aPad->GetSize().x - 2; error = true; } aPad->SetDelta( delta ); } // Read pad shape offset: x = ValueFromTextCtrl( *m_ShapeOffset_X_Ctrl ); y = ValueFromTextCtrl( *m_ShapeOffset_Y_Ctrl ); aPad->SetOffset( wxPoint( x, y ) ); aPad->SetOrientation( m_OrientValue * 10.0 ); msg = m_PadNumCtrl->GetValue().Left( 4 ); aPad->SetPadName( msg ); // Check if user has set an existing net name const NETINFO_ITEM* netinfo = m_board->FindNet( m_PadNetNameCtrl->GetValue() ); if( netinfo != NULL ) aPad->SetNetCode( netinfo->GetNet() ); else aPad->SetNetCode( NETINFO_LIST::UNCONNECTED ); // Clear some values, according to the pad type and shape switch( aPad->GetShape() ) { case PAD_SHAPE_CIRCLE: aPad->SetOffset( wxPoint( 0, 0 ) ); aPad->SetDelta( wxSize( 0, 0 ) ); x = aPad->GetSize().x; aPad->SetSize( wxSize( x, x ) ); break; case PAD_SHAPE_RECT: aPad->SetDelta( wxSize( 0, 0 ) ); break; case PAD_SHAPE_OVAL: aPad->SetDelta( wxSize( 0, 0 ) ); break; case PAD_SHAPE_TRAPEZOID: break; case PAD_SHAPE_ROUNDRECT: aPad->SetDelta( wxSize( 0, 0 ) ); break; default: ; } switch( aPad->GetAttribute() ) { case PAD_ATTRIB_STANDARD: break; case PAD_ATTRIB_CONN: case PAD_ATTRIB_SMD: // SMD and PAD_ATTRIB_CONN has no hole. // basically, SMD and PAD_ATTRIB_CONN are same type of pads // PAD_ATTRIB_CONN has just a default non technical layers that differs from SMD // and are intended to be used in virtual edge board connectors // However we can accept a non null offset, // mainly to allow complex pads build from a set of basic pad shapes aPad->SetDrillSize( wxSize( 0, 0 ) ); break; case PAD_ATTRIB_HOLE_NOT_PLATED: // Mechanical purpose only: // no offset, no net name, no pad name allowed aPad->SetOffset( wxPoint( 0, 0 ) ); aPad->SetPadName( wxEmptyString ); aPad->SetNetCode( NETINFO_LIST::UNCONNECTED ); break; default: DisplayError( NULL, wxT( "Error: unknown pad type" ) ); break; } if( aPad->GetShape() == PAD_SHAPE_ROUNDRECT ) { wxString value = m_tcCornerSizeRatio->GetValue(); double rrRadiusRatioPercent; if( value.ToDouble( &rrRadiusRatioPercent ) ) aPad->SetRoundRectRadiusRatio( rrRadiusRatioPercent / 100.0 ); } LSET padLayerMask; switch( m_rbCopperLayersSel->GetSelection() ) { case 0: padLayerMask.set( F_Cu ); break; case 1: padLayerMask.set( B_Cu ); break; case 2: padLayerMask |= LSET::AllCuMask(); break; case 3: // No copper layers break; } if( m_PadLayerAdhCmp->GetValue() ) padLayerMask.set( F_Adhes ); if( m_PadLayerAdhCu->GetValue() ) padLayerMask.set( B_Adhes ); if( m_PadLayerPateCmp->GetValue() ) padLayerMask.set( F_Paste ); if( m_PadLayerPateCu->GetValue() ) padLayerMask.set( B_Paste ); if( m_PadLayerSilkCmp->GetValue() ) padLayerMask.set( F_SilkS ); if( m_PadLayerSilkCu->GetValue() ) padLayerMask.set( B_SilkS ); if( m_PadLayerMaskCmp->GetValue() ) padLayerMask.set( F_Mask ); if( m_PadLayerMaskCu->GetValue() ) padLayerMask.set( B_Mask ); if( m_PadLayerECO1->GetValue() ) padLayerMask.set( Eco1_User ); if( m_PadLayerECO2->GetValue() ) padLayerMask.set( Eco2_User ); if( m_PadLayerDraft->GetValue() ) padLayerMask.set( Dwgs_User ); aPad->SetLayerSet( padLayerMask ); return error; }
// Redraw the BOARD items but not cursors, axis or grid void BOARD::Draw( EDA_DRAW_PANEL* aPanel, wxDC* DC, GR_DRAWMODE aDrawMode, const wxPoint& offset ) { /* The order of drawing is flexible on some systems and not on others. For * OSes which use OR to draw, the order is not important except for the * effect of the highlight and its relationship to markers. See comment * below. * This order independence comes from the fact that a binary OR operation is * commutative in nature. * However on the OSX, the OR operation is not used, and so this sequence * below is chosen to give MODULEs the highest visible priority. */ /* Draw all tracks and zones. As long as dark colors are used for the * tracks, Then the OR draw mode should show tracks underneath other * tracks. But a white track will cover any other color since it has * more bits to OR in. */ for( TRACK* track = m_Track; track; track = track->Next() ) { if( track->IsMoving() ) continue; track->Draw( aPanel, DC, aDrawMode ); } // Draw areas (i.e. zones) for( int ii = 0; ii < GetAreaCount(); ii++ ) { ZONE_CONTAINER* zone = GetArea( ii ); // Areas must be drawn here only if not moved or dragged, // because these areas are drawn by ManageCursor() in a specific manner if( ( zone->GetEditFlags() & (IN_EDIT | IS_DRAGGED | IS_MOVED) ) == 0 ) { zone->Draw( aPanel, DC, aDrawMode ); zone->DrawFilledArea( aPanel, DC, aDrawMode ); } } // Draw the graphic items for( BOARD_ITEM* item = m_Drawings; item; item = item->Next() ) { if( item->IsMoving() ) continue; switch( item->Type() ) { case PCB_DIMENSION_T: case PCB_TEXT_T: case PCB_TARGET_T: case PCB_LINE_T: item->Draw( aPanel, DC, aDrawMode ); break; default: break; } } LSET all_cu = LSET::AllCuMask(); for( MODULE* module = m_Modules; module; module = module->Next() ) { bool display = true; LSET layerMask = all_cu; if( module->IsMoving() ) continue; if( !IsElementVisible( LAYER_MOD_FR ) ) { if( module->GetLayer() == F_Cu ) display = false; layerMask.set( F_Cu, false ); } if( !IsElementVisible( LAYER_MOD_BK ) ) { if( module->GetLayer() == B_Cu ) display = false; layerMask.set( B_Cu, false ); } if( display ) module->Draw( aPanel, DC, aDrawMode ); else Trace_Pads_Only( aPanel, DC, module, 0, 0, layerMask, aDrawMode ); } // draw the BOARD's markers last, otherwise the high light will erase any marker on a pad for( unsigned i = 0; i < m_markers.size(); ++i ) { m_markers[i]->Draw( aPanel, DC, aDrawMode ); } }
/* Plot outlines of copper, for copper layer */ void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask, const PCB_PLOT_PARAMS& aPlotOpt ) { BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt ); itemplotter.SetLayerSet( aLayerMask ); SHAPE_POLY_SET outlines; for( LSEQ seq = aLayerMask.Seq( plot_seq, DIM( plot_seq ) ); seq; ++seq ) { LAYER_ID layer = *seq; outlines.RemoveAllContours(); aBoard->ConvertBrdLayerToPolygonalContours( layer, outlines ); outlines.Simplify(); // Plot outlines std::vector< wxPoint > cornerList; // Now we have one or more basic polygons: plot each polygon for( int ii = 0; ii < outlines.OutlineCount(); ii++ ) { for(int kk = 0; kk <= outlines.HoleCount (ii); kk++ ) { cornerList.clear(); const SHAPE_LINE_CHAIN& path = (kk == 0) ? outlines.COutline( ii ) : outlines.CHole( ii, kk - 1 ); for( int jj = 0; jj < path.PointCount(); jj++ ) cornerList.push_back( wxPoint( path.CPoint( jj ).x , path.CPoint( 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_PLOT::applyPlotSettings() { REPORTER& reporter = m_messagesPanel->Reporter(); PCB_PLOT_PARAMS tempOptions; tempOptions.SetExcludeEdgeLayer( m_excludeEdgeLayerOpt->GetValue() ); tempOptions.SetSubtractMaskFromSilk( m_subtractMaskFromSilk->GetValue() ); tempOptions.SetPlotFrameRef( m_plotSheetRef->GetValue() ); tempOptions.SetPlotPadsOnSilkLayer( m_plotPads_on_Silkscreen->GetValue() ); tempOptions.SetUseAuxOrigin( m_useAuxOriginCheckBox->GetValue() ); tempOptions.SetPlotValue( m_plotModuleValueOpt->GetValue() ); tempOptions.SetPlotReference( m_plotModuleRefOpt->GetValue() ); tempOptions.SetPlotInvisibleText( m_plotInvisibleText->GetValue() ); tempOptions.SetScaleSelection( m_scaleOpt->GetSelection() ); tempOptions.SetDrillMarksType( static_cast<PCB_PLOT_PARAMS::DrillMarksType> ( m_drillShapeOpt->GetSelection() ) ); tempOptions.SetMirror( m_plotMirrorOpt->GetValue() ); tempOptions.SetPlotMode( m_plotModeOpt->GetSelection() == 1 ? SKETCH : FILLED ); tempOptions.SetPlotViaOnMaskLayer( m_plotNoViaOnMaskOpt->GetValue() ); // Update settings from text fields. Rewrite values back to the fields, // since the values may have been constrained by the setters. // read HPLG pen size (this param is stored in mils) wxString msg = m_HPGLPenSizeOpt->GetValue(); int tmp = ValueFromString( g_UserUnit, msg ) / IU_PER_MILS; if( !tempOptions.SetHPGLPenDiameter( tmp ) ) { msg = StringFromValue( g_UserUnit, tempOptions.GetHPGLPenDiameter() * IU_PER_MILS ); m_HPGLPenSizeOpt->SetValue( msg ); msg.Printf( _( "HPGL pen size constrained." ) ); reporter.Report( msg, REPORTER::RPT_INFO ); } // Read HPGL pen overlay (this param is stored in mils) msg = m_HPGLPenOverlayOpt->GetValue(); tmp = ValueFromString( g_UserUnit, msg ) / IU_PER_MILS; if( !tempOptions.SetHPGLPenOverlay( tmp ) ) { msg = StringFromValue( g_UserUnit, tempOptions.GetHPGLPenOverlay() * IU_PER_MILS ); m_HPGLPenOverlayOpt->SetValue( msg ); msg.Printf( _( "HPGL pen overlay constrained." ) ); reporter.Report( msg, REPORTER::RPT_INFO ); } // Default linewidth msg = m_linesWidth->GetValue(); tmp = ValueFromString( g_UserUnit, msg ); if( !tempOptions.SetLineWidth( tmp ) ) { msg = StringFromValue( g_UserUnit, tempOptions.GetLineWidth() ); m_linesWidth->SetValue( msg ); msg.Printf( _( "Default line width constrained." ) ); reporter.Report( msg, REPORTER::RPT_INFO ); } // X scale double tmpDouble; msg = m_fineAdjustXscaleOpt->GetValue(); msg.ToDouble( &tmpDouble ); if( !setDouble( &m_XScaleAdjust, tmpDouble, PLOT_MIN_SCALE, PLOT_MAX_SCALE ) ) { msg.Printf( wxT( "%f" ), m_XScaleAdjust ); m_fineAdjustXscaleOpt->SetValue( msg ); msg.Printf( _( "X scale constrained." ) ); reporter.Report( msg, REPORTER::RPT_INFO ); } ConfigBaseWriteDouble( m_config, OPTKEY_PLOT_X_FINESCALE_ADJ, m_XScaleAdjust ); // Y scale msg = m_fineAdjustYscaleOpt->GetValue(); msg.ToDouble( &tmpDouble ); if( !setDouble( &m_YScaleAdjust, tmpDouble, PLOT_MIN_SCALE, PLOT_MAX_SCALE ) ) { msg.Printf( wxT( "%f" ), m_YScaleAdjust ); m_fineAdjustYscaleOpt->SetValue( msg ); msg.Printf( _( "Y scale constrained." ) ); reporter.Report( msg, REPORTER::RPT_INFO ); } ConfigBaseWriteDouble( m_config, OPTKEY_PLOT_Y_FINESCALE_ADJ, m_YScaleAdjust ); // PS Width correction msg = m_PSFineAdjustWidthOpt->GetValue(); int itmp = ValueFromString( g_UserUnit, msg ); if( !setInt( &m_PSWidthAdjust, itmp, m_widthAdjustMinValue, m_widthAdjustMaxValue ) ) { msg = StringFromValue( g_UserUnit, m_PSWidthAdjust ); m_PSFineAdjustWidthOpt->SetValue( msg ); msg.Printf( _( "Width correction constrained. " "The reasonable width correction value must be in a range of " " [%+f; %+f] (%s) for current design rules. " ), To_User_Unit( g_UserUnit, m_widthAdjustMinValue ), To_User_Unit( g_UserUnit, m_widthAdjustMaxValue ), ( g_UserUnit == INCHES ) ? wxT( "\"" ) : wxT( "mm" ) ); reporter.Report( msg, REPORTER::RPT_WARNING ); } // Store m_PSWidthAdjust in mm in user config ConfigBaseWriteDouble( m_config, CONFIG_PS_FINEWIDTH_ADJ, (double)m_PSWidthAdjust / IU_PER_MM ); tempOptions.SetFormat( getPlotFormat() ); tempOptions.SetUseGerberExtensions( m_useGerberExtensions->GetValue() ); tempOptions.SetUseGerberAttributes( m_useGerberAttributes->GetValue() ); tempOptions.SetGerberPrecision( m_rbGerberFormat->GetSelection() == 0 ? 5 : 6 ); LSET selectedLayers; for( unsigned i = 0; i < m_layerList.size(); i++ ) { if( m_layerCheckListBox->IsChecked( i ) ) selectedLayers.set( m_layerList[i] ); } tempOptions.SetLayerSelection( selectedLayers ); tempOptions.SetNegative( m_plotPSNegativeOpt->GetValue() ); tempOptions.SetA4Output( m_forcePSA4OutputOpt->GetValue() ); // Set output directory and replace backslashes with forward ones wxString dirStr; dirStr = m_outputDirectoryName->GetValue(); dirStr.Replace( wxT( "\\" ), wxT( "/" ) ); tempOptions.SetOutputDirectory( dirStr ); if( m_plotOpts != tempOptions ) { m_parent->SetPlotSettings( tempOptions ); m_plotOpts = tempOptions; m_parent->OnModify(); } }
void PCB_LAYER_WIDGET::ReFill() { BOARD* brd = myframe->GetBoard(); LSET enabled = brd->GetEnabledLayers(); ClearLayerRows(); wxString dsc; // show all coppers first, with front on top, back on bottom, then technical layers for( LSEQ cu_stack = enabled.CuStack(); cu_stack; ++cu_stack ) { PCB_LAYER_ID layer = *cu_stack; switch( layer ) { case F_Cu: dsc = _( "Front copper layer" ); break; case B_Cu: dsc = _( "Back copper layer" ); break; default: dsc = _( "Inner copper layer" ); break; } AppendLayerRow( LAYER_WIDGET::ROW( brd->GetLayerName( layer ), layer, myframe->Settings().Colors().GetLayerColor( layer ), dsc, true ) ); if( m_fp_editor_mode && LSET::ForbiddenFootprintLayers().test( layer ) ) { getLayerComp( GetLayerRowCount()-1, COLUMN_COLOR_LYRNAME )->Enable( false ); getLayerComp( GetLayerRowCount()-1, COLUMN_COLORBM )->SetToolTip( wxEmptyString ); } } UpdateLayouts(); // technical layers are shown in this order: // Because they are static, wxGetTranslation must be explicitly // called for tooltips. static const struct { PCB_LAYER_ID layerId; wxString tooltip; } non_cu_seq[] = { { F_Adhes, _( "Adhesive on board's front" ) }, { B_Adhes, _( "Adhesive on board's back" ) }, { F_Paste, _( "Solder paste on board's front" ) }, { B_Paste, _( "Solder paste on board's back" ) }, { F_SilkS, _( "Silkscreen on board's front" ) }, { B_SilkS, _( "Silkscreen on board's back" ) }, { F_Mask, _( "Solder mask on board's front" ) }, { B_Mask, _( "Solder mask on board's back" ) }, { Dwgs_User, _( "Explanatory drawings" ) }, { Cmts_User, _( "Explanatory comments" ) }, { Eco1_User, _( "User defined meaning" ) }, { Eco2_User, _( "User defined meaning" ) }, { Edge_Cuts, _( "Board's perimeter definition" ) }, { Margin, _( "Board's edge setback outline" ) }, { F_CrtYd, _( "Footprint courtyards on board's front" ) }, { B_CrtYd, _( "Footprint courtyards on board's back" ) }, { F_Fab, _( "Footprint assembly on board's front" ) }, { B_Fab, _( "Footprint assembly on board's back" ) } }; for( unsigned i=0; i<arrayDim( non_cu_seq ); ++i ) { PCB_LAYER_ID layer = non_cu_seq[i].layerId; if( !enabled[layer] ) continue; AppendLayerRow( LAYER_WIDGET::ROW( brd->GetLayerName( layer ), layer, myframe->Settings().Colors().GetLayerColor( layer ), wxGetTranslation( non_cu_seq[i].tooltip ), true ) ); if( m_fp_editor_mode && LSET::ForbiddenFootprintLayers().test( layer ) ) { getLayerComp( GetLayerRowCount()-1, COLUMN_COLOR_LYRNAME )->Enable( false ); getLayerComp( GetLayerRowCount()-1, COLUMN_COLORBM )->SetToolTip( wxEmptyString ); } } }
void PCB_EDIT_FRAME::Block_SelectItems() { LSET layerMask; bool selectOnlyComplete = GetScreen()->m_BlockLocate.GetWidth() > 0 ; GetScreen()->m_BlockLocate.Normalize(); PICKED_ITEMS_LIST* itemsList = &GetScreen()->m_BlockLocate.GetItems(); ITEM_PICKER picker( NULL, UR_UNSPECIFIED ); // Add modules if( blockIncludeModules ) { for( MODULE* module = m_Pcb->m_Modules; module; module = module->Next() ) { LAYER_ID layer = module->GetLayer(); if( module->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) && ( !module->IsLocked() || blockIncludeLockedModules ) ) { if( blockIncludeItemsOnInvisibleLayers || m_Pcb->IsModuleLayerVisible( layer ) ) { picker.SetItem ( module ); itemsList->PushItem( picker ); } } } } // Add tracks and vias if( blockIncludeTracks ) { for( TRACK* track = m_Pcb->m_Track; track != NULL; track = track->Next() ) { if( track->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) ) { if( blockIncludeItemsOnInvisibleLayers || m_Pcb->IsLayerVisible( track->GetLayer() ) ) { picker.SetItem( track ); itemsList->PushItem( picker ); } } } } // Add graphic items layerMask = LSET( Edge_Cuts ); if( blockIncludeItemsOnTechLayers ) layerMask.set(); if( !blockIncludeBoardOutlineLayer ) layerMask.set( Edge_Cuts, false ); 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( !layerMask[PtStruct->GetLayer()] ) break; if( !PtStruct->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) ) 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, selectOnlyComplete ) ) break; select_me = true; // This item is in bloc: select it break; case PCB_TARGET_T: if( !layerMask[PtStruct->GetLayer()] ) break; if( !PtStruct->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) ) break; select_me = true; // This item is in bloc: select it break; case PCB_DIMENSION_T: if( !layerMask[PtStruct->GetLayer()] ) break; if( !PtStruct->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) ) 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, selectOnlyComplete ) ) { if( blockIncludeItemsOnInvisibleLayers || m_Pcb->IsLayerVisible( area->GetLayer() ) ) { BOARD_ITEM* zone_c = (BOARD_ITEM*) area; picker.SetItem ( zone_c ); itemsList->PushItem( picker ); } } } } }
bool PCB_LAYER_WIDGET::isLayerAllowedInFpMode( PCB_LAYER_ID aLayer ) { static LSET allowed = LSET::AllTechMask(); allowed.set( F_Cu ).set( B_Cu ); return allowed.test( aLayer ); }
bool GENDRILL_WRITER_BASE::GenDrillReportFile( const wxString& aFullFileName ) { FILE_OUTPUTFORMATTER out( aFullFileName ); static const char separator[] = " =============================================================\n"; wxASSERT( m_pcb ); unsigned totalHoleCount; wxString brdFilename = m_pcb->GetFileName(); std::vector<DRILL_LAYER_PAIR> hole_sets = getUniqueLayerPairs(); out.Print( 0, "Drill report for %s\n", TO_UTF8( brdFilename ) ); out.Print( 0, "Created on %s\n\n", TO_UTF8( DateAndTime() ) ); // Output the cu layer stackup, so layer name references make sense. out.Print( 0, "Copper Layer Stackup:\n" ); out.Print( 0, separator ); LSET cu = m_pcb->GetEnabledLayers() & LSET::AllCuMask(); int conventional_layer_num = 1; for( LSEQ seq = cu.Seq(); seq; ++seq, ++conventional_layer_num ) { out.Print( 0, " L%-2d: %-25s %s\n", conventional_layer_num, TO_UTF8( m_pcb->GetLayerName( *seq ) ), layerName( *seq ).c_str() // generic layer name ); } out.Print( 0, "\n\n" ); /* output hole lists: * 1 - through holes * 2 - for partial holes only: by layer starting and ending pair * 3 - Non Plated through holes */ bool buildNPTHlist = false; // First pass: build PTH list only // in this loop are plated only: for( unsigned pair_ndx = 0; pair_ndx < hole_sets.size(); ++pair_ndx ) { DRILL_LAYER_PAIR pair = hole_sets[pair_ndx]; buildHolesList( pair, buildNPTHlist ); if( pair == DRILL_LAYER_PAIR( F_Cu, B_Cu ) ) { out.Print( 0, "Drill file '%s' contains\n", TO_UTF8( getDrillFileName( pair, false, m_merge_PTH_NPTH ) ) ); out.Print( 0, " plated through holes:\n" ); out.Print( 0, separator ); totalHoleCount = printToolSummary( out, false ); out.Print( 0, " Total plated holes count %u\n", totalHoleCount ); } else // blind/buried { out.Print( 0, "Drill file '%s' contains\n", TO_UTF8( getDrillFileName( pair, false, m_merge_PTH_NPTH ) ) ); out.Print( 0, " holes connecting layer pair: '%s and %s' (%s vias):\n", TO_UTF8( m_pcb->GetLayerName( ToLAYER_ID( pair.first ) ) ), TO_UTF8( m_pcb->GetLayerName( ToLAYER_ID( pair.second ) ) ), pair.first == F_Cu || pair.second == B_Cu ? "blind" : "buried" ); out.Print( 0, separator ); totalHoleCount = printToolSummary( out, false ); out.Print( 0, " Total plated holes count %u\n", totalHoleCount ); } out.Print( 0, "\n\n" ); } // NPTHoles. Generate the full list (pads+vias) if PTH and NPTH are merged, // or only the NPTH list (which never has vias) if( !m_merge_PTH_NPTH ) buildNPTHlist = true; buildHolesList( DRILL_LAYER_PAIR( F_Cu, B_Cu ), buildNPTHlist ); // nothing wrong with an empty NPTH file in report. if( m_merge_PTH_NPTH ) out.Print( 0, "Not plated through holes are merged with plated holes\n" ); else out.Print( 0, "Drill file '%s' contains\n", TO_UTF8( getDrillFileName( DRILL_LAYER_PAIR( F_Cu, B_Cu ), true, m_merge_PTH_NPTH ) ) ); out.Print( 0, " unplated through holes:\n" ); out.Print( 0, separator ); totalHoleCount = printToolSummary( out, true ); out.Print( 0, " Total unplated holes count %u\n", totalHoleCount ); return true; }
// 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 ); }