KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drill_chart_model.cpp
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
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU 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
21
22#include <algorithm>
23#include <map>
24#include <set>
25
26#include <board.h>
28#include <pcb_track.h>
29
30
32 m_profile( aProfile )
33{
34}
35
36
37namespace
38{
39
41bool matchesFilter( const DRILL_OPERATION& aOp, const DRILL_CHART_FILTER& aFilter )
42{
43 if( aOp.m_NotPlated && !aFilter.m_NonPlated )
44 return false;
45
46 if( !aOp.m_NotPlated && !aFilter.m_Plated )
47 return false;
48
49 if( aOp.m_IsSlot && !aFilter.m_Slots )
50 return false;
51
52 if( aOp.m_Kind != DRILL_OP_KIND::PRIMARY_DRILL && !aFilter.m_Backdrills )
53 return false;
54
56 return false;
57
58 const bool isVia = aOp.m_Attribute == HOLE_ATTRIBUTE::HOLE_VIA_THROUGH
60
61 if( isVia && !aFilter.m_Vias )
62 return false;
63
64 return true;
65}
66
67
68} // namespace
69
70
71void DRILL_CHART_MODEL::Build( const BOARD& aBoard, const std::vector<DRILL_SPAN>& aSpans )
72{
73 Build( aBoard, aSpans, DRILL_CHART_ROW_SPEC() );
74}
75
76
77void DRILL_CHART_MODEL::Build( const BOARD& aBoard, const std::vector<DRILL_SPAN>& aSpans,
78 const DRILL_CHART_ROW_SPEC& aSpec )
79{
80 m_groups.clear();
82
83 std::map<std::string, DRILL_CHART_GROUP> byKey;
84 std::map<std::string, std::set<std::pair<int, int>>> sitesByKey;
85
86 auto collect =
87 [&]( const DRILL_QUERY& aQuery )
88 {
89 for( const DRILL_OPERATION& op : EnumerateDrillOperations( aBoard, aQuery ) )
90 {
91 if( !matchesFilter( op, aSpec.m_Filter ) )
92 continue;
93
94 const std::string key = m_profile.GroupKeyString( op );
95 auto [it, inserted] = byKey.try_emplace( key );
96 DRILL_CHART_GROUP& group = it->second;
97
98 if( inserted )
99 {
100 group.m_Key = key;
101 group.m_SymbolKey = key;
102 group.m_Diameter = op.m_Diameter;
103 group.m_SizeXY = op.m_SizeXY;
104 group.m_IsSlot = op.m_IsSlot;
105 group.m_NotPlated = op.m_NotPlated;
106 group.m_TopLayer = op.m_TopLayer;
107 group.m_BottomLayer = op.m_BottomLayer;
108 group.m_Kind = op.m_Kind;
109 group.m_Attribute = op.m_Attribute;
110 group.m_StubLength = op.m_StubLength;
111 group.m_Filled = op.m_Filled;
112 group.m_Capped = op.m_Capped;
113 group.m_TopCovered = op.m_TopCovered;
114 group.m_BottomCovered = op.m_BottomCovered;
115 group.m_TopPlugged = op.m_TopPlugged;
116 group.m_BottomPlugged = op.m_BottomPlugged;
117 group.m_TopTented = op.m_TopTented;
118 group.m_BottomTented = op.m_BottomTented;
119 group.m_FrontPostMachining = op.m_FrontPostMachining;
120 group.m_BackPostMachining = op.m_BackPostMachining;
121 }
122
123 group.m_OperationCount++;
124
125 if( op.m_IsSlot )
126 group.m_SlotCount++;
127
128 group.m_Members.push_back( op.Id() );
129 sitesByKey[key].emplace( op.m_Position.x, op.m_Position.y );
130 }
131 };
132
133 for( const DRILL_SPAN& span : aSpans )
134 {
135 DRILL_QUERY plated;
136 plated.m_Span = span;
137 collect( plated );
138
139 DRILL_QUERY nonPlated;
140 nonPlated.m_Span = span;
141 nonPlated.m_NonPlatedOnly = true;
142 collect( nonPlated );
143 }
144
145 std::set<std::pair<int, int>> allSites;
146
147 for( auto& [key, group] : byKey )
148 {
149 group.m_SiteCount = static_cast<int>( sitesByKey[key].size() );
150
151 for( const auto& [x, y] : sitesByKey[key] )
152 group.m_Sites.emplace_back( x, y );
153
154 allSites.insert( sitesByKey[key].begin(), sitesByKey[key].end() );
155 m_totals.m_Operations += group.m_OperationCount;
156 m_groups.push_back( group );
157 }
158
159 m_totals.m_Sites = static_cast<int>( allSites.size() );
160 m_totals.m_Groups = static_cast<int>( m_groups.size() );
161
162 std::sort( m_groups.begin(), m_groups.end(),
163 []( const DRILL_CHART_GROUP& a, const DRILL_CHART_GROUP& b )
164 {
165 if( a.m_NotPlated != b.m_NotPlated )
166 return !a.m_NotPlated;
167
168 if( a.m_Diameter != b.m_Diameter )
169 return a.m_Diameter < b.m_Diameter;
170
171 return a.m_Key < b.m_Key;
172 } );
173}
174
175
176std::vector<DRILL_SPAN> EnumerateDrillSpans( const BOARD& aBoard )
177{
178 std::set<DRILL_SPAN> unique;
179
180 for( PCB_TRACK* track : aBoard.Tracks() )
181 {
182 if( track->Type() != PCB_VIA_T )
183 continue;
184
185 PCB_VIA* via = static_cast<PCB_VIA*>( track );
187 PCB_LAYER_ID bottom;
188
189 via->LayerPair( &top, &bottom );
190
191 if( DRILL_LAYER_PAIR( top, bottom ) != DRILL_LAYER_PAIR( F_Cu, B_Cu ) )
192 unique.emplace( top, bottom, false, false );
193
194 auto addBackdrill =
195 [&]( const PADSTACK::DRILL_PROPS& aDrill )
196 {
197 if( aDrill.start == UNDEFINED_LAYER || aDrill.end == UNDEFINED_LAYER )
198 return;
199
200 if( aDrill.size.x <= 0 && aDrill.size.y <= 0 )
201 return;
202
203 unique.emplace( aDrill.start, aDrill.end, true, false );
204 };
205
206 addBackdrill( via->Padstack().SecondaryDrill() );
207 addBackdrill( via->Padstack().TertiaryDrill() );
208 }
209
210 std::vector<DRILL_SPAN> spans;
211 spans.emplace_back( F_Cu, B_Cu, false, false );
212
213 for( const DRILL_SPAN& span : unique )
214 {
215 if( span.m_IsBackdrill || span.Pair() != DRILL_LAYER_PAIR( F_Cu, B_Cu ) )
216 spans.push_back( span );
217 }
218
219 return spans;
220}
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:409
const TRACKS & Tracks() const
Definition board.h:461
DRILL_CHART_TOTALS m_totals
DRILL_CHART_MODEL(const DRILL_SYMBOL_PROFILE &aProfile)
void Build(const BOARD &aBoard, const std::vector< DRILL_SPAN > &aSpans)
std::vector< DRILL_CHART_GROUP > m_groups
const DRILL_SYMBOL_PROFILE & m_profile
Grouping rules and symbol assignments, shared by reference so a chart and its map can never disagree ...
std::vector< DRILL_SPAN > EnumerateDrillSpans(const BOARD &aBoard)
Every drill span present on the board, through-holes first.
std::vector< DRILL_OPERATION > EnumerateDrillOperations(const BOARD &aBoard, const DRILL_QUERY &aQuery)
The one place that decides what the board's holes are.
std::pair< PCB_LAYER_ID, PCB_LAYER_ID > DRILL_LAYER_PAIR
Definition drill_span.h:48
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
@ F_Cu
Definition layer_ids.h:60
Which holes a chart reports on.
Turns the board's drill operations into chart rows for one symbol profile.
DRILL_CHART_FILTER m_Filter
One machining action, which is also one NC hit and one tool assignment.
DRILL_OP_KIND m_Kind
HOLE_ATTRIBUTE m_Attribute
Selects which operations EnumerateDrillOperations() returns.
bool m_NonPlatedOnly
Emit only non-plated holes.
DRILL_SPAN m_Span
The properties of a padstack drill.
Definition padstack.h:272
KIBIS top(path, &reporter)
VECTOR2I end
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:89