KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drill_enumerator.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 <board.h>
24#include <footprint.h>
25#include <pad.h>
26#include <pcb_track.h>
27
28
29namespace
30{
31
32DRILL_POST_MACHINING fromPadstack( const PADSTACK::POST_MACHINING_PROPS& aProps )
33{
35
37 pm.m_Size = aProps.size;
38 pm.m_Depth = aProps.depth;
39 pm.m_Angle = aProps.angle;
40
41 return pm;
42}
43
44
45void enumerateVia( PCB_VIA* aVia, const BOARD& aBoard, const DRILL_QUERY& aQuery,
46 std::vector<DRILL_OPERATION>& aOut )
47{
48 const DRILL_SPAN& span = aQuery.m_Span;
49
50 auto stubLength =
51 [&]( PCB_LAYER_ID aStart, PCB_LAYER_ID aEnd ) -> std::optional<int>
52 {
53 if( aStart == UNDEFINED_LAYER || aEnd == UNDEFINED_LAYER )
54 return std::optional<int>();
55
56 const BOARD_STACKUP& stackup = aBoard.GetDesignSettings().GetStackupDescriptor();
57
58 return std::optional<int>( stackup.GetLayerDistance( aStart, aEnd ) );
59 };
60
61 if( span.m_IsBackdrill )
62 {
63 auto tryBackdrill =
64 [&]( const PADSTACK::DRILL_PROPS& aDrill, DRILL_OP_KIND aKind )
65 {
66 if( aDrill.start == UNDEFINED_LAYER || aDrill.end == UNDEFINED_LAYER )
67 return;
68
69 DRILL_SPAN drillSpan( aDrill.start, aDrill.end, true, false );
70
71 if( drillSpan.Pair() != span.Pair() )
72 return;
73
74 if( aDrill.start != span.DrillStartLayer() || aDrill.end != span.DrillEndLayer() )
75 return;
76
77 if( aDrill.size.x <= 0 && aDrill.size.y <= 0 )
78 return;
79
81 op.m_Kind = aKind;
82 op.m_SourceItem = aVia;
83 op.m_SourceId = aVia->m_Uuid;
86 op.m_NotPlated = true;
87 op.m_Position = aVia->GetStart();
88 op.m_TopLayer = span.TopLayer();
89 op.m_BottomLayer = span.BottomLayer();
90
91 int diameter = aDrill.size.x;
92
93 if( aDrill.size.y > 0 )
94 diameter = ( diameter > 0 ) ? std::min( diameter, aDrill.size.y ) : aDrill.size.y;
95
96 op.m_Diameter = diameter;
97 op.m_SizeXY = aDrill.size;
98
99 if( aDrill.shape != PAD_DRILL_SHAPE::CIRCLE && aDrill.size.x != aDrill.size.y )
100 op.m_IsSlot = true;
101
102 op.m_Filled = aDrill.is_filled.value_or( false );
103 op.m_Capped = aDrill.is_capped.value_or( false );
104 op.m_TopCovered = aVia->Padstack().IsCovered( op.m_TopLayer ).value_or( false );
105 op.m_BottomCovered = aVia->Padstack().IsCovered( op.m_BottomLayer ).value_or( false );
106 op.m_TopPlugged = aVia->Padstack().IsPlugged( op.m_TopLayer ).value_or( false );
107 op.m_BottomPlugged = aVia->Padstack().IsPlugged( op.m_BottomLayer ).value_or( false );
108 op.m_TopTented = aVia->Padstack().IsTented( op.m_TopLayer ).value_or( false );
109 op.m_BottomTented = aVia->Padstack().IsTented( op.m_BottomLayer ).value_or( false );
110 op.m_DrillStart = aDrill.start;
111 op.m_DrillEnd = aDrill.end;
112 op.m_StubLength = stubLength( aDrill.start, aDrill.end );
113
114 aOut.push_back( op );
115 };
116
117 tryBackdrill( aVia->Padstack().SecondaryDrill(), DRILL_OP_KIND::SECONDARY_DRILL );
118 tryBackdrill( aVia->Padstack().TertiaryDrill(), DRILL_OP_KIND::TERTIARY_DRILL );
119 return;
120 }
121
122 int holeSize = aVia->GetDrillValue();
123
124 if( holeSize == 0 )
125 return;
126
127 PCB_LAYER_ID topLayer;
128 PCB_LAYER_ID bottomLayer;
129 aVia->LayerPair( &topLayer, &bottomLayer );
130
131 if( DRILL_LAYER_PAIR( topLayer, bottomLayer ) != span.Pair()
132 && DRILL_LAYER_PAIR( bottomLayer, topLayer ) != span.Pair() )
133 {
134 return;
135 }
136
138 op.m_SourceItem = aVia;
139 op.m_SourceId = aVia->m_Uuid;
140
141 if( span.Pair() == DRILL_LAYER_PAIR( F_Cu, B_Cu ) )
143 else
145
147 op.m_Diameter = holeSize;
148 op.m_NotPlated = false;
149 op.m_SizeXY = VECTOR2I( holeSize, holeSize );
150 op.m_Position = aVia->GetStart();
151 op.m_TopLayer = topLayer;
152 op.m_BottomLayer = bottomLayer;
153 op.m_Filled = aVia->Padstack().IsFilled().value_or( false );
154 op.m_Capped = aVia->Padstack().IsCapped().value_or( false );
155 op.m_TopCovered = aVia->Padstack().IsCovered( topLayer ).value_or( false );
156 op.m_BottomCovered = aVia->Padstack().IsCovered( bottomLayer ).value_or( false );
157 op.m_TopPlugged = aVia->Padstack().IsPlugged( topLayer ).value_or( false );
158 op.m_BottomPlugged = aVia->Padstack().IsPlugged( bottomLayer ).value_or( false );
159 op.m_TopTented = aVia->Padstack().IsTented( topLayer ).value_or( false );
160 op.m_BottomTented = aVia->Padstack().IsTented( bottomLayer ).value_or( false );
161 op.m_FrontPostMachining = fromPadstack( aVia->Padstack().FrontPostMachining() );
162 op.m_BackPostMachining = fromPadstack( aVia->Padstack().BackPostMachining() );
163 op.m_DrillStart = aVia->Padstack().Drill().start;
164 op.m_DrillEnd = bottomLayer;
165
166 aOut.push_back( op );
167}
168
169
170void enumeratePad( PAD* aPad, const DRILL_QUERY& aQuery, std::vector<DRILL_OPERATION>& aOut )
171{
172 if( !aQuery.m_MergePTHNPTH )
173 {
174 if( !aQuery.m_NonPlatedOnly && aPad->GetAttribute() == PAD_ATTRIB::NPTH )
175 return;
176
177 if( aQuery.m_NonPlatedOnly && aPad->GetAttribute() != PAD_ATTRIB::NPTH )
178 return;
179 }
180
181 if( aPad->GetDrillSize().x == 0 )
182 return;
183
185 op.m_SourceItem = aPad;
186 op.m_SourceId = aPad->m_Uuid;
187 op.m_NotPlated = ( aPad->GetAttribute() == PAD_ATTRIB::NPTH );
188
189 if( op.m_NotPlated )
190 {
192 }
193 else if( aPad->GetProperty() == PAD_PROP::CASTELLATED )
194 {
196 }
197 else if( aPad->GetProperty() == PAD_PROP::PRESSFIT )
198 {
200 }
201 else
202 {
204 }
205
206 op.m_Orientation = aPad->GetOrientation();
207 op.m_Diameter = std::min( aPad->GetDrillSize().x, aPad->GetDrillSize().y );
208
209 op.m_IsSlot = IsDrillSlot( *aPad );
210
211 op.m_SizeXY = aPad->GetDrillSize();
212 op.m_Position = aPad->GetPosition();
213 op.m_BottomLayer = B_Cu;
214 op.m_TopLayer = F_Cu;
215
216 // Pads have never carried post-machining into the drill files and adding it here would
217 // move fabrication output
218
219 aOut.push_back( op );
220}
221
222} // namespace
223
224
225bool IsDrillSlot( const PAD& aPad )
226{
227 return aPad.HasHole() && aPad.GetDrillShape() != PAD_DRILL_SHAPE::CIRCLE
228 && aPad.GetDrillSizeX() != aPad.GetDrillSizeY();
229}
230
231
232std::vector<DRILL_OPERATION> EnumerateDrillOperations( const BOARD& aBoard, const DRILL_QUERY& aQuery )
233{
234 std::vector<DRILL_OPERATION> operations;
235
236 wxASSERT( IsCopperLayerLowerThan( aQuery.m_Span.BottomLayer(), aQuery.m_Span.TopLayer() ) );
237
238 if( !aQuery.m_NonPlatedOnly )
239 {
240 for( PCB_TRACK* track : aBoard.Tracks() )
241 {
242 if( track->Type() != PCB_VIA_T )
243 continue;
244
245 enumerateVia( static_cast<PCB_VIA*>( track ), aBoard, aQuery, operations );
246 }
247 }
248
249 if( !aQuery.m_Span.m_IsBackdrill && aQuery.m_Span.Pair() == DRILL_LAYER_PAIR( F_Cu, B_Cu ) )
250 {
251 for( FOOTPRINT* footprint : aBoard.Footprints() )
252 {
253 for( PAD* pad : footprint->Pads() )
254 enumeratePad( pad, aQuery, operations );
255 }
256 }
257
258 return operations;
259}
260
261
BOARD_STACKUP & GetStackupDescriptor()
Manage layers needed to make a physical board.
int GetLayerDistance(PCB_LAYER_ID aFirstLayer, PCB_LAYER_ID aSecondLayer) const
Calculate the distance (height) between the two given copper layers.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:409
const FOOTPRINTS & Footprints() const
Definition board.h:463
const TRACKS & Tracks() const
Definition board.h:461
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1299
const KIID m_Uuid
Definition eda_item.h:597
std::optional< bool > IsFilled() const
std::optional< bool > IsTented(PCB_LAYER_ID aSide) const
Checks if this padstack is tented (covered in soldermask) on the given side.
POST_MACHINING_PROPS & FrontPostMachining()
Definition padstack.h:370
std::optional< bool > IsPlugged(PCB_LAYER_ID aSide) const
DRILL_PROPS & TertiaryDrill()
Definition padstack.h:367
DRILL_PROPS & Drill()
Definition padstack.h:361
std::optional< bool > IsCapped() const
std::optional< bool > IsCovered(PCB_LAYER_ID aSide) const
DRILL_PROPS & SecondaryDrill()
Definition padstack.h:364
POST_MACHINING_PROPS & BackPostMachining()
Definition padstack.h:373
Definition pad.h:61
PAD_PROP GetProperty() const
Definition pad.h:561
int GetDrillSizeY() const
Definition pad.h:322
PAD_ATTRIB GetAttribute() const
Definition pad.h:558
VECTOR2I GetPosition() const override
Definition pad.cpp:246
VECTOR2I GetDrillSize() const
Definition pad.h:318
int GetDrillSizeX() const
Definition pad.h:320
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition pad.cpp:1747
PAD_DRILL_SHAPE GetDrillShape() const
Definition pad.h:432
bool HasHole() const override
Definition pad.h:113
const VECTOR2I & GetStart() const
Definition pcb_track.h:93
const PADSTACK & Padstack() const
Definition pcb_track.h:418
int GetDrillValue() const
Calculate the drill value for vias (m_drill if > 0, or default drill value for the board).
void LayerPair(PCB_LAYER_ID *top_layer, PCB_LAYER_ID *bottom_layer) const
Return the 2 layers used by the via (the via actually uses all layers between these 2 layers)
bool IsDrillSlot(const PAD &aPad)
Whether a pad's hole is a slot rather than a round drill.
std::vector< DRILL_OPERATION > EnumerateDrillOperations(const BOARD &aBoard, const DRILL_QUERY &aQuery)
The one place that decides what the board's holes are.
DRILL_OP_KIND
Which of the padstack's drill props produced the operation.
std::pair< PCB_LAYER_ID, PCB_LAYER_ID > DRILL_LAYER_PAIR
Definition drill_span.h:48
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:422
bool IsCopperLayerLowerThan(PCB_LAYER_ID aLayerA, PCB_LAYER_ID aLayerB)
Return true if copper aLayerA is placed lower than aLayerB, false otherwise.
Definition layer_ids.h:850
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
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:102
@ PRESSFIT
a PTH with a hole diameter with tight tolerances for press fit pin
Definition padstack.h:122
@ CASTELLATED
a pad with a castellated through hole
Definition padstack.h:120
One machining action, which is also one NC hit and one tool assignment.
DRILL_OP_KIND m_Kind
DRILL_POST_MACHINING m_BackPostMachining
PCB_LAYER_ID m_DrillEnd
PCB_LAYER_ID m_TopLayer
PCB_LAYER_ID m_BottomLayer
VECTOR2I m_SizeXY
Source axes, never normalized to (width, length).
BOARD_ITEM * m_SourceItem
non-owning, valid only for this enumeration
EDA_ANGLE m_Orientation
DRILL_POST_MACHINING m_FrontPostMachining
std::optional< int > m_StubLength
HOLE_ATTRIBUTE m_Attribute
PCB_LAYER_ID m_DrillStart
int m_Size
int m_Depth
int m_Angle
PAD_DRILL_POST_MACHINING_MODE m_Mode
Selects which operations EnumerateDrillOperations() returns.
bool m_NonPlatedOnly
Emit only non-plated holes.
bool m_MergePTHNPTH
Emit plated and non-plated together, as the merged drill file does.
DRILL_SPAN m_Span
DRILL_LAYER_PAIR Pair() const
Definition drill_span.h:92
PCB_LAYER_ID DrillEndLayer() const
Definition drill_span.h:87
PCB_LAYER_ID TopLayer() const
Definition drill_span.h:70
PCB_LAYER_ID DrillStartLayer() const
Definition drill_span.h:82
PCB_LAYER_ID BottomLayer() const
Definition drill_span.h:77
bool m_IsBackdrill
Definition drill_span.h:129
The properties of a padstack drill.
Definition padstack.h:272
PCB_LAYER_ID start
Definition padstack.h:275
PCB_LAYER_ID end
Definition padstack.h:276
VECTOR2I size
Drill diameter (x == y) or slot dimensions (x != y)
Definition padstack.h:273
std::optional< bool > is_capped
True if the drill hole should be capped.
Definition padstack.h:279
std::optional< bool > is_filled
True if the drill hole should be filled completely.
Definition padstack.h:278
PAD_DRILL_SHAPE shape
Definition padstack.h:274
std::optional< PAD_DRILL_POST_MACHINING_MODE > mode
Definition padstack.h:287
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:89
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683