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.

155 lines
4.8 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
  5. *
  6. * This program is free software: you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation, either version 3 of the License, or (at your
  9. * option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <layer_ids.h>
  20. #ifndef LAYER_RANGE_H
  21. #define LAYER_RANGE_H
  22. class LAYER_RANGE
  23. {
  24. private:
  25. PCB_LAYER_ID m_start;
  26. PCB_LAYER_ID m_stop;
  27. int m_layer_count;
  28. class LAYER_RANGE_ITERATOR
  29. {
  30. private:
  31. int m_current;
  32. int m_stop;
  33. int m_layer_count;
  34. bool m_reverse;
  35. int next_layer( int aLayer )
  36. {
  37. if( m_reverse )
  38. {
  39. if( aLayer == B_Cu )
  40. aLayer = m_layer_count == 2 ? F_Cu : static_cast<int>( F_Cu ) + 2 * ( m_layer_count - 2 ) + 2;
  41. else if( aLayer == m_stop || aLayer == UNDEFINED_LAYER )
  42. aLayer = UNDEFINED_LAYER;
  43. else if( aLayer == In1_Cu )
  44. aLayer = F_Cu;
  45. else
  46. aLayer = static_cast<int>( aLayer ) - 2;
  47. }
  48. else
  49. {
  50. if( aLayer == F_Cu && m_layer_count == 2 )
  51. aLayer = B_Cu;
  52. else if( aLayer == m_stop || aLayer == UNDEFINED_LAYER )
  53. aLayer = UNDEFINED_LAYER;
  54. else if( aLayer == static_cast<int>( F_Cu ) + 2 * ( m_layer_count - 2 ) + 2)
  55. aLayer = B_Cu;
  56. else if( aLayer == F_Cu )
  57. aLayer = In1_Cu;
  58. else
  59. aLayer = static_cast<int>( aLayer ) + 2;
  60. }
  61. return aLayer;
  62. }
  63. public:
  64. using iterator_category = std::bidirectional_iterator_tag;
  65. using value_type = PCB_LAYER_ID;
  66. using difference_type = std::ptrdiff_t;
  67. using pointer = PCB_LAYER_ID*;
  68. using reference = PCB_LAYER_ID&;
  69. LAYER_RANGE_ITERATOR( PCB_LAYER_ID start, PCB_LAYER_ID stop, int layer_count ) :
  70. m_current( start ), m_stop( stop ), m_layer_count( layer_count )
  71. {
  72. if( start & 1 || stop & 1 )
  73. throw std::invalid_argument( "Only works for copper layers" );
  74. m_layer_count = m_layer_count & ~1;
  75. if( stop == B_Cu || m_stop >= m_current )
  76. m_reverse = false;
  77. else
  78. m_reverse = true;
  79. }
  80. PCB_LAYER_ID operator*() const { return static_cast<PCB_LAYER_ID>( m_current ); }
  81. LAYER_RANGE_ITERATOR& operator++()
  82. {
  83. m_current = next_layer( m_current );
  84. return *this;
  85. }
  86. LAYER_RANGE_ITERATOR operator++( int )
  87. {
  88. LAYER_RANGE_ITERATOR tmp = *this;
  89. ++( *this );
  90. return tmp;
  91. }
  92. bool operator==( const LAYER_RANGE_ITERATOR& other ) const
  93. {
  94. return m_current == other.m_current;
  95. }
  96. bool operator!=( const LAYER_RANGE_ITERATOR& other ) const { return !( *this == other ); }
  97. };
  98. public:
  99. LAYER_RANGE( PCB_LAYER_ID start, PCB_LAYER_ID stop, int layer_count ) :
  100. m_start( start ), m_stop( stop ), m_layer_count( layer_count )
  101. {
  102. if( start & 1 || stop & 1 )
  103. throw std::invalid_argument( "Only works for copper layers" );
  104. }
  105. LAYER_RANGE_ITERATOR begin() const { return LAYER_RANGE_ITERATOR( m_start, m_stop, m_layer_count ); }
  106. LAYER_RANGE_ITERATOR end() const
  107. {
  108. auto it = LAYER_RANGE_ITERATOR( m_stop, m_stop, m_layer_count );
  109. return ++it;
  110. }
  111. static bool Contains( int aStart_layer, int aEnd_layer, int aTest_layer )
  112. {
  113. // B_Cu is the lowest copper layer for Z order copper layers
  114. // F_cu = top, B_Cu = bottom
  115. // So set the distance from top for B_Cu to INT_MAX
  116. if( aTest_layer == B_Cu )
  117. aTest_layer = INT_MAX;
  118. if( aStart_layer == B_Cu )
  119. aStart_layer = INT_MAX;
  120. if( aEnd_layer == B_Cu )
  121. aEnd_layer = INT_MAX;
  122. if( aStart_layer > aEnd_layer )
  123. std::swap( aStart_layer, aEnd_layer );
  124. return aTest_layer >= aStart_layer && aTest_layer <= aEnd_layer;
  125. }
  126. bool Contains( int aTest_layer )
  127. {
  128. return Contains( m_start, m_stop, aTest_layer );
  129. }
  130. };
  131. #endif // LAYER_RANGE_H