KiCad PCB EDA Suite
Loading...
Searching...
No Matches
panel_pth_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
21
22#include <algorithm>
23#include <cmath>
24#include <vector>
25
26#include <wx/clipbrd.h>
27#include <wx/dcmemory.h>
28#include <wx/image.h>
29#include <wx/log.h>
30
31#include <base_units.h>
32#include <bitmaps.h>
33#include <math/util.h>
36#include <pth_hole_size.h>
37#include <render_utils.h>
38
39
40namespace
41{
42// Indexes of the items in the FBP shape and rounding choice controls. The order is fixed by
43// the FBP, so keep these in sync with the choice item lists.
44enum class SHAPE_CHOICE
45{
46 ROUND,
47 SQUARE,
49};
50
51enum class ROUNDING_CHOICE
52{
53 UP,
55};
56
57// Read a control as a size in mm and convert it to pcb IU. Returns false if the text is not a
58// finite number.
59bool readMm( const wxTextCtrl* aCtrl, int& aIU )
60{
61 const double mm = DoubleFromString( aCtrl->GetValue() );
62
63 if( !std::isfinite( mm ) )
64 return false;
65
66 aIU = pcbIUScale.mmToIU( mm );
67 return true;
68}
69
70// Format an IU value as a millimetre string.
71wxString formatMm( int aIU )
72{
73 return wxString::Format( wxT( "%.3g" ), pcbIUScale.IUTomm( aIU ) );
74}
75
76struct PTH_PREVIEW_OPTIONS
77{
78 bool m_showMinLeadSize = false;
79 bool m_showMinHoleSize = false;
80 bool m_showMaxHoleSize = false;
81 wxColour m_backgroundColour; // Background the pad is drawn against for alpha blending
82};
83
84/*
85 * Draw a sketch of a plated through hole pad per the given sizes,
86 * with the configured tolerance overlays.
87 */
88void drawPthSizePreview( wxBitmap& aBitmap, const PTH_LEAD_DEF& aLead, int aHoleIU, int aHoleMinIU, int aHoleMaxIU,
89 int aPadIU, const PTH_PREVIEW_OPTIONS& aOptions )
90{
91 wxMemoryDC dc( aBitmap );
92
93 dc.SetBackground( aOptions.m_backgroundColour );
94 dc.Clear();
95
96 const wxColour copperColor( 0xfc, 0xb2, 0x3c );
97 const wxColour padOutlineColor( 0x80, 0x80, 0x80 );
98 const wxColour leadColor( 0xc8, 0xc8, 0xc8 );
99 const wxColour minLeadColor( 0x80, 0x80, 0x80 );
100 const wxColour minMaxHoleColor( 0x00, 0x60, 0xf0 );
101
102 if( aPadIU > 0 )
103 {
104 const int size = std::min( aBitmap.GetWidth(), aBitmap.GetHeight() );
105 const double maxFeatureIU = std::max( aPadIU, aHoleMaxIU );
106
107 const int outlineWidth = 1; // px
108
109 const double scale = static_cast<double>( size - 2 * outlineWidth ) / maxFeatureIU;
110 const wxPoint centre( aBitmap.GetWidth() / 2, aBitmap.GetHeight() / 2 );
111
112 const auto toPx = [scale]( int aIU ) -> int
113 {
114 return KiROUND( aIU * scale );
115 };
116
117 const int padRadius = toPx( aPadIU ) / 2;
118 const int holeRadius = toPx( aHoleIU ) / 2;
119
120 // Copper pad with the drilled hole cut out.
121 dc.SetBrush( wxBrush( copperColor ) );
122 dc.SetPen( wxPen( copperColor ) );
123 dc.DrawCircle( centre, padRadius );
124
125 dc.SetBrush( wxBrush( aOptions.m_backgroundColour ) );
126 dc.SetPen( wxPen( aOptions.m_backgroundColour ) );
127 dc.DrawCircle( centre, holeRadius );
128
129 // Lead cross-section in the middle of the hole.
130 const bool isRectangular = aLead.m_shape == PTH_LEAD_SHAPE::RECTANGULAR;
131 const int leadWidth = toPx( aLead.m_maxX );
132 const int leadHeight = toPx( isRectangular ? aLead.m_maxY : aLead.m_maxX );
133
134 dc.SetBrush( wxBrush( leadColor ) );
135 dc.SetPen( wxPen( leadColor, outlineWidth ) );
136
137 if( aLead.m_shape == PTH_LEAD_SHAPE::ROUND )
138 dc.DrawCircle( centre, leadWidth / 2 );
139 else
140 dc.DrawRectangle( centre.x - leadWidth / 2, centre.y - leadHeight / 2, leadWidth, leadHeight );
141
142 // Minimum lead cross-section, shown dashed to indicate the tolerance band.
143 if( aOptions.m_showMinLeadSize )
144 {
145 const int minLeadWidth = toPx( aLead.m_minX );
146 const int minLeadHeight = toPx( isRectangular ? aLead.m_minY : aLead.m_minX );
147
148 dc.SetBrush( *wxTRANSPARENT_BRUSH );
149 dc.SetPen( wxPen( minLeadColor, outlineWidth, wxPENSTYLE_SHORT_DASH ) );
150
151 if( aLead.m_shape == PTH_LEAD_SHAPE::ROUND )
152 dc.DrawCircle( centre, minLeadWidth / 2 );
153 else
154 dc.DrawRectangle( centre.x - minLeadWidth / 2, centre.y - minLeadHeight / 2, minLeadWidth,
155 minLeadHeight );
156 }
157
158 dc.SetBrush( *wxTRANSPARENT_BRUSH );
159 const wxPen outlinePen( padOutlineColor, outlineWidth );
160 dc.SetPen( outlinePen );
161 dc.DrawCircle( centre, padRadius );
162 dc.DrawCircle( centre, holeRadius );
163
164 // Allowable hole size range, shown as dashed circles.
165 if( aOptions.m_showMinHoleSize )
166 {
167 const wxPen holeMinRangePen( minMaxHoleColor, outlineWidth, wxPENSTYLE_SHORT_DASH );
168 dc.SetPen( holeMinRangePen );
169 dc.DrawCircle( centre, toPx( aHoleMinIU ) / 2 );
170 }
171
172 if( aOptions.m_showMaxHoleSize )
173 {
174 const wxPen holeMaxRangePen( minMaxHoleColor, outlineWidth, wxPENSTYLE_LONG_DASH );
175 dc.SetPen( holeMaxRangePen );
176 dc.DrawCircle( centre, toPx( aHoleMaxIU ) / 2 );
177 }
178 }
179
180 dc.SelectObject( wxNullBitmap );
181}
182
183// Render the preview to a bitmap with a transparent background, so the control's own themed
184// background shows through the area round the pad and inside the drilled hole. This means the
185// preview follows theme changes without needing to be re-rendered.
186wxBitmap makePthSizePreviewBitmap( const PTH_LEAD_DEF& aLead, int aHoleIU, int aHoleMinIU, int aHoleMaxIU, int aPadIU,
187 bool aShowMinLeadSize, bool aShowMinHoleSize, bool aShowMaxHoleSize, int aPixelSize )
188{
189 // Render the pad once on white and once on black, then recover the per-pixel coverage alpha
190 // from the two renders. This gives properly feathered anti-aliased edges over the
191 // transparent background without relying on a key colour.
192 const auto render = [&]( const wxColour& aBackground )
193 {
194 wxBitmap bitmap( aPixelSize, aPixelSize );
195
196 PTH_PREVIEW_OPTIONS options;
197 options.m_showMinLeadSize = aShowMinLeadSize;
198 options.m_showMinHoleSize = aShowMinHoleSize;
199 options.m_showMaxHoleSize = aShowMaxHoleSize;
200 options.m_backgroundColour = aBackground;
201
202 drawPthSizePreview( bitmap, aLead, aHoleIU, aHoleMinIU, aHoleMaxIU, aPadIU, options );
203
204 return bitmap.ConvertToImage();
205 };
206
207 const wxImage imageOnWhite = render( *wxWHITE );
208 const wxImage imageOnBlack = render( *wxBLACK );
209
210 const tl::expected<wxImage, std::string> alphaImage = CreateAlphaImageFromTwoRenders( imageOnWhite, imageOnBlack );
211
212 if( !alphaImage )
213 {
214 wxLogError( "Failed to create alpha image for PTH size preview: %s", alphaImage.error() );
215 return wxBitmap( imageOnWhite );
216 }
217
218 return wxBitmap( *alphaImage );
219}
220
221// Pad a string to a fixed character width so the report columns line up in a monospace font.
222// Longer strings are left as-is.
223wxString padRight( const wxString& aText, size_t aWidth )
224{
225 wxString text = aText;
226
227 if( text.length() < aWidth )
228 text += wxString( ' ', aWidth - text.length() );
229
230 return text;
231}
232
233/*
234 * Generate a text report of the hole size calculation, suitable for copying to the clipboard.
235 */
236wxString pthResultReportText( const PTH_HOLE_SIZE_STANDARD* aStandard, int aLevel, const PTH_LEAD_DEF& aLead,
237 int aAnnularIU, const PTH_HOLE_SIZE_RESULT& aRange, int aHoleIU, int aPadIU )
238{
239 // The report rows: label/value pairs for the table, or a single-cell row for a full-width
240 // line (used for the blank separator between the inputs and the calculated sizes). The
241 // text is only rendered once all rows are known, so the label column can be sized to fit.
242 std::vector<std::vector<wxString>> rows;
243
244 wxString leadShapeText;
245 wxString leadSizeText;
246
247 switch( aLead.m_shape )
248 {
250 leadShapeText = _( "Round" );
251 leadSizeText = wxString::Format( _( "%s \u2013 %s mm" ), formatMm( aLead.m_minX ), formatMm( aLead.m_maxX ) );
252 break;
253
255 leadShapeText = _( "Square" );
256 leadSizeText = wxString::Format( _( "%s \u2013 %s mm" ), formatMm( aLead.m_minX ), formatMm( aLead.m_maxX ) );
257 break;
258
260 leadShapeText = _( "Rectangular" );
261 leadSizeText = wxString::Format( _( "%s \u2013 %s mm x %s \u2013 %s mm" ), formatMm( aLead.m_minX ),
262 formatMm( aLead.m_maxX ), formatMm( aLead.m_minY ), formatMm( aLead.m_maxY ) );
263 break;
264 }
265
266 rows.push_back( { _( "Standard:" ), aStandard->GetDisplayName() } );
267 rows.push_back( { _( "Production level:" ), aStandard->GetLevelName( aLevel ) } );
268 rows.push_back( { _( "Lead shape:" ), leadShapeText } );
269 rows.push_back( { _( "Lead size:" ), leadSizeText } );
270 rows.push_back(
271 { _( "Effective lead size:" ), wxString::Format( _( "%s \u2013 %s mm" ), formatMm( aRange.m_leadMin ),
272 formatMm( aRange.m_leadMax ) ) } );
273
274 rows.push_back( { wxEmptyString } );
275
276 rows.push_back( { _( "Minimum hole size:" ), wxString::Format( _( "%s mm" ), formatMm( aRange.m_holeMin ) ) } );
277 rows.push_back( { _( "Maximum hole size:" ), wxString::Format( _( "%s mm" ), formatMm( aRange.m_holeMax ) ) } );
278 rows.push_back( { _( "Recommended hole size:" ), wxString::Format( _( "%s mm" ), formatMm( aHoleIU ) ) } );
279 rows.push_back( { _( "Hole clearance over max. lead:" ),
280 wxString::Format( _( "%s mm" ), formatMm( aHoleIU - aRange.m_leadMax ) ) } );
281 rows.push_back( { _( "Annular ring:" ), wxString::Format( _( "%s mm" ), formatMm( aAnnularIU ) ) } );
282 rows.push_back( { _( "Pad diameter:" ), wxString::Format( _( "%s mm" ), formatMm( aPadIU ) ) } );
283
284 // Pad the labels to the widest one so all the values start on the same column.
285 size_t labelWidth = 0;
286
287 for( const auto& row : rows )
288 {
289 if( row.size() > 1 )
290 labelWidth = std::max( labelWidth, row[0].length() );
291 }
292
293 wxString text;
294
295 for( const auto& row : rows )
296 {
297 if( row.size() > 1 )
298 text += padRight( row[0], labelWidth ) + wxT( " " ) + row[1] + wxT( "\n" );
299 else
300 text += row[0] + wxT( "\n" );
301 }
302
303 return text;
304}
305
306} // namespace
307
308
309PANEL_PTH_SIZE::PANEL_PTH_SIZE( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style,
310 const wxString& name ) :
311 PANEL_PTH_SIZE_BASE( parent, id, pos, size, style, name )
312{
314
316
317 m_shapeChoice->SetSelection( 0 );
319
320 // Default values (mm), a typical round component lead.
321 m_sizeXMinCtrl->SetValue( wxT( "0.6" ) );
322 m_sizeXMaxCtrl->SetValue( wxT( "0.7" ) );
323 m_sizeYMinCtrl->SetValue( wxT( "0.25" ) );
324 m_sizeYMaxCtrl->SetValue( wxT( "0.3" ) );
325 m_annularCtrl->SetValue( wxT( "0.4" ) );
326 m_sizeRoundingCtrl->SetValue( wxT( "0.05" ) );
327
328 // Show the minimum lead size by default; the hole size range overlays are opt-in.
329 m_cbShowMinLeadSize->SetValue( true );
330
331 // The copy button puts the current report text on the clipboard.
332 m_bpCopyAll->SetBitmap( KiBitmapBundle( BITMAPS::copy, 16 ) );
333 m_bpCopyAll->SetToolTip( _( "Copy the report to the clipboard" ) );
334
335 // Monospace so the columns of the report line up.
336 m_ResultReport->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL,
337 wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
338
339 m_ResultReport->SetMinSize( wxSize( -1, ToPhys( 250 ) ) );
340
341 recalculate();
342
343 GetSizer()->SetSizeHints( this );
344}
345
346
350
351
353{
354 // No persisted settings yet; the panel starts from its default values.
355}
356
357
359{
360 // No persisted settings yet.
361}
362
363
365{
366 // Bitmap icons are theme dependent (light/dark variants), so re-resolve the copy icon for
367 // the new theme.
369
370 // The preview bitmap has a transparent background, so the control's themed background shows
371 // through it; just make sure the control repaints for the new theme.
372 m_bitmapPreview->Refresh();
373}
374
375
376void PANEL_PTH_SIZE::OnControlsChanged( wxCommandEvent& aEvent )
377{
378 if( aEvent.GetEventObject() == m_shapeChoice )
380 else if( aEvent.GetEventObject() == m_standardChoice )
382
383 m_level = m_levelChoice->GetSelection();
384
385 recalculate();
386}
387
388
389void PANEL_PTH_SIZE::OnValueChanged( wxCommandEvent& aEvent )
390{
391 recalculate();
392}
393
394
396{
397 m_standardChoice->Clear();
398
399 for( const auto& standard : GetPthHoleSizeStandards() )
400 m_standardChoice->Append( standard->GetDisplayName() );
401
402 m_standardChoice->SetSelection( 0 );
403}
404
405
407{
408 const int selection = m_standardChoice->GetSelection();
409 const auto& standards = GetPthHoleSizeStandards();
410
411 if( selection >= 0 && selection < static_cast<int>( standards.size() ) )
412 {
413 m_holeSizeStandard = standards[selection];
414 m_staticTextSummaryTitle->SetLabel(
415 wxString::Format( _( "%s Summary" ), standards[selection]->GetDisplayName() ) );
416 }
417
418 if( !m_holeSizeStandard )
419 return;
420
421 m_levelChoice->Clear();
422
423 for( int i = 0; i < m_holeSizeStandard->GetLevelCount(); ++i )
424 m_levelChoice->Append( m_holeSizeStandard->GetLevelName( i ) );
425
426 m_level = std::min( 1, m_holeSizeStandard->GetLevelCount() - 1 );
427 m_levelChoice->SetSelection( m_level );
428
430}
431
432
434{
435 if( !m_holeSizeStandard )
436 return;
437
438 // A bit of a hack because other standards may not work exectly like IPC-2222B,
439 // but until we have more standards, just show the IPC-2222B summary table here and think
440 // about how to generalize it later.
441 wxGrid* const grid = m_ipc2222Summary;
442 const int levelCount = m_holeSizeStandard->GetLevelCount();
443
444 // Keep one grid column per density level of the standard.
445 const int colCount = grid->GetNumberCols();
446
447 if( levelCount > colCount )
448 grid->AppendCols( levelCount - colCount );
449 else if( levelCount < colCount )
450 grid->DeleteCols( levelCount, colCount - levelCount );
451
452 for( int level = 0; level < levelCount; ++level )
453 {
454 grid->SetColLabelValue( level, m_holeSizeStandard->GetLevelName( level ) );
455
456 // The smallest allowable hole is the largest lead size plus the level allowance, and the
457 // largest allowable hole is the smallest lead size plus the level allowance.
458 grid->SetCellValue( 0, level,
459 wxString::Format( _( "Maximum lead diameter + %smm" ),
460 formatMm( m_holeSizeStandard->GetMinHoleAddend( level ) ) ) );
461
462 grid->SetCellValue( 1, level,
463 wxString::Format( _( "Minimum lead diameter + %smm" ),
464 formatMm( m_holeSizeStandard->GetMaxHoleAddend( level ) ) ) );
465 }
466
467 grid->AutoSizeColumns();
468}
469
470
472{
473 const SHAPE_CHOICE shape = static_cast<SHAPE_CHOICE>( m_shapeChoice->GetSelection() );
474 const bool showSizeY = shape == SHAPE_CHOICE::RECTANGULAR;
475
476 switch( shape )
477 {
478 case SHAPE_CHOICE::ROUND:
480 m_staticTextSizeX->SetLabel( _( "Diameter:" ) );
481 break;
482
483 case SHAPE_CHOICE::SQUARE:
485 m_staticTextSizeX->SetLabel( _( "Side length:" ) );
486 break;
487
488 default:
490 m_staticTextSizeX->SetLabel( _( "Size X:" ) );
491 break;
492 }
493
494 m_staticTextSizeY->Show( showSizeY );
495 m_sizeYMinCtrl->Show( showSizeY );
496 m_sizeYMaxCtrl->Show( showSizeY );
497 m_staticTextSizeYUnit->Show( showSizeY );
498
499 Layout();
500}
501
502
504{
505 if( !m_holeSizeStandard || m_level < 0 )
506 {
507 m_ResultReport->SetValue( wxEmptyString );
508 return;
509 }
510
511 PTH_LEAD_DEF lead;
512 int annularIU = 0;
513 int roundingStepIU = 0;
514
515 lead.m_shape = m_leadShape;
516
517 bool valid = true;
518
519 valid &= readMm( m_sizeXMinCtrl, lead.m_minX );
520 valid &= readMm( m_sizeXMaxCtrl, lead.m_maxX );
521 valid &= lead.m_minX > 0 && lead.m_minX <= lead.m_maxX;
522
524 {
525 valid &= readMm( m_sizeYMinCtrl, lead.m_minY );
526 valid &= readMm( m_sizeYMaxCtrl, lead.m_maxY );
527 valid &= lead.m_minY > 0 && lead.m_minY <= lead.m_maxY;
528 }
529
530 valid &= readMm( m_annularCtrl, annularIU ) && annularIU >= 0;
531 valid &= readMm( m_sizeRoundingCtrl, roundingStepIU ) && roundingStepIU >= 0;
532
533 // Don't leave stale results in the report when an input is incomplete or invalid.
534 if( !valid )
535 {
536 m_ResultReport->SetValue( wxEmptyString );
537 return;
538 }
539
540 const ROUNDING_CHOICE roundingChoice = static_cast<ROUNDING_CHOICE>( m_choiceRounding->GetSelection() );
541 const PTH_HOLE_ROUNDING rounding =
542 roundingChoice == ROUNDING_CHOICE::UP ? PTH_HOLE_ROUNDING::UP : PTH_HOLE_ROUNDING::NEAREST;
543
544 PTH_HOLE_SIZE_RESULT range = m_holeSizeStandard->ComputeHoleSize( m_level, lead );
545
546 const int hole = ComputeRecommendedPthHoleSize( range, roundingStepIU, rounding );
547 const int pad = hole + 2 * annularIU;
548
549 m_lastLead = lead;
550 m_lastRange = range;
551 m_lastHoleIU = hole;
553
554 m_ResultReport->SetValue( pthResultReportText( m_holeSizeStandard, m_level, lead, annularIU, range, hole, pad ) );
555
556 m_holeSizeCtrl->SetValue( formatMm( hole ) );
557 m_padSizeCtrl->SetValue( formatMm( pad ) );
558
560
561 Layout();
562}
563
564
566{
567 constexpr int PREVIEW_SIZE = 200;
568
569 const int size = ToPhys( PREVIEW_SIZE );
570 const double scale = GetDPIScaleFactor();
571
572 wxBitmap bitmap = makePthSizePreviewBitmap(
574 m_cbShowMinLeadSize->GetValue(), m_cbShowMinHoleSize->GetValue(), m_cbShowMaxHoleSize->GetValue(), size );
575
576 bitmap.SetScaleFactor( scale );
577
578 m_bitmapPreview->SetBitmap( bitmap );
579}
580
581
582void PANEL_PTH_SIZE::OnPreviewSettingCb( wxCommandEvent& aEvent )
583{
585}
586
587
588void PANEL_PTH_SIZE::OnCopyReportText( wxCommandEvent& aEvent )
589{
590 if( wxTheClipboard->Open() )
591 {
592 wxTheClipboard->SetData( new wxTextDataObject( m_ResultReport->GetValue() ) );
593 wxTheClipboard->Close();
594 }
595}
const char * name
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:106
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:995
PANEL_PTH_SIZE_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
wxTextCtrl * m_sizeRoundingCtrl
wxCheckBox * m_cbShowMinHoleSize
wxStaticText * m_staticTextSizeYUnit
wxStaticText * m_staticTextSizeY
wxStaticText * m_staticTextSummaryTitle
wxCheckBox * m_cbShowMaxHoleSize
wxStaticBitmap * m_bitmapPreview
wxBitmapButton * m_bpCopyAll
wxStaticText * m_staticTextSizeX
wxCheckBox * m_cbShowMinLeadSize
void populateStandardChoice()
void OnPreviewSettingCb(wxCommandEvent &aEvent) override
void ThemeChanged() override
Update UI elements of the panel when the theme changes to ensure the images and fonts/colors are appr...
void SaveSettings(PCB_CALCULATOR_SETTINGS *aCfg) override
Save the settings from the panel.
void OnControlsChanged(wxCommandEvent &aEvent) override
PANEL_PTH_SIZE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
void LoadSettings(PCB_CALCULATOR_SETTINGS *aCfg) override
Load the settings into the panel.
PTH_HOLE_SIZE_RESULT m_lastRange
void OnCopyReportText(wxCommandEvent &aEvent) override
void OnValueChanged(wxCommandEvent &aEvent) override
PTH_LEAD_SHAPE m_leadShape
const PTH_HOLE_SIZE_STANDARD * m_holeSizeStandard
PTH_LEAD_DEF m_lastLead
A source of hole size rules for a plated through hole.
virtual const wxString & GetDisplayName() const =0
virtual wxString GetLevelName(int aLevel) const =0
#define _(s)
#define PREVIEW_SIZE
Definition lib_tree.cpp:787
static wxColor copperColor(220, 180, 30)
double DoubleFromString(const wxString &TextValue)
int ComputeRecommendedPthHoleSize(const PTH_HOLE_SIZE_RESULT &aRange, int aRoundingStep, PTH_HOLE_ROUNDING aRounding)
Choose a recommended hole within an allowable range.
const std::vector< const PTH_HOLE_SIZE_STANDARD * > & GetPthHoleSizeStandards()
PTH_HOLE_ROUNDING
tl::expected< wxImage, std::string > CreateAlphaImageFromTwoRenders(const wxImage &aOnWhite, const wxImage &aOnBlack)
Combine two opaque renders of the same content into a single image with an alpha channel.
const int scale
PTH_LEAD_SHAPE m_shape