KiCad PCB EDA Suite
Loading...
Searching...
No Matches
odb_entity.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 * Author: SYSUEric <[email protected]>.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21
22#include <base_units.h>
23#include <optional>
24#include <board.h>
26#include <build_version.h>
27#include <callback_gal.h>
31#include <font/font.h>
32#include <footprint.h>
33#include <hash_eda.h>
34#include <pad.h>
35#include <padstack.h>
36#include <pcb_dimension.h>
37#include <pcb_shape.h>
38#include <pcb_text.h>
39#include <pcb_textbox.h>
40#include <pcb_track.h>
41#include <pcbnew_settings.h>
43#include <pgm_base.h>
44#include <progress_reporter.h>
46#include <wx_fstream_progress.h>
47
52
53#include <wx/log.h>
54#include <wx/numformatter.h>
55#include <wx/mstream.h>
56
57#include "odb_attribute.h"
58#include "odb_entity.h"
59#include "odb_defines.h"
60#include "odb_feature.h"
61#include "odb_util.h"
62#include "pcb_io_odbpp.h"
63
64
66{
67 try
68 {
70 return true;
71 }
72 catch( const std::exception& e )
73 {
74 std::cerr << e.what() << std::endl;
75 return false;
76 }
77}
78
79
81{
82 m_info = { { wxS( ODB_JOB_NAME ), wxS( "job" ) },
84 { wxS( "ODB_VERSION_MAJOR" ), wxS( "8" ) },
85 { wxS( "ODB_VERSION_MINOR" ), wxS( "1" ) },
86 { wxS( "ODB_SOURCE" ), wxS( "KiCad EDA" ) },
87 { wxS( "CREATION_DATE" ), wxDateTime::Now().Format( "%Y%m%d.%H%M%S" ) },
88 { wxS( "SAVE_DATE" ), wxDateTime::Now().Format( "%Y%m%d.%H%M%S" ) },
89 { wxS( "SAVE_APP" ), wxString::Format( wxS( "KiCad EDA %s" ), GetBuildVersion() ) } };
90}
91
92
94{
95 auto fileproxy = writer.CreateFileProxy( "info" );
96
97 ODB_TEXT_WRITER twriter( fileproxy.GetStream() );
98
99 for( auto& info : m_info )
100 {
101 twriter.WriteEquationLine( info.first, info.second );
102 }
103}
104
105
106void ODB_MATRIX_ENTITY::AddStep( const wxString& aStepName )
107{
108 m_matrixSteps.emplace( aStepName.Upper(), m_col++ );
109}
110
111
113{
114 AddStep( "PCB" );
115
117}
118
119
121{
122 BOARD_DESIGN_SETTINGS& dsnSettings = m_board->GetDesignSettings();
123 BOARD_STACKUP& stackup = dsnSettings.GetStackupDescriptor();
124 stackup.SynchronizeWithBoard( &dsnSettings );
125
126 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.GetList();
127 std::set<PCB_LAYER_ID> added_layers;
128
130
131 for( int i = 0; i < stackup.GetCount(); i++ )
132 {
133 BOARD_STACKUP_ITEM* stackup_item = layers.at( i );
134
135 for( int sublayer_id = 0; sublayer_id < stackup_item->GetSublayersCount(); sublayer_id++ )
136 {
137 wxString ly_name = stackup_item->GetLayerName();
138
139 if( ly_name.IsEmpty() )
140 {
141 if( IsValidLayer( stackup_item->GetBrdLayerId() ) )
142 ly_name = m_board->GetLayerName( stackup_item->GetBrdLayerId() );
143
144 if( ly_name.IsEmpty() && stackup_item->GetType() == BS_ITEM_TYPE_DIELECTRIC )
145 ly_name = wxString::Format( "DIELECTRIC_%d", stackup_item->GetDielectricLayerId() );
146 }
147
148 MATRIX_LAYER matrix( m_row++, ly_name );
149
150 if( stackup_item->GetType() == BS_ITEM_TYPE_DIELECTRIC )
151 {
152 if( stackup_item->GetTypeName() == KEY_CORE )
153 matrix.m_diType.emplace( ODB_DIELECTRIC_TYPE::CORE );
154 else
155 matrix.m_diType.emplace( ODB_DIELECTRIC_TYPE::PREPREG );
156
160 m_matrixLayers.push_back( matrix );
161 m_plugin->GetLayerNameList().emplace_back(
162 std::make_pair( PCB_LAYER_ID::UNDEFINED_LAYER, matrix.m_layerName ) );
163
164 continue;
165 }
166 else
167 {
168 added_layers.insert( stackup_item->GetBrdLayerId() );
169 AddMatrixLayerField( matrix, stackup_item->GetBrdLayerId() );
170 }
171 }
172 }
173
174 for( PCB_LAYER_ID layer : m_board->GetEnabledLayers().Seq() )
175 {
176 if( added_layers.find( layer ) != added_layers.end() )
177 continue;
178
179 MATRIX_LAYER matrix( m_row++, m_board->GetLayerName( layer ) );
180 added_layers.insert( layer );
181 AddMatrixLayerField( matrix, layer );
182 }
183
185
187
189
191}
192
193
195{
198 switch( aLayer )
199 {
200 case F_Paste:
201 case B_Paste:
203 break;
204
205 case F_SilkS:
206 case B_SilkS:
208 break;
209
210 case F_Mask:
211 case B_Mask:
213 break;
214
215 case B_CrtYd:
216 case F_CrtYd:
217 case Edge_Cuts:
218 case B_Fab:
219 case F_Fab:
220 case F_Adhes:
221 case B_Adhes:
222 case Dwgs_User:
223 case Cmts_User:
224 case Eco1_User:
225 case Eco2_User:
226 case Margin:
227 case User_1:
228 case User_2:
229 case User_3:
230 case User_4:
231 case User_5:
232 case User_6:
233 case User_7:
234 case User_8:
235 case User_9:
236 case User_10:
237 case User_11:
238 case User_12:
239 case User_13:
240 case User_14:
241 case User_15:
242 case User_16:
243 case User_17:
244 case User_18:
245 case User_19:
246 case User_20:
247 case User_21:
248 case User_22:
249 case User_23:
250 case User_24:
251 case User_25:
252 case User_26:
253 case User_27:
254 case User_28:
255 case User_29:
256 case User_30:
257 case User_31:
258 case User_32:
259 case User_33:
260 case User_34:
261 case User_35:
262 case User_36:
263 case User_37:
264 case User_38:
265 case User_39:
266 case User_40:
267 case User_41:
268 case User_42:
269 case User_43:
270 case User_44:
271 case User_45:
273 aMLayer.m_type = ODB_TYPE::DOCUMENT;
274 break;
275
276 default:
277 if( IsCopperLayer( aLayer ) )
278 {
279 aMLayer.m_type = ODB_TYPE::SIGNAL;
280 }
281 else
282 {
283 // Do not handle other layers :
284 aMLayer.m_type = ODB_TYPE::UNDEFINED;
285 m_row--;
286 }
287
288 break;
289 }
290
291 if( aMLayer.m_type != ODB_TYPE::UNDEFINED )
292 {
293 m_matrixLayers.push_back( aMLayer );
294 m_plugin->GetLayerNameList().emplace_back( std::make_pair( aLayer, aMLayer.m_layerName ) );
295 }
296}
297
298
300{
301 std::map<ODB_DRILL_SPAN, std::vector<BOARD_ITEM*>>& drill_layers = m_plugin->GetDrillLayerItemsMap();
302
303 std::map<std::pair<PCB_LAYER_ID, PCB_LAYER_ID>, std::vector<BOARD_ITEM*>>& slot_holes =
304 m_plugin->GetSlotHolesMap();
305
306 drill_layers.clear();
307 slot_holes.clear();
308
309 std::map<ODB_DRILL_SPAN, wxString>& span_names = m_plugin->GetDrillSpanNameMap();
310 span_names.clear();
311
312 bool has_pth_layer = false;
313 bool has_npth_layer = false;
314
315 for( BOARD_ITEM* item : m_board->Tracks() )
316 {
317 if( item->Type() == PCB_VIA_T )
318 {
319 PCB_VIA* via = static_cast<PCB_VIA*>( item );
320 has_pth_layer = true;
321
322 ODB_DRILL_SPAN platedSpan( via->TopLayer(), via->BottomLayer(), false, false );
323 drill_layers[platedSpan].push_back( via );
324
325 std::set<ODB_DRILL_SPAN> addedBackdrillSpans;
326
327 auto addBackdrillSpan = [&]( const PADSTACK::DRILL_PROPS& aDrill )
328 {
329 if( aDrill.start != UNDEFINED_LAYER && aDrill.end != UNDEFINED_LAYER
330 && ( aDrill.size.x > 0 || aDrill.size.y > 0 ) )
331 {
332 ODB_DRILL_SPAN backSpan( aDrill.start, aDrill.end, true, true );
333
334 if( addedBackdrillSpans.insert( backSpan ).second )
335 drill_layers[backSpan].push_back( via );
336 }
337 };
338
339 addBackdrillSpan( via->Padstack().SecondaryDrill() );
340 addBackdrillSpan( via->Padstack().TertiaryDrill() );
341 }
342 }
343
344 for( FOOTPRINT* fp : m_board->Footprints() )
345 {
346 if( fp->IsFlipped() )
347 {
348 m_hasBotComp = true;
349 }
350
351 for( PAD* pad : fp->Pads() )
352 {
353 if( pad->GetAttribute() == PAD_ATTRIB::PTH )
354 has_pth_layer = true;
355 if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
356 has_npth_layer = true;
357
358 if( pad->HasHole() && pad->GetDrillSizeX() != pad->GetDrillSizeY() )
359 slot_holes[std::make_pair( F_Cu, B_Cu )].push_back( pad );
360 else if( pad->HasHole() )
361 {
362 ODB_DRILL_SPAN padSpan( F_Cu, B_Cu, false, pad->GetAttribute() == PAD_ATTRIB::NPTH );
363 drill_layers[padSpan].push_back( pad );
364 }
365 }
366 }
367
368 if( has_npth_layer )
369 {
370 ODB_DRILL_SPAN npthSpan( F_Cu, B_Cu, false, true );
371 drill_layers[npthSpan];
372 }
373
374 if( has_pth_layer )
375 {
376 ODB_DRILL_SPAN platedSpan( F_Cu, B_Cu, false, false );
377 drill_layers[platedSpan];
378 }
379
380 int backdrillIndex = 1;
381
382 auto assignName =
383 [&]( const ODB_DRILL_SPAN& aSpan )
384 {
385 auto it = span_names.find( aSpan );
386
387 if( it != span_names.end() )
388 return it->second;
389
390 wxString name;
391
392 if( aSpan.m_IsBackdrill )
393 {
394 name.Printf( wxT( "drill%d" ), backdrillIndex++ );
395 }
396 else
397 {
398 wxString platedLabel = aSpan.m_IsNonPlated ? wxT( "non-plated" ) : wxT( "plated" );
399 name.Printf( wxT( "drill_%s_%s-%s" ), platedLabel,
400 m_board->GetLayerName( aSpan.TopLayer() ),
401 m_board->GetLayerName( aSpan.BottomLayer() ) );
402 }
403
404 wxString legalName = ODB::GenLegalEntityName( name );
405 span_names[aSpan] = legalName;
406
407 return legalName;
408 };
409
410 auto InitDrillMatrix =
411 [&]( const ODB_DRILL_SPAN& aSpan )
412 {
413 wxString dLayerName = assignName( aSpan );
414 MATRIX_LAYER matrix( m_row++, dLayerName );
415
416 matrix.m_type = ODB_TYPE::DRILL;
419 matrix.m_span.emplace( std::make_pair(
420 ODB::GenLegalEntityName( m_board->GetLayerName( aSpan.m_StartLayer ) ),
421 ODB::GenLegalEntityName( m_board->GetLayerName( aSpan.m_EndLayer ) ) ) );
422
423 if( aSpan.m_IsBackdrill )
424 matrix.m_addType.emplace( ODB_SUBTYPE::BACKDRILL );
425
426 m_matrixLayers.push_back( matrix );
427 m_plugin->GetLayerNameList().emplace_back(
428 std::make_pair( PCB_LAYER_ID::UNDEFINED_LAYER, matrix.m_layerName ) );
429 };
430
431 for( const auto& entry : drill_layers )
432 InitDrillMatrix( entry.first );
433}
434
435
437{
438 MATRIX_LAYER matrix( m_row++, "COMP_+_TOP" );
441
442 if( aCompSide == F_Cu )
443 {
444 m_matrixLayers.push_back( matrix );
445 m_plugin->GetLayerNameList().emplace_back(
446 std::make_pair( PCB_LAYER_ID::UNDEFINED_LAYER, matrix.m_layerName ) );
447 }
448
449 if( aCompSide == B_Cu && m_hasBotComp )
450 {
451 matrix.m_layerName = ODB::GenLegalEntityName( "COMP_+_BOT" );
452 m_matrixLayers.push_back( matrix );
453 m_plugin->GetLayerNameList().emplace_back(
454 std::make_pair( PCB_LAYER_ID::UNDEFINED_LAYER, matrix.m_layerName ) );
455 }
456}
457
459{
460 auto& auxilliary_layers = m_plugin->GetAuxilliaryLayerItemsMap();
461
462 for( BOARD_ITEM* item : m_board->Tracks() )
463 {
464 if( item->Type() == PCB_VIA_T )
465 {
466 PCB_VIA* via = static_cast<PCB_VIA*>( item );
467
468 if( via->Padstack().IsFilled().value_or( false ) )
469 {
470 auxilliary_layers[std::make_tuple( ODB_AUX_LAYER_TYPE::FILLING, via->TopLayer(),
471 via->BottomLayer() )]
472 .push_back( via );
473 }
474
475 if( via->Padstack().IsCapped().value_or( false ) )
476 {
477 auxilliary_layers[std::make_tuple( ODB_AUX_LAYER_TYPE::CAPPING, via->TopLayer(),
478 via->BottomLayer() )]
479 .push_back( via );
480 }
481
482 for( PCB_LAYER_ID layer : { via->TopLayer(), via->BottomLayer() } )
483 {
484 if( via->Padstack().IsPlugged( layer ).value_or( false ) )
485 {
486 auxilliary_layers[std::make_tuple( ODB_AUX_LAYER_TYPE::PLUGGING, layer,
488 .push_back( via );
489 }
490
491 if( via->Padstack().IsCovered( layer ).value_or( false ) )
492 {
493 auxilliary_layers[std::make_tuple( ODB_AUX_LAYER_TYPE::COVERING, layer,
495 .push_back( via );
496 }
497
498 if( via->Padstack().IsTented( layer ).value_or( false ) )
499 {
500 auxilliary_layers[std::make_tuple( ODB_AUX_LAYER_TYPE::TENTING, layer,
502 .push_back( via );
503 }
504 }
505 }
506 }
507
508 auto InitAuxMatrix =
509 [&]( std::tuple<ODB_AUX_LAYER_TYPE, PCB_LAYER_ID, PCB_LAYER_ID> aLayerPair )
510 {
511 wxString featureName = "";
512 switch( std::get<0>( aLayerPair ) )
513 {
514 case ODB_AUX_LAYER_TYPE::TENTING: featureName = "tenting"; break;
515 case ODB_AUX_LAYER_TYPE::COVERING: featureName = "covering"; break;
516 case ODB_AUX_LAYER_TYPE::PLUGGING: featureName = "plugging"; break;
517 case ODB_AUX_LAYER_TYPE::FILLING: featureName = "filling"; break;
518 case ODB_AUX_LAYER_TYPE::CAPPING: featureName = "capping"; break;
519 default: return;
520 }
521
522 wxString dLayerName;
523
524 if( std::get<2>( aLayerPair ) != PCB_LAYER_ID::UNDEFINED_LAYER )
525 {
526 dLayerName = wxString::Format( "%s_%s-%s", featureName,
527 m_board->GetLayerName( std::get<1>( aLayerPair ) ),
528 m_board->GetLayerName( std::get<2>( aLayerPair ) ) );
529 }
530 else
531 {
532 if( m_board->IsFrontLayer( std::get<1>( aLayerPair ) ) )
533 dLayerName = wxString::Format( "%s_front", featureName );
534 else if( m_board->IsBackLayer( std::get<1>( aLayerPair ) ) )
535 dLayerName = wxString::Format( "%s_back", featureName );
536 else
537 return;
538 }
539 MATRIX_LAYER matrix( m_row++, dLayerName );
540
541 matrix.m_type = ODB_TYPE::DOCUMENT;
544
545 if( std::get<2>( aLayerPair ) != PCB_LAYER_ID::UNDEFINED_LAYER )
546 {
547 matrix.m_span.emplace( std::make_pair(
548 ODB::GenLegalEntityName( m_board->GetLayerName( std::get<1>( aLayerPair ) ) ),
550 m_board->GetLayerName( std::get<2>( aLayerPair ) ) ) ) );
551 }
552
553 m_matrixLayers.push_back( matrix );
554
555 if( std::get<2>( aLayerPair ) != PCB_LAYER_ID::UNDEFINED_LAYER )
556 {
557 m_plugin->GetLayerNameList().emplace_back(
558 std::make_pair( PCB_LAYER_ID::UNDEFINED_LAYER, matrix.m_layerName ) );
559 }
560 else
561 {
562 m_plugin->GetLayerNameList().emplace_back(
563 std::make_pair( std::get<1>( aLayerPair ), matrix.m_layerName ) );
564 }
565 };
566
567 for( const auto& [layer_pair, vec] : auxilliary_layers )
568 {
569 InitAuxMatrix( layer_pair );
570 }
571}
572
573
575{
576 // Track occurrences of each layer name to detect and handle duplicates
577 std::map<wxString, std::vector<size_t>> name_to_indices;
578
579 // First pass: collect all layer names and their indices
580 for( size_t i = 0; i < m_matrixLayers.size(); ++i )
581 {
582 const wxString& layerName = m_matrixLayers[i].m_layerName;
583 name_to_indices[layerName].push_back( i );
584 }
585
586 // Second pass: for any layer names that appear more than once, add suffixes
587 for( auto& [layerName, indices] : name_to_indices )
588 {
589 if( indices.size() > 1 )
590 {
591 // Multiple layers have the same name, add suffixes to make them unique
592 for( size_t count = 0; count < indices.size(); ++count )
593 {
594 size_t idx = indices[count];
595 wxString newLayerName = wxString::Format( "%s_%zu", m_matrixLayers[idx].m_layerName, count + 1 );
596
597 // Ensure the new name doesn't exceed the 64-character limit
598 if( newLayerName.length() > 64 )
599 {
600 // Truncate the base name if necessary to fit the suffix
601 wxString baseName = m_matrixLayers[idx].m_layerName;
602 size_t suffixLen = wxString::Format( "_%zu", count + 1 ).length();
603
604 if( suffixLen < baseName.length() )
605 {
606 baseName.Truncate( 64 - suffixLen );
607 newLayerName = wxString::Format( "%s_%zu", baseName, count + 1 );
608 }
609 }
610
611 m_matrixLayers[idx].m_layerName = std::move( newLayerName );
612 }
613 }
614 }
615}
616
617
619{
620 auto fileproxy = writer.CreateFileProxy( "matrix" );
621
622 ODB_TEXT_WRITER twriter( fileproxy.GetStream() );
623
624 for( const auto& [step_name, column] : m_matrixSteps )
625 {
626 const auto array_proxy = twriter.MakeArrayProxy( "STEP" );
627 twriter.WriteEquationLine( "COL", column );
628 twriter.WriteEquationLine( "NAME", step_name );
629 }
630
631 for( const MATRIX_LAYER& layer : m_matrixLayers )
632 {
633 const auto array_proxy = twriter.MakeArrayProxy( "LAYER" );
634 twriter.WriteEquationLine( "ROW", layer.m_rowNumber );
635 twriter.write_line_enum( "CONTEXT", layer.m_context );
636 twriter.write_line_enum( "TYPE", layer.m_type );
637
638 if( layer.m_addType.has_value() )
639 {
640 twriter.write_line_enum( "ADD_TYPE", layer.m_addType.value() );
641 }
642
643 twriter.WriteEquationLine( "NAME", layer.m_layerName.Upper() );
644 twriter.WriteEquationLine( "OLD_NAME", wxEmptyString );
645 twriter.write_line_enum( "POLARITY", layer.m_polarity );
646
647 if( layer.m_diType.has_value() )
648 {
649 twriter.write_line_enum( "DIELECTRIC_TYPE", layer.m_diType.value() );
650 // twriter.WriteEquationLine( "DIELECTRIC_NAME", wxEmptyString );
651
652 // Can be used with DIELECTRIC_TYPE=CORE
653 // twriter.WriteEquationLine( "CU_TOP", wxEmptyString );
654 // twriter.WriteEquationLine( "CU_BOTTOM", wxEmptyString );
655 }
656
657 // Only applies to: soldermask, silkscreen, solderpaste and specifies the relevant cu layer
658 // twriter.WriteEquationLine( "REF", wxEmptyString );
659
660 if( layer.m_span.has_value() )
661 {
662 twriter.WriteEquationLine( "START_NAME", layer.m_span->first.Upper() );
663 twriter.WriteEquationLine( "END_NAME", layer.m_span->second.Upper() );
664 }
665
666 twriter.WriteEquationLine( "COLOR", "0" );
667 }
668}
669
670
672 std::map<int, std::vector<BOARD_ITEM*>>& aMap,
673 const PCB_LAYER_ID& aLayerID, const wxString& aLayerName ) :
674 ODB_ENTITY_BASE( aBoard, aPlugin ), m_layerItems( aMap ), m_layerID( aLayerID ),
675 m_matrixLayerName( aLayerName )
676{
677 m_featuresMgr = std::make_unique<FEATURES_MANAGER>( aBoard, aPlugin, aLayerName );
678}
679
680
682{
683 if( m_matrixLayerName.Contains( "drill" ) )
684 {
687 return;
688 }
689
690 if( m_matrixLayerName.Contains( "filling" ) || m_matrixLayerName.Contains( "capping" )
691 || m_matrixLayerName.Contains( "covering" ) || m_matrixLayerName.Contains( "plugging" )
692 || m_matrixLayerName.Contains( "tenting" ) )
693 {
696 return;
697 }
698
700 {
702 }
703}
704
706{
707 if( m_layerItems.empty() )
708 return;
709
710 const NETINFO_LIST& nets = m_board->GetNetInfo();
711
712 for( const NETINFO_ITEM* net : nets )
713 {
714 std::vector<BOARD_ITEM*>& vec = m_layerItems[net->GetNetCode()];
715
716 std::stable_sort( vec.begin(), vec.end(),
717 []( BOARD_ITEM* a, BOARD_ITEM* b )
718 {
719 if( a->GetParentFootprint() == b->GetParentFootprint() )
720 return a->Type() < b->Type();
721
722 return a->GetParentFootprint() < b->GetParentFootprint();
723 } );
724
725 if( vec.empty() )
726 continue;
727
728 m_featuresMgr->InitFeatureList( m_layerID, vec );
729 }
730}
731
732
734 const EDA_DATA::PACKAGE& aPkg )
735{
736 if( m_matrixLayerName == "COMP_+_BOT" )
737 {
738 if( !m_compBot.has_value() )
739 {
740 m_compBot.emplace();
741 }
742 return m_compBot.value().AddComponent( aFp, aPkg );
743 }
744 else
745 {
746 if( !m_compTop.has_value() )
747 {
748 m_compTop.emplace();
749 }
750
751 return m_compTop.value().AddComponent( aFp, aPkg );
752 }
753}
754
755
757{
758 std::map<ODB_DRILL_SPAN, std::vector<BOARD_ITEM*>>& drill_layers =
759 m_plugin->GetDrillLayerItemsMap();
760
761 std::map<std::pair<PCB_LAYER_ID, PCB_LAYER_ID>, std::vector<BOARD_ITEM*>>& slot_holes =
762 m_plugin->GetSlotHolesMap();
763
764 std::map<ODB_DRILL_SPAN, wxString>& span_names = m_plugin->GetDrillSpanNameMap();
765
766 if( !m_layerItems.empty() )
767 {
768 m_layerItems.clear();
769 }
770
772
773 std::optional<ODB_DRILL_SPAN> matchedSpan;
774
775 for( const auto& [span, name] : span_names )
776 {
777 if( name == m_matrixLayerName )
778 {
779 matchedSpan = span;
780 break;
781 }
782 }
783
784 bool useLegacyMatching = !matchedSpan.has_value();
785 bool isBackdrillLayer = matchedSpan.has_value() && matchedSpan->m_IsBackdrill;
786 bool isNonPlatedLayer = matchedSpan.has_value() && matchedSpan->m_IsNonPlated;
787 bool isNPTHLayer = matchedSpan.has_value() && matchedSpan->m_IsNonPlated
788 && !matchedSpan->m_IsBackdrill;
789 bool isPlatedDrillLayer = matchedSpan.has_value() && !matchedSpan->m_IsNonPlated
790 && !matchedSpan->m_IsBackdrill;
791
792 if( matchedSpan.has_value() && ( isNPTHLayer || isPlatedDrillLayer ) )
793 {
794 // Slotted (oval) holes are routed to a separate map; emit them on the matching
795 // plated or non-plated drill layer. Plated slots belong on the plated layer,
796 // non-plated slots on the non-plated layer.
797 auto slotIt = slot_holes.find( matchedSpan->Pair() );
798
799 if( slotIt != slot_holes.end() )
800 {
801 for( BOARD_ITEM* item : slotIt->second )
802 {
803 if( item->Type() != PCB_PAD_T )
804 continue;
805
806 PAD* pad = static_cast<PAD*>( item );
807
808 bool padIsNPTH = pad->GetAttribute() == PAD_ATTRIB::NPTH;
809
810 if( isNPTHLayer != padIsNPTH )
811 continue;
812
813 m_tools.value().AddDrillTools( padIsNPTH ? wxT( "NON_PLATED" ) : wxT( "PLATED" ),
815 std::min( pad->GetDrillSizeX(),
816 pad->GetDrillSizeY() ) ) );
817
818 m_layerItems[pad->GetNetCode()].push_back( item );
819 }
820 }
821 }
822 else if( useLegacyMatching )
823 {
824 bool is_npth_layer = false;
825 wxString plated_name = wxT( "plated" );
826
827 if( m_matrixLayerName.Contains( wxT( "non-plated" ) ) )
828 {
829 is_npth_layer = true;
830 plated_name = wxT( "non-plated" );
831 }
832
833 for( const auto& [layer_pair, vec] : slot_holes )
834 {
835 wxString dLayerName = wxString::Format( wxT( "drill_%s_%s-%s" ), plated_name,
836 m_board->GetLayerName( layer_pair.first ),
837 m_board->GetLayerName( layer_pair.second ) );
838
839 if( ODB::GenLegalEntityName( dLayerName ) == m_matrixLayerName )
840 {
841 for( BOARD_ITEM* item : vec )
842 {
843 if( item->Type() != PCB_PAD_T )
844 continue;
845
846 PAD* pad = static_cast<PAD*>( item );
847
848 if( ( is_npth_layer && pad->GetAttribute() == PAD_ATTRIB::PTH )
849 || ( !is_npth_layer && pad->GetAttribute() == PAD_ATTRIB::NPTH ) )
850 {
851 continue;
852 }
853
854 m_tools.value().AddDrillTools(
855 pad->GetAttribute() == PAD_ATTRIB::PTH ? wxT( "PLATED" )
856 : wxT( "NON_PLATED" ),
858 std::min( pad->GetDrillSizeX(), pad->GetDrillSizeY() ) ) );
859
860 m_layerItems[pad->GetNetCode()].push_back( item );
861 }
862
863 break;
864 }
865 }
866 }
867
868 if( matchedSpan.has_value() )
869 {
870 auto drillIt = drill_layers.find( *matchedSpan );
871
872 if( drillIt != drill_layers.end() )
873 {
874 for( BOARD_ITEM* item : drillIt->second )
875 {
876 if( item->Type() == PCB_VIA_T )
877 {
878 PCB_VIA* via = static_cast<PCB_VIA*>( item );
879
880 if( isBackdrillLayer )
881 {
882 auto drillMatches = [&]( const PADSTACK::DRILL_PROPS& aDrill )
883 {
884 return aDrill.start == matchedSpan->m_StartLayer
885 && aDrill.end == matchedSpan->m_EndLayer
886 && ( aDrill.size.x > 0 || aDrill.size.y > 0 );
887 };
888
889 const PADSTACK::DRILL_PROPS& secondary = via->Padstack().SecondaryDrill();
890 const PADSTACK::DRILL_PROPS& tertiary = via->Padstack().TertiaryDrill();
891
892 const PADSTACK::DRILL_PROPS* drill = nullptr;
893
894 if( drillMatches( secondary ) )
895 drill = &secondary;
896 else if( drillMatches( tertiary ) )
897 drill = &tertiary;
898 else
899 continue;
900
901 int diameter = drill->size.x;
902
903 if( drill->size.y > 0 )
904 {
905 diameter = ( diameter > 0 ) ? std::min( diameter, drill->size.y )
906 : drill->size.y;
907 }
908
909 if( diameter <= 0 )
910 continue;
911
912 m_tools.value().AddDrillTools( wxT( "NON_PLATED" ),
913 ODB::SymDouble2String( diameter ),
914 wxT( "BLIND" ) );
915 }
916 else if( isNonPlatedLayer )
917 {
918 m_tools.value().AddDrillTools( wxT( "NON_PLATED" ),
919 ODB::SymDouble2String( via->GetDrillValue() ) );
920 }
921 else
922 {
923 m_tools.value().AddDrillTools( wxT( "VIA" ),
924 ODB::SymDouble2String( via->GetDrillValue() ) );
925 }
926
927 m_layerItems[via->GetNetCode()].push_back( item );
928 }
929 else if( item->Type() == PCB_PAD_T )
930 {
931 PAD* pad = static_cast<PAD*>( item );
932
933 bool padIsNPTH = pad->GetAttribute() == PAD_ATTRIB::NPTH;
934
935 if( isNPTHLayer && !padIsNPTH )
936 continue;
937
938 if( !isNonPlatedLayer && padIsNPTH )
939 continue;
940
941 int drillSize = pad->GetDrillSizeX();
942
943 if( pad->GetDrillSizeX() != pad->GetDrillSizeY() )
944 drillSize = std::min( pad->GetDrillSizeX(), pad->GetDrillSizeY() );
945
946 wxString typeLabel = ( padIsNPTH || isNonPlatedLayer ) ? wxT( "NON_PLATED" )
947 : wxT( "PLATED" );
948 wxString type2 = isBackdrillLayer ? wxT( "BLIND" ) : wxT( "STANDARD" );
949
950 m_tools.value().AddDrillTools( typeLabel, ODB::SymDouble2String( drillSize ),
951 type2 );
952
953 m_layerItems[pad->GetNetCode()].push_back( item );
954 }
955 }
956 }
957 }
958 else
959 {
960 bool is_npth_layer = false;
961 wxString plated_name = wxT( "plated" );
962
963 if( m_matrixLayerName.Contains( wxT( "non-plated" ) ) )
964 {
965 is_npth_layer = true;
966 plated_name = wxT( "non-plated" );
967 }
968
969 for( const auto& [span, vec] : drill_layers )
970 {
971 wxString dLayerName = wxString::Format( wxT( "drill_%s_%s-%s" ), plated_name,
972 m_board->GetLayerName( span.TopLayer() ),
973 m_board->GetLayerName( span.BottomLayer() ) );
974
975 if( ODB::GenLegalEntityName( dLayerName ) == m_matrixLayerName )
976 {
977 for( BOARD_ITEM* item : vec )
978 {
979 if( item->Type() == PCB_VIA_T && !is_npth_layer )
980 {
981 PCB_VIA* via = static_cast<PCB_VIA*>( item );
982
983 m_tools.value().AddDrillTools( wxT( "VIA" ),
984 ODB::SymDouble2String( via->GetDrillValue() ) );
985
986 m_layerItems[via->GetNetCode()].push_back( item );
987 }
988 else if( item->Type() == PCB_PAD_T )
989 {
990 PAD* pad = static_cast<PAD*>( item );
991
992 if( ( is_npth_layer && pad->GetAttribute() == PAD_ATTRIB::PTH )
993 || ( !is_npth_layer && pad->GetAttribute() == PAD_ATTRIB::NPTH ) )
994 {
995 continue;
996 }
997
998 m_tools.value().AddDrillTools(
999 pad->GetAttribute() == PAD_ATTRIB::PTH ? wxT( "PLATED" )
1000 : wxT( "NON_PLATED" ),
1001 ODB::SymDouble2String( pad->GetDrillSizeX() ) );
1002
1003 m_layerItems[pad->GetNetCode()].push_back( item );
1004 }
1005 }
1006
1007 break;
1008 }
1009 }
1010 }
1011}
1012
1014{
1015 auto& auxilliary_layers = m_plugin->GetAuxilliaryLayerItemsMap();
1016
1017 if( !m_layerItems.empty() )
1018 {
1019 m_layerItems.clear();
1020 }
1021
1022 for( const auto& [layer_pair, vec] : auxilliary_layers )
1023 {
1024 wxString featureName = "";
1025 switch( std::get<0>( layer_pair ) )
1026 {
1027 case ODB_AUX_LAYER_TYPE::TENTING: featureName = "tenting"; break;
1028 case ODB_AUX_LAYER_TYPE::COVERING: featureName = "covering"; break;
1029 case ODB_AUX_LAYER_TYPE::PLUGGING: featureName = "plugging"; break;
1030 case ODB_AUX_LAYER_TYPE::FILLING: featureName = "filling"; break;
1031 case ODB_AUX_LAYER_TYPE::CAPPING: featureName = "capping"; break;
1032 default: return;
1033 }
1034
1035 wxString dLayerName;
1036
1037 if( std::get<2>( layer_pair ) != PCB_LAYER_ID::UNDEFINED_LAYER )
1038 {
1039 dLayerName = wxString::Format( "%s_%s-%s", featureName,
1040 m_board->GetLayerName( std::get<1>( layer_pair ) ),
1041 m_board->GetLayerName( std::get<2>( layer_pair ) ) );
1042 }
1043 else
1044 {
1045 if( m_board->IsFrontLayer( std::get<1>( layer_pair ) ) )
1046 dLayerName = wxString::Format( "%s_front", featureName );
1047 else if( m_board->IsBackLayer( std::get<1>( layer_pair ) ) )
1048 dLayerName = wxString::Format( "%s_back", featureName );
1049 else
1050 return;
1051 }
1052
1053 if( ODB::GenLegalEntityName( dLayerName ) == m_matrixLayerName )
1054 {
1055 for( BOARD_ITEM* item : vec )
1056 {
1057 if( item->Type() == PCB_VIA_T )
1058 {
1059 PCB_VIA* via = static_cast<PCB_VIA*>( item );
1060
1061 m_layerItems[via->GetNetCode()].push_back( item );
1062 }
1063 }
1064
1065 break;
1066 }
1067 }
1068}
1069
1071{
1073
1074 InitEdaData();
1075
1076 // Init Layer Entity Data
1077 for( const auto& [layerName, layer_entity_ptr] : m_layerEntityMap )
1078 {
1079 layer_entity_ptr->InitEntityData();
1080 }
1081}
1082
1083
1085{
1086 GenAttrList( writer );
1087
1088 GenFeatures( writer );
1089
1090 if( m_compTop.has_value() || m_compBot.has_value() )
1091 {
1092 GenComponents( writer );
1093 }
1094
1095 if( m_tools.has_value() )
1096 {
1097 GenTools( writer );
1098 }
1099}
1100
1101
1103{
1104 auto fileproxy = writer.CreateFileProxy( "components" );
1105
1106 if( m_compTop.has_value() )
1107 {
1108 m_compTop->Write( fileproxy.GetStream() );
1109 }
1110 else if( m_compBot.has_value() )
1111 {
1112 m_compBot->Write( fileproxy.GetStream() );
1113 }
1114}
1115
1116
1118{
1119 auto fileproxy = writer.CreateFileProxy( "features" );
1120
1121 m_featuresMgr->GenerateFeatureFile( fileproxy.GetStream() );
1122}
1123
1124
1126{
1127 auto fileproxy = writer.CreateFileProxy( "attrlist" );
1128
1129 std::ostream& ost = fileproxy.GetStream();
1130
1131 BOARD_DESIGN_SETTINGS& dsnSettings = m_board->GetDesignSettings();
1132 BOARD_STACKUP& stackup = dsnSettings.GetStackupDescriptor();
1133
1134 BOARD_STACKUP_ITEM* stackupItem = nullptr;
1135
1137 {
1138 for( BOARD_STACKUP_ITEM* item : stackup.GetList() )
1139 {
1140 if( item->GetBrdLayerId() == m_layerID )
1141 {
1142 stackupItem = item;
1143 break;
1144 }
1145 }
1146 }
1147 else
1148 {
1149 for( BOARD_STACKUP_ITEM* item : stackup.GetList() )
1150 {
1151 if( item->GetType() == BS_ITEM_TYPE_DIELECTRIC )
1152 {
1153 wxString dielectricName = wxString::Format( "DIELECTRIC_%d",
1154 item->GetDielectricLayerId() );
1155
1156 if( ODB::GenLegalEntityName( dielectricName ) == m_matrixLayerName )
1157 {
1158 stackupItem = item;
1159 break;
1160 }
1161 }
1162 }
1163 }
1164
1165 if( stackupItem )
1166 {
1167 int thickness = stackupItem->GetThickness();
1168
1169 if( thickness > 0 )
1170 {
1171 double thicknessOut = PCB_IO_ODBPP::m_scale * thickness;
1172 ost << ".layer_dielectric=" << ODB::Double2String( thicknessOut ) << std::endl;
1173 }
1174
1175 if( stackupItem->GetType() == BS_ITEM_TYPE_COPPER )
1176 {
1177 double copperThicknessMM = static_cast<double>( thickness ) / pcbIUScale.mmToIU( 1.0 );
1178 double thicknessOz = copperThicknessMM / 0.035;
1179 ost << ".copper_weight=" << ODB::Double2String( thicknessOz ) << std::endl;
1180 }
1181
1182 if( stackupItem->HasEpsilonRValue() )
1183 {
1184 double epsilonR = stackupItem->GetEpsilonR();
1185
1186 if( epsilonR > 0.0 )
1187 {
1188 ost << ".dielectric_constant=" << ODB::Double2String( epsilonR ) << std::endl;
1189 }
1190 }
1191
1192 if( stackupItem->HasLossTangentValue() )
1193 {
1194 double lossTangent = stackupItem->GetLossTangent();
1195
1196 if( lossTangent > 0.0 )
1197 {
1198 ost << ".loss_tangent=" << ODB::Double2String( lossTangent ) << std::endl;
1199 }
1200 }
1201
1202 wxString material = stackupItem->GetMaterial();
1203
1204 if( !material.IsEmpty() )
1205 {
1206 ost << ".material=" << ODB::GenLegalEntityName( material ).ToStdString() << std::endl;
1207 }
1208 }
1209}
1210
1211
1213{
1214 auto fileproxy = writer.CreateFileProxy( "tools" );
1215
1216 m_tools.value().GenerateFile( fileproxy.GetStream() );
1217}
1218
1219
1221{
1222 //InitPackage
1223 for( const FOOTPRINT* fp : m_board->Footprints() )
1224 {
1225 m_edaData.AddPackage( fp );
1226 }
1227
1228 // for NET
1229 const NETINFO_LIST& nets = m_board->GetNetInfo();
1230
1231 for( const NETINFO_ITEM* net : nets )
1232 {
1233 m_edaData.AddNET( net );
1234 }
1235
1236 // for CMP
1237 size_t j = 0;
1238
1239 for( const FOOTPRINT* fp : m_board->Footprints() )
1240 {
1241 wxString compName = ODB::GenLegalEntityName( "COMP_+_TOP" );
1242 if( fp->IsFlipped() )
1243 compName = ODB::GenLegalEntityName( "COMP_+_BOT" );
1244
1245 auto iter = m_layerEntityMap.find( compName );
1246
1247 if( iter == m_layerEntityMap.end() )
1248 {
1249 wxLogError( _( "Failed to add component data" ) );
1250 return;
1251 }
1252
1253 // ODBPP only need unique PACKAGE in PKG record in eda/data file.
1254 // the PKG index can repeat to be ref in CMP record in component file.
1255 std::shared_ptr<FOOTPRINT> fp_pkg = m_edaData.GetEdaFootprints().at( j );
1256 ++j;
1257
1258 const EDA_DATA::PACKAGE& eda_pkg =
1259 m_edaData.GetPackage( hash_fp_item( fp_pkg.get(), HASH_POS | REL_COORD ) );
1260
1261 if( fp->Pads().empty() )
1262 continue;
1263
1264 ODB_COMPONENT& comp = iter->second->InitComponentData( fp, eda_pkg );
1265
1266 for( int i = 0; i < (int) fp->Pads().size(); ++i )
1267 {
1268 PAD* pad = fp->Pads()[i];
1269 EDA_DATA::NET& eda_net = m_edaData.GetNet( pad->GetNetCode() );
1270
1272 &m_edaData,
1275 comp.m_index, comp.m_toeprints.size() );
1276
1277 m_plugin->GetPadSubnetMap().emplace( pad, &subnet );
1278
1279 const std::shared_ptr<EDA_DATA::PIN> pin = eda_pkg.GetEdaPkgPin( i );
1280 const EDA_DATA::PIN& pin_ref = *pin;
1281 auto& toep = comp.m_toeprints.emplace_back( pin_ref );
1282
1283 toep.m_net_num = eda_net.m_index;
1284 toep.m_subnet_num = subnet.m_index;
1285
1286 toep.m_center = ODB::AddXY( pad->GetPosition() );
1287
1288 toep.m_rot = ODB::Double2String( ( ANGLE_360 - pad->GetOrientation() ).Normalize().AsDegrees() );
1289
1290 if( pad->IsFlipped() )
1291 toep.m_mirror = wxT( "M" );
1292 else
1293 toep.m_mirror = wxT( "N" );
1294 }
1295 }
1296
1297 for( PCB_TRACK* track : m_board->Tracks() )
1298 {
1299 EDA_DATA::NET& eda_net = m_edaData.GetNet( track->GetNetCode() );
1300 EDA_DATA::SUB_NET* subnet = nullptr;
1301
1302 if( track->Type() == PCB_VIA_T )
1303 subnet = &( eda_net.AddSubnet<EDA_DATA::SUB_NET_VIA>( &m_edaData ) );
1304 else
1305 subnet = &( eda_net.AddSubnet<EDA_DATA::SUB_NET_TRACE>( &m_edaData ) );
1306
1307 m_plugin->GetViaTraceSubnetMap().emplace( track, subnet );
1308 }
1309
1310 for( ZONE* zone : m_board->Zones() )
1311 {
1312 for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
1313 {
1314 EDA_DATA::NET& eda_net = m_edaData.GetNet( zone->GetNetCode() );
1316 &m_edaData,
1319 0 );
1320 m_plugin->GetPlaneSubnetMap().emplace( std::piecewise_construct,
1321 std::forward_as_tuple( layer, zone ),
1322 std::forward_as_tuple( &subnet ) );
1323 }
1324 }
1325}
1326
1327
1329{
1330 wxString step_root = writer.GetCurrentPath();
1331
1332 writer.CreateEntityDirectory( step_root, "layers" );
1333 GenerateLayerFiles( writer );
1334
1335 writer.CreateEntityDirectory( step_root, "eda" );
1336 GenerateEdaFiles( writer );
1337
1338 writer.CreateEntityDirectory( step_root, "netlists/cadnet" );
1339 GenerateNetlistsFiles( writer );
1340
1341 writer.SetCurrentPath( step_root );
1342 GenerateProfileFile( writer );
1343
1344 GenerateStepHeaderFile( writer );
1345
1346 //TODO: system attributes
1347 // GenerateAttrListFile( writer );
1348}
1349
1350
1352{
1353 auto fileproxy = writer.CreateFileProxy( "profile" );
1354
1355 m_profile = std::make_unique<FEATURES_MANAGER>( m_board, m_plugin, wxEmptyString );
1356
1357 SHAPE_POLY_SET board_outline;
1358
1359 if( !m_board->GetBoardPolygonOutlines( board_outline, true ) )
1360 wxLogError( "Failed to get board outline" );
1361
1362 if( !m_profile->AddContour( board_outline, 0 ) )
1363 wxLogError( "Failed to add polygon to profile" );
1364
1365 m_profile->GenerateProfileFeatures( fileproxy.GetStream() );
1366}
1367
1368
1370{
1371 auto fileproxy = writer.CreateFileProxy( "stephdr" );
1372
1373 m_stephdr = {
1375 { "X_DATUM", "0" },
1376 { "Y_DATUM", "0" },
1377 { "X_ORIGIN", "0" },
1378 { "Y_ORIGIN", "0" },
1379 { "TOP_ACTIVE", "0" },
1380 { "BOTTOM_ACTIVE", "0" },
1381 { "RIGHT_ACTIVE", "0" },
1382 { "LEFT_ACTIVE", "0" },
1383 { "AFFECTING_BOM", "" },
1384 { "AFFECTING_BOM_CHANGED", "0" },
1385 };
1386
1387 ODB_TEXT_WRITER twriter( fileproxy.GetStream() );
1388
1389 for( const auto& [key, value] : m_stephdr )
1390 {
1391 twriter.WriteEquationLine( key, value );
1392 }
1393}
1394
1395
1397{
1398 wxString layers_root = writer.GetCurrentPath();
1399
1400 for( auto& [layerName, layerEntity] : m_layerEntityMap )
1401 {
1402 writer.CreateEntityDirectory( layers_root, layerName );
1403
1404 layerEntity->GenerateFiles( writer );
1405 }
1406}
1407
1408
1410{
1411 auto fileproxy = writer.CreateFileProxy( "data" );
1412
1413 m_edaData.Write( fileproxy.GetStream() );
1414}
1415
1416
1418{
1419 auto fileproxy = writer.CreateFileProxy( "netlist" );
1420
1421 m_netlist.Write( fileproxy.GetStream() );
1422}
1423
1424
1426{
1427 try
1428 {
1429 writer.CreateEntityDirectory( writer.GetRootPath(), "steps" );
1431 return true;
1432 }
1433 catch( const std::exception& e )
1434 {
1435 std::cerr << e.what() << std::endl;
1436 return false;
1437 }
1438}
1439
1440
1442{
1443 LSET layers = m_board->GetEnabledLayers();
1444
1445 // To avoid the overhead of repeatedly cycling through the layers and nets,
1446 // we pre-sort the board items into a map of layer -> net -> items
1447 std::map<PCB_LAYER_ID, std::map<int, std::vector<BOARD_ITEM*>>>& elements = m_plugin->GetLayerElementsMap();
1448
1449 std::for_each( m_board->Tracks().begin(), m_board->Tracks().end(),
1450 [&layers, &elements]( PCB_TRACK* aTrack )
1451 {
1452 if( aTrack->Type() == PCB_VIA_T )
1453 {
1454 PCB_VIA* via = static_cast<PCB_VIA*>( aTrack );
1455
1456 for( PCB_LAYER_ID layer : layers )
1457 {
1458 if( via->FlashLayer( layer ) )
1459 elements[layer][via->GetNetCode()].push_back( via );
1460 }
1461 }
1462 else
1463 {
1464 elements[aTrack->GetLayer()][aTrack->GetNetCode()].push_back( aTrack );
1465 }
1466 } );
1467
1468 std::for_each( m_board->Zones().begin(), m_board->Zones().end(),
1469 [&elements]( ZONE* zone )
1470 {
1471 for( PCB_LAYER_ID layer : zone->GetLayerSet() )
1472 elements[layer][zone->GetNetCode()].push_back( zone );
1473 } );
1474
1475 for( BOARD_ITEM* item : m_board->Drawings() )
1476 {
1477 if( BOARD_CONNECTED_ITEM* conn_it = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
1478 elements[conn_it->GetLayer()][conn_it->GetNetCode()].push_back( conn_it );
1479 else
1480 elements[item->GetLayer()][0].push_back( item );
1481 }
1482
1483 for( FOOTPRINT* fp : m_board->Footprints() )
1484 {
1485 for( PCB_FIELD* field : fp->GetFields() )
1486 elements[field->GetLayer()][0].push_back( field );
1487
1488 for( BOARD_ITEM* item : fp->GraphicalItems() )
1489 elements[item->GetLayer()][0].push_back( item );
1490
1491 for( PAD* pad : fp->Pads() )
1492 {
1493 VECTOR2I margin;
1494
1495 for( PCB_LAYER_ID layer : pad->GetLayerSet() )
1496 {
1497 bool onCopperLayer = LSET::AllCuMask().test( layer );
1498 bool onSolderMaskLayer = LSET( { F_Mask, B_Mask } ).test( layer );
1499 bool onSolderPasteLayer = LSET( { F_Paste, B_Paste } ).test( layer );
1500
1501 if( onSolderMaskLayer )
1502 margin.x = margin.y = pad->GetSolderMaskExpansion( PADSTACK::ALL_LAYERS );
1503
1504 if( onSolderPasteLayer )
1505 margin = pad->GetSolderPasteMargin( PADSTACK::ALL_LAYERS );
1506
1507 VECTOR2I padPlotsSize = pad->GetSize( PADSTACK::ALL_LAYERS ) + margin * 2;
1508
1509 if( onCopperLayer && !pad->IsOnCopperLayer() )
1510 continue;
1511
1512 if( onCopperLayer && !pad->FlashLayer( layer ) )
1513 continue;
1514
1515 if( pad->GetShape( PADSTACK::ALL_LAYERS ) != PAD_SHAPE::CUSTOM
1516 && ( padPlotsSize.x <= 0 || padPlotsSize.y <= 0 ) )
1517 {
1518 continue;
1519 }
1520
1521 elements[layer][pad->GetNetCode()].push_back( pad );
1522 }
1523 }
1524 }
1525
1526 for( const auto& [layerID, layerName] : m_plugin->GetLayerNameList() )
1527 {
1528 std::shared_ptr<ODB_LAYER_ENTITY> layer_entity_ptr = std::make_shared<ODB_LAYER_ENTITY>(
1529 m_board, m_plugin, elements[layerID], layerID, layerName );
1530
1531 m_layerEntityMap.emplace( layerName, layer_entity_ptr );
1532 }
1533}
const char * name
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
@ BS_ITEM_TYPE_COPPER
@ BS_ITEM_TYPE_DIELECTRIC
wxString GetBuildVersion()
Get the full KiCad version string.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
Container for design settings for a BOARD object.
BOARD_STACKUP & GetStackupDescriptor()
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:81
Manage one layer needed to make a physical board.
wxString GetTypeName() const
int GetSublayersCount() const
double GetEpsilonR(int aDielectricSubLayer=0) const
bool HasEpsilonRValue() const
wxString GetLayerName() const
bool HasLossTangentValue() const
PCB_LAYER_ID GetBrdLayerId() const
int GetThickness(int aDielectricSubLayer=0) const
BOARD_STACKUP_ITEM_TYPE GetType() const
wxString GetMaterial(int aDielectricSubLayer=0) const
int GetDielectricLayerId() const
double GetLossTangent(int aDielectricSubLayer=0) const
Manage layers needed to make a physical board.
const std::vector< BOARD_STACKUP_ITEM * > & GetList() const
int GetCount() const
bool SynchronizeWithBoard(BOARD_DESIGN_SETTINGS *aSettings)
Synchronize the BOARD_STACKUP_ITEM* list with the board.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:372
T & AddSubnet(Args &&... args)
const size_t m_index
const std::shared_ptr< PIN > GetEdaPkgPin(size_t aPadIndex) const
const size_t m_index
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:604
Handle the data for a net.
Definition netinfo.h:46
Container for NETINFO_ITEM elements, which are the nets.
Definition netinfo.h:221
virtual std::string GetEntityName()=0
virtual bool CreateDirectoryTree(ODB_TREE_WRITER &writer)
BOARD * m_board
Definition odb_entity.h:59
PCB_IO_ODBPP * m_plugin
Definition odb_entity.h:61
ODB_ENTITY_BASE(BOARD *aBoard, PCB_IO_ODBPP *aPlugin)
Definition odb_entity.h:45
std::ostream & GetStream()
Definition odb_util.h:236
void GenFeatures(ODB_TREE_WRITER &writer)
PCB_LAYER_ID m_layerID
Definition odb_entity.h:209
void GenComponents(ODB_TREE_WRITER &writer)
wxString m_matrixLayerName
Definition odb_entity.h:210
std::optional< COMPONENTS_MANAGER > m_compTop
Definition odb_entity.h:213
virtual void GenerateFiles(ODB_TREE_WRITER &writer) override
std::optional< COMPONENTS_MANAGER > m_compBot
Definition odb_entity.h:214
std::optional< ODB_DRILL_TOOLS > m_tools
Definition odb_entity.h:212
void GenTools(ODB_TREE_WRITER &writer)
std::map< int, std::vector< BOARD_ITEM * > > m_layerItems
Definition odb_entity.h:208
ODB_LAYER_ENTITY(BOARD *aBoard, PCB_IO_ODBPP *aPlugin, std::map< int, std::vector< BOARD_ITEM * > > &aMap, const PCB_LAYER_ID &aLayerID, const wxString &aLayerName)
ODB_COMPONENT & InitComponentData(const FOOTPRINT *aFp, const EDA_DATA::PACKAGE &aPkg)
virtual void InitEntityData() override
void GenAttrList(ODB_TREE_WRITER &writer)
std::unique_ptr< FEATURES_MANAGER > m_featuresMgr
Definition odb_entity.h:215
void AddStep(const wxString &aStepName)
unsigned int m_col
Definition odb_entity.h:114
std::vector< MATRIX_LAYER > m_matrixLayers
Definition odb_entity.h:112
void AddMatrixLayerField(MATRIX_LAYER &aMLayer, PCB_LAYER_ID aLayer)
virtual void GenerateFiles(ODB_TREE_WRITER &writer) override
std::map< wxString, unsigned int > m_matrixSteps
Definition odb_entity.h:111
unsigned int m_row
Definition odb_entity.h:113
void AddAuxilliaryMatrixLayer()
void EnsureUniqueLayerNames()
virtual void InitEntityData() override
void AddCOMPMatrixLayer(PCB_LAYER_ID aCompSide)
std::vector< std::pair< wxString, wxString > > m_info
Definition odb_entity.h:131
virtual void GenerateFiles(ODB_TREE_WRITER &writer) override
virtual std::string GetEntityName() override
Definition odb_entity.h:147
std::unordered_map< wxString, wxString > m_stephdr
Definition odb_entity.h:174
void GenerateProfileFile(ODB_TREE_WRITER &writer)
EDA_DATA m_edaData
Definition odb_entity.h:173
void GenerateStepHeaderFile(ODB_TREE_WRITER &writer)
void GenerateEdaFiles(ODB_TREE_WRITER &writer)
virtual void InitEntityData() override
void GenerateLayerFiles(ODB_TREE_WRITER &writer)
std::map< wxString, std::shared_ptr< ODB_LAYER_ENTITY > > m_layerEntityMap
Definition odb_entity.h:170
ODB_NET_LIST m_netlist
Definition odb_entity.h:175
std::unique_ptr< FEATURES_MANAGER > m_profile
Definition odb_entity.h:171
virtual bool CreateDirectoryTree(ODB_TREE_WRITER &writer) override
void GenerateNetlistsFiles(ODB_TREE_WRITER &writer)
virtual void GenerateFiles(ODB_TREE_WRITER &writer) override
void WriteEquationLine(const std::string &var, int value)
Definition odb_util.cpp:308
ARRAY_PROXY MakeArrayProxy(const std::string &aStr)
Definition odb_util.h:314
void write_line_enum(const std::string &var, const T &value)
Definition odb_util.h:288
const wxString GetRootPath() const
Definition odb_util.h:269
void CreateEntityDirectory(const wxString &aPareDir, const wxString &aSubDir=wxEmptyString)
Definition odb_util.cpp:232
ODB_FILE_WRITER CreateFileProxy(const wxString &aFileName)
Definition odb_util.h:256
void SetCurrentPath(const wxString &aDir)
Definition odb_util.h:265
const wxString GetCurrentPath() const
Definition odb_util.h:263
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:177
Definition pad.h:61
static std::string m_unitsStr
static double m_scale
Represent a set of closed polygons.
Handle a list of polygons defining a copper zone.
Definition zone.h:70
#define _(s)
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:417
size_t hash_fp_item(const EDA_ITEM *aItem, int aFlags)
Calculate hash of an EDA_ITEM.
Definition hash_eda.cpp:54
Hashing functions for EDA_ITEMs.
@ HASH_POS
Definition hash_eda.h:43
@ REL_COORD
Use coordinates relative to the parent object.
Definition hash_eda.h:46
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:675
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ User_16
Definition layer_ids.h:135
@ User_29
Definition layer_ids.h:148
@ User_40
Definition layer_ids.h:159
@ User_15
Definition layer_ids.h:134
@ User_8
Definition layer_ids.h:127
@ F_CrtYd
Definition layer_ids.h:112
@ User_11
Definition layer_ids.h:130
@ User_25
Definition layer_ids.h:144
@ User_34
Definition layer_ids.h:153
@ User_45
Definition layer_ids.h:164
@ B_Adhes
Definition layer_ids.h:99
@ User_36
Definition layer_ids.h:155
@ Edge_Cuts
Definition layer_ids.h:108
@ Dwgs_User
Definition layer_ids.h:103
@ F_Paste
Definition layer_ids.h:100
@ Cmts_User
Definition layer_ids.h:104
@ User_6
Definition layer_ids.h:125
@ User_7
Definition layer_ids.h:126
@ User_19
Definition layer_ids.h:138
@ User_23
Definition layer_ids.h:142
@ F_Adhes
Definition layer_ids.h:98
@ User_41
Definition layer_ids.h:160
@ B_Mask
Definition layer_ids.h:94
@ B_Cu
Definition layer_ids.h:61
@ User_14
Definition layer_ids.h:133
@ User_39
Definition layer_ids.h:158
@ User_5
Definition layer_ids.h:124
@ User_20
Definition layer_ids.h:139
@ Eco1_User
Definition layer_ids.h:105
@ F_Mask
Definition layer_ids.h:93
@ User_42
Definition layer_ids.h:161
@ User_43
Definition layer_ids.h:162
@ B_Paste
Definition layer_ids.h:101
@ User_10
Definition layer_ids.h:129
@ User_9
Definition layer_ids.h:128
@ User_27
Definition layer_ids.h:146
@ User_28
Definition layer_ids.h:147
@ F_Fab
Definition layer_ids.h:115
@ Margin
Definition layer_ids.h:109
@ F_SilkS
Definition layer_ids.h:96
@ B_CrtYd
Definition layer_ids.h:111
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ Eco2_User
Definition layer_ids.h:106
@ User_35
Definition layer_ids.h:154
@ User_31
Definition layer_ids.h:150
@ User_3
Definition layer_ids.h:122
@ User_1
Definition layer_ids.h:120
@ User_12
Definition layer_ids.h:131
@ B_SilkS
Definition layer_ids.h:97
@ User_30
Definition layer_ids.h:149
@ User_37
Definition layer_ids.h:156
@ User_22
Definition layer_ids.h:141
@ User_38
Definition layer_ids.h:157
@ User_4
Definition layer_ids.h:123
@ User_21
Definition layer_ids.h:140
@ User_24
Definition layer_ids.h:143
@ User_13
Definition layer_ids.h:132
@ User_2
Definition layer_ids.h:121
@ User_17
Definition layer_ids.h:136
@ User_33
Definition layer_ids.h:152
@ User_26
Definition layer_ids.h:145
@ User_32
Definition layer_ids.h:151
@ User_18
Definition layer_ids.h:137
@ User_44
Definition layer_ids.h:163
@ F_Cu
Definition layer_ids.h:60
@ 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
std::pair< wxString, wxString > AddXY(const VECTOR2I &aVec)
Definition odb_util.cpp:191
wxString GenLegalEntityName(const wxString &aStr)
Definition odb_util.cpp:106
wxString Double2String(double aVal)
Definition odb_util.cpp:151
wxString SymDouble2String(double aVal)
Definition odb_util.cpp:179
#define ODB_JOB_NAME
Definition odb_defines.h:27
#define ODB_UNITS
Definition odb_defines.h:28
@ UNDEFINED
Definition odb_util.h:35
@ COMPONENT
Definition odb_util.h:47
@ SOLDER_PASTE
Definition odb_util.h:42
@ SILK_SCREEN
Definition odb_util.h:43
@ DOCUMENT
Definition odb_util.h:46
@ SOLDER_MASK
Definition odb_util.h:41
@ DIELECTRIC
Definition odb_util.h:39
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:103
@ PTH
Plated through hole pad.
Definition padstack.h:98
see class PGM_BASE
#define KEY_CORE
std::optional< ODB_SUBTYPE > m_addType
Definition odb_entity.h:83
std::optional< ODB_DIELECTRIC_TYPE > m_diType
Definition odb_entity.h:84
std::optional< std::pair< wxString, wxString > > m_span
Definition odb_entity.h:82
! The properties of a padstack drill. Drill position is always the pad position (origin).
Definition padstack.h:266
VECTOR2I size
Drill diameter (x == y) or slot dimensions (x != y)
Definition padstack.h:267
KIBIS_COMPONENT * comp
KIBIS_PIN * pin
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:90
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:80
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683