diff options
Diffstat (limited to 'common/lset.cpp')
-rw-r--r-- | common/lset.cpp | 747 |
1 files changed, 747 insertions, 0 deletions
diff --git a/common/lset.cpp b/common/lset.cpp new file mode 100644 index 0000000..4e4248d --- /dev/null +++ b/common/lset.cpp @@ -0,0 +1,747 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> + * Copyright (C) 2014 KiCad Developers, see change_log.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 <stdarg.h> +#include <assert.h> + +#include <layers_id_colors_and_visibility.h> +#include <class_board.h> + + +LSET::LSET( const LAYER_ID* aArray, unsigned aCount ) : + BASE_SET() +{ + for( unsigned i=0; i<aCount; ++i ) + set( aArray[i] ); +} + + +LSET::LSET( unsigned aIdCount, LAYER_ID aFirst, ... ) : + BASE_SET() +{ + // The constructor, without the mandatory aFirst argument, could have been confused + // by the compiler with the LSET( LAYER_ID ). With aFirst, that ambiguity is not + // present. Therefore aIdCount must always be >=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<aIdCount; ++i ) + { + LAYER_ID id = (LAYER_ID) va_arg( ap, int ); + + // printf( "%s: id:%d LAYER_ID_COUNT:%d\n", __func__, id, LAYER_ID_COUNT ); + + assert( unsigned( id ) < LAYER_ID_COUNT ); + + set( id ); + } + + va_end( ap ); + } +} + + +const wxChar* LSET::Name( LAYER_ID aLayerId ) +{ + const wxChar* txt; + + // using a switch to explicitly show the mapping more clearly + switch( aLayerId ) + { + case F_Cu: txt = wxT( "F.Cu" ); break; + case In1_Cu: txt = wxT( "In1.Cu" ); break; + case In2_Cu: txt = wxT( "In2.Cu" ); break; + case In3_Cu: txt = wxT( "In3.Cu" ); break; + case In4_Cu: txt = wxT( "In4.Cu" ); break; + case In5_Cu: txt = wxT( "In5.Cu" ); break; + case In6_Cu: txt = wxT( "In6.Cu" ); break; + case In7_Cu: txt = wxT( "In7.Cu" ); break; + case In8_Cu: txt = wxT( "In8.Cu" ); break; + case In9_Cu: txt = wxT( "In9.Cu" ); break; + case In10_Cu: txt = wxT( "In10.Cu" ); break; + case In11_Cu: txt = wxT( "In11.Cu" ); break; + case In12_Cu: txt = wxT( "In12.Cu" ); break; + case In13_Cu: txt = wxT( "In13.Cu" ); break; + case In14_Cu: txt = wxT( "In14.Cu" ); break; + case In15_Cu: txt = wxT( "In15.Cu" ); break; + case In16_Cu: txt = wxT( "In16.Cu" ); break; + case In17_Cu: txt = wxT( "In17.Cu" ); break; + case In18_Cu: txt = wxT( "In18.Cu" ); break; + case In19_Cu: txt = wxT( "In19.Cu" ); break; + case In20_Cu: txt = wxT( "In20.Cu" ); break; + case In21_Cu: txt = wxT( "In21.Cu" ); break; + case In22_Cu: txt = wxT( "In22.Cu" ); break; + case In23_Cu: txt = wxT( "In23.Cu" ); break; + case In24_Cu: txt = wxT( "In24.Cu" ); break; + case In25_Cu: txt = wxT( "In25.Cu" ); break; + case In26_Cu: txt = wxT( "In26.Cu" ); break; + case In27_Cu: txt = wxT( "In27.Cu" ); break; + case In28_Cu: txt = wxT( "In28.Cu" ); break; + case In29_Cu: txt = wxT( "In29.Cu" ); break; + case In30_Cu: txt = wxT( "In30.Cu" ); break; + case B_Cu: txt = wxT( "B.Cu" ); break; + + // Technicals + case B_Adhes: txt = wxT( "B.Adhes" ); break; + case F_Adhes: txt = wxT( "F.Adhes" ); break; + case B_Paste: txt = wxT( "B.Paste" ); break; + case F_Paste: txt = wxT( "F.Paste" ); break; + case B_SilkS: txt = wxT( "B.SilkS" ); break; + case F_SilkS: txt = wxT( "F.SilkS" ); break; + case B_Mask: txt = wxT( "B.Mask" ); break; + case F_Mask: txt = wxT( "F.Mask" ); break; + + // Users + case Dwgs_User: txt = wxT( "Dwgs.User" ); break; + case Cmts_User: txt = wxT( "Cmts.User" ); break; + case Eco1_User: txt = wxT( "Eco1.User" ); break; + case Eco2_User: txt = wxT( "Eco2.User" ); break; + case Edge_Cuts: txt = wxT( "Edge.Cuts" ); break; + case Margin: txt = wxT( "Margin" ); break; + + // Footprint + case F_CrtYd: txt = wxT( "F.CrtYd" ); break; + case B_CrtYd: txt = wxT( "B.CrtYd" ); break; + case F_Fab: txt = wxT( "F.Fab" ); break; + case B_Fab: txt = wxT( "B.Fab" ); break; + + default: + wxASSERT_MSG( 0, wxT( "aLayerId out of range" ) ); + txt = wxT( "BAD INDEX!" ); break; + } + + return txt; +} + + +LSEQ LSET::CuStack() const +{ + // desired sequence + static const LAYER_ID sequence[] = { + F_Cu, + 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, + B_Cu, // 31 + }; + + return Seq( sequence, DIM( sequence ) ); +} + + +LSEQ LSET::Technicals( LSET aSetToOmit ) const +{ + // desired sequence + static const LAYER_ID sequence[] = { + B_Adhes, + F_Adhes, + B_Paste, + F_Paste, + B_SilkS, + F_SilkS, + B_Mask, + F_Mask, + B_CrtYd, + F_CrtYd, + B_Fab, + F_Fab, + }; + + LSET subset = ~aSetToOmit & *this; + + return subset.Seq( sequence, DIM( sequence ) ); +} + + +LSEQ LSET::Users() const +{ + // desired + static const LAYER_ID sequence[] = { + Dwgs_User, + Cmts_User, + Eco1_User, + Eco2_User, + Edge_Cuts, + Margin, + }; + + return Seq( sequence, DIM( sequence ) ); +} + + +std::string LSET::FmtBin() const +{ + std::string ret; + + int bit_count = size(); + + for( int bit=0; bit<bit_count; ++bit ) + { + if( bit ) + { + if( !( bit % 8 ) ) + ret += '|'; + else if( !( bit % 4 ) ) + ret += '_'; + } + + ret += (*this)[bit] ? '1' : '0'; + } + + // reverse of string + return std::string( ret.rbegin(), ret.rend() ); +} + + +std::string LSET::FmtHex() const +{ + std::string ret; + + static const char hex[] = "0123456789abcdef"; + + int nibble_count = ( size() + 3 ) / 4; + + for( int nibble=0; nibble<nibble_count; ++nibble ) + { + unsigned ndx = 0; + + // test 4 consecutive bits and set ndx to 0-15: + for( int nibble_bit=0; nibble_bit<4; ++nibble_bit ) + { + if( (*this)[nibble_bit + nibble*4] ) + ndx |= (1 << nibble_bit); + } + + if( nibble && !( nibble % 8 ) ) + ret += '_'; + + assert( ndx < DIM( 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 && ndx<4; ++bit, ++ndx ) + if( nibble & (1<<ndx) ) + tmp.set( bit ); + + if( 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 LAYER_ID* aWishListSequence, unsigned aCount ) const +{ + LSEQ ret; + +#if defined(DEBUG) && 0 + LSET dup_detector; + + for( unsigned i=0; i<aCount; ++i ) + { + LAYER_ID id = aWishListSequence[i]; + + if( test( id ) ) + { + wxASSERT_MSG( !dup_detector[id], wxT( "Duplicate in aWishListSequence" ) ); + dup_detector[id] = true; + + ret.push_back( id ); + } + } +#else + + for( unsigned i=0; i<aCount; ++i ) + { + LAYER_ID id = aWishListSequence[i]; + + if( test( id ) ) + ret.push_back( id ); + } +#endif + + return ret; +} + + +LSEQ LSET::Seq() const +{ + LSEQ ret; + + for( unsigned i=0; i<size(); ++i ) + { + if( test(i) ) + ret.push_back( LAYER_ID( i ) ); + } + + return ret; +} + + +LSEQ LSET::SeqStackupBottom2Top() const +{ + // bottom-to-top stack-up layers + static const LAYER_ID sequence[] = { + B_Fab, + B_CrtYd, + B_Adhes, + B_SilkS, + B_Paste, + B_Mask, + B_Cu, + In30_Cu, + In29_Cu, + In28_Cu, + In27_Cu, + In26_Cu, + In25_Cu, + In24_Cu, + In23_Cu, + In22_Cu, + In21_Cu, + In20_Cu, + In19_Cu, + In18_Cu, + In17_Cu, + In16_Cu, + In15_Cu, + In14_Cu, + In13_Cu, + In12_Cu, + In11_Cu, + In10_Cu, + In9_Cu, + In8_Cu, + In7_Cu, + In6_Cu, + In5_Cu, + In4_Cu, + In3_Cu, + In2_Cu, + In1_Cu, + F_Cu, + F_Mask, + F_Paste, + F_SilkS, + F_Adhes, + F_CrtYd, + F_Fab, + Dwgs_User, + Cmts_User, + Eco1_User, + Eco2_User, + Margin, + Edge_Cuts, + }; + + return Seq( sequence, DIM( sequence ) ); +} + + +LAYER_ID FlipLayer( LAYER_ID aLayerId, int aCopperLayersCount ) +{ + switch( aLayerId ) + { + case B_Cu: return F_Cu; + case F_Cu: return B_Cu; + + case B_SilkS: return F_SilkS; + case F_SilkS: return B_SilkS; + + case B_Adhes: return F_Adhes; + case F_Adhes: return B_Adhes; + + case B_Mask: return F_Mask; + case F_Mask: return B_Mask; + + case B_Paste: return F_Paste; + case F_Paste: return B_Paste; + + case B_CrtYd: return F_CrtYd; + case F_CrtYd: return B_CrtYd; + + case B_Fab: return F_Fab; + case F_Fab: return B_Fab; + + default: // change internal layer if aCopperLayersCount is >= 4 + if( IsCopperLayer( aLayerId ) && aCopperLayersCount >= 4 ) + { + // internal copper layers count is aCopperLayersCount-2 + LAYER_ID fliplayer = 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; + + for( int ii = 0; ii < innerLayerCnt; ii++ ) + { + if( internalMask[innerLayerCnt - ii + In1_Cu] ) + newMask.set( ii + In1_Cu ); + else + newMask.reset( ii + In1_Cu ); + } + } + } + + return newMask; +} + + +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 LAYER_ID( i ); + } + + wxASSERT( 0 ); // set_count was verified as 1 above, what did you break? + + return UNDEFINED_LAYER; +} + + +LSET LSET::InternalCuMask() +{ + static const 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, DIM( 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( LAYER_NUM 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::AllLayersMask() +{ + static const LSET saved = LSET().set(); + return saved; +} + + +LSET LSET::BackTechMask() +{ + // (SILKSCREEN_LAYER_BACK | SOLDERMASK_LAYER_BACK | ADHESIVE_LAYER_BACK | SOLDERPASTE_LAYER_BACK) + static const LSET saved( 6, B_SilkS, B_Mask, B_Adhes, B_Paste, B_CrtYd, B_Fab ); + return saved; +} + + +LSET LSET::FrontTechMask() +{ + // (SILKSCREEN_LAYER_FRONT | SOLDERMASK_LAYER_FRONT | ADHESIVE_LAYER_FRONT | SOLDERPASTE_LAYER_FRONT) + static const LSET saved( 6, F_SilkS, F_Mask, F_Adhes, F_Paste, F_CrtYd, F_Fab ); + return saved; +} + + +LSET LSET::AllTechMask() +{ + static const LSET saved = BackTechMask() | FrontTechMask(); + 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::FrontMask() +{ + static const LSET saved = FrontTechMask().set( F_Cu ); + return saved; +} + + +LSET LSET::BackMask() +{ + static const LSET saved = BackTechMask().set( B_Cu ); + return saved; +} + + +LSEQ LSET::UIOrder() const +{ + LAYER_ID order[LAYER_ID_COUNT]; + + // Assmuming that the LAYER_ID order is according to preferred UI order, as of + // today this is true. When that becomes not true, its easy to change the order + // in here to compensate. + + for( unsigned i=0; i<DIM(order); ++i ) + order[i] = LAYER_ID( i ); + + return Seq( order, DIM( order ) ); +} + + +LAYER_ID ToLAYER_ID( int aLayer ) +{ + wxASSERT( unsigned( aLayer ) < LAYER_ID_COUNT ); + return LAYER_ID( aLayer ); +} + |