You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1187 lines
37 KiB

  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 <jzzhuang666@gmail.com>.
  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. #include <base_units.h>
  21. #include <board_stackup_manager/stackup_predefined_prms.h>
  22. #include <build_version.h>
  23. #include <callback_gal.h>
  24. #include <connectivity/connectivity_data.h>
  25. #include <connectivity/connectivity_algo.h>
  26. #include <convert_basic_shapes_to_polygon.h>
  27. #include <font/font.h>
  28. #include <footprint.h>
  29. #include <hash_eda.h>
  30. #include <pad.h>
  31. #include <pcb_dimension.h>
  32. #include <pcb_shape.h>
  33. #include <pcb_text.h>
  34. #include <pcb_textbox.h>
  35. #include <pcb_track.h>
  36. #include <pcbnew_settings.h>
  37. #include <board_design_settings.h>
  38. #include <pgm_base.h>
  39. #include <progress_reporter.h>
  40. #include <settings/settings_manager.h>
  41. #include <wx_fstream_progress.h>
  42. #include <geometry/shape_circle.h>
  43. #include <geometry/shape_line_chain.h>
  44. #include <geometry/shape_poly_set.h>
  45. #include <geometry/shape_segment.h>
  46. #include <wx/log.h>
  47. #include <wx/numformatter.h>
  48. #include <wx/mstream.h>
  49. #include "odb_attribute.h"
  50. #include "odb_entity.h"
  51. #include "odb_defines.h"
  52. #include "odb_feature.h"
  53. #include "odb_util.h"
  54. #include "pcb_io_odbpp.h"
  55. bool ODB_ENTITY_BASE::CreateDirectoryTree( ODB_TREE_WRITER& writer )
  56. {
  57. try
  58. {
  59. writer.CreateEntityDirectory( writer.GetRootPath(), GetEntityName() );
  60. return true;
  61. }
  62. catch( const std::exception& e )
  63. {
  64. std::cerr << e.what() << std::endl;
  65. return false;
  66. }
  67. }
  68. ODB_MISC_ENTITY::ODB_MISC_ENTITY()
  69. {
  70. m_info = { { wxS( ODB_JOB_NAME ), wxS( "job" ) },
  71. { wxS( ODB_UNITS ), PCB_IO_ODBPP::m_unitsStr },
  72. { wxS( "ODB_VERSION_MAJOR" ), wxS( "8" ) },
  73. { wxS( "ODB_VERSION_MINOR" ), wxS( "1" ) },
  74. { wxS( "ODB_SOURCE" ), wxS( "KiCad EDA" ) },
  75. { wxS( "CREATION_DATE" ), wxDateTime::Now().Format( "%Y%m%d.%H%M%S" ) },
  76. { wxS( "SAVE_DATE" ), wxDateTime::Now().Format( "%Y%m%d.%H%M%S" ) },
  77. { wxS( "SAVE_APP" ), wxString::Format( wxS( "KiCad EDA %s" ), GetBuildVersion() ) } };
  78. }
  79. void ODB_MISC_ENTITY::GenerateFiles( ODB_TREE_WRITER& writer )
  80. {
  81. auto fileproxy = writer.CreateFileProxy( "info" );
  82. ODB_TEXT_WRITER twriter( fileproxy.GetStream() );
  83. for( auto& info : m_info )
  84. {
  85. twriter.WriteEquationLine( info.first, info.second );
  86. }
  87. }
  88. void ODB_MATRIX_ENTITY::AddStep( const wxString& aStepName )
  89. {
  90. m_matrixSteps.emplace( aStepName.Upper(), m_col++ );
  91. }
  92. void ODB_MATRIX_ENTITY::InitEntityData()
  93. {
  94. AddStep( "PCB" );
  95. InitMatrixLayerData();
  96. }
  97. void ODB_MATRIX_ENTITY::InitMatrixLayerData()
  98. {
  99. BOARD_DESIGN_SETTINGS& dsnSettings = m_board->GetDesignSettings();
  100. BOARD_STACKUP& stackup = dsnSettings.GetStackupDescriptor();
  101. stackup.SynchronizeWithBoard( &dsnSettings );
  102. std::vector<BOARD_STACKUP_ITEM*> layers = stackup.GetList();
  103. std::set<PCB_LAYER_ID> added_layers;
  104. AddCOMPMatrixLayer( F_Cu );
  105. for( int i = 0; i < stackup.GetCount(); i++ )
  106. {
  107. BOARD_STACKUP_ITEM* stackup_item = layers.at( i );
  108. for( int sublayer_id = 0; sublayer_id < stackup_item->GetSublayersCount(); sublayer_id++ )
  109. {
  110. wxString ly_name = stackup_item->GetLayerName();
  111. if( ly_name.IsEmpty() )
  112. {
  113. if( IsValidLayer( stackup_item->GetBrdLayerId() ) )
  114. ly_name = m_board->GetLayerName( stackup_item->GetBrdLayerId() );
  115. if( ly_name.IsEmpty() && stackup_item->GetType() == BS_ITEM_TYPE_DIELECTRIC )
  116. ly_name = wxString::Format( "DIELECTRIC_%d",
  117. stackup_item->GetDielectricLayerId() );
  118. }
  119. MATRIX_LAYER matrix( m_row++, ly_name );
  120. if( stackup_item->GetType() == BS_ITEM_TYPE_DIELECTRIC )
  121. {
  122. if( stackup_item->GetTypeName() == KEY_CORE )
  123. matrix.m_diType.emplace( ODB_DIELECTRIC_TYPE::CORE );
  124. else
  125. matrix.m_diType.emplace( ODB_DIELECTRIC_TYPE::PREPREG );
  126. matrix.m_type = ODB_TYPE::DIELECTRIC;
  127. matrix.m_context = ODB_CONTEXT::BOARD;
  128. matrix.m_polarity = ODB_POLARITY::POSITIVE;
  129. m_matrixLayers.push_back( matrix );
  130. m_plugin->GetLayerNameList().emplace_back(
  131. std::make_pair( PCB_LAYER_ID::UNDEFINED_LAYER, matrix.m_layerName ) );
  132. continue;
  133. }
  134. else
  135. {
  136. added_layers.insert( stackup_item->GetBrdLayerId() );
  137. AddMatrixLayerField( matrix, stackup_item->GetBrdLayerId() );
  138. }
  139. }
  140. }
  141. for( PCB_LAYER_ID layer : m_board->GetEnabledLayers().Seq() )
  142. {
  143. if( added_layers.find( layer ) != added_layers.end() )
  144. continue;
  145. MATRIX_LAYER matrix( m_row++, m_board->GetLayerName( layer ) );
  146. added_layers.insert( layer );
  147. AddMatrixLayerField( matrix, layer );
  148. }
  149. AddDrillMatrixLayer();
  150. AddAuxilliaryMatrixLayer();
  151. AddCOMPMatrixLayer( B_Cu );
  152. }
  153. void ODB_MATRIX_ENTITY::AddMatrixLayerField( MATRIX_LAYER& aMLayer, PCB_LAYER_ID aLayer )
  154. {
  155. aMLayer.m_polarity = ODB_POLARITY::POSITIVE;
  156. aMLayer.m_context = ODB_CONTEXT::BOARD;
  157. switch( aLayer )
  158. {
  159. case F_Paste:
  160. case B_Paste: aMLayer.m_type = ODB_TYPE::SOLDER_PASTE; break;
  161. case F_SilkS:
  162. case B_SilkS: aMLayer.m_type = ODB_TYPE::SILK_SCREEN; break;
  163. case F_Mask:
  164. case B_Mask: aMLayer.m_type = ODB_TYPE::SOLDER_MASK; break;
  165. case B_CrtYd:
  166. case F_CrtYd:
  167. case Edge_Cuts:
  168. case B_Fab:
  169. case F_Fab:
  170. case F_Adhes:
  171. case B_Adhes:
  172. case Dwgs_User:
  173. case Cmts_User:
  174. case Eco1_User:
  175. case Eco2_User:
  176. case Margin:
  177. case User_1:
  178. case User_2:
  179. case User_3:
  180. case User_4:
  181. case User_5:
  182. case User_6:
  183. case User_7:
  184. case User_8:
  185. case User_9:
  186. case User_10:
  187. case User_11:
  188. case User_12:
  189. case User_13:
  190. case User_14:
  191. case User_15:
  192. case User_16:
  193. case User_17:
  194. case User_18:
  195. case User_19:
  196. case User_20:
  197. case User_21:
  198. case User_22:
  199. case User_23:
  200. case User_24:
  201. case User_25:
  202. case User_26:
  203. case User_27:
  204. case User_28:
  205. case User_29:
  206. case User_30:
  207. case User_31:
  208. case User_32:
  209. case User_33:
  210. case User_34:
  211. case User_35:
  212. case User_36:
  213. case User_37:
  214. case User_38:
  215. case User_39:
  216. case User_40:
  217. case User_41:
  218. case User_42:
  219. case User_43:
  220. case User_44:
  221. case User_45:
  222. aMLayer.m_context = ODB_CONTEXT::MISC;
  223. aMLayer.m_type = ODB_TYPE::DOCUMENT;
  224. break;
  225. default:
  226. if( IsCopperLayer( aLayer ) )
  227. {
  228. aMLayer.m_type = ODB_TYPE::SIGNAL;
  229. }
  230. else
  231. {
  232. // Do not handle other layers :
  233. aMLayer.m_type = ODB_TYPE::UNDEFINED;
  234. m_row--;
  235. }
  236. break;
  237. }
  238. if( aMLayer.m_type != ODB_TYPE::UNDEFINED )
  239. {
  240. m_matrixLayers.push_back( aMLayer );
  241. m_plugin->GetLayerNameList().emplace_back( std::make_pair( aLayer, aMLayer.m_layerName ) );
  242. }
  243. }
  244. void ODB_MATRIX_ENTITY::AddDrillMatrixLayer()
  245. {
  246. std::map<std::pair<PCB_LAYER_ID, PCB_LAYER_ID>, std::vector<BOARD_ITEM*>>& drill_layers =
  247. m_plugin->GetDrillLayerItemsMap();
  248. std::map<std::pair<PCB_LAYER_ID, PCB_LAYER_ID>, std::vector<BOARD_ITEM*>>& slot_holes =
  249. m_plugin->GetSlotHolesMap();
  250. bool has_pth_layer = false;
  251. bool has_npth_layer = false;
  252. for( BOARD_ITEM* item : m_board->Tracks() )
  253. {
  254. if( item->Type() == PCB_VIA_T )
  255. {
  256. PCB_VIA* via = static_cast<PCB_VIA*>( item );
  257. drill_layers[std::make_pair( via->TopLayer(), via->BottomLayer() )].push_back( via );
  258. }
  259. }
  260. for( FOOTPRINT* fp : m_board->Footprints() )
  261. {
  262. // std::shared_ptr<FOOTPRINT> fp( static_cast<FOOTPRINT*>( it_fp->Clone() ) );
  263. if( fp->IsFlipped() )
  264. {
  265. m_hasBotComp = true;
  266. }
  267. for( PAD* pad : fp->Pads() )
  268. {
  269. if( !has_pth_layer && pad->GetAttribute() == PAD_ATTRIB::PTH )
  270. has_pth_layer = true;
  271. if( !has_npth_layer && pad->GetAttribute() == PAD_ATTRIB::NPTH )
  272. has_npth_layer = true;
  273. if( pad->HasHole() && pad->GetDrillSizeX() != pad->GetDrillSizeY() )
  274. slot_holes[std::make_pair( F_Cu, B_Cu )].push_back( pad );
  275. else if( pad->HasHole() )
  276. drill_layers[std::make_pair( F_Cu, B_Cu )].push_back( pad );
  277. }
  278. // m_plugin->GetLoadedFootprintList().push_back( std::move( fp ) );
  279. }
  280. auto InitDrillMatrix =
  281. [&]( const wxString& aHasPlated, std::pair<PCB_LAYER_ID, PCB_LAYER_ID> aLayerPair )
  282. {
  283. wxString dLayerName = wxString::Format( "drill_%s_%s-%s", aHasPlated,
  284. m_board->GetLayerName( aLayerPair.first ),
  285. m_board->GetLayerName( aLayerPair.second ) );
  286. MATRIX_LAYER matrix( m_row++, dLayerName );
  287. matrix.m_type = ODB_TYPE::DRILL;
  288. matrix.m_context = ODB_CONTEXT::BOARD;
  289. matrix.m_polarity = ODB_POLARITY::POSITIVE;
  290. matrix.m_span.emplace( std::make_pair(
  291. ODB::GenLegalEntityName( m_board->GetLayerName( aLayerPair.first ) ),
  292. ODB::GenLegalEntityName( m_board->GetLayerName( aLayerPair.second ) ) ) );
  293. m_matrixLayers.push_back( matrix );
  294. m_plugin->GetLayerNameList().emplace_back(
  295. std::make_pair( PCB_LAYER_ID::UNDEFINED_LAYER, matrix.m_layerName ) );
  296. };
  297. if( has_npth_layer )
  298. InitDrillMatrix( "non-plated", std::make_pair( F_Cu, B_Cu ) );
  299. // at least one non plated hole is present.
  300. if( has_pth_layer && drill_layers.find( std::make_pair( F_Cu, B_Cu ) ) == drill_layers.end() )
  301. InitDrillMatrix( "plated", std::make_pair( F_Cu, B_Cu ) );
  302. // there is no circular plated dril hole present.
  303. for( const auto& [layer_pair, vec] : drill_layers )
  304. {
  305. InitDrillMatrix( "plated", layer_pair );
  306. }
  307. }
  308. void ODB_MATRIX_ENTITY::AddCOMPMatrixLayer( PCB_LAYER_ID aCompSide )
  309. {
  310. MATRIX_LAYER matrix( m_row++, "COMP_+_TOP" );
  311. matrix.m_type = ODB_TYPE::COMPONENT;
  312. matrix.m_context = ODB_CONTEXT::BOARD;
  313. if( aCompSide == F_Cu )
  314. {
  315. m_matrixLayers.push_back( matrix );
  316. m_plugin->GetLayerNameList().emplace_back(
  317. std::make_pair( PCB_LAYER_ID::UNDEFINED_LAYER, matrix.m_layerName ) );
  318. }
  319. if( aCompSide == B_Cu && m_hasBotComp )
  320. {
  321. matrix.m_layerName = ODB::GenLegalEntityName( "COMP_+_BOT" );
  322. m_matrixLayers.push_back( matrix );
  323. m_plugin->GetLayerNameList().emplace_back(
  324. std::make_pair( PCB_LAYER_ID::UNDEFINED_LAYER, matrix.m_layerName ) );
  325. }
  326. }
  327. void ODB_MATRIX_ENTITY::AddAuxilliaryMatrixLayer()
  328. {
  329. auto& auxilliary_layers = m_plugin->GetAuxilliaryLayerItemsMap();
  330. for( BOARD_ITEM* item : m_board->Tracks() )
  331. {
  332. if( item->Type() == PCB_VIA_T )
  333. {
  334. PCB_VIA* via = static_cast<PCB_VIA*>( item );
  335. if( via->Padstack().IsFilled().value_or( false ) )
  336. {
  337. auxilliary_layers[std::make_tuple( ODB_AUX_LAYER_TYPE::FILLING, via->TopLayer(),
  338. via->BottomLayer() )]
  339. .push_back( via );
  340. }
  341. if( via->Padstack().IsCapped().value_or( false ) )
  342. {
  343. auxilliary_layers[std::make_tuple( ODB_AUX_LAYER_TYPE::CAPPING, via->TopLayer(),
  344. via->BottomLayer() )]
  345. .push_back( via );
  346. }
  347. for( PCB_LAYER_ID layer : { via->TopLayer(), via->BottomLayer() } )
  348. {
  349. if( via->Padstack().IsPlugged( layer ).value_or( false ) )
  350. {
  351. auxilliary_layers[std::make_tuple( ODB_AUX_LAYER_TYPE::PLUGGING, layer,
  352. PCB_LAYER_ID::UNDEFINED_LAYER )]
  353. .push_back( via );
  354. }
  355. if( via->Padstack().IsCovered( layer ).value_or( false ) )
  356. {
  357. auxilliary_layers[std::make_tuple( ODB_AUX_LAYER_TYPE::COVERING, layer,
  358. PCB_LAYER_ID::UNDEFINED_LAYER )]
  359. .push_back( via );
  360. }
  361. if( via->Padstack().IsTented( layer ).value_or( false ) )
  362. {
  363. auxilliary_layers[std::make_tuple( ODB_AUX_LAYER_TYPE::TENTING, layer,
  364. PCB_LAYER_ID::UNDEFINED_LAYER )]
  365. .push_back( via );
  366. }
  367. }
  368. }
  369. }
  370. auto InitAuxMatrix =
  371. [&]( std::tuple<ODB_AUX_LAYER_TYPE, PCB_LAYER_ID, PCB_LAYER_ID> aLayerPair )
  372. {
  373. wxString featureName = "";
  374. switch( std::get<0>( aLayerPair ) )
  375. {
  376. case ODB_AUX_LAYER_TYPE::TENTING: featureName = "tenting"; break;
  377. case ODB_AUX_LAYER_TYPE::COVERING: featureName = "covering"; break;
  378. case ODB_AUX_LAYER_TYPE::PLUGGING: featureName = "plugging"; break;
  379. case ODB_AUX_LAYER_TYPE::FILLING: featureName = "filling"; break;
  380. case ODB_AUX_LAYER_TYPE::CAPPING: featureName = "capping"; break;
  381. default: return;
  382. }
  383. wxString dLayerName;
  384. if( std::get<2>( aLayerPair ) != PCB_LAYER_ID::UNDEFINED_LAYER )
  385. {
  386. dLayerName = wxString::Format( "%s_%s-%s", featureName,
  387. m_board->GetLayerName( std::get<1>( aLayerPair ) ),
  388. m_board->GetLayerName( std::get<2>( aLayerPair ) ) );
  389. }
  390. else
  391. {
  392. if( IsFrontLayer( std::get<1>( aLayerPair ) ) )
  393. dLayerName = wxString::Format( "%s_front", featureName );
  394. else if( IsBackLayer( std::get<1>( aLayerPair ) ) )
  395. dLayerName = wxString::Format( "%s_back", featureName );
  396. else
  397. return;
  398. }
  399. MATRIX_LAYER matrix( m_row++, dLayerName );
  400. matrix.m_type = ODB_TYPE::DOCUMENT;
  401. matrix.m_context = ODB_CONTEXT::BOARD;
  402. matrix.m_polarity = ODB_POLARITY::POSITIVE;
  403. if( std::get<2>( aLayerPair ) != PCB_LAYER_ID::UNDEFINED_LAYER )
  404. {
  405. matrix.m_span.emplace( std::make_pair(
  406. ODB::GenLegalEntityName( m_board->GetLayerName( std::get<1>( aLayerPair ) ) ),
  407. ODB::GenLegalEntityName(
  408. m_board->GetLayerName( std::get<2>( aLayerPair ) ) ) ) );
  409. }
  410. m_matrixLayers.push_back( matrix );
  411. if( std::get<2>( aLayerPair ) != PCB_LAYER_ID::UNDEFINED_LAYER )
  412. {
  413. m_plugin->GetLayerNameList().emplace_back(
  414. std::make_pair( PCB_LAYER_ID::UNDEFINED_LAYER, matrix.m_layerName ) );
  415. }
  416. else
  417. {
  418. m_plugin->GetLayerNameList().emplace_back(
  419. std::make_pair( std::get<1>( aLayerPair ), matrix.m_layerName ) );
  420. }
  421. };
  422. for( const auto& [layer_pair, vec] : auxilliary_layers )
  423. {
  424. InitAuxMatrix( layer_pair );
  425. }
  426. }
  427. void ODB_MATRIX_ENTITY::GenerateFiles( ODB_TREE_WRITER& writer )
  428. {
  429. auto fileproxy = writer.CreateFileProxy( "matrix" );
  430. ODB_TEXT_WRITER twriter( fileproxy.GetStream() );
  431. for( const auto& [step_name, column] : m_matrixSteps )
  432. {
  433. const auto array_proxy = twriter.MakeArrayProxy( "STEP" );
  434. twriter.WriteEquationLine( "COL", column );
  435. twriter.WriteEquationLine( "NAME", step_name );
  436. }
  437. for( const MATRIX_LAYER& layer : m_matrixLayers )
  438. {
  439. const auto array_proxy = twriter.MakeArrayProxy( "LAYER" );
  440. twriter.WriteEquationLine( "ROW", layer.m_rowNumber );
  441. twriter.write_line_enum( "CONTEXT", layer.m_context );
  442. twriter.write_line_enum( "TYPE", layer.m_type );
  443. if( layer.m_addType.has_value() )
  444. {
  445. twriter.write_line_enum( "ADD_TYPE", layer.m_addType.value() );
  446. }
  447. twriter.WriteEquationLine( "NAME", layer.m_layerName.Upper() );
  448. twriter.WriteEquationLine( "OLD_NAME", wxEmptyString );
  449. twriter.write_line_enum( "POLARITY", layer.m_polarity );
  450. if( layer.m_diType.has_value() )
  451. {
  452. twriter.write_line_enum( "DIELECTRIC_TYPE", layer.m_diType.value() );
  453. // twriter.WriteEquationLine( "DIELECTRIC_NAME", wxEmptyString );
  454. // Can be used with DIELECTRIC_TYPE=CORE
  455. // twriter.WriteEquationLine( "CU_TOP", wxEmptyString );
  456. // twriter.WriteEquationLine( "CU_BOTTOM", wxEmptyString );
  457. }
  458. // Only applies to: soldermask, silkscreen, solderpaste and specifies the relevant cu layer
  459. // twriter.WriteEquationLine( "REF", wxEmptyString );
  460. if( layer.m_span.has_value() )
  461. {
  462. twriter.WriteEquationLine( "START_NAME", layer.m_span->first.Upper() );
  463. twriter.WriteEquationLine( "END_NAME", layer.m_span->second.Upper() );
  464. }
  465. twriter.WriteEquationLine( "COLOR", "0" );
  466. }
  467. }
  468. ODB_LAYER_ENTITY::ODB_LAYER_ENTITY( BOARD* aBoard, PCB_IO_ODBPP* aPlugin,
  469. std::map<int, std::vector<BOARD_ITEM*>>& aMap,
  470. const PCB_LAYER_ID& aLayerID, const wxString& aLayerName ) :
  471. ODB_ENTITY_BASE( aBoard, aPlugin ), m_layerItems( aMap ), m_layerID( aLayerID ),
  472. m_matrixLayerName( aLayerName )
  473. {
  474. m_featuresMgr = std::make_unique<FEATURES_MANAGER>( aBoard, aPlugin, aLayerName );
  475. }
  476. void ODB_LAYER_ENTITY::InitEntityData()
  477. {
  478. if( m_matrixLayerName.Contains( "drill" ) )
  479. {
  480. InitDrillData();
  481. InitFeatureData();
  482. return;
  483. }
  484. if( m_matrixLayerName.Contains( "filling" ) || m_matrixLayerName.Contains( "capping" )
  485. || m_matrixLayerName.Contains( "covering" ) || m_matrixLayerName.Contains( "plugging" )
  486. || m_matrixLayerName.Contains( "tenting" ) )
  487. {
  488. InitAuxilliaryData();
  489. InitFeatureData();
  490. return;
  491. }
  492. if( m_layerID != PCB_LAYER_ID::UNDEFINED_LAYER )
  493. {
  494. InitFeatureData();
  495. }
  496. }
  497. void ODB_LAYER_ENTITY::InitFeatureData()
  498. {
  499. if( m_layerItems.empty() )
  500. return;
  501. const NETINFO_LIST& nets = m_board->GetNetInfo();
  502. for( const NETINFO_ITEM* net : nets )
  503. {
  504. std::vector<BOARD_ITEM*>& vec = m_layerItems[net->GetNetCode()];
  505. std::stable_sort( vec.begin(), vec.end(),
  506. []( BOARD_ITEM* a, BOARD_ITEM* b )
  507. {
  508. if( a->GetParentFootprint() == b->GetParentFootprint() )
  509. return a->Type() < b->Type();
  510. return a->GetParentFootprint() < b->GetParentFootprint();
  511. } );
  512. if( vec.empty() )
  513. continue;
  514. m_featuresMgr->InitFeatureList( m_layerID, vec );
  515. }
  516. }
  517. ODB_COMPONENT& ODB_LAYER_ENTITY::InitComponentData( const FOOTPRINT* aFp,
  518. const EDA_DATA::PACKAGE& aPkg )
  519. {
  520. if( m_matrixLayerName == "COMP_+_BOT" )
  521. {
  522. if( !m_compBot.has_value() )
  523. {
  524. m_compBot.emplace();
  525. }
  526. return m_compBot.value().AddComponent( aFp, aPkg );
  527. }
  528. else
  529. {
  530. if( !m_compTop.has_value() )
  531. {
  532. m_compTop.emplace();
  533. }
  534. return m_compTop.value().AddComponent( aFp, aPkg );
  535. }
  536. }
  537. void ODB_LAYER_ENTITY::InitDrillData()
  538. {
  539. std::map<std::pair<PCB_LAYER_ID, PCB_LAYER_ID>, std::vector<BOARD_ITEM*>>& drill_layers =
  540. m_plugin->GetDrillLayerItemsMap();
  541. std::map<std::pair<PCB_LAYER_ID, PCB_LAYER_ID>, std::vector<BOARD_ITEM*>>& slot_holes =
  542. m_plugin->GetSlotHolesMap();
  543. if( !m_layerItems.empty() )
  544. {
  545. m_layerItems.clear();
  546. }
  547. m_tools.emplace( PCB_IO_ODBPP::m_unitsStr );
  548. bool is_npth_layer = false;
  549. wxString plated_name = "plated";
  550. if( m_matrixLayerName.Contains( "non-plated" ) )
  551. {
  552. is_npth_layer = true;
  553. plated_name = "non-plated";
  554. }
  555. for( const auto& [layer_pair, vec] : slot_holes )
  556. {
  557. wxString dLayerName = wxString::Format( "drill_%s_%s-%s", plated_name,
  558. m_board->GetLayerName( layer_pair.first ),
  559. m_board->GetLayerName( layer_pair.second ) );
  560. if( ODB::GenLegalEntityName( dLayerName ) == m_matrixLayerName )
  561. {
  562. for( BOARD_ITEM* item : vec )
  563. {
  564. if( item->Type() == PCB_PAD_T )
  565. {
  566. PAD* pad = static_cast<PAD*>( item );
  567. if( ( is_npth_layer && pad->GetAttribute() == PAD_ATTRIB::PTH )
  568. || ( !is_npth_layer && pad->GetAttribute() == PAD_ATTRIB::NPTH ) )
  569. {
  570. continue;
  571. }
  572. m_tools.value().AddDrillTools(
  573. pad->GetAttribute() == PAD_ATTRIB::PTH ? "PLATED" : "NON_PLATED",
  574. ODB::SymDouble2String(
  575. std::min( pad->GetDrillSizeX(), pad->GetDrillSizeY() ) ) );
  576. // for drill features
  577. m_layerItems[pad->GetNetCode()].push_back( item );
  578. }
  579. }
  580. break;
  581. }
  582. }
  583. for( const auto& [layer_pair, vec] : drill_layers )
  584. {
  585. wxString dLayerName = wxString::Format( "drill_%s_%s-%s", plated_name,
  586. m_board->GetLayerName( layer_pair.first ),
  587. m_board->GetLayerName( layer_pair.second ) );
  588. if( ODB::GenLegalEntityName( dLayerName ) == m_matrixLayerName )
  589. {
  590. for( BOARD_ITEM* item : vec )
  591. {
  592. if( item->Type() == PCB_VIA_T && !is_npth_layer )
  593. {
  594. PCB_VIA* via = static_cast<PCB_VIA*>( item );
  595. m_tools.value().AddDrillTools( "VIA",
  596. ODB::SymDouble2String( via->GetDrillValue() ) );
  597. // for drill features
  598. m_layerItems[via->GetNetCode()].push_back( item );
  599. }
  600. else if( item->Type() == PCB_PAD_T )
  601. {
  602. PAD* pad = static_cast<PAD*>( item );
  603. if( ( is_npth_layer && pad->GetAttribute() == PAD_ATTRIB::PTH )
  604. || ( !is_npth_layer && pad->GetAttribute() == PAD_ATTRIB::NPTH ) )
  605. {
  606. continue;
  607. }
  608. m_tools.value().AddDrillTools(
  609. pad->GetAttribute() == PAD_ATTRIB::PTH ? "PLATED" : "NON_PLATED",
  610. ODB::SymDouble2String( pad->GetDrillSizeX() ) );
  611. // for drill features
  612. m_layerItems[pad->GetNetCode()].push_back( item );
  613. }
  614. }
  615. break;
  616. }
  617. }
  618. }
  619. void ODB_LAYER_ENTITY::InitAuxilliaryData()
  620. {
  621. auto& auxilliary_layers = m_plugin->GetAuxilliaryLayerItemsMap();
  622. if( !m_layerItems.empty() )
  623. {
  624. m_layerItems.clear();
  625. }
  626. for( const auto& [layer_pair, vec] : auxilliary_layers )
  627. {
  628. wxString featureName = "";
  629. switch( std::get<0>( layer_pair ) )
  630. {
  631. case ODB_AUX_LAYER_TYPE::TENTING: featureName = "tenting"; break;
  632. case ODB_AUX_LAYER_TYPE::COVERING: featureName = "covering"; break;
  633. case ODB_AUX_LAYER_TYPE::PLUGGING: featureName = "plugging"; break;
  634. case ODB_AUX_LAYER_TYPE::FILLING: featureName = "filling"; break;
  635. case ODB_AUX_LAYER_TYPE::CAPPING: featureName = "capping"; break;
  636. default: return;
  637. }
  638. wxString dLayerName;
  639. bool drill_value = false;
  640. if( std::get<2>( layer_pair ) != PCB_LAYER_ID::UNDEFINED_LAYER )
  641. {
  642. drill_value = true;
  643. dLayerName = wxString::Format( "%s_%s-%s", featureName,
  644. m_board->GetLayerName( std::get<1>( layer_pair ) ),
  645. m_board->GetLayerName( std::get<2>( layer_pair ) ) );
  646. }
  647. else
  648. {
  649. if( IsFrontLayer( std::get<1>( layer_pair ) ) )
  650. dLayerName = wxString::Format( "%s_front", featureName );
  651. else if( IsBackLayer( std::get<1>( layer_pair ) ) )
  652. dLayerName = wxString::Format( "%s_back", featureName );
  653. else
  654. return;
  655. }
  656. if( ODB::GenLegalEntityName( dLayerName ) == m_matrixLayerName )
  657. {
  658. for( BOARD_ITEM* item : vec )
  659. {
  660. if( item->Type() == PCB_VIA_T )
  661. {
  662. PCB_VIA* via = static_cast<PCB_VIA*>( item );
  663. m_layerItems[via->GetNetCode()].push_back( item );
  664. }
  665. }
  666. break;
  667. }
  668. }
  669. }
  670. void ODB_STEP_ENTITY::InitEntityData()
  671. {
  672. MakeLayerEntity();
  673. InitEdaData();
  674. // Init Layer Entity Data
  675. for( const auto& [layerName, layer_entity_ptr] : m_layerEntityMap )
  676. {
  677. layer_entity_ptr->InitEntityData();
  678. }
  679. }
  680. void ODB_LAYER_ENTITY::GenerateFiles( ODB_TREE_WRITER& writer )
  681. {
  682. GenAttrList( writer );
  683. GenFeatures( writer );
  684. if( m_compTop.has_value() || m_compBot.has_value() )
  685. {
  686. GenComponents( writer );
  687. }
  688. if( m_tools.has_value() )
  689. {
  690. GenTools( writer );
  691. }
  692. }
  693. void ODB_LAYER_ENTITY::GenComponents( ODB_TREE_WRITER& writer )
  694. {
  695. auto fileproxy = writer.CreateFileProxy( "components" );
  696. if( m_compTop.has_value() )
  697. {
  698. m_compTop->Write( fileproxy.GetStream() );
  699. }
  700. else if( m_compBot.has_value() )
  701. {
  702. m_compBot->Write( fileproxy.GetStream() );
  703. }
  704. }
  705. void ODB_LAYER_ENTITY::GenFeatures( ODB_TREE_WRITER& writer )
  706. {
  707. auto fileproxy = writer.CreateFileProxy( "features" );
  708. m_featuresMgr->GenerateFeatureFile( fileproxy.GetStream() );
  709. }
  710. void ODB_LAYER_ENTITY::GenAttrList( ODB_TREE_WRITER& writer )
  711. {
  712. auto fileproxy = writer.CreateFileProxy( "attrlist" );
  713. }
  714. void ODB_LAYER_ENTITY::GenTools( ODB_TREE_WRITER& writer )
  715. {
  716. auto fileproxy = writer.CreateFileProxy( "tools" );
  717. m_tools.value().GenerateFile( fileproxy.GetStream() );
  718. }
  719. void ODB_STEP_ENTITY::InitEdaData()
  720. {
  721. //InitPackage
  722. for( const FOOTPRINT* fp : m_board->Footprints() )
  723. {
  724. m_edaData.AddPackage( fp );
  725. }
  726. // for NET
  727. const NETINFO_LIST& nets = m_board->GetNetInfo();
  728. for( const NETINFO_ITEM* net : nets )
  729. {
  730. m_edaData.AddNET( net );
  731. }
  732. // for CMP
  733. size_t j = 0;
  734. for( const FOOTPRINT* fp : m_board->Footprints() )
  735. {
  736. wxString compName = ODB::GenLegalEntityName( "COMP_+_TOP" );
  737. if( fp->IsFlipped() )
  738. compName = ODB::GenLegalEntityName( "COMP_+_BOT" );
  739. auto iter = m_layerEntityMap.find( compName );
  740. if( iter == m_layerEntityMap.end() )
  741. {
  742. wxLogError( _( "Failed to add component data" ) );
  743. return;
  744. }
  745. // ODBPP only need unique PACKAGE in PKG record in eda/data file.
  746. // the PKG index can repeat to be ref in CMP record in component file.
  747. std::shared_ptr<FOOTPRINT> fp_pkg = m_edaData.GetEdaFootprints().at( j );
  748. ++j;
  749. const EDA_DATA::PACKAGE& eda_pkg =
  750. m_edaData.GetPackage( hash_fp_item( fp_pkg.get(), HASH_POS | REL_COORD ) );
  751. ODB_COMPONENT& comp = iter->second->InitComponentData( fp, eda_pkg );
  752. for( int i = 0; i < fp->Pads().size(); ++i )
  753. {
  754. PAD* pad = fp->Pads()[i];
  755. auto& eda_net = m_edaData.GetNet( pad->GetNetCode() );
  756. auto& subnet = eda_net.AddSubnet<EDA_DATA::SUB_NET_TOEPRINT>(
  757. &m_edaData,
  758. fp->IsFlipped() ? EDA_DATA::SUB_NET_TOEPRINT::SIDE::BOTTOM
  759. : EDA_DATA::SUB_NET_TOEPRINT::SIDE::TOP,
  760. comp.m_index, comp.m_toeprints.size() );
  761. m_plugin->GetPadSubnetMap().emplace( pad, &subnet );
  762. const std::shared_ptr<EDA_DATA::PIN> pin = eda_pkg.GetEdaPkgPin( i );
  763. const EDA_DATA::PIN& pin_ref = *pin;
  764. auto& toep = comp.m_toeprints.emplace_back( pin_ref );
  765. toep.m_net_num = eda_net.m_index;
  766. toep.m_subnet_num = subnet.m_index;
  767. toep.m_center = ODB::AddXY( pad->GetPosition() );
  768. toep.m_rot = ODB::Double2String(
  769. ( ANGLE_360 - pad->GetOrientation() ).Normalize().AsDegrees() );
  770. if( pad->IsFlipped() )
  771. toep.m_mirror = wxT( "M" );
  772. else
  773. toep.m_mirror = wxT( "N" );
  774. }
  775. }
  776. for( PCB_TRACK* track : m_board->Tracks() )
  777. {
  778. auto& eda_net = m_edaData.GetNet( track->GetNetCode() );
  779. EDA_DATA::SUB_NET* subnet = nullptr;
  780. if( track->Type() == PCB_VIA_T )
  781. subnet = &( eda_net.AddSubnet<EDA_DATA::SUB_NET_VIA>( &m_edaData ) );
  782. else
  783. subnet = &( eda_net.AddSubnet<EDA_DATA::SUB_NET_TRACE>( &m_edaData ) );
  784. m_plugin->GetViaTraceSubnetMap().emplace( track, subnet );
  785. }
  786. for( ZONE* zone : m_board->Zones() )
  787. {
  788. for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
  789. {
  790. auto& eda_net = m_edaData.GetNet( zone->GetNetCode() );
  791. auto& subnet = eda_net.AddSubnet<EDA_DATA::SUB_NET_PLANE>( &m_edaData,
  792. EDA_DATA::SUB_NET_PLANE::FILL_TYPE::SOLID,
  793. EDA_DATA::SUB_NET_PLANE::CUTOUT_TYPE::EXACT,
  794. 0 );
  795. m_plugin->GetPlaneSubnetMap().emplace( std::piecewise_construct,
  796. std::forward_as_tuple( layer, zone ),
  797. std::forward_as_tuple( &subnet ) );
  798. }
  799. }
  800. }
  801. void ODB_STEP_ENTITY::GenerateFiles( ODB_TREE_WRITER& writer )
  802. {
  803. wxString step_root = writer.GetCurrentPath();
  804. writer.CreateEntityDirectory( step_root, "layers" );
  805. GenerateLayerFiles( writer );
  806. writer.CreateEntityDirectory( step_root, "eda" );
  807. GenerateEdaFiles( writer );
  808. writer.CreateEntityDirectory( step_root, "netlists/cadnet" );
  809. GenerateNetlistsFiles( writer );
  810. writer.SetCurrentPath( step_root );
  811. GenerateProfileFile( writer );
  812. GenerateStepHeaderFile( writer );
  813. //TODO: system attributes
  814. // GenerateAttrListFile( writer );
  815. }
  816. void ODB_STEP_ENTITY::GenerateProfileFile( ODB_TREE_WRITER& writer )
  817. {
  818. auto fileproxy = writer.CreateFileProxy( "profile" );
  819. m_profile = std::make_unique<FEATURES_MANAGER>( m_board, m_plugin, wxEmptyString );
  820. SHAPE_POLY_SET board_outline;
  821. if( !m_board->GetBoardPolygonOutlines( board_outline ) )
  822. {
  823. wxLogError( "Failed to get board outline" );
  824. }
  825. if( !m_profile->AddContour( board_outline, 0 ) )
  826. {
  827. wxLogError( "Failed to add polygon to profile" );
  828. }
  829. m_profile->GenerateProfileFeatures( fileproxy.GetStream() );
  830. }
  831. void ODB_STEP_ENTITY::GenerateStepHeaderFile( ODB_TREE_WRITER& writer )
  832. {
  833. auto fileproxy = writer.CreateFileProxy( "stephdr" );
  834. m_stephdr = {
  835. { ODB_UNITS, PCB_IO_ODBPP::m_unitsStr },
  836. { "X_DATUM", "0" },
  837. { "Y_DATUM", "0" },
  838. { "X_ORIGIN", "0" },
  839. { "Y_ORIGIN", "0" },
  840. { "TOP_ACTIVE", "0" },
  841. { "BOTTOM_ACTIVE", "0" },
  842. { "RIGHT_ACTIVE", "0" },
  843. { "LEFT_ACTIVE", "0" },
  844. { "AFFECTING_BOM", "" },
  845. { "AFFECTING_BOM_CHANGED", "0" },
  846. };
  847. ODB_TEXT_WRITER twriter( fileproxy.GetStream() );
  848. for( const auto& [key, value] : m_stephdr )
  849. {
  850. twriter.WriteEquationLine( key, value );
  851. }
  852. }
  853. void ODB_STEP_ENTITY::GenerateLayerFiles( ODB_TREE_WRITER& writer )
  854. {
  855. wxString layers_root = writer.GetCurrentPath();
  856. for( auto& [layerName, layerEntity] : m_layerEntityMap )
  857. {
  858. writer.CreateEntityDirectory( layers_root, layerName );
  859. layerEntity->GenerateFiles( writer );
  860. }
  861. }
  862. void ODB_STEP_ENTITY::GenerateEdaFiles( ODB_TREE_WRITER& writer )
  863. {
  864. auto fileproxy = writer.CreateFileProxy( "data" );
  865. m_edaData.Write( fileproxy.GetStream() );
  866. }
  867. void ODB_STEP_ENTITY::GenerateNetlistsFiles( ODB_TREE_WRITER& writer )
  868. {
  869. auto fileproxy = writer.CreateFileProxy( "netlist" );
  870. m_netlist.Write( fileproxy.GetStream() );
  871. }
  872. bool ODB_STEP_ENTITY::CreateDirectoryTree( ODB_TREE_WRITER& writer )
  873. {
  874. try
  875. {
  876. writer.CreateEntityDirectory( writer.GetRootPath(), "steps" );
  877. writer.CreateEntityDirectory( writer.GetCurrentPath(), GetEntityName() );
  878. return true;
  879. }
  880. catch( const std::exception& e )
  881. {
  882. std::cerr << e.what() << std::endl;
  883. return false;
  884. }
  885. }
  886. void ODB_STEP_ENTITY::MakeLayerEntity()
  887. {
  888. LSET layers = m_board->GetEnabledLayers();
  889. const NETINFO_LIST& nets = m_board->GetNetInfo();
  890. // To avoid the overhead of repeatedly cycling through the layers and nets,
  891. // we pre-sort the board items into a map of layer -> net -> items
  892. std::map<PCB_LAYER_ID, std::map<int, std::vector<BOARD_ITEM*>>>& elements = m_plugin->GetLayerElementsMap();
  893. std::for_each( m_board->Tracks().begin(), m_board->Tracks().end(),
  894. [&layers, &elements]( PCB_TRACK* aTrack )
  895. {
  896. if( aTrack->Type() == PCB_VIA_T )
  897. {
  898. PCB_VIA* via = static_cast<PCB_VIA*>( aTrack );
  899. for( PCB_LAYER_ID layer : layers )
  900. {
  901. if( via->FlashLayer( layer ) )
  902. elements[layer][via->GetNetCode()].push_back( via );
  903. }
  904. }
  905. else
  906. {
  907. elements[aTrack->GetLayer()][aTrack->GetNetCode()].push_back( aTrack );
  908. }
  909. } );
  910. std::for_each( m_board->Zones().begin(), m_board->Zones().end(),
  911. [&elements]( ZONE* zone )
  912. {
  913. for( PCB_LAYER_ID layer : zone->GetLayerSet() )
  914. elements[layer][zone->GetNetCode()].push_back( zone );
  915. } );
  916. for( BOARD_ITEM* item : m_board->Drawings() )
  917. {
  918. if( BOARD_CONNECTED_ITEM* conn_it = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
  919. elements[conn_it->GetLayer()][conn_it->GetNetCode()].push_back( conn_it );
  920. else
  921. elements[item->GetLayer()][0].push_back( item );
  922. }
  923. for( FOOTPRINT* fp : m_board->Footprints() )
  924. {
  925. for( PCB_FIELD* field : fp->GetFields() )
  926. elements[field->GetLayer()][0].push_back( field );
  927. for( BOARD_ITEM* item : fp->GraphicalItems() )
  928. elements[item->GetLayer()][0].push_back( item );
  929. for( PAD* pad : fp->Pads() )
  930. {
  931. VECTOR2I margin;
  932. for( PCB_LAYER_ID layer : pad->GetLayerSet() )
  933. {
  934. bool onCopperLayer = LSET::AllCuMask().test( layer );
  935. bool onSolderMaskLayer = LSET( { F_Mask, B_Mask } ).test( layer );
  936. bool onSolderPasteLayer = LSET( { F_Paste, B_Paste } ).test( layer );
  937. if( onSolderMaskLayer )
  938. margin.x = margin.y = pad->GetSolderMaskExpansion( PADSTACK::ALL_LAYERS );
  939. if( onSolderPasteLayer )
  940. margin = pad->GetSolderPasteMargin( PADSTACK::ALL_LAYERS );
  941. VECTOR2I padPlotsSize = pad->GetSize( PADSTACK::ALL_LAYERS ) + margin * 2;
  942. if( onCopperLayer && !pad->IsOnCopperLayer() )
  943. continue;
  944. if( onCopperLayer && !pad->FlashLayer( layer ) )
  945. continue;
  946. if( pad->GetShape( PADSTACK::ALL_LAYERS ) != PAD_SHAPE::CUSTOM
  947. && ( padPlotsSize.x <= 0 || padPlotsSize.y <= 0 ) )
  948. {
  949. continue;
  950. }
  951. elements[layer][pad->GetNetCode()].push_back( pad );
  952. }
  953. }
  954. }
  955. for( const auto& [layerID, layerName] : m_plugin->GetLayerNameList() )
  956. {
  957. std::shared_ptr<ODB_LAYER_ENTITY> layer_entity_ptr = std::make_shared<ODB_LAYER_ENTITY>(
  958. m_board, m_plugin, elements[layerID], layerID, layerName );
  959. m_layerEntityMap.emplace( layerName, layer_entity_ptr );
  960. }
  961. }