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