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