KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pth_hole_size.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 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 <pth_hole_size.h>
21
22#include <algorithm>
23#include <cmath>
24#include <cstdint>
25#include <utility>
26
27#include <base_units.h>
28#include <math/util.h>
29
30#include <wx/intl.h>
31
32
33namespace
34{
35
39std::pair<int, int> effectiveLeadSize( const PTH_LEAD_DEF& aLead )
40{
41 switch( aLead.m_shape )
42 {
43 case PTH_LEAD_SHAPE::ROUND: return { aLead.m_minX, aLead.m_maxX };
44
46 return { KiROUND( std::hypot( static_cast<double>( aLead.m_minX ), aLead.m_minX ) ),
47 KiROUND( std::hypot( static_cast<double>( aLead.m_maxX ), aLead.m_maxX ) ) };
48
50 return { KiROUND( std::hypot( static_cast<double>( aLead.m_minX ), aLead.m_minY ) ),
51 KiROUND( std::hypot( static_cast<double>( aLead.m_maxX ), aLead.m_maxY ) ) };
52 }
53
54 return { 0, 0 };
55}
56
69class IPC2222_HOLE_SIZE_STANDARD : public PTH_HOLE_SIZE_STANDARD
70{
71 // Smallest-hole allowances per density level A, B, C, added to the largest lead size.
72 static constexpr int MIN_HOLE_ADDED[3] = { pcbIUScale.mmToIU( 0.25 ), pcbIUScale.mmToIU( 0.20 ),
73 pcbIUScale.mmToIU( 0.15 ) };
74
75 // Largest-hole allowances per density level A, B, C, added to the smallest lead size.
76 static constexpr int MAX_HOLE_ADDED[3] = { pcbIUScale.mmToIU( 0.70 ), pcbIUScale.mmToIU( 0.70 ),
77 pcbIUScale.mmToIU( 0.60 ) };
78
79public:
80 const wxString& GetID() const override
81 {
82 static const wxString id = "IPC-2222B";
83 return id;
84 }
85
86 const wxString& GetDisplayName() const override { return GetID(); }
87
88 int GetLevelCount() const override { return 3; }
89
90 wxString GetLevelName( int aLevel ) const override
91 {
92 switch( std::clamp( aLevel, 0, GetLevelCount() - 1 ) )
93 {
94 case 0: return _( "A (General)" );
95 case 1: return _( "B (Moderate)" );
96 default: return _( "C (High density)" );
97 }
98 }
99
100 int GetMinHoleAddend( int aLevel ) const override
101 {
102 return MIN_HOLE_ADDED[std::clamp( aLevel, 0, GetLevelCount() - 1 )];
103 }
104
105 int GetMaxHoleAddend( int aLevel ) const override
106 {
107 return MAX_HOLE_ADDED[std::clamp( aLevel, 0, GetLevelCount() - 1 )];
108 }
109
110 PTH_HOLE_SIZE_RESULT ComputeHoleSize( int aLevel, const PTH_LEAD_DEF& aLead ) const override
111 {
112 const int level = std::clamp( aLevel, 0, GetLevelCount() - 1 );
113
114 const auto [leadMin, leadMax] = effectiveLeadSize( aLead );
115
116 PTH_HOLE_SIZE_RESULT result;
117 result.m_leadMin = leadMin;
118 result.m_leadMax = leadMax;
119 result.m_holeMin = leadMax + GetMinHoleAddend( level );
120 result.m_holeMax = leadMin + GetMaxHoleAddend( level );
121
122 return result;
123 }
124};
125
126} // namespace
127
128
129int ComputeRecommendedPthHoleSize( const PTH_HOLE_SIZE_RESULT& aRange, int aRoundingStep, PTH_HOLE_ROUNDING aRounding )
130{
131 // Midpoint of the allowable range. Integer arithmetic keeps the rounding exact.
132 const int64_t mid = ( static_cast<int64_t>( aRange.m_holeMin ) + aRange.m_holeMax ) / 2;
133
134 if( aRoundingStep <= 0 )
135 return static_cast<int>( mid );
136
137 int64_t hole = 0;
138
139 if( aRounding == PTH_HOLE_ROUNDING::UP )
140 hole = ( mid + aRoundingStep - 1 ) / aRoundingStep * aRoundingStep;
141 else
142 hole = ( mid + aRoundingStep / 2 ) / aRoundingStep * aRoundingStep;
143
144 // Rounding must not take the recommended hole below the smallest allowable hole.
145 if( hole < aRange.m_holeMin )
146 hole = ( static_cast<int64_t>( aRange.m_holeMin ) + aRoundingStep - 1 ) / aRoundingStep * aRoundingStep;
147
148 return static_cast<int>( hole );
149}
150
151
153{
154 for( const PTH_HOLE_SIZE_STANDARD* standard : GetPthHoleSizeStandards() )
155 {
156 if( aId == standard->GetID() )
157 return standard;
158 }
159
160 return nullptr;
161}
162
163
164const std::vector<const PTH_HOLE_SIZE_STANDARD*>& GetPthHoleSizeStandards()
165{
166 static const IPC2222_HOLE_SIZE_STANDARD ipc2222b_std;
167
168 static const std::vector<const PTH_HOLE_SIZE_STANDARD*> standards = {
169 &ipc2222b_std,
170 };
171
172 return standards;
173}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:995
A source of hole size rules for a plated through hole.
#define _(s)
int ComputeRecommendedPthHoleSize(const PTH_HOLE_SIZE_RESULT &aRange, int aRoundingStep, PTH_HOLE_ROUNDING aRounding)
Choose a recommended hole within an allowable range.
const PTH_HOLE_SIZE_STANDARD * FindPthHoleSizeStandard(const wxString &aId)
Find a hole size standard in the registry by its ID (e.g.
const std::vector< const PTH_HOLE_SIZE_STANDARD * > & GetPthHoleSizeStandards()
PTH_HOLE_ROUNDING
constexpr int mmToIU(double mm) const
Definition base_units.h:90
PTH_LEAD_SHAPE m_shape
wxString result
Test unit parsing edge cases and error handling.