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