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.

167 lines
5.1 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright The 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 :
  41. static_cast<int>( F_Cu ) + 2 * ( m_layer_count - 2 ) + 2;
  42. else if( aLayer == m_stop || aLayer == UNDEFINED_LAYER )
  43. aLayer = UNDEFINED_LAYER;
  44. else if( aLayer == In1_Cu )
  45. aLayer = F_Cu;
  46. else
  47. aLayer = static_cast<int>( aLayer ) - 2;
  48. }
  49. else
  50. {
  51. if( aLayer == F_Cu && m_layer_count == 2 )
  52. aLayer = B_Cu;
  53. else if( aLayer == m_stop || aLayer == UNDEFINED_LAYER )
  54. aLayer = UNDEFINED_LAYER;
  55. else if( aLayer == static_cast<int>( F_Cu ) + 2 * ( m_layer_count - 2 ) + 2)
  56. aLayer = B_Cu;
  57. else if( aLayer == F_Cu )
  58. aLayer = In1_Cu;
  59. else
  60. aLayer = static_cast<int>( aLayer ) + 2;
  61. }
  62. return aLayer;
  63. }
  64. public:
  65. using iterator_category = std::bidirectional_iterator_tag;
  66. using value_type = PCB_LAYER_ID;
  67. using difference_type = std::ptrdiff_t;
  68. using pointer = PCB_LAYER_ID*;
  69. using reference = PCB_LAYER_ID&;
  70. LAYER_RANGE_ITERATOR( PCB_LAYER_ID start, PCB_LAYER_ID stop, int layer_count ) :
  71. m_current( start ), m_stop( stop ), m_layer_count( layer_count )
  72. {
  73. if( start & 1 || stop & 1 )
  74. throw std::invalid_argument( "Only works for copper layers" );
  75. m_layer_count = m_layer_count & ~1;
  76. if( stop == B_Cu || m_stop >= m_current )
  77. m_reverse = false;
  78. else
  79. m_reverse = true;
  80. }
  81. PCB_LAYER_ID operator*() const { return static_cast<PCB_LAYER_ID>( m_current ); }
  82. LAYER_RANGE_ITERATOR& operator++()
  83. {
  84. m_current = next_layer( m_current );
  85. return *this;
  86. }
  87. LAYER_RANGE_ITERATOR operator++( int )
  88. {
  89. LAYER_RANGE_ITERATOR tmp = *this;
  90. ++( *this );
  91. return tmp;
  92. }
  93. bool operator==( const LAYER_RANGE_ITERATOR& other ) const
  94. {
  95. return m_current == other.m_current;
  96. }
  97. bool operator!=( const LAYER_RANGE_ITERATOR& other ) const { return !( *this == other ); }
  98. };
  99. public:
  100. LAYER_RANGE( PCB_LAYER_ID start, PCB_LAYER_ID stop, int layer_count ) :
  101. m_start( start ), m_stop( stop ), m_layer_count( layer_count )
  102. {
  103. if( start & 1 || stop & 1 )
  104. throw std::invalid_argument( "Only works for copper layers" );
  105. }
  106. LAYER_RANGE_ITERATOR begin() const { return LAYER_RANGE_ITERATOR( m_start, m_stop,
  107. m_layer_count ); }
  108. LAYER_RANGE_ITERATOR end() const
  109. {
  110. auto it = LAYER_RANGE_ITERATOR( m_stop, m_stop, m_layer_count );
  111. return ++it;
  112. }
  113. static bool Contains( int aStart_layer, int aEnd_layer, int aTest_layer )
  114. {
  115. // B_Cu is the lowest copper layer for Z order copper layers
  116. // F_cu = top, B_Cu = bottom
  117. // So set the distance from top for B_Cu to INT_MAX
  118. if( aTest_layer == B_Cu )
  119. aTest_layer = INT_MAX;
  120. if( aStart_layer == B_Cu )
  121. aStart_layer = INT_MAX;
  122. if( aEnd_layer == B_Cu )
  123. aEnd_layer = INT_MAX;
  124. if( aStart_layer > aEnd_layer )
  125. std::swap( aStart_layer, aEnd_layer );
  126. return aTest_layer >= aStart_layer && aTest_layer <= aEnd_layer;
  127. }
  128. bool Contains( int aTest_layer )
  129. {
  130. return Contains( m_start, m_stop, aTest_layer );
  131. }
  132. size_t size() const
  133. {
  134. if( m_start == B_Cu )
  135. return m_layer_count;
  136. else
  137. return ( m_stop - m_start ) / 2 + 1;
  138. }
  139. };
  140. #endif // LAYER_RANGE_H