/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2014 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2014-2023 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or you may search the http://www.gnu.org website for the version 2 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include // for bitset, __bitset<>::ref... #include #include #include // for string, endl, basic_ost... #include // for size_t #include #include // for Clamp #include // for LSET, PCB_LAYER_ID, LSEQ #include // for arrayDim #include // for wxASSERT, wxASSERT_MSG #include LSET::LSET( const PCB_LAYER_ID* aArray, unsigned aCount ) : BASE_SET() { for( unsigned i=0; i=1. wxASSERT_MSG( aIdCount > 0, wxT( "aIdCount must be >= 1" ) ); set( aFirst ); if( --aIdCount ) { va_list ap; va_start( ap, aFirst ); for( unsigned i=0; i= size() ) break; if( ( *this )[nibble_pos] ) ndx |= ( 1 << nibble_bit ); } if( nibble && !( nibble % 8 ) ) ret += '_'; assert( ndx < arrayDim( hex ) ); ret += hex[ndx]; } // reverse of string return std::string( ret.rbegin(), ret.rend() ); } int LSET::ParseHex( const char* aStart, int aCount ) { LSET tmp; const char* rstart = aStart + aCount - 1; const char* rend = aStart - 1; const int bitcount = size(); int nibble_ndx = 0; while( rstart > rend ) { int cc = *rstart--; if( cc == '_' ) continue; int nibble; if( cc >= '0' && cc <= '9' ) nibble = cc - '0'; else if( cc >= 'a' && cc <= 'f' ) nibble = cc - 'a' + 10; else if( cc >= 'A' && cc <= 'F' ) nibble = cc - 'A' + 10; else break; int bit = nibble_ndx * 4; for( int ndx=0; bit= bitcount ) break; ++nibble_ndx; } int byte_count = aStart + aCount - 1 - rstart; assert( byte_count >= 0 ); if( byte_count > 0 ) *this = tmp; return byte_count; } LSEQ LSET::Seq( const PCB_LAYER_ID* aWishListSequence, unsigned aCount ) const { LSEQ ret; #if defined(DEBUG) && 0 LSET dup_detector; for( unsigned i=0; i= 4 if( IsCopperLayer( aLayerId ) && aCopperLayersCount >= 4 ) { // internal copper layers count is aCopperLayersCount-2 PCB_LAYER_ID fliplayer = PCB_LAYER_ID(aCopperLayersCount - 2 - ( aLayerId - In1_Cu ) ); // Ensure fliplayer has a value which does not crash Pcbnew: if( fliplayer < F_Cu ) fliplayer = F_Cu; if( fliplayer > B_Cu ) fliplayer = B_Cu; return fliplayer; } // No change for the other layers return aLayerId; } } LSET FlipLayerMask( LSET aMask, int aCopperLayersCount ) { // layers on physical outside of a board: const static LSET and_mask( 16, // !! update count B_Cu, F_Cu, B_SilkS, F_SilkS, B_Adhes, F_Adhes, B_Mask, F_Mask, B_Paste, F_Paste, B_Adhes, F_Adhes, B_CrtYd, F_CrtYd, B_Fab, F_Fab ); LSET newMask = aMask & ~and_mask; if( aMask[B_Cu] ) newMask.set( F_Cu ); if( aMask[F_Cu] ) newMask.set( B_Cu ); if( aMask[B_SilkS] ) newMask.set( F_SilkS ); if( aMask[F_SilkS] ) newMask.set( B_SilkS ); if( aMask[B_Adhes] ) newMask.set( F_Adhes ); if( aMask[F_Adhes] ) newMask.set( B_Adhes ); if( aMask[B_Mask] ) newMask.set( F_Mask ); if( aMask[F_Mask] ) newMask.set( B_Mask ); if( aMask[B_Paste] ) newMask.set( F_Paste ); if( aMask[F_Paste] ) newMask.set( B_Paste ); if( aMask[B_Adhes] ) newMask.set( F_Adhes ); if( aMask[F_Adhes] ) newMask.set( B_Adhes ); if( aMask[B_CrtYd] ) newMask.set( F_CrtYd ); if( aMask[F_CrtYd] ) newMask.set( B_CrtYd ); if( aMask[B_Fab] ) newMask.set( F_Fab ); if( aMask[F_Fab] ) newMask.set( B_Fab ); if( aCopperLayersCount >= 4 ) // Internal layers exist { LSET internalMask = aMask & LSET::InternalCuMask(); if( internalMask != LSET::InternalCuMask() ) { // the mask does not include all internal layers. Therefore // the flipped mask for internal copper layers must be built int innerLayerCnt = aCopperLayersCount -2; // the flipped mask is the innerLayerCnt bits rewritten in reverse order // ( bits innerLayerCnt to 1 rewritten in bits 1 to innerLayerCnt ) for( int ii = 0; ii < innerLayerCnt; ii++ ) { if( internalMask[innerLayerCnt - ii] ) { newMask.set( ii + In1_Cu ); } else { newMask.reset( ii + In1_Cu ); } } } } return newMask; } PCB_LAYER_ID LSET::ExtractLayer() const { unsigned set_count = count(); if( !set_count ) return UNSELECTED_LAYER; else if( set_count > 1 ) return UNDEFINED_LAYER; for( unsigned i=0; i < size(); ++i ) { if( test( i ) ) return PCB_LAYER_ID( i ); } wxASSERT( 0 ); // set_count was verified as 1 above, what did you break? return UNDEFINED_LAYER; } LSET LSET::FrontAssembly() { static const PCB_LAYER_ID front_assembly[] = { F_SilkS, F_Mask, F_Fab, F_CrtYd }; static const LSET saved( front_assembly, arrayDim( front_assembly ) ); return saved; } LSET LSET::BackAssembly() { static const PCB_LAYER_ID back_assembly[] = { B_SilkS, B_Mask, B_Fab, B_CrtYd }; static const LSET saved( back_assembly, arrayDim( back_assembly ) ); return saved; } LSET LSET::InternalCuMask() { static const PCB_LAYER_ID cu_internals[] = { In1_Cu, In2_Cu, In3_Cu, In4_Cu, In5_Cu, In6_Cu, In7_Cu, In8_Cu, In9_Cu, In10_Cu, In11_Cu, In12_Cu, In13_Cu, In14_Cu, In15_Cu, In16_Cu, In17_Cu, In18_Cu, In19_Cu, In20_Cu, In21_Cu, In22_Cu, In23_Cu, In24_Cu, In25_Cu, In26_Cu, In27_Cu, In28_Cu, In29_Cu, In30_Cu, }; static const LSET saved( cu_internals, arrayDim( cu_internals ) ); return saved; } LSET LSET::AllCuMask( int aCuLayerCount ) { // retain all in static as the full set, which is a common case. static const LSET all = InternalCuMask().set( F_Cu ).set( B_Cu ); if( aCuLayerCount == MAX_CU_LAYERS ) return all; // subtract out some Cu layers not wanted in the mask. LSET ret = all; int clear_count = MAX_CU_LAYERS - aCuLayerCount; clear_count = Clamp( 0, clear_count, MAX_CU_LAYERS - 2 ); for( int elem = In30_Cu; clear_count; --elem, --clear_count ) ret.set( elem, false ); return ret; } LSET LSET::AllNonCuMask() { static const LSET saved = LSET().set() & ~AllCuMask(); return saved; } LSET LSET::ExternalCuMask() { static const LSET saved( 2, F_Cu, B_Cu ); return saved; } LSET LSET::AllLayersMask() { static const LSET saved = LSET().set(); return saved; } LSET LSET::BackTechMask() { static const LSET saved( 6, B_SilkS, B_Mask, B_Adhes, B_Paste, B_CrtYd, B_Fab ); return saved; } LSET LSET::BackBoardTechMask() { static const LSET saved( 4, B_SilkS, B_Mask, B_Adhes, B_Paste ); return saved; } LSET LSET::FrontTechMask() { static const LSET saved( 6, F_SilkS, F_Mask, F_Adhes, F_Paste, F_CrtYd, F_Fab ); return saved; } LSET LSET::FrontBoardTechMask() { static const LSET saved( 4, F_SilkS, F_Mask, F_Adhes, F_Paste ); return saved; } LSET LSET::AllTechMask() { static const LSET saved = BackTechMask() | FrontTechMask(); return saved; } LSET LSET::AllBoardTechMask() { static const LSET saved = BackBoardTechMask() | FrontBoardTechMask(); return saved; } LSET LSET::UserMask() { static const LSET saved( 6, Dwgs_User, Cmts_User, Eco1_User, Eco2_User, Edge_Cuts, Margin ); return saved; } LSET LSET::PhysicalLayersMask() { static const LSET saved = AllBoardTechMask() | AllCuMask(); return saved; } LSET LSET::UserDefinedLayers() { static const LSET saved( 9, User_1, User_2, User_3, User_4, User_5, User_6, User_7, User_8, User_9 ); return saved; } LSET LSET::FrontMask() { static const LSET saved = FrontTechMask().set( F_Cu ); return saved; } LSET LSET::BackMask() { static const LSET saved = BackTechMask().set( B_Cu ); return saved; } LSET LSET::SideSpecificMask() { static const LSET saved = BackTechMask() | FrontTechMask() | AllCuMask(); return saved; } LSET LSET::ForbiddenFootprintLayers() { static const LSET saved = InternalCuMask(); return saved; } LSEQ LSET::UIOrder() const { LSEQ order = CuStack(); LSEQ techuser = TechAndUserUIOrder(); order.insert( order.end(), techuser.begin(), techuser.end() ); return order; } PCB_LAYER_ID ToLAYER_ID( int aLayer ) { wxASSERT( aLayer < GAL_LAYER_ID_END ); return PCB_LAYER_ID( aLayer ); } GAL_SET::GAL_SET( const GAL_LAYER_ID* aArray, unsigned aCount ) : GAL_SET() { for( unsigned i = 0; i < aCount; ++i ) set( aArray[i] ); } std::vector GAL_SET::Seq() const { std::vector ret; for( size_t i = 0; i < size(); ++i ) { if( test( i ) ) ret.push_back( static_cast( i + GAL_LAYER_ID_START ) ); } return ret; } GAL_SET GAL_SET::DefaultVisible() { static const GAL_LAYER_ID visible[] = { LAYER_VIAS, LAYER_VIA_MICROVIA, LAYER_VIA_BBLIND, LAYER_VIA_THROUGH, // LAYER_HIDDEN_TEXT, // Invisible text hidden by default LAYER_ANCHOR, LAYER_PADS_SMD_FR, LAYER_PADS_SMD_BK, LAYER_RATSNEST, LAYER_GRID, LAYER_GRID_AXES, LAYER_FOOTPRINTS_FR, LAYER_FOOTPRINTS_BK, LAYER_FP_TEXT, LAYER_FP_VALUES, LAYER_FP_REFERENCES, LAYER_TRACKS, LAYER_PADS_TH, LAYER_PAD_PLATEDHOLES, LAYER_NON_PLATEDHOLES, LAYER_PAD_HOLEWALLS, LAYER_VIA_HOLES, LAYER_VIA_HOLEWALLS, LAYER_DRC_ERROR, LAYER_DRC_WARNING, // LAYER_DRC_EXCLUSION, // DRC exclusions hidden by default LAYER_DRAWINGSHEET, LAYER_GP_OVERLAY, LAYER_SELECT_OVERLAY, LAYER_PCB_BACKGROUND, LAYER_CURSOR, LAYER_AUX_ITEMS, LAYER_DRAW_BITMAPS, LAYER_PADS, LAYER_ZONES, LAYER_SHAPES, LAYER_LOCKED_ITEM_SHADOW, LAYER_CONFLICTS_SHADOW }; static const GAL_SET saved( visible, arrayDim( visible ) ); return saved; }