KiCad PCB EDA Suite
Loading...
Searching...
No Matches
layer_range.h
Go to the documentation of this file.
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
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <layer_ids.h>
21
22#include <algorithm>
23#include <cstdlib>
24
25#ifndef LAYER_RANGE_H
26#define LAYER_RANGE_H
27
28
30{
31private:
35
37 {
38 private:
40 int m_stop;
43
44 int next_layer( int aLayer )
45 {
46 if( m_reverse )
47 {
48 if( aLayer == B_Cu )
49 aLayer = m_layer_count == 2 ? F_Cu :
50 static_cast<int>( F_Cu ) + 2 * ( m_layer_count - 2 ) + 2;
51 else if( aLayer == m_stop || aLayer == UNDEFINED_LAYER )
52 aLayer = UNDEFINED_LAYER;
53 else if( aLayer == In1_Cu )
54 aLayer = F_Cu;
55 else
56 aLayer = static_cast<int>( aLayer ) - 2;
57 }
58 else
59 {
60 if( aLayer == F_Cu && m_layer_count == 2 )
61 aLayer = B_Cu;
62 else if( aLayer == m_stop || aLayer == UNDEFINED_LAYER )
63 aLayer = UNDEFINED_LAYER;
64 else if( aLayer == static_cast<int>( F_Cu ) + 2 * ( m_layer_count - 2 ) + 2)
65 aLayer = B_Cu;
66 else if( aLayer == F_Cu )
67 aLayer = In1_Cu;
68 else
69 aLayer = static_cast<int>( aLayer ) + 2;
70 }
71
72 return aLayer;
73 }
74
75 public:
76 using iterator_category = std::bidirectional_iterator_tag;
78 using difference_type = std::ptrdiff_t;
81
82 LAYER_RANGE_ITERATOR( PCB_LAYER_ID start, PCB_LAYER_ID stop, int layer_count ) :
83 m_current( start ), m_stop( stop ), m_layer_count( layer_count )
84 {
85 if( start & 1 || stop & 1 )
86 throw std::invalid_argument( "Only works for copper layers" );
87
88 // B_Cu has a lower numeric id than any inner layer, but is physically below them.
89 // When iterating from B_Cu toward an inner layer we must walk the stack in reverse
90 // so the B_Cu special-case in next_layer() produces the correct physical order.
91 if( m_current == B_Cu && m_stop != B_Cu )
92 m_reverse = true;
93 else if( stop == B_Cu || m_stop >= m_current )
94 m_reverse = false;
95 else
96 m_reverse = true;
97 }
98
99 PCB_LAYER_ID operator*() const { return static_cast<PCB_LAYER_ID>( m_current ); }
100
102 {
104 return *this;
105 }
106
108 {
109 LAYER_RANGE_ITERATOR tmp = *this;
110 ++( *this );
111 return tmp;
112 }
113
114 bool operator==( const LAYER_RANGE_ITERATOR& other ) const
115 {
116 return m_current == other.m_current;
117 }
118
119 bool operator!=( const LAYER_RANGE_ITERATOR& other ) const { return !( *this == other ); }
120 };
121
122public:
123 LAYER_RANGE( PCB_LAYER_ID start, PCB_LAYER_ID stop, int layer_count ) :
124 m_start( start ), m_stop( stop ), m_layer_count( std::max( layer_count, 2 ) )
125 {
126 if( start & 1 || stop & 1 )
127 throw std::invalid_argument( "Only works for copper layers" );
128 }
129
132
134 {
136 return ++it;
137 }
138
139 static bool Contains( int aStart_layer, int aEnd_layer, int aTest_layer )
140 {
141 // B_Cu is the lowest copper layer for Z order copper layers
142 // F_cu = top, B_Cu = bottom
143 // So set the distance from top for B_Cu to INT_MAX
144 if( aTest_layer == B_Cu )
145 aTest_layer = INT_MAX;
146
147 if( aStart_layer == B_Cu )
148 aStart_layer = INT_MAX;
149
150 if( aEnd_layer == B_Cu )
151 aEnd_layer = INT_MAX;
152
153 if( aStart_layer > aEnd_layer )
154 std::swap( aStart_layer, aEnd_layer );
155
156 return aTest_layer >= aStart_layer && aTest_layer <= aEnd_layer;
157 }
158
159 bool Contains( int aTest_layer )
160 {
161 return Contains( m_start, m_stop, aTest_layer );
162 }
163
164 size_t size() const
165 {
166 // Map a copper layer to its physical position in the stack so that size() matches the
167 // iterator's traversal instead of the enum's numeric ordering (F_Cu=0, B_Cu=2, In1_Cu=4,
168 // In2_Cu=6, ...). F_Cu sits at position 0, each In<N>_Cu at position N, and B_Cu at the
169 // bottom of whatever stackup the caller specified.
170 auto ordinal = [this]( PCB_LAYER_ID aLayer ) -> int
171 {
172 if( aLayer == F_Cu )
173 return 0;
174
175 if( aLayer == B_Cu )
176 return m_layer_count - 1;
177
178 return static_cast<int>( aLayer ) / 2 - 1;
179 };
180
181 int start = ordinal( m_start );
182 int stop = ordinal( m_stop );
183
184 return static_cast<size_t>( std::abs( start - stop ) + 1 );
185 }
186};
187
188#endif // LAYER_RANGE_H
PCB_LAYER_ID operator*() const
Definition layer_range.h:99
bool operator==(const LAYER_RANGE_ITERATOR &other) const
LAYER_RANGE_ITERATOR operator++(int)
bool operator!=(const LAYER_RANGE_ITERATOR &other) const
LAYER_RANGE_ITERATOR & operator++()
std::bidirectional_iterator_tag iterator_category
Definition layer_range.h:76
LAYER_RANGE_ITERATOR(PCB_LAYER_ID start, PCB_LAYER_ID stop, int layer_count)
Definition layer_range.h:82
int m_layer_count
Definition layer_range.h:34
PCB_LAYER_ID m_stop
Definition layer_range.h:33
static bool Contains(int aStart_layer, int aEnd_layer, int aTest_layer)
LAYER_RANGE_ITERATOR end() const
size_t size() const
LAYER_RANGE_ITERATOR begin() const
PCB_LAYER_ID m_start
Definition layer_range.h:32
LAYER_RANGE(PCB_LAYER_ID start, PCB_LAYER_ID stop, int layer_count)
bool Contains(int aTest_layer)
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ B_Cu
Definition layer_ids.h:61
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ In1_Cu
Definition layer_ids.h:62
@ F_Cu
Definition layer_ids.h:60
STL namespace.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400