You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

993 lines
22 KiB

12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
1 year ago
1 year ago
1 year ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2014 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  5. * Copyright (C) 2014-2023 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #include <algorithm>
  25. #include <bitset> // for bitset, __bitset<>::ref...
  26. #include <cassert>
  27. #include <cstdarg>
  28. #include <iostream> // for string, endl, basic_ost...
  29. #include <cstddef> // for size_t
  30. #include <map>
  31. #include <core/arraydim.h>
  32. #include <layer_ids.h> // for PCB_LAYER_ID
  33. #include <layer_range.h>
  34. #include <lseq.h>
  35. #include <macros.h> // for arrayDim
  36. #include <wx/debug.h> // for wxASSERT, wxASSERT_MSG
  37. #include <wx/string.h>
  38. #include <lset.h>
  39. LSET::LSET( std::initializer_list<PCB_LAYER_ID> aList ) :
  40. LSET()
  41. {
  42. for( PCB_LAYER_ID layer : aList )
  43. {
  44. if( layer >= 0 )
  45. set( layer );
  46. }
  47. }
  48. LSET::LSET( const std::vector<PCB_LAYER_ID>& aList ) :
  49. LSET()
  50. {
  51. for( PCB_LAYER_ID layer : aList )
  52. {
  53. if( layer >= 0 )
  54. set( layer );
  55. }
  56. }
  57. LSET::LSET( const LSEQ& aSeq ) :
  58. LSET()
  59. {
  60. for( PCB_LAYER_ID layer : aSeq )
  61. {
  62. if( layer >= 0 )
  63. set( layer );
  64. }
  65. }
  66. LSET::LSET( const LAYER_RANGE& aRange )
  67. {
  68. for( PCB_LAYER_ID layer : aRange )
  69. {
  70. if( layer >= 0 )
  71. set( layer );
  72. }
  73. }
  74. int LSET::LayerCount( PCB_LAYER_ID aStart, PCB_LAYER_ID aEnd, int aCopperLayerCount )
  75. {
  76. int start = aStart;
  77. int end = aEnd;
  78. // Both layers need to be copper
  79. wxCHECK( IsCopperLayer( aStart ) && IsCopperLayer( aEnd ), aCopperLayerCount );
  80. if( aStart == B_Cu )
  81. std::swap( start, end );
  82. if( aStart == aEnd )
  83. return 1;
  84. if( aStart == F_Cu )
  85. {
  86. if ( aEnd == B_Cu )
  87. return aCopperLayerCount;
  88. else
  89. return ( end - start ) / 2 - 1;
  90. }
  91. else if ( aEnd == B_Cu )
  92. {
  93. // Add 1 for the B_Cu layer
  94. return aCopperLayerCount - start / 2 + 1;
  95. }
  96. return ( end - start ) / 2;
  97. }
  98. int LSET::NameToLayer( wxString& aName )
  99. {
  100. std::map<wxString, PCB_LAYER_ID> layerMap = {
  101. { "F.Cu", F_Cu },
  102. { "B.Cu", B_Cu },
  103. { "F.Adhes", F_Adhes },
  104. { "B.Adhes", B_Adhes },
  105. { "F.Paste", F_Paste },
  106. { "B.Paste", B_Paste },
  107. { "F.SilkS", F_SilkS },
  108. { "B.SilkS", B_SilkS },
  109. { "F.Mask", F_Mask },
  110. { "B.Mask", B_Mask },
  111. { "Dwgs.User", Dwgs_User },
  112. { "Cmts.User", Cmts_User },
  113. { "Eco1.User", Eco1_User },
  114. { "Eco2.User", Eco2_User },
  115. { "Edge.Cuts", Edge_Cuts },
  116. { "Margin", Margin },
  117. { "F.CrtYd", F_CrtYd },
  118. { "B.CrtYd", B_CrtYd },
  119. { "F.Fab", F_Fab },
  120. { "B.Fab", B_Fab },
  121. { "Rescue", Rescue },
  122. { "B.Cu", B_Cu },
  123. };
  124. if( auto it = layerMap.find( aName ); it != layerMap.end() )
  125. return static_cast<int>( it->second );
  126. if( aName.StartsWith( "User." ) )
  127. {
  128. long offset;
  129. if( aName.Mid( 5 ).ToLong( &offset ) && offset > 0 )
  130. return static_cast<int>( User_1 ) + ( offset - 1 ) * 2;
  131. }
  132. if( aName.StartsWith( "In" ) )
  133. {
  134. long offset;
  135. wxString str_num = aName.Mid( 2 );
  136. str_num.RemoveLast( 3 ); // Removes .Cu
  137. if( str_num.ToLong( &offset ) && offset > 0 )
  138. return static_cast<int>( In1_Cu ) + ( offset - 1 ) * 2;
  139. }
  140. return -1;
  141. }
  142. bool LSET::IsBetween( PCB_LAYER_ID aStart, PCB_LAYER_ID aEnd, PCB_LAYER_ID aLayer )
  143. {
  144. if( aLayer == aStart || aLayer == aEnd )
  145. return true;
  146. int start = std::min( aStart, aEnd );
  147. int end = std::max( aStart, aEnd );
  148. int layer = aLayer;
  149. if( end == B_Cu )
  150. {
  151. //Reassign the end layer to the largest possible positive even number
  152. end = std::numeric_limits<PCB_LAYER_ID>::max() & ~1;
  153. }
  154. return !( layer & 1 ) && ( layer >= start ) && ( layer <= end );
  155. }
  156. /**
  157. * NOTE: These names must not be translated or changed. They are used as tokens in the board
  158. * file format because the ordinal value of the PCB_LAYER_ID enum was not stable over time.
  159. * @see LayerName() for what should be used to display the default name of a layer in the GUI.
  160. */
  161. wxString LSET::Name( PCB_LAYER_ID aLayerId )
  162. {
  163. wxString txt;
  164. // using a switch to explicitly show the mapping more clearly
  165. switch( aLayerId )
  166. {
  167. case F_Cu: txt = wxT( "F.Cu" ); break;
  168. case B_Cu: txt = wxT( "B.Cu" ); break;
  169. // Technicals
  170. case B_Adhes: txt = wxT( "B.Adhes" ); break;
  171. case F_Adhes: txt = wxT( "F.Adhes" ); break;
  172. case B_Paste: txt = wxT( "B.Paste" ); break;
  173. case F_Paste: txt = wxT( "F.Paste" ); break;
  174. case B_SilkS: txt = wxT( "B.SilkS" ); break;
  175. case F_SilkS: txt = wxT( "F.SilkS" ); break;
  176. case B_Mask: txt = wxT( "B.Mask" ); break;
  177. case F_Mask: txt = wxT( "F.Mask" ); break;
  178. // Users
  179. case Dwgs_User: txt = wxT( "Dwgs.User" ); break;
  180. case Cmts_User: txt = wxT( "Cmts.User" ); break;
  181. case Eco1_User: txt = wxT( "Eco1.User" ); break;
  182. case Eco2_User: txt = wxT( "Eco2.User" ); break;
  183. case Edge_Cuts: txt = wxT( "Edge.Cuts" ); break;
  184. case Margin: txt = wxT( "Margin" ); break;
  185. // Footprint
  186. case F_CrtYd: txt = wxT( "F.CrtYd" ); break;
  187. case B_CrtYd: txt = wxT( "B.CrtYd" ); break;
  188. case F_Fab: txt = wxT( "F.Fab" ); break;
  189. case B_Fab: txt = wxT( "B.Fab" ); break;
  190. // Rescue
  191. case Rescue: txt = wxT( "Rescue" ); break;
  192. default:
  193. if( static_cast<int>( aLayerId ) & 1 )
  194. {
  195. int offset = ( aLayerId - Rescue ) / 2;
  196. txt = wxString::Format( wxT( "User.%d" ), offset );
  197. }
  198. else
  199. {
  200. int offset = ( aLayerId - B_Cu ) / 2;
  201. txt = wxString::Format( wxT( "In%d.Cu" ), offset );
  202. }
  203. }
  204. return txt;
  205. }
  206. LSEQ LSET::CuStack() const
  207. {
  208. LSEQ ret;
  209. ret.reserve( 32 );
  210. for( auto it = copper_layers_begin(); it != copper_layers_end(); ++it )
  211. ret.push_back( *it );
  212. return ret;
  213. }
  214. LSEQ LSET::TechAndUserUIOrder() const
  215. {
  216. LSEQ ret;
  217. ret.reserve( 32 );
  218. ret = Seq( {
  219. F_Adhes,
  220. B_Adhes,
  221. F_Paste,
  222. B_Paste,
  223. F_SilkS,
  224. B_SilkS,
  225. F_Mask,
  226. B_Mask,
  227. Dwgs_User,
  228. Cmts_User,
  229. Eco1_User,
  230. Eco2_User,
  231. Edge_Cuts,
  232. Margin,
  233. F_CrtYd,
  234. B_CrtYd,
  235. F_Fab,
  236. B_Fab
  237. } );
  238. for( auto it = non_copper_layers_begin(); it != non_copper_layers_end(); ++it )
  239. {
  240. if( *it >= User_1 )
  241. ret.push_back( *it );
  242. }
  243. return ret;
  244. }
  245. std::string LSET::FmtBin() const
  246. {
  247. std::string ret;
  248. int bit_count = size();
  249. for( int bit=0; bit<bit_count; ++bit )
  250. {
  251. if( bit )
  252. {
  253. if( !( bit % 8 ) )
  254. ret += '|';
  255. else if( !( bit % 4 ) )
  256. ret += '_';
  257. }
  258. ret += (*this)[bit] ? '1' : '0';
  259. }
  260. // reverse of string
  261. return std::string( ret.rbegin(), ret.rend() );
  262. }
  263. std::string LSET::FmtHex() const
  264. {
  265. std::string ret;
  266. static const char hex[] = "0123456789abcdef";
  267. size_t nibble_count = ( size() + 3 ) / 4;
  268. for( size_t nibble = 0; nibble < nibble_count; ++nibble )
  269. {
  270. unsigned int ndx = 0;
  271. // test 4 consecutive bits and set ndx to 0-15
  272. for( size_t nibble_bit = 0; nibble_bit < 4; ++nibble_bit )
  273. {
  274. size_t nibble_pos = nibble_bit + ( nibble * 4 );
  275. // make sure it's not extra bits that don't exist in the bitset but need to in the
  276. // hex format
  277. if( nibble_pos >= size() )
  278. break;
  279. if( ( *this )[nibble_pos] )
  280. ndx |= ( 1 << nibble_bit );
  281. }
  282. if( nibble && !( nibble % 8 ) )
  283. ret += '_';
  284. assert( ndx < arrayDim( hex ) );
  285. ret += hex[ndx];
  286. }
  287. // reverse of string
  288. return std::string( ret.rbegin(), ret.rend() );
  289. }
  290. int LSET::ParseHex( const std::string& str )
  291. {
  292. return ParseHex( str.c_str(), str.length() );
  293. }
  294. int LSET::ParseHex( const char* aStart, int aCount )
  295. {
  296. LSET tmp;
  297. const char* rstart = aStart + aCount - 1;
  298. const char* rend = aStart - 1;
  299. const int bitcount = size();
  300. int nibble_ndx = 0;
  301. while( rstart > rend )
  302. {
  303. int cc = *rstart--;
  304. if( cc == '_' )
  305. continue;
  306. int nibble;
  307. if( cc >= '0' && cc <= '9' )
  308. nibble = cc - '0';
  309. else if( cc >= 'a' && cc <= 'f' )
  310. nibble = cc - 'a' + 10;
  311. else if( cc >= 'A' && cc <= 'F' )
  312. nibble = cc - 'A' + 10;
  313. else
  314. break;
  315. int bit = nibble_ndx * 4;
  316. for( int ndx=0; bit<bitcount && ndx<4; ++bit, ++ndx )
  317. if( nibble & (1<<ndx) )
  318. tmp.set( bit );
  319. if( bit >= bitcount )
  320. break;
  321. ++nibble_ndx;
  322. }
  323. int byte_count = aStart + aCount - 1 - rstart;
  324. assert( byte_count >= 0 );
  325. if( byte_count > 0 )
  326. *this = tmp;
  327. return byte_count;
  328. }
  329. LSEQ LSET::Seq( const LSEQ& aSequence ) const
  330. {
  331. LSEQ ret;
  332. for( PCB_LAYER_ID layer : aSequence )
  333. {
  334. if( test( layer ) )
  335. ret.push_back( layer );
  336. }
  337. return ret;
  338. }
  339. LSEQ LSET::Seq() const
  340. {
  341. LSEQ ret;
  342. ret.reserve( size() );
  343. for( unsigned i = 0; i < size(); ++i )
  344. {
  345. if( test( i ) )
  346. ret.push_back( PCB_LAYER_ID( i ) );
  347. }
  348. return ret;
  349. }
  350. LSEQ LSET::SeqStackupTop2Bottom( PCB_LAYER_ID aSelectedLayer ) const
  351. {
  352. LSEQ base_sequence = Seq( {
  353. Edge_Cuts,
  354. Margin,
  355. Dwgs_User,
  356. Cmts_User,
  357. Eco1_User,
  358. Eco2_User
  359. } );
  360. LSEQ top_tech_sequence = Seq( {
  361. F_Fab,
  362. F_SilkS,
  363. F_Paste,
  364. F_Adhes,
  365. F_Mask,
  366. F_CrtYd,
  367. } );
  368. LSEQ bottom_tech_sequence = Seq( {
  369. B_CrtYd,
  370. B_Mask,
  371. B_Adhes,
  372. B_Paste,
  373. B_SilkS,
  374. B_Fab,
  375. } );
  376. LSEQ seq = Seq( base_sequence );
  377. for( auto it = non_copper_layers_begin(); it != non_copper_layers_end(); ++it )
  378. {
  379. if( *it >= User_1 )
  380. seq.push_back( *it );
  381. }
  382. std::copy( top_tech_sequence.begin(), top_tech_sequence.end(), std::back_inserter( seq ) );
  383. for( auto it = copper_layers_begin(); it != copper_layers_end(); ++it )
  384. seq.push_back( *it );
  385. std::copy( bottom_tech_sequence.begin(), bottom_tech_sequence.end(), std::back_inserter( seq ) );
  386. if( aSelectedLayer != UNDEFINED_LAYER )
  387. {
  388. auto it = std::find( seq.begin(), seq.end(), aSelectedLayer );
  389. if( it != seq.end() )
  390. {
  391. seq.erase( it );
  392. seq.insert( seq.begin(), aSelectedLayer );
  393. }
  394. }
  395. return seq;
  396. }
  397. LSEQ LSET::SeqStackupForPlotting() const
  398. {
  399. // bottom-to-top stack-up layers
  400. // Note that the bottom technical layers are flipped so that when plotting a bottom-side view,
  401. // they appear in the correct sequence.
  402. LSEQ bottom_tech_sequence = Seq( {
  403. B_Cu,
  404. B_Mask,
  405. B_Paste,
  406. B_SilkS,
  407. B_Adhes,
  408. B_CrtYd,
  409. B_Fab,
  410. } );
  411. // Copper layers go here
  412. LSEQ top_tech_sequence = Seq( {
  413. F_Mask,
  414. F_Paste,
  415. F_SilkS,
  416. F_Adhes,
  417. F_CrtYd,
  418. F_Fab,
  419. } );
  420. LSEQ user_sequence = Seq( {
  421. Dwgs_User,
  422. Cmts_User,
  423. Eco1_User,
  424. Eco2_User,
  425. } );
  426. // User layers go here
  427. LSEQ base_sequence = Seq( {
  428. Margin,
  429. Edge_Cuts,
  430. } );
  431. LSEQ seq = Seq( bottom_tech_sequence );
  432. std::vector<PCB_LAYER_ID> temp_layers;
  433. // We are going to reverse the copper layers and then add them to the sequence
  434. // because the plotting order is bottom-to-top
  435. for( auto it = copper_layers_begin(); it != copper_layers_end(); ++it )
  436. {
  437. // Skip B_Cu because it is already in the sequence (if it exists)
  438. if( *it != B_Cu )
  439. temp_layers.push_back( *it );
  440. }
  441. for( auto it = temp_layers.rbegin(); it != temp_layers.rend(); ++it )
  442. seq.push_back( *it );
  443. std::copy( top_tech_sequence.begin(), top_tech_sequence.end(), std::back_inserter( seq ) );
  444. std::copy( user_sequence.begin(), user_sequence.end(), std::back_inserter( seq ) );
  445. temp_layers.clear();
  446. for( auto it = non_copper_layers_begin(); it != non_copper_layers_end(); ++it )
  447. {
  448. if( *it >= User_1 )
  449. temp_layers.push_back( *it );
  450. }
  451. for( auto it = temp_layers.rbegin(); it != temp_layers.rend(); ++it )
  452. {
  453. seq.push_back( *it );
  454. }
  455. std::copy( base_sequence.begin(), base_sequence.end(), std::back_inserter( seq ) );
  456. return seq;
  457. }
  458. LSET& LSET::Flip( int aCopperLayersCount )
  459. {
  460. LSET oldMask = *this;
  461. reset();
  462. // Mapping for Copper and Non-Copper layers
  463. const std::map<PCB_LAYER_ID, PCB_LAYER_ID> flip_map =
  464. {
  465. {F_Cu, B_Cu},
  466. {B_Cu, F_Cu},
  467. {F_SilkS, B_SilkS},
  468. {B_SilkS, F_SilkS},
  469. {F_Adhes, B_Adhes},
  470. {B_Adhes, F_Adhes},
  471. {F_Mask, B_Mask},
  472. {B_Mask, F_Mask},
  473. {F_Paste, B_Paste},
  474. {B_Paste, F_Paste},
  475. {F_CrtYd, B_CrtYd},
  476. {B_CrtYd, F_CrtYd},
  477. {F_Fab, B_Fab},
  478. {B_Fab, F_Fab}
  479. };
  480. for( const auto& pair : flip_map )
  481. {
  482. if( oldMask.test( pair.first ) )
  483. set( pair.second );
  484. }
  485. if( aCopperLayersCount >= 4 )
  486. {
  487. LSET internalMask = oldMask & InternalCuMask();
  488. int innerLayerCount = aCopperLayersCount - 2;
  489. for( int ii = 1; ii <= innerLayerCount; ii++ )
  490. {
  491. if( internalMask.test( ( innerLayerCount - ii + 1 ) * 2 + B_Cu ) )
  492. {
  493. set( ii * 2 + B_Cu );
  494. }
  495. }
  496. }
  497. return *this;
  498. }
  499. PCB_LAYER_ID LSET::ExtractLayer() const
  500. {
  501. unsigned set_count = count();
  502. if( !set_count )
  503. return UNSELECTED_LAYER;
  504. else if( set_count > 1 )
  505. return UNDEFINED_LAYER;
  506. for( unsigned i=0; i < size(); ++i )
  507. {
  508. if( test( i ) )
  509. return PCB_LAYER_ID( i );
  510. }
  511. wxASSERT( 0 ); // set_count was verified as 1 above, what did you break?
  512. return UNDEFINED_LAYER;
  513. }
  514. LSET LSET::FrontAssembly()
  515. {
  516. static const LSET saved( { F_SilkS, F_Mask, F_Fab, F_CrtYd } );
  517. return saved;
  518. }
  519. LSET LSET::BackAssembly()
  520. {
  521. static const LSET saved( { B_SilkS, B_Mask, B_Fab, B_CrtYd } );
  522. return saved;
  523. }
  524. LSET LSET::InternalCuMask()
  525. {
  526. static const LSET saved( { In1_Cu, In2_Cu, In3_Cu, In4_Cu, In5_Cu, In6_Cu,
  527. In7_Cu, In8_Cu, In9_Cu, In10_Cu, In11_Cu, In12_Cu,
  528. In13_Cu, In14_Cu, In15_Cu, In16_Cu, In17_Cu, In18_Cu,
  529. In19_Cu, In20_Cu, In21_Cu, In22_Cu, In23_Cu, In24_Cu,
  530. In25_Cu, In26_Cu, In27_Cu, In28_Cu, In29_Cu, In30_Cu } );
  531. return saved;
  532. }
  533. LSET LSET::AllCuMask( int aCuLayerCount )
  534. {
  535. LSET ret;
  536. for( PCB_LAYER_ID layer : LAYER_RANGE( F_Cu, B_Cu, aCuLayerCount ) )
  537. ret.set( layer );
  538. return ret;
  539. }
  540. LSET LSET::AllNonCuMask()
  541. {
  542. static const LSET saved = LSET().set() & ~AllCuMask();
  543. return saved;
  544. }
  545. LSET LSET::ExternalCuMask()
  546. {
  547. static const LSET saved( { F_Cu, B_Cu } );
  548. return saved;
  549. }
  550. LSET LSET::AllLayersMask()
  551. {
  552. static const LSET saved = LSET().set();
  553. return saved;
  554. }
  555. LSET LSET::BackTechMask()
  556. {
  557. static const LSET saved( { B_SilkS, B_Mask, B_Adhes, B_Paste, B_CrtYd, B_Fab } );
  558. return saved;
  559. }
  560. LSET LSET::BackBoardTechMask()
  561. {
  562. static const LSET saved( { B_SilkS, B_Mask, B_Adhes, B_Paste } );
  563. return saved;
  564. }
  565. LSET LSET::FrontTechMask()
  566. {
  567. static const LSET saved( { F_SilkS, F_Mask, F_Adhes, F_Paste, F_CrtYd, F_Fab } );
  568. return saved;
  569. }
  570. LSET LSET::FrontBoardTechMask()
  571. {
  572. static const LSET saved( { F_SilkS, F_Mask, F_Adhes, F_Paste } );
  573. return saved;
  574. }
  575. LSET LSET::AllTechMask()
  576. {
  577. static const LSET saved = BackTechMask() | FrontTechMask();
  578. return saved;
  579. }
  580. LSET LSET::AllBoardTechMask()
  581. {
  582. static const LSET saved = BackBoardTechMask() | FrontBoardTechMask();
  583. return saved;
  584. }
  585. LSET LSET::UserMask()
  586. {
  587. static const LSET saved( { Dwgs_User, Cmts_User, Eco1_User, Eco2_User, Edge_Cuts, Margin } );
  588. return saved;
  589. }
  590. LSET LSET::PhysicalLayersMask()
  591. {
  592. static const LSET saved = AllBoardTechMask() | AllCuMask();
  593. return saved;
  594. }
  595. LSET LSET::UserDefinedLayers()
  596. {
  597. static const LSET saved(
  598. { User_1, User_2, User_3, User_4, User_5, User_6, User_7, User_8, User_9 } );
  599. return saved;
  600. }
  601. LSET LSET::FrontMask()
  602. {
  603. static const LSET saved = FrontTechMask().set( F_Cu );
  604. return saved;
  605. }
  606. LSET LSET::BackMask()
  607. {
  608. static const LSET saved = BackTechMask().set( B_Cu );
  609. return saved;
  610. }
  611. LSET LSET::SideSpecificMask()
  612. {
  613. static const LSET saved = BackTechMask() | FrontTechMask() | AllCuMask();
  614. return saved;
  615. }
  616. LSET LSET::ForbiddenFootprintLayers()
  617. {
  618. static const LSET saved = InternalCuMask();
  619. return saved;
  620. }
  621. LSEQ LSET::UIOrder() const
  622. {
  623. LSEQ order = CuStack();
  624. LSEQ techuser = TechAndUserUIOrder();
  625. order.insert( order.end(), techuser.begin(), techuser.end() );
  626. return order;
  627. }
  628. PCB_LAYER_ID ToLAYER_ID( int aLayer )
  629. {
  630. // We use std::numeric_limits<int>::max() to represent B_Cu for the connectivity_rtree
  631. if( aLayer == std::numeric_limits<int>::max() )
  632. return B_Cu;
  633. wxASSERT( aLayer < GAL_LAYER_ID_END );
  634. return PCB_LAYER_ID( aLayer );
  635. }
  636. GAL_SET::GAL_SET( const GAL_LAYER_ID* aArray, unsigned aCount ) : GAL_SET()
  637. {
  638. for( unsigned i = 0; i < aCount; ++i )
  639. set( aArray[i] );
  640. }
  641. std::vector<GAL_LAYER_ID> GAL_SET::Seq() const
  642. {
  643. std::vector<GAL_LAYER_ID> ret;
  644. for( size_t i = 0; i < size(); ++i )
  645. {
  646. if( test( i ) )
  647. ret.push_back( static_cast<GAL_LAYER_ID>( i + GAL_LAYER_ID_START ) );
  648. }
  649. return ret;
  650. }
  651. GAL_SET GAL_SET::DefaultVisible()
  652. {
  653. static const GAL_LAYER_ID visible[] = {
  654. LAYER_VIAS,
  655. LAYER_VIA_MICROVIA,
  656. LAYER_VIA_BBLIND,
  657. LAYER_VIA_THROUGH,
  658. // LAYER_HIDDEN_TEXT, // DEPCREATED SINCE 9.0. Invisible text hidden by default
  659. LAYER_ANCHOR,
  660. LAYER_RATSNEST,
  661. LAYER_GRID,
  662. LAYER_GRID_AXES,
  663. LAYER_FOOTPRINTS_FR,
  664. LAYER_FOOTPRINTS_BK,
  665. LAYER_FP_TEXT,
  666. LAYER_FP_VALUES,
  667. LAYER_FP_REFERENCES,
  668. LAYER_TRACKS,
  669. LAYER_PAD_PLATEDHOLES,
  670. LAYER_NON_PLATEDHOLES,
  671. LAYER_PAD_HOLEWALLS,
  672. LAYER_VIA_HOLES,
  673. LAYER_VIA_HOLEWALLS,
  674. LAYER_DRC_ERROR,
  675. LAYER_DRC_WARNING,
  676. LAYER_DRC_SHAPE1,
  677. LAYER_DRC_SHAPE2,
  678. // LAYER_DRC_EXCLUSION, // DRC exclusions hidden by default
  679. LAYER_DRAWINGSHEET,
  680. LAYER_GP_OVERLAY,
  681. LAYER_SELECT_OVERLAY,
  682. LAYER_PCB_BACKGROUND,
  683. LAYER_CURSOR,
  684. LAYER_AUX_ITEMS,
  685. LAYER_DRAW_BITMAPS,
  686. LAYER_PADS,
  687. LAYER_ZONES,
  688. LAYER_SHAPES,
  689. LAYER_LOCKED_ITEM_SHADOW,
  690. LAYER_CONFLICTS_SHADOW
  691. };
  692. static const GAL_SET saved( visible, arrayDim( visible ) );
  693. return saved;
  694. }
  695. #ifndef SWIG // Skip SWIG generators for the iterators because it requires a default constructor
  696. // Custom iterators for Copper and Non-Copper layers
  697. LSET::copper_layers_iterator::copper_layers_iterator( const BASE_SET& set, size_t index ) :
  698. BASE_SET::set_bits_iterator( set, index )
  699. {
  700. m_index = ( index + 1 ) & ~1;
  701. advance_to_next_set_copper_bit();
  702. }
  703. PCB_LAYER_ID LSET::copper_layers_iterator::operator*() const
  704. {
  705. return static_cast<PCB_LAYER_ID>( m_index );
  706. }
  707. LSET::copper_layers_iterator& LSET::copper_layers_iterator::operator++()
  708. {
  709. next_copper_layer();
  710. advance_to_next_set_copper_bit();
  711. return *this;
  712. }
  713. void LSET::copper_layers_iterator::next_copper_layer()
  714. {
  715. if( m_index == F_Cu )
  716. {
  717. m_index += 4;
  718. }
  719. else if( m_index == B_Cu )
  720. {
  721. m_index = m_baseSet.size();
  722. return;
  723. }
  724. else
  725. {
  726. m_index += 2;
  727. if( m_index >= m_baseSet.size() )
  728. m_index = B_Cu;
  729. }
  730. }
  731. void LSET::copper_layers_iterator::advance_to_next_set_copper_bit()
  732. {
  733. while( m_index < m_baseSet.size() && !m_baseSet.test( m_index ) )
  734. next_copper_layer();
  735. }
  736. LSET::non_copper_layers_iterator::non_copper_layers_iterator( const BASE_SET& set, size_t index ) :
  737. BASE_SET::set_bits_iterator( set, index )
  738. {
  739. advance_to_next_set_non_copper_bit();
  740. }
  741. PCB_LAYER_ID LSET::non_copper_layers_iterator::operator*() const
  742. {
  743. return static_cast<PCB_LAYER_ID>( m_index );
  744. }
  745. LSET::non_copper_layers_iterator& LSET::non_copper_layers_iterator::operator++()
  746. {
  747. ++m_index;
  748. advance_to_next_set_non_copper_bit();
  749. return *this;
  750. }
  751. void LSET::non_copper_layers_iterator::advance_to_next_set_non_copper_bit()
  752. {
  753. while( m_index < m_baseSet.size() && ( m_index % 2 != 1 || !m_baseSet.test( m_index ) ) )
  754. {
  755. ++m_index;
  756. }
  757. }
  758. LSET::copper_layers_iterator LSET::copper_layers_begin() const
  759. {
  760. return copper_layers_iterator( *this, 0 );
  761. }
  762. LSET::copper_layers_iterator LSET::copper_layers_end() const
  763. {
  764. return copper_layers_iterator( *this, size() );
  765. }
  766. LSET::non_copper_layers_iterator LSET::non_copper_layers_begin() const
  767. {
  768. return non_copper_layers_iterator( *this, 0 );
  769. }
  770. LSET::non_copper_layers_iterator LSET::non_copper_layers_end() const
  771. {
  772. return non_copper_layers_iterator( *this, size() );
  773. }
  774. #endif