KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_map_gerber_layers_to_pcb.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#include <gerber_file_image.h>
23#include <gerbview.h>
24#include <gerbview_frame.h>
25#include <gerbview_id.h>
26#include <gerbview_settings.h>
27#include <kiface_base.h>
28#include <layer_ids.h>
29#include <lset.h>
30#include <confirm.h>
31
33
34#include <wx/msgdlg.h>
35#include <gestfich.h>
36
37
43
44
46
47
50 wxEVT_COMMAND_BUTTON_CLICKED,
51 DIALOG_MAP_GERBER_LAYERS_TO_PCB::OnSelectLayer )
52END_EVENT_TABLE()
53
54
57{
58 m_Parent = parent;
59 initDialog();
60
61 // Resize the dialog
62 Layout();
63 GetSizer()->SetSizeHints( this );
64 Centre();
65}
66
67
69{
70 wxStaticText* label;
71 wxStaticText* text;
72 int item_ID;
73 wxString msg;
74 wxSize goodSize;
76
77 for( int ii = 0; ii < GERBER_DRAWLAYERS_COUNT; ++ii )
78 {
79 // Specify the default value for each member of these arrays.
80 m_buttonTable[ii] = -1;
82 }
83
84 // Ensure we have:
85 // At least 2 copper layers and less than max pcb copper layers count
86 // Even number of layers because a board *must* have even layers count
88
89 int idx = ( m_exportBoardCopperLayersCount / 2 ) - 1;
90 m_comboCopperLayersCount->SetSelection( idx );
91
93 GERBER_FILE_IMAGE_LIST* images = m_Parent->GetGerberLayout()->GetImagesList();
94
95 for( unsigned ii = 0; ii < GERBER_DRAWLAYERS_COUNT; ++ii )
96 {
97 if( images->GetGbrImage( ii ) == nullptr )
98 break;
99
102 }
103
104 if( m_gerberActiveLayersCount <= GERBER_DRAWLAYERS_COUNT / 2 ) // Only one list is enough
105 m_staticlineSep->Hide();
106
107 wxFlexGridSizer* flexColumnBoxSizer = m_flexLeftColumnBoxSizer;
108
109 for( int ii = 0; ii < m_gerberActiveLayersCount; ii++ )
110 {
111 // Each Gerber layer has an associated static text string (to
112 // identify that layer), a button (for invoking a child dialog
113 // box to change which Pcbnew layer that the Gerber layer is
114 // mapped to), and a second static text string (to depict which
115 // Pcbnew layer that the Gerber layer has been mapped to). Each
116 // of those items are placed into the left hand column, middle
117 // column, and right hand column (respectively) of the Flexgrid
118 // sizer, and the color of the second text string is set to
119 // fuchsia or blue (to respectively indicate whether the Gerber
120 // layer has been mapped to a Pcbnew layer or is not being
121 // exported at all). (Experimentation has shown that if a text
122 // control is used to depict which Pcbnew layer that each Gerber
123 // layer is mapped to (instead of a static text string), then
124 // those controls do not behave in a fully satisfactory manner
125 // in the Linux version. Even when the read-only attribute is
126 // specified for all of those controls, they can still be selected
127 // when the arrow keys or Tab key is used to step through all of
128 // the controls within the dialog box, and directives to set the
129 // foreground color of the text of each such control to blue (to
130 // indicate that the text is of a read-only nature) are disregarded.
131 // Specify a FlexGrid sizer with an appropriate number of rows
132 // and three columns. If nb_items < 16, then the number of rows
133 // is nb_items; otherwise, the number of rows is 16 (with two
134 // separate columns of controls being used if nb_items > 16).
135
136 if( ii == GERBER_DRAWLAYERS_COUNT / 2 )
137 flexColumnBoxSizer = m_flexRightColumnBoxSizer;
138
139 // Provide a text string to identify the Gerber layer
140 msg.Printf( _( "Layer %d:" ), m_buttonTable[ii] + 1 );
141
142 label = new wxStaticText( this, wxID_STATIC, msg );
143 flexColumnBoxSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
144
145 /* Add file name and extension without path. */
146 wxFileName fn( images->GetGbrImage( ii )->m_FileName );
147 label = new wxStaticText( this, wxID_STATIC, fn.GetFullName() );
148 flexColumnBoxSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
149
150 // Provide a button for this layer (which will invoke a child dialog box)
151 item_ID = ID_BUTTON_0 + ii;
152 wxButton * Button = new wxButton( this, item_ID, wxT( "..." ), wxDefaultPosition, wxDefaultSize,
153 wxBU_EXACTFIT );
154
155 flexColumnBoxSizer->Add( Button, 0, wxALIGN_CENTER_VERTICAL | wxALL );
156
157 // Provide another text string to specify which Pcbnew layer that this
158 // Gerber layer is mapped to. All layers initially default to
159 // "Do NotExport" (which corresponds to UNSELECTED_LAYER). Whenever
160 // a layer is set to "Do Not Export" it's displayed in blue. When a
161 // user selects a specific KiCad layer to map to, it's displayed in
162 // magenta which indicates it will be exported.
163 item_ID = ID_TEXT_0 + ii;
164
165 // All layers default to "Do Not Export" displayed in blue
166 msg = _( "Do not export" );
167 text = new wxStaticText( this, item_ID, msg );
168 text->SetForegroundColour( *wxBLUE );
169
170 // When the first of these text strings is being added, determine what
171 // size is necessary to to be able to display any possible string
172 // without it being truncated. Then specify that size as the minimum
173 // size for all of these text strings. (If this minimum size is not
174 // determined in this fashion, then it is possible for the display of
175 // one or more of these strings to be truncated after different Pcbnew
176 // layers are selected.)
177
178 if( ii == 0 )
179 {
180 goodSize = text->GetSize();
181
182 for( int jj = 0; jj < GERBER_DRAWLAYERS_COUNT; ++jj )
183 {
184 text->SetLabel( LSET::Name( PCB_LAYER_ID( jj ) ) );
185
186 if( goodSize.x < text->GetSize().x )
187 goodSize.x = text->GetSize().x;
188 }
189 text->SetLabel( msg ); // Reset label to default text
190 }
191
192 text->SetMinSize( goodSize );
193 flexColumnBoxSizer->Add( text, 1, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
194
195 m_layersList[ii] = text;
196 }
197
198 // If the user has never stored any Gerber to KiCad layer mapping,
199 // then disable the button to retrieve it
200 if( config->m_GerberToPcbLayerMapping.size() == 0 )
201 m_buttonRetrieve->Enable( false );
202
203 std::vector<int> gerber2KicadMapping;
204
205 // See how many of the loaded Gerbers can be mapped to KiCad layers automatically
206 int numMappedGerbers = findKnownGerbersLoaded( gerber2KicadMapping );
207
208 if( numMappedGerbers > 0 )
209 {
210 KICAD_MESSAGE_DIALOG dlg ( this,
211 wxString::Format( _( "Gerbers with known layers: %d" ), numMappedGerbers )
212 + wxT( "\n\n" ) + _( "Assign to matching PCB layers?" ),
213 _( "Automatic Layer Assignment" ), wxOK | wxCANCEL | wxOK_DEFAULT );
214
215 if( dlg.ShowModal() == wxID_OK )
216 {
217 int total_copper = 0;
218
219 for( int ii = 0; ii < m_gerberActiveLayersCount; ii++ )
220 {
221 int currLayer = gerber2KicadMapping[ii];
222
223 if( IsCopperLayer( currLayer ) )
224 total_copper++;
225
226 // Default to "Do Not Export" for unselected or undefined layer
227 if( currLayer == UNSELECTED_LAYER )
228 {
229 m_layersList[ii]->SetLabel( _( "Do not export" ) );
230 m_layersList[ii]->SetForegroundColour( *wxBLUE );
231
232 // Set the layer internally to unselected
234 }
235 else
236 {
237 m_layersList[ii]->SetLabel( LSET::Name( PCB_LAYER_ID( currLayer ) ) );
238 m_layersList[ii]->SetForegroundColour( wxColour( 255, 0, 128 ) );
239
240 // Set the layer internally to the matching KiCad layer
241 m_layersLookUpTable[ii] = currLayer;
242 }
243 }
244
245 // Reset the number of copper layers to the total found
246 m_exportBoardCopperLayersCount = std::max( total_copper, 2 );
247 m_comboCopperLayersCount->SetSelection( ( m_exportBoardCopperLayersCount / 2 ) - 1 );
248 }
249 }
250}
251
252
265
266
268{
269 int id = event.GetSelection();
270 m_exportBoardCopperLayersCount = ( id + 1 ) * 2;
271}
272
273
275{
276 for( int ii = 0; ii < m_gerberActiveLayersCount; ++ii )
277 {
279 m_layersList[ii]->SetLabel( _( "Do not export" ) );
280 m_layersList[ii]->SetForegroundColour( *wxBLUE );
281 m_buttonTable[ii] = ii;
282 }
283 // wxWidgets doesn't appear to invalidate / update the StaticText displays for color change
284 // so we do it manually
285 Refresh();
286 Update();
287}
288
289
291{
293 config->m_BoardLayersCount = m_exportBoardCopperLayersCount;
294
295 config->m_GerberToPcbLayerMapping.clear();
296
297 for( int ii = 0; ii < GERBER_DRAWLAYERS_COUNT; ++ii )
298 config->m_GerberToPcbLayerMapping.push_back( m_layersLookUpTable[ii] );
299
300 // Enable the "Get Stored Choice" button in case it was disabled in "initDialog()"
301 // due to no previously stored choices.
302 m_buttonRetrieve->Enable( true );
303}
304
305
307{
309
310 m_exportBoardCopperLayersCount = config->m_BoardLayersCount;
312
313 int idx = ( m_exportBoardCopperLayersCount / 2 ) - 1;
314 m_comboCopperLayersCount->SetSelection( idx );
315
316 for( int ii = 0; ii < GERBER_DRAWLAYERS_COUNT; ++ii )
317 {
318 // Ensure the layer mapping in config exists for this layer, and store it
319 if( (size_t)ii >= config->m_GerberToPcbLayerMapping.size() )
320 break;
321
322 m_layersLookUpTable[ii] = config->m_GerberToPcbLayerMapping[ ii ];
323 }
324
325 for( int ii = 0; ii < m_gerberActiveLayersCount; ii++ )
326 {
327 int layer = m_layersLookUpTable[ii];
328
329 if( layer == UNSELECTED_LAYER )
330 {
331 m_layersList[ii]->SetLabel( _( "Do not export" ) );
332 m_layersList[ii]->SetForegroundColour( *wxBLUE );
333 }
334 else if( layer == UNDEFINED_LAYER )
335 {
336 m_layersList[ii]->SetLabel( _( "Hole data" ) );
337 m_layersList[ii]->SetForegroundColour( wxColour( 255, 0, 128 ) );
338 }
339 else
340 {
341 m_layersList[ii]->SetLabel( LSET::Name( PCB_LAYER_ID( layer ) ) );
342 m_layersList[ii]->SetForegroundColour( wxColour( 255, 0, 128 ) );
343 }
344 }
345}
346
347
349{
350 int ii = event.GetId() - ID_BUTTON_0;
351
352 if( ii < 0 || ii >= GERBER_DRAWLAYERS_COUNT )
353 {
354 wxFAIL_MSG( wxT( "Bad layer id" ) );
355 return;
356 }
357
358 int jj = m_layersLookUpTable[ m_buttonTable[ii] ];
359
360 if( jj != UNSELECTED_LAYER && jj != UNDEFINED_LAYER && !IsValidLayer( jj ) )
361 jj = B_Cu; // (Defaults to "Copper" layer.)
362
363 // Get file name of Gerber loaded on this layer
364 wxFileName fn( m_Parent->GetGerberLayout()->GetImagesList()->GetGbrImage( ii )->m_FileName );
365
366 // Surround it with quotes to make it stand out on the dialog title bar
367 wxString layerName = wxT( "\"" ) + fn.GetFullName() + wxT( "\"" );
368
369 // Display dialog to let user select a layer for the Gerber
370 jj = m_Parent->SelectPCBLayer( jj, m_exportBoardCopperLayersCount, layerName );
371
372 if( jj != UNSELECTED_LAYER && jj != UNDEFINED_LAYER && !IsValidLayer( jj ) )
373 return;
374
375 if( jj != m_layersLookUpTable[m_buttonTable[ii]] )
376 {
378
379 if( jj == UNSELECTED_LAYER )
380 {
381 m_layersList[ii]->SetLabel( _( "Do not export" ) );
382
383 // Change the text color to blue (to highlight
384 // that this layer is *not* being exported)
385 m_layersList[ii]->SetForegroundColour( *wxBLUE );
386 }
387 else if( jj == UNDEFINED_LAYER )
388 {
389 m_layersList[ii]->SetLabel( _( "Hole data" ) );
390
391 // Change the text color to fuchsia (to highlight
392 // that this layer *is* being exported)
393 m_layersList[ii]->SetForegroundColour( wxColour( 255, 0, 128 ) );
394 }
395 else
396 {
397 m_layersList[ii]->SetLabel( LSET::Name( PCB_LAYER_ID( jj ) ) );
398
399 // Change the text color to fuchsia (to highlight
400 // that this layer *is* being exported)
401 m_layersList[ii]->SetForegroundColour( wxColour( 255, 0, 128 ) );
402 }
403 }
404 // wxWidgets doesn't appear to invalidate / update the StaticText displays for color change
405 // so we do it manually
406 Refresh();
407 Update();
408}
409
410
412{
413 if( !wxDialog::TransferDataFromWindow() )
414 return false;
415
416 // Board must have enough copper layers to handle selected internal layers.
418
419 int inner_layer_max = 0;
420
421 for( int ii = 0; ii < GERBER_DRAWLAYERS_COUNT; ++ii )
422 {
424 {
425 if( m_layersLookUpTable[ii ] > inner_layer_max )
426 inner_layer_max = m_layersLookUpTable[ii];
427 }
428 }
429
430 // inner_layer_max must be less than or equal to the number of internal copper layers
431 // internal copper layers = m_exportBoardCopperLayersCount-2
432 if( (int) CopperLayerToOrdinal( ToLAYER_ID( inner_layer_max ) ) > m_exportBoardCopperLayersCount-2 )
433 {
434 wxMessageBox( _( "Exported board does not have enough copper layers to handle selected "
435 "inner layers" ) );
436 return false;
437 }
438
439 return true;
440}
441
442
443int DIALOG_MAP_GERBER_LAYERS_TO_PCB::findKnownGerbersLoaded( std::vector<int>& aGerber2KicadMapping )
444{
445 int numKnownGerbers = 0;
446
447 // Check if any of the loaded Gerbers are X2 Gerbers and if they contain
448 // layer information in "File Functions". For info about X2 Gerbers see
449 // http://www.ucamco.com/files/downloads/file/81/the_gerber_file_format_specification.pdf
450 numKnownGerbers += findNumX2GerbersLoaded( aGerber2KicadMapping );
451
452 // Finally, check if any of the loaded Gerbers use the KiCad naming conventions
453 numKnownGerbers += findNumKiCadGerbersLoaded( aGerber2KicadMapping );
454
455 // The last option is to match using just the file extension
456 // This checkes for known Altium/Protel file extensions
457 numKnownGerbers += findNumAltiumGerbersLoaded( aGerber2KicadMapping );
458
459 return numKnownGerbers;
460}
461
462
463int DIALOG_MAP_GERBER_LAYERS_TO_PCB::findNumAltiumGerbersLoaded( std::vector<int>& aGerber2KicadMapping )
464{
465 // The next comment preserves initializer formatting below it
466 // clang-format off
467 // This map contains the known Altium file extensions for Gerbers that we care about,
468 // along with their corresponding KiCad layer
469 std::map<wxString, PCB_LAYER_ID> altiumExt{
470 { wxT( "GTL" ), F_Cu }, // Top copper
471 { wxT( "G1" ), In1_Cu }, // Inner layers 1 - 30
472 { wxT( "G2" ), In2_Cu },
473 { wxT( "G3" ), In3_Cu },
474 { wxT( "G4" ), In4_Cu },
475 { wxT( "G5" ), In5_Cu },
476 { wxT( "G6" ), In6_Cu },
477 { wxT( "G7" ), In7_Cu },
478 { wxT( "G8" ), In8_Cu },
479 { wxT( "G9" ), In9_Cu },
480 { wxT( "G10" ), In10_Cu },
481 { wxT( "G11" ), In11_Cu },
482 { wxT( "G12" ), In12_Cu },
483 { wxT( "G13" ), In13_Cu },
484 { wxT( "G14" ), In14_Cu },
485 { wxT( "G15" ), In15_Cu },
486 { wxT( "G16" ), In16_Cu },
487 { wxT( "G17" ), In17_Cu },
488 { wxT( "G18" ), In18_Cu },
489 { wxT( "G19" ), In19_Cu },
490 { wxT( "G20" ), In20_Cu },
491 { wxT( "G21" ), In21_Cu },
492 { wxT( "G22" ), In22_Cu },
493 { wxT( "G23" ), In23_Cu },
494 { wxT( "G24" ), In24_Cu },
495 { wxT( "G25" ), In25_Cu },
496 { wxT( "G26" ), In26_Cu },
497 { wxT( "G27" ), In27_Cu },
498 { wxT( "G28" ), In28_Cu },
499 { wxT( "G29" ), In29_Cu },
500 { wxT( "G30" ), In30_Cu },
501 { wxT( "GBL" ), B_Cu }, // Bottom copper
502 { wxT( "GTP" ), F_Paste }, // Paste top
503 { wxT( "GBP" ), B_Paste }, // Paste bottom
504 { wxT( "GTO" ), F_SilkS }, // Silkscreen top
505 { wxT( "GBO" ), B_SilkS }, // Silkscreen bottom
506 { wxT( "GTS" ), F_Mask }, // Soldermask top
507 { wxT( "GBS" ), B_Mask }, // Soldermask bottom
508 { wxT( "GM1" ), Eco1_User }, // Altium mechanical layer 1
509 { wxT( "GM2" ), Eco2_User }, // Altium mechanical layer 2
510 { wxT( "GKO" ), Edge_Cuts } // PCB Outline
511 };
512 // clang-format on
513
514 std::map<wxString, PCB_LAYER_ID>::iterator it;
515
516 int numAltiumMatches = 0; // Assume we won't find Altium Gerbers
517
518 GERBER_FILE_IMAGE_LIST* images = m_Parent->GetGerberLayout()->GetImagesList();
519
520 // If the passed vector isn't empty but is too small to hold the loaded
521 // Gerbers, then bail because something isn't right.
522
523 if( ( aGerber2KicadMapping.size() != 0 )
524 && ( aGerber2KicadMapping.size() != (size_t) m_gerberActiveLayersCount ) )
525 return numAltiumMatches;
526
527 // If the passed vector is empty, set it to the same number of elements as there
528 // are loaded Gerbers, and set each to "UNSELECTED_LAYER"
529
530 if( aGerber2KicadMapping.size() == 0 )
531 aGerber2KicadMapping.assign( m_gerberActiveLayersCount, UNSELECTED_LAYER );
532
533 // Loop through all loaded Gerbers looking for any with Altium specific extensions
534 for( int ii = 0; ii < m_gerberActiveLayersCount; ii++ )
535 {
536 if( images->GetGbrImage( ii ) )
537 {
538 // Get file name of Gerber loaded on this layer.
539 wxFileName fn( images->GetGbrImage( ii )->m_FileName );
540
541 // Get uppercase version of file extension
542 wxString FileExt = fn.GetExt();
543 FileExt.MakeUpper();
544
545 // Check for matching Altium Gerber file extension we'll handle
546 it = altiumExt.find( FileExt );
547
548 if( it != altiumExt.end() )
549 {
550 // We got a match, so store the KiCad layer number. We verify it's set to
551 // "UNSELECTED_LAYER" in case the passed vector already had entries
552 // matched to other known Gerber files. This will preserve them.
553
554 if( aGerber2KicadMapping[ii] == UNSELECTED_LAYER )
555 {
556 aGerber2KicadMapping[ii] = it->second;
557 numAltiumMatches++;
558 }
559 }
560 }
561 }
562
563 // Return number of Altium Gerbers we found. Each index in the passed vector corresponds to
564 // a loaded Gerber layer, and the entry will contain the index to the matching
565 // KiCad layer for Altium Gerbers, or "UNSELECTED_LAYER" for the rest.
566 return numAltiumMatches;
567}
568
569
570int DIALOG_MAP_GERBER_LAYERS_TO_PCB::findNumKiCadGerbersLoaded( std::vector<int>& aGerber2KicadMapping )
571{
572 // The next comment preserves initializer formatting below it
573 // clang-format off
574 // This map contains the known KiCad suffixes used for Gerbers that we care about,
575 // along with their corresponding KiCad layer
576 std::map<wxString, PCB_LAYER_ID> kicadLayers
577 {
578 { "-F_Cu", F_Cu },
579 { "-In1_Cu", In1_Cu },
580 { "-In2_Cu", In2_Cu },
581 { "-In3_Cu", In3_Cu },
582 { "-In4_Cu", In4_Cu },
583 { "-In5_Cu", In5_Cu },
584 { "-In6_Cu", In6_Cu },
585 { "-In7_Cu", In7_Cu },
586 { "-In8_Cu", In8_Cu },
587 { "-In9_Cu", In9_Cu },
588 { "-In10_Cu", In10_Cu },
589 { "-In11_Cu", In11_Cu },
590 { "-In12_Cu", In12_Cu },
591 { "-In13_Cu", In13_Cu },
592 { "-In14_Cu", In14_Cu },
593 { "-In15_Cu", In15_Cu },
594 { "-In16_Cu", In16_Cu },
595 { "-In17_Cu", In17_Cu },
596 { "-In18_Cu", In18_Cu },
597 { "-In19_Cu", In19_Cu },
598 { "-In20_Cu", In20_Cu },
599 { "-In21_Cu", In21_Cu },
600 { "-In22_Cu", In22_Cu },
601 { "-In23_Cu", In23_Cu },
602 { "-In24_Cu", In24_Cu },
603 { "-In25_Cu", In25_Cu },
604 { "-In26_Cu", In26_Cu },
605 { "-In27_Cu", In27_Cu },
606 { "-In28_Cu", In28_Cu },
607 { "-In29_Cu", In29_Cu },
608 { "-In30_Cu", In30_Cu },
609 { "-B_Cu", B_Cu },
610 { "-B_Adhes", B_Adhes },
611 { "-F_Adhes", F_Adhes },
612 { "-B_Adhesive", B_Adhes },
613 { "-F_Adhesive", F_Adhes },
614 { "-B_Paste", B_Paste },
615 { "-F_Paste", F_Paste },
616 { "-B_SilkS", B_SilkS },
617 { "-F_SilkS", F_SilkS },
618 { "-B_Silkscreen",B_SilkS },
619 { "-F_Silkscreen",F_SilkS },
620 { "-B_Mask", B_Mask },
621 { "-F_Mask", F_Mask },
622 { "-F_Fab", F_Fab },
623 { "-B_Fab", B_Fab },
624 { "-Dwgs_User", Dwgs_User },
625 { "-Cmts_User", Cmts_User },
626 { "-Eco1_User", Eco1_User },
627 { "-Eco2_User", Eco2_User },
628 { "-Edge_Cuts", Edge_Cuts },
629 { "-Margin", Margin },
630 { "-F_Courtyard", F_CrtYd },
631 { "-B_Courtyard", B_CrtYd },
632 };
633 // clang-format on
634
635 std::map<wxString, PCB_LAYER_ID>::iterator it;
636
637 int numKicadMatches = 0; // Assume we won't find KiCad Gerbers
638
639 GERBER_FILE_IMAGE_LIST* images = m_Parent->GetGerberLayout()->GetImagesList();
640
641 // If the passed vector isn't empty but is too small to hold the loaded
642 // Gerbers, then bail because something isn't right.
643
644 if( ( aGerber2KicadMapping.size() != 0 )
645 && ( aGerber2KicadMapping.size() < (size_t) m_gerberActiveLayersCount ) )
646 return numKicadMatches;
647
648 // If the passed vector is empty, set it to the same number of elements as there
649 // are loaded Gerbers, and set each to "UNSELECTED_LAYER"
650
651 if( aGerber2KicadMapping.size() == 0 )
652 aGerber2KicadMapping.assign( m_gerberActiveLayersCount, UNSELECTED_LAYER );
653
654 // Loop through all loaded Gerbers looking for any with KiCad specific layer names
655 for( int ii = 0; ii < m_gerberActiveLayersCount; ii++ )
656 {
657 if( images->GetGbrImage( ii ) )
658 {
659 // Get file name of Gerber loaded on this layer.
660 wxFileName fn( images->GetGbrImage( ii )->m_FileName );
661
662 wxString layerName = fn.GetName();
663
664 // To create Gerber file names, KiCad appends a suffix consisting of a "-" and the
665 // name of the layer to the project name. We need to isolate the suffix if present
666 // and see if it's a known KiCad layer name. Start by looking for the last "-" in
667 // the file name.
668 int dashPos = layerName.Find( '-', true );
669
670 // If one was found, isolate the suffix from the "-" to the end of the file name
671 wxString suffix;
672
673 if( dashPos != wxNOT_FOUND )
674 suffix = layerName.Right( layerName.length() - dashPos );
675
676 // Check if the string we've isolated matches any known KiCad layer names
677 it = kicadLayers.find( suffix );
678
679 if( it != kicadLayers.end() )
680 {
681 // We got a match, so store the KiCad layer number. We verify it's set to
682 // "UNSELECTED_LAYER" in case the passed vector already had entries
683 // matched to other known Gerber files. This will preserve them.
684
685 if( aGerber2KicadMapping[ii] == UNSELECTED_LAYER )
686 {
687 aGerber2KicadMapping[ii] = it->second;
688 numKicadMatches++;
689 }
690 }
691 }
692 }
693
694 // Return number of KiCad Gerbers we found. Each index in the passed vector corresponds to
695 // a loaded Gerber layer, and the entry will contain the index to the matching
696 // KiCad layer for KiCad Gerbers, or "UNSELECTED_LAYER" for the rest.
697 return numKicadMatches;
698}
699
700
701int DIALOG_MAP_GERBER_LAYERS_TO_PCB::findNumX2GerbersLoaded( std::vector<int>& aGerber2KicadMapping )
702{
703 // The next comment preserves initializer formatting below it
704 // clang-format off
705 // This map contains the known KiCad X2 "File Function" values used for Gerbers that we
706 // care about, along with their corresponding KiCad layer
707 std::map<wxString, PCB_LAYER_ID> kicadLayers
708 {
709 { wxT( "Top" ), F_Cu },
710 { wxT( "L2" ), In1_Cu },
711 { wxT( "L3" ), In2_Cu },
712 { wxT( "L4" ), In3_Cu },
713 { wxT( "L5" ), In4_Cu },
714 { wxT( "L6" ), In5_Cu },
715 { wxT( "L7" ), In6_Cu },
716 { wxT( "L8" ), In7_Cu },
717 { wxT( "L9" ), In8_Cu },
718 { wxT( "L10" ), In9_Cu },
719 { wxT( "L11" ), In10_Cu },
720 { wxT( "L12" ), In11_Cu },
721 { wxT( "L13" ), In12_Cu },
722 { wxT( "L14" ), In13_Cu },
723 { wxT( "L15" ), In14_Cu },
724 { wxT( "L16" ), In15_Cu },
725 { wxT( "L17" ), In16_Cu },
726 { wxT( "L18" ), In17_Cu },
727 { wxT( "L19" ), In18_Cu },
728 { wxT( "L20" ), In19_Cu },
729 { wxT( "L21" ), In20_Cu },
730 { wxT( "L22" ), In21_Cu },
731 { wxT( "L23" ), In22_Cu },
732 { wxT( "L24" ), In23_Cu },
733 { wxT( "L25" ), In24_Cu },
734 { wxT( "L26" ), In25_Cu },
735 { wxT( "L27" ), In26_Cu },
736 { wxT( "L28" ), In27_Cu },
737 { wxT( "L29" ), In28_Cu },
738 { wxT( "L30" ), In29_Cu },
739 { wxT( "Bot" ), B_Cu },
740 { wxT( "BotGlue" ), B_Adhes },
741 { wxT( "TopGlue" ), F_Adhes },
742 { wxT( "BotPaste" ), B_Paste },
743 { wxT( "TopPaste" ), F_Paste },
744 { wxT( "BotLegend" ), B_SilkS },
745 { wxT( "TopLegend" ), F_SilkS },
746 { wxT( "BotSoldermask" ), B_Mask },
747 { wxT( "TopSoldermask" ), F_Mask },
748 { wxT( "FabricationDrawing" ), Dwgs_User },
749 { wxT( "OtherDrawing" ), Cmts_User },
750 { wxT( "TopAssemblyDrawing" ), F_Fab },
751 { wxT( "BotAssemblyDrawing" ), B_Fab },
752 { wxT( "PProfile" ), Edge_Cuts }, // Plated PCB outline
753 { wxT( "NPProfile" ), Edge_Cuts } // Non-plated PCB outline
754 };
755 // clang-format on
756
757 std::map<wxString, PCB_LAYER_ID>::iterator it;
758
759 int numKicadMatches = 0; // Assume we won't find KiCad Gerbers
760
761 wxString mapThis;
762
763 GERBER_FILE_IMAGE_LIST* images = m_Parent->GetGerberLayout()->GetImagesList();
764
765 // If the passed vector isn't empty but is too small to hold the loaded
766 // Gerbers, then bail because something isn't right.
767
768 if( ( aGerber2KicadMapping.size() != 0 )
769 && ( aGerber2KicadMapping.size() < (size_t) m_gerberActiveLayersCount ) )
770 {
771 return numKicadMatches;
772 }
773
774 // If the passed vector is empty, set it to the same number of elements as there
775 // are loaded Gerbers, and set each to "UNSELECTED_LAYER"
776
777 if( aGerber2KicadMapping.size() == 0 )
778 aGerber2KicadMapping.assign( m_gerberActiveLayersCount, UNSELECTED_LAYER );
779
780 // Loop through all loaded Gerbers looking for any with X2 File Functions
781 for( int ii = 0; ii < m_gerberActiveLayersCount; ii++ )
782 {
783 if( images->GetGbrImage( ii ) )
784 {
786
787 mapThis = "";
788
789 if( images->GetGbrImage( ii )->m_IsX2_file )
790 {
791 wxCHECK( x2, numKicadMatches );
792
793 if( x2->IsCopper() )
794 {
795 // This is a copper layer, so figure out which one
796 mapThis = x2->GetBrdLayerSide(); // Returns "Top", "Bot" or "Inr"
797
798 // To map inner layers properly, we need the layer number
799 if( mapThis.IsSameAs( wxT( "Inr" ), false ) )
800 mapThis = x2->GetBrdLayerId(); // Returns "L2", "L5", etc
801 }
802 else
803 {
804 // Create strings like "TopSolderMask" or "BotPaste" for non-copper layers
805 mapThis << x2->GetBrdLayerId() << x2->GetFileType();
806 }
807
808 // Check if the string we've isolated matches any known X2 layer names
809 it = kicadLayers.find( mapThis );
810
811 if( it != kicadLayers.end() )
812 {
813 // We got a match, so store the KiCad layer number. We verify it's set to
814 // "UNSELECTED_LAYER" in case the passed vector already had entries
815 // matched to other known Gerber files. This will preserve them.
816
817 if( aGerber2KicadMapping[ii] == UNSELECTED_LAYER )
818 {
819 aGerber2KicadMapping[ii] = it->second;
820 numKicadMatches++;
821 }
822 }
823 }
824 }
825 }
826
827 return numKicadMatches;
828}
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
Class DIALOG_MAP_GERBER_LAYERS_TO_PCB_BASE.
Show the Gerber files loaded and allow the user to choose between Gerber layers and pcb layers.
void OnStoreSetup(wxCommandEvent &event) override
int findNumKiCadGerbersLoaded(std::vector< int > &aGerber2KicadMapping)
Find number of loaded Gerbers using KiCad naming convention.
wxStaticText * m_layersList[int(GERBER_DRAWLAYERS_COUNT)+1]
void OnResetClick(wxCommandEvent &event) override
int m_buttonTable[int(GERBER_DRAWLAYERS_COUNT)+1]
int findNumX2GerbersLoaded(std::vector< int > &aGerber2KicadMapping)
Find number of loaded Gerbers using X2 File Functions to define layers.
void OnBrdLayersCountSelection(wxCommandEvent &event) override
int findKnownGerbersLoaded(std::vector< int > &aGerber2KicadMapping)
Find number of loaded Gerbers where the matching KiCad layer can be identified.
void OnGetSetup(wxCommandEvent &event) override
int findNumAltiumGerbersLoaded(std::vector< int > &aGerber2KicadMapping)
Find number of loaded Gerbers using Altium file extensions.
GERBER_FILE_IMAGE_LIST is a helper class to handle a list of GERBER_FILE_IMAGE files which are loaded...
GERBER_FILE_IMAGE * GetGbrImage(int aIdx)
X2_ATTRIBUTE_FILEFUNCTION * m_FileFunction
file function parameters, found in a TF command or a G04
wxString m_FileName
Full File Name for this layer.
bool m_IsX2_file
True if a X2 gerber attribute was found in file.
APP_SETTINGS_BASE * KifaceSettings() const
Definition kiface_base.h:91
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition lset.cpp:184
X2_ATTRIBUTE_FILEFUNCTION ( from TF.FileFunction in Gerber file) Example file function: TF....
bool IsCopper()
return true if the filefunction type is "Copper"
const wxString & GetBrdLayerSide()
the brd layer Pos: Top, Bot, Inr same as GetBrdLayerId() for non copper type
const wxString & GetFileType()
the type of layer (Copper, Soldermask ... )
const wxString & GetBrdLayerId()
the brd layer identifier: Ln, only for Copper type or Top, Bot for other types
This file is part of the common library.
#define KICAD_MESSAGE_DIALOG
Definition confirm.h:48
#define _(s)
@ ID_GERBER_END_LIST
Definition gerbview_id.h:64
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:675
size_t CopperLayerToOrdinal(PCB_LAYER_ID aLayer)
Converts KiCad copper layer enum to an ordinal between the front and back layers.
Definition layer_ids.h:911
bool IsInnerCopperLayer(int aLayerId)
Test whether a layer is an inner (In1_Cu to In30_Cu) copper layer.
Definition layer_ids.h:697
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ In22_Cu
Definition layer_ids.h:83
@ In11_Cu
Definition layer_ids.h:72
@ In29_Cu
Definition layer_ids.h:90
@ In30_Cu
Definition layer_ids.h:91
@ F_CrtYd
Definition layer_ids.h:112
@ In17_Cu
Definition layer_ids.h:78
@ B_Adhes
Definition layer_ids.h:99
@ Edge_Cuts
Definition layer_ids.h:108
@ Dwgs_User
Definition layer_ids.h:103
@ F_Paste
Definition layer_ids.h:100
@ In9_Cu
Definition layer_ids.h:70
@ Cmts_User
Definition layer_ids.h:104
@ In19_Cu
Definition layer_ids.h:80
@ In7_Cu
Definition layer_ids.h:68
@ In28_Cu
Definition layer_ids.h:89
@ In26_Cu
Definition layer_ids.h:87
@ F_Adhes
Definition layer_ids.h:98
@ B_Mask
Definition layer_ids.h:94
@ B_Cu
Definition layer_ids.h:61
@ Eco1_User
Definition layer_ids.h:105
@ F_Mask
Definition layer_ids.h:93
@ In21_Cu
Definition layer_ids.h:82
@ In23_Cu
Definition layer_ids.h:84
@ B_Paste
Definition layer_ids.h:101
@ In15_Cu
Definition layer_ids.h:76
@ In2_Cu
Definition layer_ids.h:63
@ UNSELECTED_LAYER
Definition layer_ids.h:58
@ F_Fab
Definition layer_ids.h:115
@ In10_Cu
Definition layer_ids.h:71
@ Margin
Definition layer_ids.h:109
@ F_SilkS
Definition layer_ids.h:96
@ In4_Cu
Definition layer_ids.h:65
@ B_CrtYd
Definition layer_ids.h:111
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ Eco2_User
Definition layer_ids.h:106
@ In16_Cu
Definition layer_ids.h:77
@ In24_Cu
Definition layer_ids.h:85
@ In1_Cu
Definition layer_ids.h:62
@ B_SilkS
Definition layer_ids.h:97
@ In13_Cu
Definition layer_ids.h:74
@ In8_Cu
Definition layer_ids.h:69
@ In14_Cu
Definition layer_ids.h:75
@ In12_Cu
Definition layer_ids.h:73
@ In27_Cu
Definition layer_ids.h:88
@ In6_Cu
Definition layer_ids.h:67
@ In5_Cu
Definition layer_ids.h:66
@ In3_Cu
Definition layer_ids.h:64
@ In20_Cu
Definition layer_ids.h:81
@ F_Cu
Definition layer_ids.h:60
@ In18_Cu
Definition layer_ids.h:79
@ In25_Cu
Definition layer_ids.h:86
@ B_Fab
Definition layer_ids.h:114
bool IsValidLayer(int aLayerId)
Test whether a given integer is a valid layer index, i.e.
Definition layer_ids.h:653
#define GERBER_DRAWLAYERS_COUNT
Number of draw layers in Gerbview.
Definition layer_ids.h:517
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition lset.cpp:750
EVT_COMMAND_RANGE(ID_MATRIX_0, ID_MATRIX_0+(PINMAP_TYPE_COUNT *PINMAP_TYPE_COUNT) - 1, wxEVT_COMMAND_BUTTON_CLICKED, PANEL_SETUP_PINMAP::changeErrorLevel) PANEL_SETUP_PINMAP