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.

3047 lines
103 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2020 Thomas Pointhuber <thomas.pointhuber@gmx.at>
  5. * Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU 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, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #include <memory>
  25. #include "altium_parser_sch.h"
  26. #include "sch_shape.h"
  27. #include <plugins/altium/altium_parser.h>
  28. #include <plugins/altium/altium_parser_utils.h>
  29. #include <sch_plugins/altium/sch_altium_plugin.h>
  30. #include <schematic.h>
  31. #include <lib_shape.h>
  32. #include <lib_id.h>
  33. #include <lib_item.h>
  34. #include <lib_pin.h>
  35. #include <lib_text.h>
  36. #include <sch_bitmap.h>
  37. #include <sch_bus_entry.h>
  38. #include <sch_symbol.h>
  39. #include <sch_junction.h>
  40. #include <sch_line.h>
  41. #include <sch_no_connect.h>
  42. #include <sch_screen.h>
  43. #include <sch_label.h>
  44. #include <sch_sheet.h>
  45. #include <sch_sheet_pin.h>
  46. #include <sch_textbox.h>
  47. #include <bezier_curves.h>
  48. #include <compoundfilereader.h>
  49. #include <string_utils.h>
  50. #include <sch_edit_frame.h>
  51. #include <trigo.h>
  52. #include <wildcards_and_files_ext.h>
  53. #include <wx/mstream.h>
  54. #include <wx/log.h>
  55. #include <wx/zstream.h>
  56. #include <wx/wfstream.h>
  57. #include <trigo.h>
  58. // Harness port object itself does not contain color information about itself
  59. // It seems altium is drawing harness ports using these colors
  60. #define HARNESS_PORT_COLOR_DEFAULT_BACKGROUND COLOR4D( 0.92941176470588238, \
  61. 0.94901960784313721, \
  62. 0.98431372549019602, 1.0 )
  63. #define HARNESS_PORT_COLOR_DEFAULT_OUTLINE COLOR4D( 0.56078431372549020, \
  64. 0.61960784313725492, \
  65. 0.78823529411764703, 1.0 )
  66. static const VECTOR2I GetRelativePosition( const VECTOR2I& aPosition, const SCH_SYMBOL* aSymbol )
  67. {
  68. TRANSFORM t = aSymbol->GetTransform().InverseTransform();
  69. return t.TransformCoordinate( aPosition - aSymbol->GetPosition() );
  70. }
  71. static COLOR4D GetColorFromInt( int color )
  72. {
  73. int red = color & 0x0000FF;
  74. int green = ( color & 0x00FF00 ) >> 8;
  75. int blue = ( color & 0xFF0000 ) >> 16;
  76. return COLOR4D().FromCSSRGBA( red, green, blue, 1.0 );
  77. }
  78. static PLOT_DASH_TYPE GetPlotDashType( const ASCH_POLYLINE_LINESTYLE linestyle )
  79. {
  80. switch( linestyle )
  81. {
  82. case ASCH_POLYLINE_LINESTYLE::SOLID: return PLOT_DASH_TYPE::SOLID;
  83. case ASCH_POLYLINE_LINESTYLE::DASHED: return PLOT_DASH_TYPE::DASH;
  84. case ASCH_POLYLINE_LINESTYLE::DOTTED: return PLOT_DASH_TYPE::DOT;
  85. case ASCH_POLYLINE_LINESTYLE::DASH_DOTTED: return PLOT_DASH_TYPE::DASHDOT;
  86. default: return PLOT_DASH_TYPE::DEFAULT;
  87. }
  88. }
  89. static void SetSchShapeFillAndColor( const ASCH_SHAPE_INTERFACE& elem, SCH_SHAPE* shape )
  90. {
  91. shape->SetStroke( STROKE_PARAMS( elem.LineWidth, PLOT_DASH_TYPE::SOLID,
  92. GetColorFromInt( elem.Color ) ) );
  93. if( !elem.IsSolid )
  94. {
  95. shape->SetFillMode( FILL_T::NO_FILL );
  96. }
  97. else
  98. {
  99. shape->SetFillMode( FILL_T::FILLED_WITH_COLOR );
  100. shape->SetFillColor( GetColorFromInt( elem.AreaColor ) );
  101. }
  102. }
  103. static void SetLibShapeFillAndColor( const ASCH_SHAPE_INTERFACE& elem, LIB_SHAPE* shape )
  104. {
  105. shape->SetStroke( STROKE_PARAMS( elem.LineWidth, PLOT_DASH_TYPE::SOLID ) );
  106. if( !elem.IsSolid )
  107. {
  108. shape->SetFillMode( FILL_T::NO_FILL );
  109. }
  110. else if( elem.Color == elem.AreaColor )
  111. {
  112. shape->SetFillMode( FILL_T::FILLED_SHAPE );
  113. }
  114. else
  115. {
  116. shape->SetFillMode( FILL_T::FILLED_WITH_BG_BODYCOLOR );
  117. }
  118. }
  119. SCH_ALTIUM_PLUGIN::SCH_ALTIUM_PLUGIN()
  120. {
  121. m_rootSheet = nullptr;
  122. m_schematic = nullptr;
  123. m_harnessOwnerIndexOffset = 0;
  124. m_harnessEntryParent = 0;
  125. m_reporter = &WXLOG_REPORTER::GetInstance();
  126. }
  127. SCH_ALTIUM_PLUGIN::~SCH_ALTIUM_PLUGIN()
  128. {
  129. }
  130. const wxString SCH_ALTIUM_PLUGIN::GetName() const
  131. {
  132. return "Altium";
  133. }
  134. const wxString SCH_ALTIUM_PLUGIN::GetFileExtension() const
  135. {
  136. return "SchDoc";
  137. }
  138. const wxString SCH_ALTIUM_PLUGIN::GetLibraryFileExtension() const
  139. {
  140. return "SchLib";
  141. }
  142. int SCH_ALTIUM_PLUGIN::GetModifyHash() const
  143. {
  144. return 0;
  145. }
  146. bool SCH_ALTIUM_PLUGIN::CheckHeader( const wxString& aFileName )
  147. {
  148. // TODO
  149. return true;
  150. }
  151. wxString SCH_ALTIUM_PLUGIN::getLibName()
  152. {
  153. if( m_libName.IsEmpty() )
  154. {
  155. // Try to come up with a meaningful name
  156. m_libName = m_schematic->Prj().GetProjectName();
  157. if( m_libName.IsEmpty() )
  158. {
  159. wxFileName fn( m_rootSheet->GetFileName() );
  160. m_libName = fn.GetName();
  161. }
  162. if( m_libName.IsEmpty() )
  163. m_libName = "noname";
  164. m_libName += "-altium-import";
  165. m_libName = LIB_ID::FixIllegalChars( m_libName, true );
  166. }
  167. return m_libName;
  168. }
  169. wxFileName SCH_ALTIUM_PLUGIN::getLibFileName()
  170. {
  171. wxFileName fn( m_schematic->Prj().GetProjectPath(), getLibName(), KiCadSymbolLibFileExtension );
  172. return fn;
  173. }
  174. SCH_SHEET* SCH_ALTIUM_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchematic,
  175. SCH_SHEET* aAppendToMe, const STRING_UTF8_MAP* aProperties )
  176. {
  177. wxCHECK( !aFileName.IsEmpty() && aSchematic, nullptr );
  178. wxFileName fileName( aFileName );
  179. fileName.SetExt( KiCadSchematicFileExtension );
  180. m_schematic = aSchematic;
  181. // Delete on exception, if I own m_rootSheet, according to aAppendToMe
  182. std::unique_ptr<SCH_SHEET> deleter( aAppendToMe ? nullptr : m_rootSheet );
  183. if( aAppendToMe )
  184. {
  185. wxCHECK_MSG( aSchematic->IsValid(), nullptr, "Can't append to a schematic with no root!" );
  186. m_rootSheet = &aSchematic->Root();
  187. }
  188. else
  189. {
  190. m_rootSheet = new SCH_SHEET( aSchematic );
  191. m_rootSheet->SetFileName( fileName.GetFullPath() );
  192. aSchematic->SetRoot( m_rootSheet );
  193. SCH_SHEET_PATH sheetpath;
  194. sheetpath.push_back( m_rootSheet );
  195. // We'll update later if we find a pageNumber record for it.
  196. sheetpath.SetPageNumber( "#" );
  197. }
  198. if( !m_rootSheet->GetScreen() )
  199. {
  200. SCH_SCREEN* screen = new SCH_SCREEN( m_schematic );
  201. screen->SetFileName( aFileName );
  202. m_rootSheet->SetScreen( screen );
  203. const_cast<KIID&>( m_rootSheet->m_Uuid ) = screen->GetUuid();
  204. }
  205. SYMBOL_LIB_TABLE* libTable = m_schematic->Prj().SchSymbolLibTable();
  206. wxCHECK_MSG( libTable, nullptr, "Could not load symbol lib table." );
  207. m_pi.set( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
  208. /// @note No check is being done here to see if the existing symbol library exists so this
  209. /// will overwrite the existing one.
  210. if( !libTable->HasLibrary( getLibName() ) )
  211. {
  212. // Create a new empty symbol library.
  213. m_pi->CreateSymbolLib( getLibFileName().GetFullPath() );
  214. wxString libTableUri = "${KIPRJMOD}/" + getLibFileName().GetFullName();
  215. // Add the new library to the project symbol library table.
  216. libTable->InsertRow( new SYMBOL_LIB_TABLE_ROW( getLibName(), libTableUri,
  217. wxString( "KiCad" ) ) );
  218. // Save project symbol library table.
  219. wxFileName fn( m_schematic->Prj().GetProjectPath(),
  220. SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
  221. // So output formatter goes out of scope and closes the file before reloading.
  222. {
  223. FILE_OUTPUTFORMATTER formatter( fn.GetFullPath() );
  224. libTable->Format( &formatter, 0 );
  225. }
  226. // Reload the symbol library table.
  227. m_schematic->Prj().SetElem( PROJECT::ELEM_SYMBOL_LIB_TABLE, nullptr );
  228. m_schematic->Prj().SchSymbolLibTable();
  229. }
  230. m_sheetPath.push_back( m_rootSheet );
  231. SCH_SCREEN* rootScreen = m_rootSheet->GetScreen();
  232. wxCHECK( rootScreen, nullptr );
  233. SCH_SHEET_INSTANCE sheetInstance;
  234. sheetInstance.m_Path = m_sheetPath.Path();
  235. sheetInstance.m_PageNumber = wxT( "#" );
  236. rootScreen->m_sheetInstances.emplace_back( sheetInstance );
  237. ParseAltiumSch( aFileName );
  238. m_pi->SaveLibrary( getLibFileName().GetFullPath() );
  239. SCH_SCREENS allSheets( m_rootSheet );
  240. allSheets.UpdateSymbolLinks(); // Update all symbol library links for all sheets.
  241. allSheets.ClearEditFlags();
  242. return m_rootSheet;
  243. }
  244. SCH_SCREEN* SCH_ALTIUM_PLUGIN::getCurrentScreen()
  245. {
  246. return m_sheetPath.LastScreen();
  247. }
  248. SCH_SHEET* SCH_ALTIUM_PLUGIN::getCurrentSheet()
  249. {
  250. return m_sheetPath.Last();
  251. }
  252. void SCH_ALTIUM_PLUGIN::ParseAltiumSch( const wxString& aFileName )
  253. {
  254. ALTIUM_COMPOUND_FILE altiumSchFile( aFileName );
  255. // Load path may be different from the project path.
  256. wxFileName parentFileName = aFileName;
  257. try
  258. {
  259. ParseStorage( altiumSchFile ); // we need this before parsing the FileHeader
  260. ParseFileHeader( altiumSchFile );
  261. // Parse "Additional" because sheet is set up during "FileHeader" parsing.
  262. ParseAdditional( altiumSchFile );
  263. }
  264. catch( CFB::CFBException& exception )
  265. {
  266. THROW_IO_ERROR( exception.what() );
  267. }
  268. SCH_SCREEN* currentScreen = getCurrentScreen();
  269. wxCHECK( currentScreen, /* void */ );
  270. // Descend the sheet hierarchy.
  271. for( SCH_ITEM* item : currentScreen->Items().OfType( SCH_SHEET_T ) )
  272. {
  273. SCH_SCREEN* loadedScreen = nullptr;
  274. SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( item );
  275. wxCHECK2( sheet, continue );
  276. // The assumption is that all of the Altium schematic files will be in the same
  277. // path as the parent sheet path.
  278. wxFileName loadAltiumFileName( parentFileName.GetPath(), sheet->GetFileName() );
  279. m_rootSheet->SearchHierarchy( loadAltiumFileName.GetFullPath(), &loadedScreen );
  280. if( loadedScreen )
  281. {
  282. sheet->SetScreen( loadedScreen );
  283. // Do not need to load the sub-sheets - this has already been done.
  284. }
  285. else
  286. {
  287. sheet->SetScreen( new SCH_SCREEN( m_schematic ) );
  288. SCH_SCREEN* screen = sheet->GetScreen();
  289. sheet->SetName( loadAltiumFileName.GetName() );
  290. wxCHECK2( screen, continue );
  291. m_sheetPath.push_back( sheet );
  292. ParseAltiumSch( loadAltiumFileName.GetFullPath() );
  293. // Map the loaded Altium file to the project file.
  294. wxFileName projectFileName = loadAltiumFileName;
  295. projectFileName.SetPath( m_schematic->Prj().GetProjectPath() );
  296. projectFileName.SetExt( KiCadSchematicFileExtension );
  297. sheet->SetFileName( projectFileName.GetFullName() );
  298. screen->SetFileName( projectFileName.GetFullPath() );
  299. m_sheetPath.pop_back();
  300. }
  301. }
  302. }
  303. void SCH_ALTIUM_PLUGIN::ParseStorage( const ALTIUM_COMPOUND_FILE& aAltiumSchFile )
  304. {
  305. const CFB::COMPOUND_FILE_ENTRY* file = aAltiumSchFile.FindStream( { "Storage" } );
  306. if( file == nullptr )
  307. return;
  308. ALTIUM_PARSER reader( aAltiumSchFile, file );
  309. std::map<wxString, wxString> properties = reader.ReadProperties();
  310. wxString header = ALTIUM_PARSER::ReadString( properties, "HEADER", "" );
  311. int weight = ALTIUM_PARSER::ReadInt( properties, "WEIGHT", 0 );
  312. if( weight < 0 )
  313. THROW_IO_ERROR( "Storage weight is negative!" );
  314. for( int i = 0; i < weight; i++ )
  315. {
  316. m_altiumStorage.emplace_back( reader );
  317. }
  318. if( reader.HasParsingError() )
  319. THROW_IO_ERROR( "stream was not parsed correctly!" );
  320. // TODO pointhi: is it possible to have multiple headers in one Storage file? Otherwise
  321. // throw IO Error.
  322. if( reader.GetRemainingBytes() != 0 )
  323. {
  324. m_reporter->Report( wxString::Format( _( "Storage file not fully parsed "
  325. "(%d bytes remaining)." ),
  326. reader.GetRemainingBytes() ),
  327. RPT_SEVERITY_ERROR );
  328. }
  329. }
  330. void SCH_ALTIUM_PLUGIN::ParseAdditional( const ALTIUM_COMPOUND_FILE& aAltiumSchFile )
  331. {
  332. const CFB::COMPOUND_FILE_ENTRY* file = aAltiumSchFile.FindStream( { "Additional" } );
  333. if( file == nullptr )
  334. return;
  335. ALTIUM_PARSER reader( aAltiumSchFile, file );
  336. if( reader.GetRemainingBytes() <= 0 )
  337. {
  338. THROW_IO_ERROR( "Additional section does not contain any data" );
  339. }
  340. else
  341. {
  342. std::map<wxString, wxString> properties = reader.ReadProperties();
  343. int recordId = ALTIUM_PARSER::ReadInt( properties, "RECORD", 0 );
  344. ALTIUM_SCH_RECORD record = static_cast<ALTIUM_SCH_RECORD>( recordId );
  345. if( record != ALTIUM_SCH_RECORD::HEADER )
  346. THROW_IO_ERROR( "Header expected" );
  347. }
  348. for( int index = 0; reader.GetRemainingBytes() > 0; index++ )
  349. {
  350. std::map<wxString, wxString> properties = reader.ReadProperties();
  351. int recordId = ALTIUM_PARSER::ReadInt( properties, "RECORD", 0 );
  352. ALTIUM_SCH_RECORD record = static_cast<ALTIUM_SCH_RECORD>( recordId );
  353. // see: https://github.com/vadmium/python-altium/blob/master/format.md
  354. switch( record )
  355. {
  356. case ALTIUM_SCH_RECORD::HARNESS_CONNECTOR:
  357. ParseHarnessConnector( index, properties );
  358. break;
  359. case ALTIUM_SCH_RECORD::HARNESS_ENTRY:
  360. ParseHarnessEntry( properties );
  361. break;
  362. case ALTIUM_SCH_RECORD::HARNESS_TYPE:
  363. ParseHarnessType( properties );
  364. break;
  365. case ALTIUM_SCH_RECORD::SIGNAL_HARNESS:
  366. ParseSignalHarness( properties );
  367. break;
  368. default:
  369. m_reporter->Report( wxString::Format( _( "Unknown or unexpected record ID %d found "
  370. "inside \"Additional\" section." ),
  371. recordId ),
  372. RPT_SEVERITY_ERROR );
  373. break;
  374. }
  375. }
  376. // Handle harness Ports
  377. for( const ASCH_PORT& port : m_altiumHarnessPortsCurrentSheet )
  378. ParseHarnessPort( port );
  379. if( reader.HasParsingError() )
  380. THROW_IO_ERROR( "stream was not parsed correctly!" );
  381. if( reader.GetRemainingBytes() != 0 )
  382. THROW_IO_ERROR( "stream is not fully parsed" );
  383. }
  384. void SCH_ALTIUM_PLUGIN::ParseFileHeader( const ALTIUM_COMPOUND_FILE& aAltiumSchFile )
  385. {
  386. const CFB::COMPOUND_FILE_ENTRY* file = aAltiumSchFile.FindStream( { "FileHeader" } );
  387. if( file == nullptr )
  388. THROW_IO_ERROR( "FileHeader not found" );
  389. ALTIUM_PARSER reader( aAltiumSchFile, file );
  390. if( reader.GetRemainingBytes() <= 0 )
  391. {
  392. THROW_IO_ERROR( "FileHeader does not contain any data" );
  393. }
  394. else
  395. {
  396. std::map<wxString, wxString> properties = reader.ReadProperties();
  397. int recordId = ALTIUM_PARSER::ReadInt( properties, "RECORD", 0 );
  398. ALTIUM_SCH_RECORD record = static_cast<ALTIUM_SCH_RECORD>( recordId );
  399. if( record != ALTIUM_SCH_RECORD::HEADER )
  400. THROW_IO_ERROR( "Header expected" );
  401. }
  402. // Prepare some local variables
  403. wxCHECK( m_altiumPortsCurrentSheet.empty(), /* void */ );
  404. wxCHECK( !m_currentTitleBlock, /* void */ );
  405. m_currentTitleBlock = std::make_unique<TITLE_BLOCK>();
  406. // index is required to resolve OWNERINDEX
  407. for( int index = 0; reader.GetRemainingBytes() > 0; index++ )
  408. {
  409. std::map<wxString, wxString> properties = reader.ReadProperties();
  410. int recordId = ALTIUM_PARSER::ReadInt( properties, "RECORD", 0 );
  411. ALTIUM_SCH_RECORD record = static_cast<ALTIUM_SCH_RECORD>( recordId );
  412. // see: https://github.com/vadmium/python-altium/blob/master/format.md
  413. switch( record )
  414. {
  415. case ALTIUM_SCH_RECORD::HEADER:
  416. THROW_IO_ERROR( "Header already parsed" );
  417. case ALTIUM_SCH_RECORD::COMPONENT:
  418. ParseComponent( index, properties );
  419. break;
  420. case ALTIUM_SCH_RECORD::PIN:
  421. ParsePin( properties );
  422. break;
  423. case ALTIUM_SCH_RECORD::IEEE_SYMBOL:
  424. m_reporter->Report( _( "Record 'IEEE_SYMBOL' not handled." ),
  425. RPT_SEVERITY_INFO );
  426. break;
  427. case ALTIUM_SCH_RECORD::LABEL:
  428. ParseLabel( properties );
  429. break;
  430. case ALTIUM_SCH_RECORD::BEZIER:
  431. ParseBezier( properties );
  432. break;
  433. case ALTIUM_SCH_RECORD::POLYLINE:
  434. ParsePolyline( properties );
  435. break;
  436. case ALTIUM_SCH_RECORD::POLYGON:
  437. ParsePolygon( properties );
  438. break;
  439. case ALTIUM_SCH_RECORD::ELLIPSE:
  440. ParseEllipse( properties );
  441. break;
  442. case ALTIUM_SCH_RECORD::PIECHART:
  443. m_reporter->Report( _( "Record 'PIECHART' not handled." ),
  444. RPT_SEVERITY_INFO );
  445. break;
  446. case ALTIUM_SCH_RECORD::ROUND_RECTANGLE:
  447. ParseRoundRectangle( properties );
  448. break;
  449. case ALTIUM_SCH_RECORD::ELLIPTICAL_ARC:
  450. case ALTIUM_SCH_RECORD::ARC:
  451. ParseArc( properties );
  452. break;
  453. case ALTIUM_SCH_RECORD::LINE:
  454. ParseLine( properties );
  455. break;
  456. case ALTIUM_SCH_RECORD::RECTANGLE:
  457. ParseRectangle( properties );
  458. break;
  459. case ALTIUM_SCH_RECORD::SHEET_SYMBOL:
  460. ParseSheetSymbol( index, properties );
  461. break;
  462. case ALTIUM_SCH_RECORD::SHEET_ENTRY:
  463. ParseSheetEntry( properties );
  464. break;
  465. case ALTIUM_SCH_RECORD::POWER_PORT:
  466. ParsePowerPort( properties );
  467. break;
  468. case ALTIUM_SCH_RECORD::PORT:
  469. // Ports are parsed after the sheet was parsed
  470. // This is required because we need all electrical connection points before placing.
  471. m_altiumPortsCurrentSheet.emplace_back( properties );
  472. break;
  473. case ALTIUM_SCH_RECORD::NO_ERC:
  474. ParseNoERC( properties );
  475. break;
  476. case ALTIUM_SCH_RECORD::NET_LABEL:
  477. ParseNetLabel( properties );
  478. break;
  479. case ALTIUM_SCH_RECORD::BUS:
  480. ParseBus( properties );
  481. break;
  482. case ALTIUM_SCH_RECORD::WIRE:
  483. ParseWire( properties );
  484. break;
  485. case ALTIUM_SCH_RECORD::TEXT_FRAME:
  486. ParseTextFrame( properties );
  487. break;
  488. case ALTIUM_SCH_RECORD::JUNCTION:
  489. ParseJunction( properties );
  490. break;
  491. case ALTIUM_SCH_RECORD::IMAGE:
  492. ParseImage( properties );
  493. break;
  494. case ALTIUM_SCH_RECORD::SHEET:
  495. ParseSheet( properties );
  496. break;
  497. case ALTIUM_SCH_RECORD::SHEET_NAME:
  498. ParseSheetName( properties );
  499. break;
  500. case ALTIUM_SCH_RECORD::FILE_NAME:
  501. ParseFileName( properties );
  502. break;
  503. case ALTIUM_SCH_RECORD::DESIGNATOR:
  504. ParseDesignator( properties );
  505. break;
  506. case ALTIUM_SCH_RECORD::BUS_ENTRY:
  507. ParseBusEntry( properties );
  508. break;
  509. case ALTIUM_SCH_RECORD::TEMPLATE:
  510. break;
  511. case ALTIUM_SCH_RECORD::PARAMETER:
  512. ParseParameter( properties );
  513. break;
  514. case ALTIUM_SCH_RECORD::WARNING_SIGN:
  515. break;
  516. case ALTIUM_SCH_RECORD::IMPLEMENTATION_LIST:
  517. ParseImplementationList( index, properties );
  518. break;
  519. case ALTIUM_SCH_RECORD::IMPLEMENTATION:
  520. ParseImplementation( properties );
  521. break;
  522. case ALTIUM_SCH_RECORD::RECORD_46:
  523. break;
  524. case ALTIUM_SCH_RECORD::RECORD_47:
  525. break;
  526. case ALTIUM_SCH_RECORD::RECORD_48:
  527. break;
  528. case ALTIUM_SCH_RECORD::NOTE:
  529. ParseNote( properties );
  530. break;
  531. case ALTIUM_SCH_RECORD::COMPILE_MASK:
  532. m_reporter->Report( _( "Compile mask not currently supported." ), RPT_SEVERITY_ERROR );
  533. break;
  534. case ALTIUM_SCH_RECORD::RECORD_226:
  535. break;
  536. default:
  537. m_reporter->Report( wxString::Format( _( "Unknown or unexpected record id %d found "
  538. "inside \"FileHeader\" section." ),
  539. recordId ),
  540. RPT_SEVERITY_ERROR );
  541. break;
  542. }
  543. SCH_ALTIUM_PLUGIN::m_harnessOwnerIndexOffset = index;
  544. }
  545. if( reader.HasParsingError() )
  546. THROW_IO_ERROR( "stream was not parsed correctly!" );
  547. if( reader.GetRemainingBytes() != 0 )
  548. THROW_IO_ERROR( "stream is not fully parsed" );
  549. // assign LIB_SYMBOL -> COMPONENT
  550. for( std::pair<const int, SCH_SYMBOL*>& symbol : m_symbols )
  551. {
  552. auto libSymbolIt = m_libSymbols.find( symbol.first );
  553. if( libSymbolIt == m_libSymbols.end() )
  554. THROW_IO_ERROR( "every symbol should have a symbol attached" );
  555. m_pi->SaveSymbol( getLibFileName().GetFullPath(),
  556. new LIB_SYMBOL( *( libSymbolIt->second ) ), m_properties.get() );
  557. symbol.second->SetLibSymbol( libSymbolIt->second );
  558. }
  559. SCH_SCREEN* screen = getCurrentScreen();
  560. wxCHECK( screen, /* void */ );
  561. // Handle title blocks
  562. screen->SetTitleBlock( *m_currentTitleBlock );
  563. m_currentTitleBlock.reset();
  564. // Handle Ports
  565. for( const ASCH_PORT& port : m_altiumPortsCurrentSheet )
  566. ParsePort( port );
  567. m_altiumPortsCurrentSheet.clear();
  568. m_altiumComponents.clear();
  569. m_symbols.clear();
  570. m_libSymbols.clear();
  571. // Otherwise we cannot save the imported sheet?
  572. SCH_SHEET* sheet = getCurrentSheet();
  573. wxCHECK( sheet, /* void */ );
  574. sheet->SetModified();
  575. }
  576. bool SCH_ALTIUM_PLUGIN::IsComponentPartVisible( int aOwnerindex, int aOwnerpartdisplaymode ) const
  577. {
  578. const auto& component = m_altiumComponents.find( aOwnerindex );
  579. if( component == m_altiumComponents.end() )
  580. return false;
  581. return component->second.displaymode == aOwnerpartdisplaymode;
  582. }
  583. const ASCH_STORAGE_FILE* SCH_ALTIUM_PLUGIN::GetFileFromStorage( const wxString& aFilename ) const
  584. {
  585. const ASCH_STORAGE_FILE* nonExactMatch = nullptr;
  586. for( const ASCH_STORAGE_FILE& file : m_altiumStorage )
  587. {
  588. if( file.filename.IsSameAs( aFilename ) )
  589. return &file;
  590. if( file.filename.EndsWith( aFilename ) )
  591. nonExactMatch = &file;
  592. }
  593. return nonExactMatch;
  594. }
  595. void SCH_ALTIUM_PLUGIN::ParseComponent( int aIndex,
  596. const std::map<wxString, wxString>& aProperties )
  597. {
  598. SCH_SHEET* currentSheet = m_sheetPath.Last();
  599. wxCHECK( currentSheet, /* void */ );
  600. wxString sheetName = currentSheet->GetName();
  601. if( sheetName.IsEmpty() )
  602. sheetName = wxT( "root" );
  603. ASCH_SYMBOL altiumSymbol( aProperties );
  604. if( m_altiumComponents.count( aIndex ) )
  605. {
  606. const ASCH_SYMBOL& currentSymbol = m_altiumComponents.at( aIndex );
  607. m_reporter->Report( wxString::Format( _( "Symbol \"%s\" in sheet \"%s\" at index %d "
  608. "replaced with symbol \"%s\"." ),
  609. currentSymbol.libreference,
  610. sheetName,
  611. aIndex,
  612. altiumSymbol.libreference ),
  613. RPT_SEVERITY_ERROR );
  614. }
  615. auto pair = m_altiumComponents.insert( { aIndex, altiumSymbol } );
  616. const ASCH_SYMBOL& elem = pair.first->second;
  617. // TODO: this is a hack until we correctly apply all transformations to every element
  618. wxString name = wxString::Format( "%s_%d%s_%s",
  619. sheetName,
  620. elem.orientation,
  621. elem.isMirrored ? "_mirrored" : "",
  622. elem.libreference );
  623. LIB_ID libId = AltiumToKiCadLibID( getLibName(), name );
  624. LIB_SYMBOL* ksymbol = new LIB_SYMBOL( wxEmptyString );
  625. ksymbol->SetName( name );
  626. ksymbol->SetDescription( elem.componentdescription );
  627. ksymbol->SetLibId( libId );
  628. m_libSymbols.insert( { aIndex, ksymbol } );
  629. // each component has its own symbol for now
  630. SCH_SYMBOL* symbol = new SCH_SYMBOL();
  631. symbol->SetPosition( elem.location + m_sheetOffset );
  632. // TODO: keep it simple for now, and only set position.
  633. // component->SetOrientation( elem.orientation );
  634. symbol->SetLibId( libId );
  635. symbol->SetUnit( std::max( 0, elem.currentpartid ) );
  636. SCH_SCREEN* screen = getCurrentScreen();
  637. wxCHECK( screen, /* void */ );
  638. screen->Append( symbol );
  639. m_symbols.insert( { aIndex, symbol } );
  640. }
  641. void SCH_ALTIUM_PLUGIN::ParsePin( const std::map<wxString, wxString>& aProperties )
  642. {
  643. ASCH_PIN elem( aProperties );
  644. const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
  645. if( libSymbolIt == m_libSymbols.end() )
  646. {
  647. // TODO: e.g. can depend on Template (RECORD=39
  648. m_reporter->Report( wxString::Format( wxT( "Pin's owner (%d) not found." ),
  649. elem.ownerindex ),
  650. RPT_SEVERITY_DEBUG );
  651. return;
  652. }
  653. if( !IsComponentPartVisible( elem.ownerindex, elem.ownerpartdisplaymode ) )
  654. return;
  655. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  656. LIB_PIN* pin = new LIB_PIN( libSymbolIt->second );
  657. libSymbolIt->second->AddDrawItem( pin );
  658. pin->SetUnit( std::max( 0, elem.ownerpartid ) );
  659. pin->SetName( elem.name );
  660. pin->SetNumber( elem.designator );
  661. pin->SetLength( elem.pinlength );
  662. if( !elem.showDesignator )
  663. pin->SetNumberTextSize( 0 );
  664. if( !elem.showPinName )
  665. pin->SetNameTextSize( 0 );
  666. VECTOR2I pinLocation = elem.location; // the location given is not the connection point!
  667. switch( elem.orientation )
  668. {
  669. case ASCH_RECORD_ORIENTATION::RIGHTWARDS:
  670. pin->SetOrientation( DrawPinOrient::PIN_LEFT );
  671. pinLocation.x += elem.pinlength;
  672. break;
  673. case ASCH_RECORD_ORIENTATION::UPWARDS:
  674. pin->SetOrientation( DrawPinOrient::PIN_DOWN );
  675. pinLocation.y -= elem.pinlength;
  676. break;
  677. case ASCH_RECORD_ORIENTATION::LEFTWARDS:
  678. pin->SetOrientation( DrawPinOrient::PIN_RIGHT );
  679. pinLocation.x -= elem.pinlength;
  680. break;
  681. case ASCH_RECORD_ORIENTATION::DOWNWARDS:
  682. pin->SetOrientation( DrawPinOrient::PIN_UP );
  683. pinLocation.y += elem.pinlength;
  684. break;
  685. default:
  686. m_reporter->Report( _( "Pin has unexpected orientation." ), RPT_SEVERITY_WARNING );
  687. break;
  688. }
  689. // TODO: position can be sometimes off a little bit!
  690. pin->SetPosition( GetRelativePosition( pinLocation + m_sheetOffset, symbol ) );
  691. // TODO: the following fix is even worse for now?
  692. // pin->SetPosition( GetRelativePosition( elem.kicadLocation, symbol ) );
  693. switch( elem.electrical )
  694. {
  695. case ASCH_PIN_ELECTRICAL::INPUT:
  696. pin->SetType( ELECTRICAL_PINTYPE::PT_INPUT );
  697. break;
  698. case ASCH_PIN_ELECTRICAL::BIDI:
  699. pin->SetType( ELECTRICAL_PINTYPE::PT_BIDI );
  700. break;
  701. case ASCH_PIN_ELECTRICAL::OUTPUT:
  702. pin->SetType( ELECTRICAL_PINTYPE::PT_OUTPUT );
  703. break;
  704. case ASCH_PIN_ELECTRICAL::OPEN_COLLECTOR:
  705. pin->SetType( ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR );
  706. break;
  707. case ASCH_PIN_ELECTRICAL::PASSIVE:
  708. pin->SetType( ELECTRICAL_PINTYPE::PT_PASSIVE );
  709. break;
  710. case ASCH_PIN_ELECTRICAL::TRISTATE:
  711. pin->SetType( ELECTRICAL_PINTYPE::PT_TRISTATE );
  712. break;
  713. case ASCH_PIN_ELECTRICAL::OPEN_EMITTER:
  714. pin->SetType( ELECTRICAL_PINTYPE::PT_OPENEMITTER );
  715. break;
  716. case ASCH_PIN_ELECTRICAL::POWER:
  717. pin->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN );
  718. break;
  719. case ASCH_PIN_ELECTRICAL::UNKNOWN:
  720. default:
  721. pin->SetType( ELECTRICAL_PINTYPE::PT_UNSPECIFIED );
  722. m_reporter->Report( _( "Pin has unexpected electrical type." ), RPT_SEVERITY_WARNING );
  723. break;
  724. }
  725. if( elem.symbolOuterEdge == ASCH_PIN_SYMBOL_OUTEREDGE::UNKNOWN )
  726. m_reporter->Report( _( "Pin has unexpected outer edge type." ), RPT_SEVERITY_WARNING );
  727. if( elem.symbolInnerEdge == ASCH_PIN_SYMBOL_INNEREDGE::UNKNOWN )
  728. m_reporter->Report( _( "Pin has unexpected inner edge type." ), RPT_SEVERITY_WARNING );
  729. if( elem.symbolOuterEdge == ASCH_PIN_SYMBOL_OUTEREDGE::NEGATED )
  730. {
  731. switch( elem.symbolInnerEdge )
  732. {
  733. case ASCH_PIN_SYMBOL_INNEREDGE::CLOCK:
  734. pin->SetShape( GRAPHIC_PINSHAPE::INVERTED_CLOCK );
  735. break;
  736. default:
  737. pin->SetShape( GRAPHIC_PINSHAPE::INVERTED );
  738. break;
  739. }
  740. }
  741. else if( elem.symbolOuterEdge == ASCH_PIN_SYMBOL_OUTEREDGE::LOW_INPUT )
  742. {
  743. switch( elem.symbolInnerEdge )
  744. {
  745. case ASCH_PIN_SYMBOL_INNEREDGE::CLOCK:
  746. pin->SetShape( GRAPHIC_PINSHAPE::CLOCK_LOW );
  747. break;
  748. default:
  749. pin->SetShape( GRAPHIC_PINSHAPE::INPUT_LOW );
  750. break;
  751. }
  752. }
  753. else if( elem.symbolOuterEdge == ASCH_PIN_SYMBOL_OUTEREDGE::LOW_OUTPUT )
  754. {
  755. pin->SetShape( GRAPHIC_PINSHAPE::OUTPUT_LOW );
  756. }
  757. else
  758. {
  759. switch( elem.symbolInnerEdge )
  760. {
  761. case ASCH_PIN_SYMBOL_INNEREDGE::CLOCK:
  762. pin->SetShape( GRAPHIC_PINSHAPE::CLOCK );
  763. break;
  764. default:
  765. pin->SetShape( GRAPHIC_PINSHAPE::LINE ); // nothing to do
  766. break;
  767. }
  768. }
  769. }
  770. void SetTextPositioning( EDA_TEXT* text, ASCH_LABEL_JUSTIFICATION justification,
  771. ASCH_RECORD_ORIENTATION orientation )
  772. {
  773. int vjustify, hjustify;
  774. EDA_ANGLE angle = ANGLE_HORIZONTAL;
  775. switch( justification )
  776. {
  777. default:
  778. case ASCH_LABEL_JUSTIFICATION::UNKNOWN:
  779. case ASCH_LABEL_JUSTIFICATION::BOTTOM_LEFT:
  780. case ASCH_LABEL_JUSTIFICATION::BOTTOM_CENTER:
  781. case ASCH_LABEL_JUSTIFICATION::BOTTOM_RIGHT:
  782. vjustify = GR_TEXT_V_ALIGN_BOTTOM;
  783. break;
  784. case ASCH_LABEL_JUSTIFICATION::CENTER_LEFT:
  785. case ASCH_LABEL_JUSTIFICATION::CENTER_CENTER:
  786. case ASCH_LABEL_JUSTIFICATION::CENTER_RIGHT:
  787. vjustify = GR_TEXT_V_ALIGN_CENTER;
  788. break;
  789. case ASCH_LABEL_JUSTIFICATION::TOP_LEFT:
  790. case ASCH_LABEL_JUSTIFICATION::TOP_CENTER:
  791. case ASCH_LABEL_JUSTIFICATION::TOP_RIGHT:
  792. vjustify = GR_TEXT_V_ALIGN_TOP;
  793. break;
  794. }
  795. switch( justification )
  796. {
  797. default:
  798. case ASCH_LABEL_JUSTIFICATION::UNKNOWN:
  799. case ASCH_LABEL_JUSTIFICATION::BOTTOM_LEFT:
  800. case ASCH_LABEL_JUSTIFICATION::CENTER_LEFT:
  801. case ASCH_LABEL_JUSTIFICATION::TOP_LEFT:
  802. hjustify = GR_TEXT_H_ALIGN_LEFT;
  803. break;
  804. case ASCH_LABEL_JUSTIFICATION::BOTTOM_CENTER:
  805. case ASCH_LABEL_JUSTIFICATION::CENTER_CENTER:
  806. case ASCH_LABEL_JUSTIFICATION::TOP_CENTER:
  807. hjustify = GR_TEXT_H_ALIGN_CENTER;
  808. break;
  809. case ASCH_LABEL_JUSTIFICATION::BOTTOM_RIGHT:
  810. case ASCH_LABEL_JUSTIFICATION::CENTER_RIGHT:
  811. case ASCH_LABEL_JUSTIFICATION::TOP_RIGHT:
  812. hjustify = GR_TEXT_H_ALIGN_RIGHT;
  813. break;
  814. }
  815. switch( orientation )
  816. {
  817. case ASCH_RECORD_ORIENTATION::RIGHTWARDS:
  818. angle = ANGLE_HORIZONTAL;
  819. break;
  820. case ASCH_RECORD_ORIENTATION::LEFTWARDS:
  821. vjustify *= -1;
  822. hjustify *= -1;
  823. angle = ANGLE_HORIZONTAL;
  824. break;
  825. case ASCH_RECORD_ORIENTATION::UPWARDS:
  826. angle = ANGLE_VERTICAL;
  827. break;
  828. case ASCH_RECORD_ORIENTATION::DOWNWARDS:
  829. vjustify *= -1;
  830. hjustify *= -1;
  831. angle = ANGLE_VERTICAL;
  832. break;
  833. }
  834. text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( vjustify ) );
  835. text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( hjustify ) );
  836. text->SetTextAngle( angle );
  837. }
  838. void SCH_ALTIUM_PLUGIN::ParseLabel( const std::map<wxString, wxString>& aProperties )
  839. {
  840. ASCH_LABEL elem( aProperties );
  841. if( elem.ownerpartid == ALTIUM_COMPONENT_NONE )
  842. {
  843. std::map<wxString, wxString> variableMap = {
  844. { "APPLICATION_BUILDNUMBER", "KICAD_VERSION" },
  845. { "SHEETNUMBER", "#" },
  846. { "SHEETTOTAL", "##" },
  847. { "TITLE", "TITLE" }, // 1:1 maps are sort of useless, but it makes it
  848. { "REVISION", "REVISION" }, // easier to see that the list is complete
  849. { "DATE", "ISSUE_DATE" },
  850. { "CURRENTDATE", "CURRENT_DATE" },
  851. { "COMPANYNAME", "COMPANY" },
  852. { "DOCUMENTNAME", "FILENAME" },
  853. { "PROJECTNAME", "PROJECTNAME" },
  854. };
  855. wxString kicadText = AltiumSpecialStringsToKiCadVariables( elem.text, variableMap );
  856. SCH_TEXT* textItem = new SCH_TEXT( elem.location + m_sheetOffset, kicadText );
  857. SetTextPositioning( textItem, elem.justification, elem.orientation );
  858. size_t fontId = static_cast<int>( elem.fontId );
  859. if( m_altiumSheet && fontId > 0 && fontId <= m_altiumSheet->fonts.size() )
  860. {
  861. const ASCH_SHEET_FONT& font = m_altiumSheet->fonts.at( fontId - 1 );
  862. textItem->SetItalic( font.Italic );
  863. textItem->SetBold( font.Bold );
  864. textItem->SetTextSize( { font.Size / 2, font.Size / 2 } );
  865. }
  866. textItem->SetFlags(IS_NEW );
  867. SCH_SCREEN* screen = getCurrentScreen();
  868. wxCHECK( screen, /* void */ );
  869. screen->Append( textItem );
  870. }
  871. else
  872. {
  873. const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
  874. if( libSymbolIt == m_libSymbols.end() )
  875. {
  876. // TODO: e.g. can depend on Template (RECORD=39
  877. m_reporter->Report( wxString::Format( wxT( "Label's owner (%d) not found." ),
  878. elem.ownerindex ),
  879. RPT_SEVERITY_DEBUG );
  880. return;
  881. }
  882. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  883. LIB_TEXT* textItem = new LIB_TEXT( libSymbolIt->second );
  884. libSymbolIt->second->AddDrawItem( textItem );
  885. textItem->SetUnit( std::max( 0, elem.ownerpartid ) );
  886. textItem->SetPosition( GetRelativePosition( elem.location + m_sheetOffset, symbol ) );
  887. textItem->SetText( elem.text );
  888. SetTextPositioning( textItem, elem.justification, elem.orientation );
  889. size_t fontId = static_cast<int>( elem.fontId );
  890. if( m_altiumSheet && fontId > 0 && fontId <= m_altiumSheet->fonts.size() )
  891. {
  892. const ASCH_SHEET_FONT& font = m_altiumSheet->fonts.at( fontId - 1 );
  893. textItem->SetItalic( font.Italic );
  894. textItem->SetBold( font.Bold );
  895. textItem->SetTextSize( { font.Size / 2, font.Size / 2 } );
  896. }
  897. }
  898. }
  899. void SCH_ALTIUM_PLUGIN::ParseTextFrame( const std::map<wxString, wxString>& aProperties )
  900. {
  901. ASCH_TEXT_FRAME elem( aProperties );
  902. AddTextBox( &elem );
  903. }
  904. void SCH_ALTIUM_PLUGIN::ParseNote( const std::map<wxString, wxString>& aProperties )
  905. {
  906. ASCH_NOTE elem( aProperties );
  907. AddTextBox( static_cast<ASCH_TEXT_FRAME*>( &elem ) );
  908. // TODO: need some sort of property system for storing author....
  909. }
  910. void SCH_ALTIUM_PLUGIN::AddTextBox(const ASCH_TEXT_FRAME *aElem )
  911. {
  912. SCH_TEXTBOX* textBox = new SCH_TEXTBOX();
  913. VECTOR2I sheetTopRight = aElem->TopRight + m_sheetOffset;
  914. VECTOR2I sheetBottomLeft = aElem->BottomLeft + m_sheetOffset;
  915. textBox->SetStart( sheetTopRight );
  916. textBox->SetEnd( sheetBottomLeft );
  917. textBox->SetText( aElem->Text );
  918. textBox->SetFillColor( GetColorFromInt( aElem->AreaColor ) );
  919. if( aElem->IsSolid)
  920. textBox->SetFillMode( FILL_T::FILLED_WITH_COLOR );
  921. else
  922. textBox->SetFilled( false );
  923. if( aElem->ShowBorder )
  924. textBox->SetStroke( STROKE_PARAMS( 0, PLOT_DASH_TYPE::DEFAULT,
  925. GetColorFromInt( aElem->BorderColor ) ) );
  926. else
  927. textBox->SetStroke( STROKE_PARAMS( -1, PLOT_DASH_TYPE::DEFAULT,
  928. GetColorFromInt( aElem->BorderColor ) ) );
  929. switch( aElem->Alignment )
  930. {
  931. default:
  932. case ASCH_TEXT_FRAME_ALIGNMENT::LEFT:
  933. textBox->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
  934. break;
  935. case ASCH_TEXT_FRAME_ALIGNMENT::CENTER:
  936. textBox->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
  937. break;
  938. case ASCH_TEXT_FRAME_ALIGNMENT::RIGHT:
  939. textBox->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
  940. break;
  941. }
  942. // JEY TODO: word-wrap once KiCad supports wrapped text.
  943. size_t fontId = static_cast<int>( aElem->FontID );
  944. if( m_altiumSheet && fontId > 0 && fontId <= m_altiumSheet->fonts.size() )
  945. {
  946. const ASCH_SHEET_FONT& font = m_altiumSheet->fonts.at( fontId - 1 );
  947. textBox->SetItalic( font.Italic );
  948. textBox->SetBold( font.Bold );
  949. textBox->SetTextSize( { font.Size / 2, font.Size / 2 } );
  950. //textBox->SetFont( //how to set font, we have a font mane here: ( font.fontname );
  951. }
  952. textBox->SetFlags( IS_NEW );
  953. SCH_SCREEN* screen = getCurrentScreen();
  954. wxCHECK( screen, /* void */ );
  955. screen->Append( textBox );
  956. }
  957. void SCH_ALTIUM_PLUGIN::ParseBezier( const std::map<wxString, wxString>& aProperties )
  958. {
  959. ASCH_BEZIER elem( aProperties );
  960. if( elem.points.size() < 2 )
  961. {
  962. m_reporter->Report( wxString::Format( _( "Bezier has %d control points. At least 2 are "
  963. "expected." ),
  964. static_cast<int>( elem.points.size() ) ),
  965. RPT_SEVERITY_WARNING );
  966. return;
  967. }
  968. SCH_SCREEN* screen = getCurrentScreen();
  969. wxCHECK( screen, /* void */ );
  970. if( elem.ownerpartid == ALTIUM_COMPONENT_NONE )
  971. {
  972. for( size_t i = 0; i + 1 < elem.points.size(); i += 3 )
  973. {
  974. if( i + 2 == elem.points.size() )
  975. {
  976. // special case: single line
  977. SCH_LINE* line = new SCH_LINE( elem.points.at( i ) + m_sheetOffset,
  978. SCH_LAYER_ID::LAYER_NOTES );
  979. line->SetEndPoint( elem.points.at( i + 1 ) + m_sheetOffset );
  980. line->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) );
  981. line->SetFlags( IS_NEW );
  982. screen->Append( line );
  983. }
  984. else
  985. {
  986. // simulate Bezier using line segments
  987. std::vector<VECTOR2I> bezierPoints;
  988. std::vector<VECTOR2I> polyPoints;
  989. for( size_t j = i; j < elem.points.size() && j < i + 4; j++ )
  990. bezierPoints.push_back( elem.points.at( j ) );
  991. BEZIER_POLY converter( bezierPoints );
  992. converter.GetPoly( polyPoints );
  993. for( size_t k = 0; k + 1 < polyPoints.size(); k++ )
  994. {
  995. SCH_LINE* line = new SCH_LINE( polyPoints.at( k ) + m_sheetOffset,
  996. SCH_LAYER_ID::LAYER_NOTES );
  997. line->SetEndPoint( polyPoints.at( k + 1 ) + m_sheetOffset );
  998. line->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) );
  999. line->SetFlags( IS_NEW );
  1000. screen->Append( line );
  1001. }
  1002. }
  1003. }
  1004. }
  1005. else
  1006. {
  1007. const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
  1008. if( libSymbolIt == m_libSymbols.end() )
  1009. {
  1010. // TODO: e.g. can depend on Template (RECORD=39
  1011. m_reporter->Report( wxString::Format( wxT( "Bezier's owner (%d) not found." ),
  1012. elem.ownerindex ),
  1013. RPT_SEVERITY_DEBUG );
  1014. return;
  1015. }
  1016. if( !IsComponentPartVisible( elem.ownerindex, elem.ownerpartdisplaymode ) )
  1017. return;
  1018. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  1019. for( size_t i = 0; i + 1 < elem.points.size(); i += 3 )
  1020. {
  1021. if( i + 2 == elem.points.size() )
  1022. {
  1023. // special case: single line
  1024. LIB_SHAPE* line = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::POLY );
  1025. libSymbolIt->second->AddDrawItem( line );
  1026. line->SetUnit( std::max( 0, elem.ownerpartid ) );
  1027. for( size_t j = i; j < elem.points.size() && j < i + 2; j++ )
  1028. {
  1029. line->AddPoint( GetRelativePosition( elem.points.at( j ) + m_sheetOffset,
  1030. symbol ) );
  1031. }
  1032. line->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) );
  1033. }
  1034. else if( i + 3 == elem.points.size() )
  1035. {
  1036. // TODO: special case of a single line with an extra point?
  1037. // I haven't a clue what this is all about, but the sample document we have in
  1038. // https://gitlab.com/kicad/code/kicad/-/issues/8974 responds best by treating it
  1039. // as another single line special case.
  1040. LIB_SHAPE* line = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::POLY );
  1041. libSymbolIt->second->AddDrawItem( line );
  1042. line->SetUnit( std::max( 0, elem.ownerpartid ) );
  1043. for( size_t j = i; j < elem.points.size() && j < i + 2; j++ )
  1044. {
  1045. line->AddPoint( GetRelativePosition( elem.points.at( j ) + m_sheetOffset,
  1046. symbol ) );
  1047. }
  1048. line->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) );
  1049. }
  1050. else
  1051. {
  1052. // Bezier always has exactly 4 control points
  1053. LIB_SHAPE* bezier = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::BEZIER );
  1054. libSymbolIt->second->AddDrawItem( bezier );
  1055. bezier->SetUnit( std::max( 0, elem.ownerpartid ) );
  1056. for( size_t j = i; j < elem.points.size() && j < i + 4; j++ )
  1057. {
  1058. VECTOR2I pos =
  1059. GetRelativePosition( elem.points.at( j ) + m_sheetOffset, symbol );
  1060. switch( j - i )
  1061. {
  1062. case 0: bezier->SetStart( pos ); break;
  1063. case 1: bezier->SetBezierC1( pos ); break;
  1064. case 2: bezier->SetBezierC2( pos ); break;
  1065. case 3: bezier->SetEnd( pos ); break;
  1066. default: break; // Can't get here but silence warnings
  1067. }
  1068. }
  1069. bezier->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) );
  1070. }
  1071. }
  1072. }
  1073. }
  1074. void SCH_ALTIUM_PLUGIN::ParsePolyline( const std::map<wxString, wxString>& aProperties )
  1075. {
  1076. ASCH_POLYLINE elem( aProperties );
  1077. SCH_SCREEN* screen = getCurrentScreen();
  1078. wxCHECK( screen, /* void */ );
  1079. if( elem.OwnerPartID == ALTIUM_COMPONENT_NONE )
  1080. {
  1081. SCH_SHAPE* poly = new SCH_SHAPE( SHAPE_T::POLY );
  1082. for( VECTOR2I& point : elem.Points )
  1083. poly->AddPoint( point + m_sheetOffset );
  1084. poly->SetStroke( STROKE_PARAMS( elem.LineWidth, GetPlotDashType( elem.LineStyle ),
  1085. GetColorFromInt( elem.Color ) ) );
  1086. poly->SetFlags( IS_NEW );
  1087. screen->Append( poly );
  1088. }
  1089. else
  1090. {
  1091. const auto& libSymbolIt = m_libSymbols.find( elem.OwnerIndex );
  1092. if( libSymbolIt == m_libSymbols.end() )
  1093. {
  1094. // TODO: e.g. can depend on Template (RECORD=39
  1095. m_reporter->Report( wxString::Format( wxT( "Polyline's owner (%d) not found." ),
  1096. elem.OwnerIndex ),
  1097. RPT_SEVERITY_DEBUG );
  1098. return;
  1099. }
  1100. if( !IsComponentPartVisible( elem.OwnerIndex, elem.OwnerPartDisplayMode ) )
  1101. return;
  1102. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  1103. LIB_SHAPE* line = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::POLY );
  1104. libSymbolIt->second->AddDrawItem( line );
  1105. line->SetUnit( elem.OwnerPartID );
  1106. for( VECTOR2I& point : elem.Points )
  1107. line->AddPoint( GetRelativePosition( point + m_sheetOffset, symbol ) );
  1108. line->SetStroke( STROKE_PARAMS( elem.LineWidth, GetPlotDashType( elem.LineStyle ),
  1109. GetColorFromInt( elem.Color ) ) );
  1110. }
  1111. }
  1112. void SCH_ALTIUM_PLUGIN::ParsePolygon( const std::map<wxString, wxString>& aProperties )
  1113. {
  1114. ASCH_POLYGON elem( aProperties );
  1115. SCH_SCREEN* screen = getCurrentScreen();
  1116. wxCHECK( screen, /* void */ );
  1117. if( elem.OwnerPartID == ALTIUM_COMPONENT_NONE )
  1118. {
  1119. SCH_SHAPE* poly = new SCH_SHAPE( SHAPE_T::POLY );
  1120. for( VECTOR2I& point : elem.points )
  1121. poly->AddPoint( point + m_sheetOffset );
  1122. poly->AddPoint( elem.points.front() + m_sheetOffset );
  1123. SetSchShapeFillAndColor( elem, poly );
  1124. poly->SetFlags( IS_NEW );
  1125. screen->Append( poly );
  1126. }
  1127. else
  1128. {
  1129. const auto& libSymbolIt = m_libSymbols.find( elem.OwnerIndex );
  1130. if( libSymbolIt == m_libSymbols.end() )
  1131. {
  1132. // TODO: e.g. can depend on Template (RECORD=39
  1133. m_reporter->Report( wxString::Format( wxT( "Polygon's owner (%d) not found." ),
  1134. elem.OwnerIndex ),
  1135. RPT_SEVERITY_DEBUG );
  1136. return;
  1137. }
  1138. if( !IsComponentPartVisible( elem.OwnerIndex, elem.OwnerPartDisplayMode ) )
  1139. return;
  1140. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  1141. LIB_SHAPE* line = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::POLY );
  1142. libSymbolIt->second->AddDrawItem( line );
  1143. line->SetUnit( elem.OwnerPartID );
  1144. for( VECTOR2I& point : elem.points )
  1145. line->AddPoint( GetRelativePosition( point + m_sheetOffset, symbol ) );
  1146. line->AddPoint( GetRelativePosition( elem.points.front() + m_sheetOffset, symbol ) );
  1147. SetLibShapeFillAndColor( elem, line );
  1148. }
  1149. }
  1150. void SCH_ALTIUM_PLUGIN::ParseRoundRectangle( const std::map<wxString, wxString>& aProperties )
  1151. {
  1152. ASCH_ROUND_RECTANGLE elem( aProperties );
  1153. VECTOR2I sheetTopRight = elem.TopRight + m_sheetOffset;
  1154. VECTOR2I sheetBottomLeft = elem.BottomLeft + m_sheetOffset;
  1155. SCH_SCREEN* screen = getCurrentScreen();
  1156. wxCHECK( screen, /* void */ );
  1157. if( elem.OwnerPartID == ALTIUM_COMPONENT_NONE )
  1158. {
  1159. // TODO: misses rounded edges
  1160. SCH_SHAPE* rect = new SCH_SHAPE( SHAPE_T::RECT );
  1161. rect->SetPosition( sheetTopRight );
  1162. rect->SetEnd( sheetBottomLeft );
  1163. SetSchShapeFillAndColor( elem, rect );
  1164. rect->SetFlags( IS_NEW );
  1165. screen->Append( rect );
  1166. }
  1167. else
  1168. {
  1169. const auto& libSymbolIt = m_libSymbols.find( elem.OwnerIndex );
  1170. if( libSymbolIt == m_libSymbols.end() )
  1171. {
  1172. // TODO: e.g. can depend on Template (RECORD=39
  1173. m_reporter->Report( wxString::Format( wxT( "Rounded rectangle's owner (%d) not "
  1174. "found." ),
  1175. elem.OwnerIndex ),
  1176. RPT_SEVERITY_DEBUG );
  1177. return;
  1178. }
  1179. if( !IsComponentPartVisible( elem.OwnerIndex, elem.OwnerPartDisplayMode ) )
  1180. return;
  1181. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  1182. // TODO: misses rounded edges
  1183. LIB_SHAPE* rect = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::RECT );
  1184. libSymbolIt->second->AddDrawItem( rect );
  1185. rect->SetUnit( elem.OwnerPartID );
  1186. rect->SetPosition( GetRelativePosition( elem.TopRight + m_sheetOffset, symbol ) );
  1187. rect->SetEnd( GetRelativePosition( elem.BottomLeft + m_sheetOffset, symbol ) );
  1188. SetLibShapeFillAndColor( elem, rect );
  1189. }
  1190. }
  1191. void SCH_ALTIUM_PLUGIN::ParseArc( const std::map<wxString, wxString>& aProperties )
  1192. {
  1193. // The Arc can be ALTIUM_SCH_RECORD::ELLIPTICAL_ARC or ALTIUM_SCH_RECORD::ARC
  1194. // Elliptical arcs are not handled in kicad. So use an arc instead
  1195. // TODO: handle elliptical arc better.
  1196. ASCH_ARC elem( aProperties );
  1197. SCH_SCREEN* screen = getCurrentScreen();
  1198. wxCHECK( screen, /* void */ );
  1199. int arc_radius = elem.m_Radius;
  1200. // Try to approxiammate this ellipse by an arc. use the biggest of radius and secondary radius
  1201. // One can of course use another recipe
  1202. if( elem.m_IsElliptical )
  1203. arc_radius = std::max( elem.m_Radius, elem.m_SecondaryRadius );
  1204. if( elem.ownerpartid == ALTIUM_COMPONENT_NONE )
  1205. {
  1206. if( elem.m_StartAngle == 0 && ( elem.m_EndAngle == 0 || elem.m_EndAngle == 360 ) )
  1207. {
  1208. SCH_SHAPE* circle = new SCH_SHAPE( SHAPE_T::CIRCLE );
  1209. circle->SetPosition( elem.m_Center + m_sheetOffset );
  1210. circle->SetEnd( circle->GetPosition() + VECTOR2I( arc_radius, 0 ) );
  1211. circle->SetStroke( STROKE_PARAMS( elem.m_LineWidth, PLOT_DASH_TYPE::SOLID ) );
  1212. screen->Append( circle );
  1213. }
  1214. else
  1215. {
  1216. SCH_SHAPE* arc = new SCH_SHAPE( SHAPE_T::ARC );
  1217. EDA_ANGLE includedAngle( elem.m_EndAngle - elem.m_StartAngle, DEGREES_T );
  1218. EDA_ANGLE startAngle( elem.m_EndAngle, DEGREES_T );
  1219. VECTOR2I startOffset( KiROUND( arc_radius * startAngle.Cos() ),
  1220. -KiROUND( arc_radius * startAngle.Sin() ) );
  1221. arc->SetCenter( elem.m_Center + m_sheetOffset );
  1222. arc->SetStart( elem.m_Center + startOffset + m_sheetOffset );
  1223. arc->SetArcAngleAndEnd( includedAngle.Normalize(), true );
  1224. arc->SetStroke( STROKE_PARAMS( elem.m_LineWidth, PLOT_DASH_TYPE::SOLID ) );
  1225. screen->Append( arc );
  1226. }
  1227. }
  1228. else
  1229. {
  1230. const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
  1231. if( libSymbolIt == m_libSymbols.end() )
  1232. {
  1233. // TODO: e.g. can depend on Template (RECORD=39
  1234. m_reporter->Report( wxString::Format( wxT( "Arc's owner (%d) not found." ),
  1235. elem.ownerindex ),
  1236. RPT_SEVERITY_DEBUG );
  1237. return;
  1238. }
  1239. if( !IsComponentPartVisible( elem.ownerindex, elem.ownerpartdisplaymode ) )
  1240. return;
  1241. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  1242. if( elem.m_StartAngle == 0 && ( elem.m_EndAngle == 0 || elem.m_EndAngle == 360 ) )
  1243. {
  1244. LIB_SHAPE* circle = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::CIRCLE );
  1245. libSymbolIt->second->AddDrawItem( circle );
  1246. circle->SetUnit( std::max( 0, elem.ownerpartid ) );
  1247. circle->SetPosition( GetRelativePosition( elem.m_Center + m_sheetOffset, symbol ) );
  1248. circle->SetEnd( circle->GetPosition() + VECTOR2I( arc_radius, 0 ) );
  1249. circle->SetStroke( STROKE_PARAMS( elem.m_LineWidth, PLOT_DASH_TYPE::SOLID ) );
  1250. }
  1251. else
  1252. {
  1253. LIB_SHAPE* arc = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::ARC );
  1254. libSymbolIt->second->AddDrawItem( arc );
  1255. arc->SetUnit( std::max( 0, elem.ownerpartid ) );
  1256. arc->SetCenter( GetRelativePosition( elem.m_Center + m_sheetOffset, symbol ) );
  1257. VECTOR2I arcStart( arc_radius, 0 );
  1258. RotatePoint( arcStart, -EDA_ANGLE( elem.m_StartAngle, DEGREES_T ) );
  1259. arcStart += arc->GetCenter();
  1260. arc->SetStart( arcStart );
  1261. VECTOR2I arcEnd( arc_radius, 0 );
  1262. RotatePoint( arcEnd, -EDA_ANGLE( elem.m_EndAngle, DEGREES_T ) );
  1263. arcEnd += arc->GetCenter();
  1264. arc->SetEnd( arcEnd );
  1265. arc->SetStroke( STROKE_PARAMS( elem.m_LineWidth, PLOT_DASH_TYPE::SOLID ) );
  1266. }
  1267. }
  1268. }
  1269. void SCH_ALTIUM_PLUGIN::ParseEllipse( const std::map<wxString, wxString>& aProperties )
  1270. {
  1271. ASCH_ELLIPSE elem( aProperties );
  1272. SCH_SCREEN* screen = getCurrentScreen();
  1273. wxCHECK( screen, /* void */ );
  1274. // To do: Import true ellipses when KiCad supports them
  1275. if( elem.Radius != elem.SecondaryRadius )
  1276. {
  1277. m_reporter->Report( wxString::Format( _( "Unsupported ellipse was not imported at "
  1278. "(X = %d; Y = %d)." ),
  1279. ( elem.Center + m_sheetOffset ).x,
  1280. ( elem.Center + m_sheetOffset ).y ),
  1281. RPT_SEVERITY_ERROR );
  1282. return;
  1283. }
  1284. if( elem.OwnerPartID == ALTIUM_COMPONENT_NONE )
  1285. {
  1286. SCH_SHAPE* circle = new SCH_SHAPE( SHAPE_T::CIRCLE );
  1287. circle->SetPosition( elem.Center + m_sheetOffset );
  1288. circle->SetEnd( circle->GetPosition() + VECTOR2I( elem.Radius, 0 ) );
  1289. circle->SetStroke( STROKE_PARAMS( 1, PLOT_DASH_TYPE::SOLID ) );
  1290. circle->SetFillColor( GetColorFromInt( elem.AreaColor ) );
  1291. if( elem.IsSolid )
  1292. circle->SetFillMode( FILL_T::FILLED_WITH_COLOR );
  1293. else
  1294. circle->SetFilled( false );
  1295. screen->Append( circle );
  1296. }
  1297. else
  1298. {
  1299. const auto& libSymbolIt = m_libSymbols.find( elem.OwnerIndex );
  1300. if( libSymbolIt == m_libSymbols.end() )
  1301. {
  1302. // TODO: e.g. can depend on Template (RECORD=39
  1303. m_reporter->Report( wxString::Format( wxT( "Ellipse's owner (%d) not found." ),
  1304. elem.OwnerIndex ),
  1305. RPT_SEVERITY_DEBUG );
  1306. return;
  1307. }
  1308. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  1309. LIB_SHAPE* circle = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::CIRCLE );
  1310. libSymbolIt->second->AddDrawItem( circle );
  1311. circle->SetUnit( elem.OwnerPartID );
  1312. circle->SetPosition( GetRelativePosition( elem.Center + m_sheetOffset, symbol ) );
  1313. circle->SetEnd( circle->GetPosition() + VECTOR2I( elem.Radius, 0 ) );
  1314. circle->SetStroke( STROKE_PARAMS( 1, PLOT_DASH_TYPE::SOLID ) );
  1315. circle->SetFillColor( GetColorFromInt( elem.AreaColor ) );
  1316. if( elem.IsSolid )
  1317. circle->SetFillMode( FILL_T::FILLED_WITH_COLOR );
  1318. else
  1319. circle->SetFilled( false );
  1320. }
  1321. }
  1322. void SCH_ALTIUM_PLUGIN::ParseLine( const std::map<wxString, wxString>& aProperties )
  1323. {
  1324. ASCH_LINE elem( aProperties );
  1325. SCH_SCREEN* screen = getCurrentScreen();
  1326. wxCHECK( screen, /* void */ );
  1327. if( elem.ownerpartid == ALTIUM_COMPONENT_NONE )
  1328. {
  1329. // close polygon
  1330. SCH_LINE* line = new SCH_LINE( elem.point1 + m_sheetOffset, SCH_LAYER_ID::LAYER_NOTES );
  1331. line->SetEndPoint( elem.point2 + m_sheetOffset );
  1332. line->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) ); // TODO?
  1333. line->SetFlags( IS_NEW );
  1334. screen->Append( line );
  1335. }
  1336. else
  1337. {
  1338. const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
  1339. if( libSymbolIt == m_libSymbols.end() )
  1340. {
  1341. // TODO: e.g. can depend on Template (RECORD=39
  1342. m_reporter->Report( wxString::Format( wxT( "Line's owner (%d) not found." ),
  1343. elem.ownerindex ),
  1344. RPT_SEVERITY_DEBUG );
  1345. return;
  1346. }
  1347. if( !IsComponentPartVisible( elem.ownerindex, elem.ownerpartdisplaymode ) )
  1348. return;
  1349. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  1350. LIB_SHAPE* line = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::POLY );
  1351. libSymbolIt->second->AddDrawItem( line );
  1352. line->SetUnit( std::max( 0, elem.ownerpartid ) );
  1353. line->AddPoint( GetRelativePosition( elem.point1 + m_sheetOffset, symbol ) );
  1354. line->AddPoint( GetRelativePosition( elem.point2 + m_sheetOffset, symbol ) );
  1355. line->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) );
  1356. }
  1357. }
  1358. void SCH_ALTIUM_PLUGIN::ParseSignalHarness( const std::map<wxString, wxString>& aProperties )
  1359. {
  1360. ASCH_SIGNAL_HARNESS elem( aProperties );
  1361. SCH_SCREEN* screen = getCurrentScreen();
  1362. wxCHECK( screen, /* void */ );
  1363. if( elem.OwnerPartID == ALTIUM_COMPONENT_NONE )
  1364. {
  1365. SCH_SHAPE* poly = new SCH_SHAPE( SHAPE_T::POLY );
  1366. for( VECTOR2I& point : elem.Points )
  1367. poly->AddPoint( point + m_sheetOffset );
  1368. poly->SetStroke( STROKE_PARAMS( elem.LineWidth, PLOT_DASH_TYPE::SOLID,
  1369. GetColorFromInt( elem.Color ) ) );
  1370. poly->SetFlags( IS_NEW );
  1371. screen->Append( poly );
  1372. }
  1373. else
  1374. {
  1375. // No clue if this situation can ever exist
  1376. m_reporter->Report( wxT( "Signal harness, belonging to the part is not currently "
  1377. "supported." ), RPT_SEVERITY_DEBUG );
  1378. }
  1379. }
  1380. void SCH_ALTIUM_PLUGIN::ParseHarnessConnector( int aIndex, const std::map<wxString,
  1381. wxString>& aProperties )
  1382. {
  1383. ASCH_HARNESS_CONNECTOR elem( aProperties );
  1384. SCH_SCREEN* currentScreen = getCurrentScreen();
  1385. wxCHECK( currentScreen, /* void */ );
  1386. if( elem.OwnerPartID == ALTIUM_COMPONENT_NONE )
  1387. {
  1388. SCH_SHEET* sheet = new SCH_SHEET( getCurrentSheet(), elem.Location + m_sheetOffset,
  1389. elem.Size );
  1390. sheet->SetBackgroundColor( GetColorFromInt( elem.AreaColor ) );
  1391. sheet->SetBorderColor( GetColorFromInt( elem.Color ) );
  1392. currentScreen->Append( sheet );
  1393. SCH_SHEET_PATH sheetpath = m_sheetPath;
  1394. sheetpath.push_back( sheet );
  1395. sheetpath.SetPageNumber( "Harness #" );
  1396. m_harnessEntryParent = aIndex + m_harnessOwnerIndexOffset;
  1397. m_sheets.insert( { m_harnessEntryParent, sheet } );
  1398. }
  1399. else
  1400. {
  1401. // I have no clue if this situation can ever exist
  1402. m_reporter->Report( wxT( "Harness connector, belonging to the part is not currently "
  1403. "supported." ),
  1404. RPT_SEVERITY_DEBUG );
  1405. }
  1406. }
  1407. void SCH_ALTIUM_PLUGIN::ParseHarnessEntry( const std::map<wxString, wxString>& aProperties )
  1408. {
  1409. ASCH_HARNESS_ENTRY elem( aProperties );
  1410. const auto& sheetIt = m_sheets.find( m_harnessEntryParent );
  1411. if( sheetIt == m_sheets.end() )
  1412. {
  1413. m_reporter->Report( wxString::Format( wxT( "Harness entry's parent (%d) not found." ),
  1414. SCH_ALTIUM_PLUGIN::m_harnessEntryParent ),
  1415. RPT_SEVERITY_DEBUG );
  1416. return;
  1417. }
  1418. SCH_SHEET_PIN* sheetPin = new SCH_SHEET_PIN( sheetIt->second );
  1419. sheetIt->second->AddPin( sheetPin );
  1420. sheetPin->SetText( elem.Name );
  1421. sheetPin->SetShape( LABEL_FLAG_SHAPE::L_UNSPECIFIED );
  1422. VECTOR2I pos = sheetIt->second->GetPosition();
  1423. wxSize size = sheetIt->second->GetSize();
  1424. switch( elem.Side )
  1425. {
  1426. default:
  1427. case ASCH_SHEET_ENTRY_SIDE::LEFT:
  1428. sheetPin->SetPosition( { pos.x, pos.y + elem.DistanceFromTop } );
  1429. sheetPin->SetTextSpinStyle( TEXT_SPIN_STYLE::LEFT );
  1430. sheetPin->SetSide( SHEET_SIDE::LEFT );
  1431. break;
  1432. case ASCH_SHEET_ENTRY_SIDE::RIGHT:
  1433. sheetPin->SetPosition( { pos.x + size.x, pos.y + elem.DistanceFromTop } );
  1434. sheetPin->SetTextSpinStyle( TEXT_SPIN_STYLE::RIGHT );
  1435. sheetPin->SetSide( SHEET_SIDE::RIGHT );
  1436. break;
  1437. case ASCH_SHEET_ENTRY_SIDE::TOP:
  1438. sheetPin->SetPosition( { pos.x + elem.DistanceFromTop, pos.y } );
  1439. sheetPin->SetTextSpinStyle( TEXT_SPIN_STYLE::UP );
  1440. sheetPin->SetSide( SHEET_SIDE::TOP );
  1441. break;
  1442. case ASCH_SHEET_ENTRY_SIDE::BOTTOM:
  1443. sheetPin->SetPosition( { pos.x + elem.DistanceFromTop, pos.y + size.y } );
  1444. sheetPin->SetTextSpinStyle( TEXT_SPIN_STYLE::BOTTOM );
  1445. sheetPin->SetSide( SHEET_SIDE::BOTTOM );
  1446. break;
  1447. }
  1448. }
  1449. void SCH_ALTIUM_PLUGIN::ParseHarnessType( const std::map<wxString, wxString>& aProperties )
  1450. {
  1451. ASCH_HARNESS_TYPE elem( aProperties );
  1452. const auto& sheetIt = m_sheets.find( m_harnessEntryParent );
  1453. if( sheetIt == m_sheets.end() )
  1454. {
  1455. m_reporter->Report( wxString::Format( wxT( "Harness type's parent (%d) not found." ),
  1456. m_harnessEntryParent ),
  1457. RPT_SEVERITY_DEBUG );
  1458. return;
  1459. }
  1460. SCH_FIELD& sheetNameField = sheetIt->second->GetFields()[SHEETNAME];
  1461. sheetNameField.SetPosition( elem.Location + m_sheetOffset );
  1462. sheetNameField.SetText( elem.Text );
  1463. // Always set as visible so user is aware about ( !elem.isHidden );
  1464. sheetNameField.SetVisible( true );
  1465. SetTextPositioning( &sheetNameField, ASCH_LABEL_JUSTIFICATION::BOTTOM_LEFT,
  1466. ASCH_RECORD_ORIENTATION::RIGHTWARDS );
  1467. sheetNameField.SetTextColor( GetColorFromInt( elem.Color ) );
  1468. m_reporter->Report( wxString::Format( _( "Altium's harness connector (%s) was imported as a "
  1469. "hierarchical sheet. Please review the imported "
  1470. "schematic." ),
  1471. elem.Text ),
  1472. RPT_SEVERITY_WARNING );
  1473. }
  1474. void SCH_ALTIUM_PLUGIN::ParseRectangle( const std::map<wxString, wxString>& aProperties )
  1475. {
  1476. ASCH_RECTANGLE elem( aProperties );
  1477. VECTOR2I sheetTopRight = elem.TopRight + m_sheetOffset;
  1478. VECTOR2I sheetBottomLeft = elem.BottomLeft + m_sheetOffset;
  1479. SCH_SCREEN* screen = getCurrentScreen();
  1480. wxCHECK( screen, /* void */ );
  1481. if( elem.OwnerPartID == ALTIUM_COMPONENT_NONE )
  1482. {
  1483. SCH_SHAPE* rect = new SCH_SHAPE( SHAPE_T::RECT );
  1484. rect->SetPosition( sheetTopRight );
  1485. rect->SetEnd( sheetBottomLeft );
  1486. SetSchShapeFillAndColor( elem, rect );
  1487. rect->SetFlags( IS_NEW );
  1488. screen->Append( rect );
  1489. }
  1490. else
  1491. {
  1492. const auto& libSymbolIt = m_libSymbols.find( elem.OwnerIndex );
  1493. if( libSymbolIt == m_libSymbols.end() )
  1494. {
  1495. // TODO: e.g. can depend on Template (RECORD=39
  1496. m_reporter->Report( wxString::Format( wxT( "Rectangle's owner (%d) not found." ),
  1497. elem.OwnerIndex ),
  1498. RPT_SEVERITY_DEBUG );
  1499. return;
  1500. }
  1501. if( !IsComponentPartVisible( elem.OwnerIndex, elem.OwnerPartDisplayMode ) )
  1502. return;
  1503. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  1504. LIB_SHAPE* rect = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::RECT );
  1505. libSymbolIt->second->AddDrawItem( rect );
  1506. rect->SetUnit( elem.OwnerPartID );
  1507. rect->SetPosition( GetRelativePosition( sheetTopRight, symbol ) );
  1508. rect->SetEnd( GetRelativePosition( sheetBottomLeft, symbol ) );
  1509. SetLibShapeFillAndColor( elem, rect );
  1510. }
  1511. }
  1512. void SCH_ALTIUM_PLUGIN::ParseSheetSymbol( int aIndex,
  1513. const std::map<wxString, wxString>& aProperties )
  1514. {
  1515. ASCH_SHEET_SYMBOL elem( aProperties );
  1516. SCH_SHEET* sheet = new SCH_SHEET( getCurrentSheet(), elem.location + m_sheetOffset,
  1517. elem.size );
  1518. sheet->SetBorderColor( GetColorFromInt( elem.color ) );
  1519. if( elem.isSolid )
  1520. sheet->SetBackgroundColor( GetColorFromInt( elem.areacolor ) );
  1521. sheet->SetFlags( IS_NEW );
  1522. SCH_SCREEN* currentScreen = getCurrentScreen();
  1523. wxCHECK( currentScreen, /* void */ );
  1524. currentScreen->Append( sheet );
  1525. SCH_SHEET_PATH sheetpath = m_sheetPath;
  1526. sheetpath.push_back( sheet );
  1527. // We'll update later if we find a pageNumber record for it.
  1528. sheetpath.SetPageNumber( "#" );
  1529. SCH_SCREEN* rootScreen = m_rootSheet->GetScreen();
  1530. wxCHECK( rootScreen, /* void */ );
  1531. SCH_SHEET_INSTANCE sheetInstance;
  1532. sheetInstance.m_Path = sheetpath.Path();
  1533. sheetInstance.m_PageNumber = wxT( "#" );
  1534. rootScreen->m_sheetInstances.emplace_back( sheetInstance );
  1535. m_sheets.insert( { aIndex, sheet } );
  1536. }
  1537. void SCH_ALTIUM_PLUGIN::ParseSheetEntry( const std::map<wxString, wxString>& aProperties )
  1538. {
  1539. ASCH_SHEET_ENTRY elem( aProperties );
  1540. const auto& sheetIt = m_sheets.find( elem.ownerindex );
  1541. if( sheetIt == m_sheets.end() )
  1542. {
  1543. m_reporter->Report( wxString::Format( wxT( "Sheet entry's owner (%d) not found." ),
  1544. elem.ownerindex ),
  1545. RPT_SEVERITY_DEBUG );
  1546. return;
  1547. }
  1548. SCH_SHEET_PIN* sheetPin = new SCH_SHEET_PIN( sheetIt->second );
  1549. sheetIt->second->AddPin( sheetPin );
  1550. sheetPin->SetText( elem.name );
  1551. sheetPin->SetShape( LABEL_FLAG_SHAPE::L_UNSPECIFIED );
  1552. //sheetPin->SetTextSpinStyle( getSpinStyle( term.OrientAngle, false ) );
  1553. //sheetPin->SetPosition( getKiCadPoint( term.Position ) );
  1554. VECTOR2I pos = sheetIt->second->GetPosition();
  1555. wxSize size = sheetIt->second->GetSize();
  1556. switch( elem.side )
  1557. {
  1558. default:
  1559. case ASCH_SHEET_ENTRY_SIDE::LEFT:
  1560. sheetPin->SetPosition( { pos.x, pos.y + elem.distanceFromTop } );
  1561. sheetPin->SetTextSpinStyle( TEXT_SPIN_STYLE::LEFT );
  1562. sheetPin->SetSide( SHEET_SIDE::LEFT );
  1563. break;
  1564. case ASCH_SHEET_ENTRY_SIDE::RIGHT:
  1565. sheetPin->SetPosition( { pos.x + size.x, pos.y + elem.distanceFromTop } );
  1566. sheetPin->SetTextSpinStyle( TEXT_SPIN_STYLE::RIGHT );
  1567. sheetPin->SetSide( SHEET_SIDE::RIGHT );
  1568. break;
  1569. case ASCH_SHEET_ENTRY_SIDE::TOP:
  1570. sheetPin->SetPosition( { pos.x + elem.distanceFromTop, pos.y } );
  1571. sheetPin->SetTextSpinStyle( TEXT_SPIN_STYLE::UP );
  1572. sheetPin->SetSide( SHEET_SIDE::TOP );
  1573. break;
  1574. case ASCH_SHEET_ENTRY_SIDE::BOTTOM:
  1575. sheetPin->SetPosition( { pos.x + elem.distanceFromTop, pos.y + size.y } );
  1576. sheetPin->SetTextSpinStyle( TEXT_SPIN_STYLE::BOTTOM );
  1577. sheetPin->SetSide( SHEET_SIDE::BOTTOM );
  1578. break;
  1579. }
  1580. switch( elem.iotype )
  1581. {
  1582. default:
  1583. case ASCH_PORT_IOTYPE::UNSPECIFIED:
  1584. sheetPin->SetShape( LABEL_FLAG_SHAPE::L_UNSPECIFIED );
  1585. break;
  1586. case ASCH_PORT_IOTYPE::OUTPUT:
  1587. sheetPin->SetShape( LABEL_FLAG_SHAPE::L_OUTPUT );
  1588. break;
  1589. case ASCH_PORT_IOTYPE::INPUT:
  1590. sheetPin->SetShape( LABEL_FLAG_SHAPE::L_INPUT );
  1591. break;
  1592. case ASCH_PORT_IOTYPE::BIDI:
  1593. sheetPin->SetShape( LABEL_FLAG_SHAPE::L_BIDI );
  1594. break;
  1595. }
  1596. }
  1597. VECTOR2I HelperGeneratePowerPortGraphics( LIB_SYMBOL* aKsymbol, ASCH_POWER_PORT_STYLE aStyle,
  1598. REPORTER* aReporter )
  1599. {
  1600. if( aStyle == ASCH_POWER_PORT_STYLE::CIRCLE || aStyle == ASCH_POWER_PORT_STYLE::ARROW )
  1601. {
  1602. LIB_SHAPE* line1 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1603. aKsymbol->AddDrawItem( line1 );
  1604. line1->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1605. line1->AddPoint( { 0, 0 } );
  1606. line1->AddPoint( { 0, schIUScale.MilsToIU( -50 ) } );
  1607. if( aStyle == ASCH_POWER_PORT_STYLE::CIRCLE )
  1608. {
  1609. LIB_SHAPE* circle = new LIB_SHAPE( aKsymbol, SHAPE_T::CIRCLE );
  1610. aKsymbol->AddDrawItem( circle );
  1611. circle->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 5 ), PLOT_DASH_TYPE::SOLID ) );
  1612. circle->SetPosition( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( -75 ) } );
  1613. circle->SetEnd( circle->GetPosition() + VECTOR2I( schIUScale.MilsToIU( 25 ), 0 ) );
  1614. }
  1615. else
  1616. {
  1617. LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1618. aKsymbol->AddDrawItem( line2 );
  1619. line2->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1620. line2->AddPoint( { schIUScale.MilsToIU( -25 ), schIUScale.MilsToIU( -50 ) } );
  1621. line2->AddPoint( { schIUScale.MilsToIU( 25 ), schIUScale.MilsToIU( -50 ) } );
  1622. line2->AddPoint( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( -100 ) } );
  1623. line2->AddPoint( { schIUScale.MilsToIU( -25 ), schIUScale.MilsToIU( -50 ) } );
  1624. }
  1625. return { 0, schIUScale.MilsToIU( 150 ) };
  1626. }
  1627. else if( aStyle == ASCH_POWER_PORT_STYLE::WAVE )
  1628. {
  1629. LIB_SHAPE* line = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1630. aKsymbol->AddDrawItem( line );
  1631. line->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1632. line->AddPoint( { 0, 0 } );
  1633. line->AddPoint( { 0, schIUScale.MilsToIU( -72 ) } );
  1634. LIB_SHAPE* bezier = new LIB_SHAPE( aKsymbol, SHAPE_T::BEZIER );
  1635. aKsymbol->AddDrawItem( bezier );
  1636. bezier->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 5 ), PLOT_DASH_TYPE::SOLID ) );
  1637. bezier->AddPoint( { schIUScale.MilsToIU( 30 ), schIUScale.MilsToIU( -50 ) } );
  1638. bezier->AddPoint( { schIUScale.MilsToIU( 30 ), schIUScale.MilsToIU( -87 ) } );
  1639. bezier->AddPoint( { schIUScale.MilsToIU( -30 ), schIUScale.MilsToIU( -63 ) } );
  1640. bezier->AddPoint( { schIUScale.MilsToIU( -30 ), schIUScale.MilsToIU( -100 ) } );
  1641. return { 0, schIUScale.MilsToIU( 150 ) };
  1642. }
  1643. else if( aStyle == ASCH_POWER_PORT_STYLE::POWER_GROUND
  1644. || aStyle == ASCH_POWER_PORT_STYLE::SIGNAL_GROUND
  1645. || aStyle == ASCH_POWER_PORT_STYLE::EARTH
  1646. || aStyle == ASCH_POWER_PORT_STYLE::GOST_ARROW )
  1647. {
  1648. LIB_SHAPE* line1 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1649. aKsymbol->AddDrawItem( line1 );
  1650. line1->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1651. line1->AddPoint( { 0, 0 } );
  1652. line1->AddPoint( { 0, schIUScale.MilsToIU( -100 ) } );
  1653. if( aStyle == ASCH_POWER_PORT_STYLE::POWER_GROUND )
  1654. {
  1655. LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1656. aKsymbol->AddDrawItem( line2 );
  1657. line2->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1658. line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( -100 ) } );
  1659. line2->AddPoint( { schIUScale.MilsToIU( 100 ), schIUScale.MilsToIU( -100 ) } );
  1660. LIB_SHAPE* line3 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1661. aKsymbol->AddDrawItem( line3 );
  1662. line3->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1663. line3->AddPoint( { schIUScale.MilsToIU( -70 ), schIUScale.MilsToIU( -130 ) } );
  1664. line3->AddPoint( { schIUScale.MilsToIU( 70 ), schIUScale.MilsToIU( -130 ) } );
  1665. LIB_SHAPE* line4 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1666. aKsymbol->AddDrawItem( line4 );
  1667. line4->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1668. line4->AddPoint( { schIUScale.MilsToIU( -40 ), schIUScale.MilsToIU( -160 ) } );
  1669. line4->AddPoint( { schIUScale.MilsToIU( 40 ), schIUScale.MilsToIU( -160 ) } );
  1670. LIB_SHAPE* line5 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1671. aKsymbol->AddDrawItem( line5 );
  1672. line5->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1673. line5->AddPoint( { schIUScale.MilsToIU( -10 ), schIUScale.MilsToIU( -190 ) } );
  1674. line5->AddPoint( { schIUScale.MilsToIU( 10 ), schIUScale.MilsToIU( -190 ) } );
  1675. }
  1676. else if( aStyle == ASCH_POWER_PORT_STYLE::SIGNAL_GROUND )
  1677. {
  1678. LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1679. aKsymbol->AddDrawItem( line2 );
  1680. line2->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1681. line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( -100 ) } );
  1682. line2->AddPoint( { schIUScale.MilsToIU( 100 ), schIUScale.MilsToIU( -100 ) } );
  1683. line2->AddPoint( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( -200 ) } );
  1684. line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( -100 ) } );
  1685. }
  1686. else if( aStyle == ASCH_POWER_PORT_STYLE::EARTH )
  1687. {
  1688. LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1689. aKsymbol->AddDrawItem( line2 );
  1690. line2->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1691. line2->AddPoint( { schIUScale.MilsToIU( -150 ), schIUScale.MilsToIU( -200 ) } );
  1692. line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( -100 ) } );
  1693. line2->AddPoint( { schIUScale.MilsToIU( 100 ), schIUScale.MilsToIU( -100 ) } );
  1694. line2->AddPoint( { schIUScale.MilsToIU( 50 ), schIUScale.MilsToIU( -200 ) } );
  1695. LIB_SHAPE* line3 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1696. aKsymbol->AddDrawItem( line3 );
  1697. line3->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1698. line3->AddPoint( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( -100 ) } );
  1699. line3->AddPoint( { schIUScale.MilsToIU( -50 ), schIUScale.MilsToIU( -200 ) } );
  1700. }
  1701. else // ASCH_POWER_PORT_STYLE::GOST_ARROW
  1702. {
  1703. LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1704. aKsymbol->AddDrawItem( line2 );
  1705. line2->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1706. line2->AddPoint( { schIUScale.MilsToIU( -25 ), schIUScale.MilsToIU( -50 ) } );
  1707. line2->AddPoint( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( -100 ) } );
  1708. line2->AddPoint( { schIUScale.MilsToIU( 25 ), schIUScale.MilsToIU( -50 ) } );
  1709. return { 0, schIUScale.MilsToIU( 150 ) }; // special case
  1710. }
  1711. return { 0, schIUScale.MilsToIU( 250 ) };
  1712. }
  1713. else if( aStyle == ASCH_POWER_PORT_STYLE::GOST_POWER_GROUND
  1714. || aStyle == ASCH_POWER_PORT_STYLE::GOST_EARTH )
  1715. {
  1716. LIB_SHAPE* line1 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1717. aKsymbol->AddDrawItem( line1 );
  1718. line1->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1719. line1->AddPoint( { 0, 0 } );
  1720. line1->AddPoint( { 0, schIUScale.MilsToIU( -160 ) } );
  1721. LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1722. aKsymbol->AddDrawItem( line2 );
  1723. line2->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1724. line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( -160 ) } );
  1725. line2->AddPoint( { schIUScale.MilsToIU( 100 ), schIUScale.MilsToIU( -160 ) } );
  1726. LIB_SHAPE* line3 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1727. aKsymbol->AddDrawItem( line3 );
  1728. line3->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1729. line3->AddPoint( { schIUScale.MilsToIU( -60 ), schIUScale.MilsToIU( -200 ) } );
  1730. line3->AddPoint( { schIUScale.MilsToIU( 60 ), schIUScale.MilsToIU( -200 ) } );
  1731. LIB_SHAPE* line4 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1732. aKsymbol->AddDrawItem( line4 );
  1733. line4->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1734. line4->AddPoint( { schIUScale.MilsToIU( -20 ), schIUScale.MilsToIU( -240 ) } );
  1735. line4->AddPoint( { schIUScale.MilsToIU( 20 ), schIUScale.MilsToIU( -240 ) } );
  1736. if( aStyle == ASCH_POWER_PORT_STYLE::GOST_POWER_GROUND )
  1737. return { 0, schIUScale.MilsToIU( 300 ) };
  1738. LIB_SHAPE* circle = new LIB_SHAPE( aKsymbol, SHAPE_T::CIRCLE );
  1739. aKsymbol->AddDrawItem( circle );
  1740. circle->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1741. circle->SetPosition( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( -160 ) } );
  1742. circle->SetEnd( circle->GetPosition() + VECTOR2I( schIUScale.MilsToIU( 120 ), 0 ) );
  1743. return { 0, schIUScale.MilsToIU( 350 ) };
  1744. }
  1745. else if( aStyle == ASCH_POWER_PORT_STYLE::GOST_BAR )
  1746. {
  1747. LIB_SHAPE* line1 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1748. aKsymbol->AddDrawItem( line1 );
  1749. line1->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1750. line1->AddPoint( { 0, 0 } );
  1751. line1->AddPoint( { 0, schIUScale.MilsToIU( -200 ) } );
  1752. LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1753. aKsymbol->AddDrawItem( line2 );
  1754. line2->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1755. line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( -200 ) } );
  1756. line2->AddPoint( { schIUScale.MilsToIU( 100 ), schIUScale.MilsToIU( -200 ) } );
  1757. return { 0, schIUScale.MilsToIU( 250 ) };
  1758. }
  1759. else
  1760. {
  1761. if( aStyle != ASCH_POWER_PORT_STYLE::BAR )
  1762. {
  1763. aReporter->Report( _( "Power Port with unknown style imported as 'Bar' type." ),
  1764. RPT_SEVERITY_WARNING );
  1765. }
  1766. LIB_SHAPE* line1 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1767. aKsymbol->AddDrawItem( line1 );
  1768. line1->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1769. line1->AddPoint( { 0, 0 } );
  1770. line1->AddPoint( { 0, schIUScale.MilsToIU( -100 ) } );
  1771. LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1772. aKsymbol->AddDrawItem( line2 );
  1773. line2->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1774. line2->AddPoint( { schIUScale.MilsToIU( -50 ), schIUScale.MilsToIU( -100 ) } );
  1775. line2->AddPoint( { schIUScale.MilsToIU( 50 ), schIUScale.MilsToIU( -100 ) } );
  1776. return { 0, schIUScale.MilsToIU( 150 ) };
  1777. }
  1778. }
  1779. void SCH_ALTIUM_PLUGIN::ParsePowerPort( const std::map<wxString, wxString>& aProperties )
  1780. {
  1781. ASCH_POWER_PORT elem( aProperties );
  1782. LIB_ID libId = AltiumToKiCadLibID( getLibName(), elem.text );
  1783. LIB_SYMBOL* libSymbol = nullptr;
  1784. const auto& powerSymbolIt = m_powerSymbols.find( elem.text );
  1785. if( powerSymbolIt != m_powerSymbols.end() )
  1786. {
  1787. libSymbol = powerSymbolIt->second; // cache hit
  1788. }
  1789. else
  1790. {
  1791. libSymbol = new LIB_SYMBOL( wxEmptyString );
  1792. libSymbol->SetPower();
  1793. libSymbol->SetName( elem.text );
  1794. libSymbol->GetReferenceField().SetText( "#PWR" );
  1795. libSymbol->GetValueField().SetText( elem.text );
  1796. libSymbol->GetValueField().SetVisible( true );
  1797. libSymbol->SetDescription( wxString::Format( _( "Power symbol creates a global "
  1798. "label with name '%s'" ), elem.text ) );
  1799. libSymbol->SetKeyWords( "power-flag" );
  1800. libSymbol->SetLibId( libId );
  1801. // generate graphic
  1802. LIB_PIN* pin = new LIB_PIN( libSymbol );
  1803. libSymbol->AddDrawItem( pin );
  1804. pin->SetName( elem.text );
  1805. pin->SetPosition( { 0, 0 } );
  1806. pin->SetLength( 0 );
  1807. // marks the pin as a global label
  1808. pin->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN );
  1809. pin->SetVisible( false );
  1810. VECTOR2I valueFieldPos =
  1811. HelperGeneratePowerPortGraphics( libSymbol, elem.style, m_reporter );
  1812. libSymbol->GetValueField().SetPosition( valueFieldPos );
  1813. // this has to be done after parsing the LIB_SYMBOL!
  1814. m_pi->SaveSymbol( getLibFileName().GetFullPath(), libSymbol, m_properties.get() );
  1815. m_powerSymbols.insert( { elem.text, libSymbol } );
  1816. }
  1817. SCH_SCREEN* screen = getCurrentScreen();
  1818. wxCHECK( screen, /* void */ );
  1819. // each symbol has its own powerSymbolIt for now
  1820. SCH_SYMBOL* symbol = new SCH_SYMBOL();
  1821. symbol->SetRef( &m_sheetPath, "#PWR?" );
  1822. symbol->SetValue( &m_sheetPath, elem.text );
  1823. symbol->SetLibId( libId );
  1824. symbol->SetLibSymbol( new LIB_SYMBOL( *libSymbol ) );
  1825. SCH_FIELD* valueField = symbol->GetField( VALUE_FIELD );
  1826. valueField->SetVisible( elem.showNetName );
  1827. // TODO: Why do I need to set this a second time?
  1828. valueField->SetPosition( libSymbol->GetValueField().GetPosition() );
  1829. symbol->SetPosition( elem.location + m_sheetOffset );
  1830. switch( elem.orientation )
  1831. {
  1832. case ASCH_RECORD_ORIENTATION::RIGHTWARDS:
  1833. symbol->SetOrientation( SYMBOL_ORIENTATION_T::SYM_ORIENT_90 );
  1834. valueField->SetTextAngle( ANGLE_VERTICAL );
  1835. valueField->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
  1836. break;
  1837. case ASCH_RECORD_ORIENTATION::UPWARDS:
  1838. symbol->SetOrientation( SYMBOL_ORIENTATION_T::SYM_ORIENT_180 );
  1839. valueField->SetTextAngle( ANGLE_HORIZONTAL );
  1840. valueField->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
  1841. break;
  1842. case ASCH_RECORD_ORIENTATION::LEFTWARDS:
  1843. symbol->SetOrientation( SYMBOL_ORIENTATION_T::SYM_ORIENT_270 );
  1844. valueField->SetTextAngle( ANGLE_VERTICAL );
  1845. valueField->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
  1846. break;
  1847. case ASCH_RECORD_ORIENTATION::DOWNWARDS:
  1848. symbol->SetOrientation( SYMBOL_ORIENTATION_T::SYM_ORIENT_0 );
  1849. valueField->SetTextAngle( ANGLE_HORIZONTAL );
  1850. valueField->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
  1851. break;
  1852. default:
  1853. m_reporter->Report( _( "Pin has unexpected orientation." ), RPT_SEVERITY_WARNING );
  1854. break;
  1855. }
  1856. screen->Append( symbol );
  1857. }
  1858. void SCH_ALTIUM_PLUGIN::ParseHarnessPort( const ASCH_PORT& aElem )
  1859. {
  1860. SCH_TEXTBOX* textBox = new SCH_TEXTBOX();
  1861. textBox->SetText( aElem.Name );
  1862. textBox->SetTextColor( GetColorFromInt( aElem.TextColor ) );
  1863. int height = aElem.Height;
  1864. if( height <= 0 )
  1865. height = schIUScale.MilsToIU( 100 ); // chose default 50 grid
  1866. textBox->SetStartX( ( aElem.Location + m_sheetOffset ).x );
  1867. textBox->SetStartY( ( aElem.Location + m_sheetOffset ).y - ( height / 2 ) );
  1868. textBox->SetEndX( ( aElem.Location + m_sheetOffset ).x + ( aElem.Width ) );
  1869. textBox->SetEndY( ( aElem.Location + m_sheetOffset ).y + ( height / 2 ) );
  1870. textBox->SetFillColor( HARNESS_PORT_COLOR_DEFAULT_BACKGROUND );
  1871. textBox->SetFillMode( FILL_T::FILLED_WITH_COLOR );
  1872. textBox->SetStroke( STROKE_PARAMS( 2, PLOT_DASH_TYPE::DEFAULT,
  1873. HARNESS_PORT_COLOR_DEFAULT_OUTLINE ) );
  1874. switch( aElem.Alignment )
  1875. {
  1876. default:
  1877. case ASCH_TEXT_FRAME_ALIGNMENT::LEFT:
  1878. textBox->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
  1879. break;
  1880. case ASCH_TEXT_FRAME_ALIGNMENT::CENTER:
  1881. textBox->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
  1882. break;
  1883. case ASCH_TEXT_FRAME_ALIGNMENT::RIGHT:
  1884. textBox->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
  1885. break;
  1886. }
  1887. size_t fontId = static_cast<int>( aElem.FontID );
  1888. if( m_altiumSheet && fontId > 0 && fontId <= m_altiumSheet->fonts.size() )
  1889. {
  1890. const ASCH_SHEET_FONT& font = m_altiumSheet->fonts.at( fontId - 1 );
  1891. textBox->SetItalic( font.Italic );
  1892. textBox->SetBold( font.Bold );
  1893. textBox->SetTextSize( { font.Size / 2, font.Size / 2 } );
  1894. //textBox->SetFont( //how to set font, we have a font mane here: ( font.fontname );
  1895. }
  1896. textBox->SetFlags( IS_NEW );
  1897. SCH_SCREEN* screen = getCurrentScreen();
  1898. wxCHECK( screen, /* void */ );
  1899. screen->Append( textBox );
  1900. m_reporter->Report( wxString::Format( _( "Altium's harness port (%s) was imported as "
  1901. "a text box. Please review the imported "
  1902. "schematic." ),
  1903. aElem.Name ),
  1904. RPT_SEVERITY_WARNING );
  1905. }
  1906. void SCH_ALTIUM_PLUGIN::ParsePort( const ASCH_PORT& aElem )
  1907. {
  1908. if( !aElem.HarnessType.IsEmpty() )
  1909. {
  1910. // Parse harness ports after "Additional" compound section is parsed
  1911. m_altiumHarnessPortsCurrentSheet.emplace_back( aElem );
  1912. return;
  1913. }
  1914. VECTOR2I start = aElem.Location + m_sheetOffset;
  1915. VECTOR2I end = start;
  1916. switch( aElem.Style )
  1917. {
  1918. default:
  1919. case ASCH_PORT_STYLE::NONE_HORIZONTAL:
  1920. case ASCH_PORT_STYLE::LEFT:
  1921. case ASCH_PORT_STYLE::RIGHT:
  1922. case ASCH_PORT_STYLE::LEFT_RIGHT:
  1923. end.x += aElem.Width;
  1924. break;
  1925. case ASCH_PORT_STYLE::NONE_VERTICAL:
  1926. case ASCH_PORT_STYLE::TOP:
  1927. case ASCH_PORT_STYLE::BOTTOM:
  1928. case ASCH_PORT_STYLE::TOP_BOTTOM:
  1929. end.y -= aElem.Width;
  1930. break;
  1931. }
  1932. // Check which connection points exists in the schematic
  1933. SCH_SCREEN* screen = getCurrentScreen();
  1934. wxCHECK( screen, /* void */ );
  1935. bool startIsWireTerminal = screen->IsTerminalPoint( start, LAYER_WIRE );
  1936. bool startIsBusTerminal = screen->IsTerminalPoint( start, LAYER_BUS );
  1937. bool endIsWireTerminal = screen->IsTerminalPoint( end, LAYER_WIRE );
  1938. bool endIsBusTerminal = screen->IsTerminalPoint( end, LAYER_BUS );
  1939. // check if any of the points is a terminal point
  1940. // TODO: there seems a problem to detect approximated connections towards component pins?
  1941. bool connectionFound = startIsWireTerminal
  1942. || startIsBusTerminal
  1943. || endIsWireTerminal
  1944. || endIsBusTerminal;
  1945. if( !connectionFound )
  1946. {
  1947. m_reporter->Report( wxString::Format( _( "Port %s has no connections." ), aElem.Name ),
  1948. RPT_SEVERITY_WARNING );
  1949. }
  1950. // Select label position. In case both match, we will add a line later.
  1951. VECTOR2I position = ( startIsWireTerminal || startIsBusTerminal ) ? start : end;
  1952. SCH_LABEL_BASE* label;
  1953. // TODO: detect correct label type depending on sheet settings, etc.
  1954. #if 1 // Set to 1 to use SCH_HIERLABEL label, 0 to use SCH_GLOBALLABEL
  1955. {
  1956. label = new SCH_HIERLABEL( position, aElem.Name );
  1957. }
  1958. #else
  1959. label = new SCH_GLOBALLABEL( position, aElem.Name );
  1960. #endif
  1961. switch( aElem.IOtype )
  1962. {
  1963. default:
  1964. case ASCH_PORT_IOTYPE::UNSPECIFIED:
  1965. label->SetShape( LABEL_FLAG_SHAPE::L_UNSPECIFIED );
  1966. break;
  1967. case ASCH_PORT_IOTYPE::OUTPUT:
  1968. label->SetShape( LABEL_FLAG_SHAPE::L_OUTPUT );
  1969. break;
  1970. case ASCH_PORT_IOTYPE::INPUT:
  1971. label->SetShape( LABEL_FLAG_SHAPE::L_INPUT );
  1972. break;
  1973. case ASCH_PORT_IOTYPE::BIDI:
  1974. label->SetShape( LABEL_FLAG_SHAPE::L_BIDI );
  1975. break;
  1976. }
  1977. switch( aElem.Style )
  1978. {
  1979. default:
  1980. case ASCH_PORT_STYLE::NONE_HORIZONTAL:
  1981. case ASCH_PORT_STYLE::LEFT:
  1982. case ASCH_PORT_STYLE::RIGHT:
  1983. case ASCH_PORT_STYLE::LEFT_RIGHT:
  1984. if( ( startIsWireTerminal || startIsBusTerminal ) )
  1985. label->SetTextSpinStyle( TEXT_SPIN_STYLE::RIGHT );
  1986. else
  1987. label->SetTextSpinStyle( TEXT_SPIN_STYLE::LEFT );
  1988. break;
  1989. case ASCH_PORT_STYLE::NONE_VERTICAL:
  1990. case ASCH_PORT_STYLE::TOP:
  1991. case ASCH_PORT_STYLE::BOTTOM:
  1992. case ASCH_PORT_STYLE::TOP_BOTTOM:
  1993. if( ( startIsWireTerminal || startIsBusTerminal ) )
  1994. label->SetTextSpinStyle( TEXT_SPIN_STYLE::UP );
  1995. else
  1996. label->SetTextSpinStyle( TEXT_SPIN_STYLE::BOTTOM );
  1997. break;
  1998. }
  1999. label->AutoplaceFields( screen, false );
  2000. // Default "Sheet References" field should be hidden, at least for now
  2001. if( label->GetFields().size() > 0 )
  2002. label->GetFields()[0].SetVisible( false );
  2003. label->SetFlags( IS_NEW );
  2004. screen->Append( label );
  2005. // This is a hack, for the case both connection points are valid: add a small wire
  2006. if( ( startIsWireTerminal && endIsWireTerminal ) )
  2007. {
  2008. SCH_LINE* wire = new SCH_LINE( start, SCH_LAYER_ID::LAYER_WIRE );
  2009. wire->SetEndPoint( end );
  2010. wire->SetLineWidth( schIUScale.MilsToIU( 2 ) );
  2011. wire->SetFlags( IS_NEW );
  2012. screen->Append( wire );
  2013. }
  2014. else if( startIsBusTerminal && endIsBusTerminal )
  2015. {
  2016. SCH_LINE* wire = new SCH_LINE( start, SCH_LAYER_ID::LAYER_BUS );
  2017. wire->SetEndPoint( end );
  2018. wire->SetLineWidth( schIUScale.MilsToIU( 2 ) );
  2019. wire->SetFlags( IS_NEW );
  2020. screen->Append( wire );
  2021. }
  2022. }
  2023. void SCH_ALTIUM_PLUGIN::ParseNoERC( const std::map<wxString, wxString>& aProperties )
  2024. {
  2025. ASCH_NO_ERC elem( aProperties );
  2026. SCH_SCREEN* screen = getCurrentScreen();
  2027. wxCHECK( screen, /* void */ );
  2028. if( elem.isActive )
  2029. {
  2030. SCH_NO_CONNECT* noConnect = new SCH_NO_CONNECT( elem.location + m_sheetOffset );
  2031. noConnect->SetFlags( IS_NEW );
  2032. screen->Append( noConnect );
  2033. }
  2034. }
  2035. void SCH_ALTIUM_PLUGIN::ParseNetLabel( const std::map<wxString, wxString>& aProperties )
  2036. {
  2037. ASCH_NET_LABEL elem( aProperties );
  2038. SCH_LABEL* label = new SCH_LABEL( elem.location + m_sheetOffset, elem.text );
  2039. SCH_SCREEN* screen = getCurrentScreen();
  2040. wxCHECK( screen, /* void */ );
  2041. switch( elem.orientation )
  2042. {
  2043. case ASCH_RECORD_ORIENTATION::RIGHTWARDS:
  2044. label->SetTextSpinStyle( TEXT_SPIN_STYLE::RIGHT );
  2045. break;
  2046. case ASCH_RECORD_ORIENTATION::UPWARDS:
  2047. label->SetTextSpinStyle( TEXT_SPIN_STYLE::UP );
  2048. break;
  2049. case ASCH_RECORD_ORIENTATION::LEFTWARDS:
  2050. label->SetTextSpinStyle( TEXT_SPIN_STYLE::LEFT );
  2051. break;
  2052. case ASCH_RECORD_ORIENTATION::DOWNWARDS:
  2053. label->SetTextSpinStyle( TEXT_SPIN_STYLE::BOTTOM );
  2054. break;
  2055. default:
  2056. break;
  2057. }
  2058. label->SetFlags( IS_NEW );
  2059. screen->Append( label );
  2060. }
  2061. void SCH_ALTIUM_PLUGIN::ParseBus( const std::map<wxString, wxString>& aProperties )
  2062. {
  2063. ASCH_BUS elem( aProperties );
  2064. SCH_SCREEN* screen = getCurrentScreen();
  2065. wxCHECK( screen, /* void */ );
  2066. for( size_t i = 0; i + 1 < elem.points.size(); i++ )
  2067. {
  2068. SCH_LINE* bus = new SCH_LINE( elem.points.at( i ) + m_sheetOffset,
  2069. SCH_LAYER_ID::LAYER_BUS );
  2070. bus->SetEndPoint( elem.points.at( i + 1 ) + m_sheetOffset );
  2071. bus->SetLineWidth( elem.lineWidth );
  2072. bus->SetFlags( IS_NEW );
  2073. screen->Append( bus );
  2074. }
  2075. }
  2076. void SCH_ALTIUM_PLUGIN::ParseWire( const std::map<wxString, wxString>& aProperties )
  2077. {
  2078. ASCH_WIRE elem( aProperties );
  2079. SCH_SCREEN* screen = getCurrentScreen();
  2080. wxCHECK( screen, /* void */ );
  2081. for( size_t i = 0; i + 1 < elem.points.size(); i++ )
  2082. {
  2083. SCH_LINE* wire =
  2084. new SCH_LINE( elem.points.at( i ) + m_sheetOffset, SCH_LAYER_ID::LAYER_WIRE );
  2085. wire->SetEndPoint( elem.points.at( i + 1 ) + m_sheetOffset );
  2086. wire->SetLineWidth( elem.lineWidth );
  2087. wire->SetFlags( IS_NEW );
  2088. screen->Append( wire );
  2089. }
  2090. }
  2091. void SCH_ALTIUM_PLUGIN::ParseJunction( const std::map<wxString, wxString>& aProperties )
  2092. {
  2093. ASCH_JUNCTION elem( aProperties );
  2094. SCH_JUNCTION* junction = new SCH_JUNCTION( elem.location + m_sheetOffset );
  2095. SCH_SCREEN* screen = getCurrentScreen();
  2096. wxCHECK( screen, /* void */ );
  2097. junction->SetFlags( IS_NEW );
  2098. screen->Append( junction );
  2099. }
  2100. void SCH_ALTIUM_PLUGIN::ParseImage( const std::map<wxString, wxString>& aProperties )
  2101. {
  2102. ASCH_IMAGE elem( aProperties );
  2103. VECTOR2I center = ( elem.location + elem.corner ) / 2 + m_sheetOffset;
  2104. std::unique_ptr<SCH_BITMAP> bitmap = std::make_unique<SCH_BITMAP>( center );
  2105. SCH_SCREEN* screen = getCurrentScreen();
  2106. wxCHECK( screen, /* void */ );
  2107. if( elem.embedimage )
  2108. {
  2109. const ASCH_STORAGE_FILE* storageFile = GetFileFromStorage( elem.filename );
  2110. if( !storageFile )
  2111. {
  2112. wxString msg = wxString::Format( _( "Embedded file %s not found in storage." ),
  2113. elem.filename );
  2114. m_reporter->Report( msg, RPT_SEVERITY_ERROR );
  2115. return;
  2116. }
  2117. wxString storagePath = wxFileName::CreateTempFileName( "kicad_import_" );
  2118. // As wxZlibInputStream is not seekable, we need to write a temporary file
  2119. wxMemoryInputStream fileStream( storageFile->data.data(), storageFile->data.size() );
  2120. wxZlibInputStream zlibInputStream( fileStream );
  2121. wxFFileOutputStream outputStream( storagePath );
  2122. outputStream.Write( zlibInputStream );
  2123. outputStream.Close();
  2124. if( !bitmap->ReadImageFile( storagePath ) )
  2125. {
  2126. m_reporter->Report( wxString::Format( _( "Error reading image %s." ), storagePath ),
  2127. RPT_SEVERITY_ERROR );
  2128. return;
  2129. }
  2130. // Remove temporary file
  2131. wxRemoveFile( storagePath );
  2132. }
  2133. else
  2134. {
  2135. if( !wxFileExists( elem.filename ) )
  2136. {
  2137. m_reporter->Report( wxString::Format( _( "File not found %s." ), elem.filename ),
  2138. RPT_SEVERITY_ERROR );
  2139. return;
  2140. }
  2141. if( !bitmap->ReadImageFile( elem.filename ) )
  2142. {
  2143. m_reporter->Report( wxString::Format( _( "Error reading image %s." ), elem.filename ),
  2144. RPT_SEVERITY_ERROR );
  2145. return;
  2146. }
  2147. }
  2148. // we only support one scale, thus we need to select one in case it does not keep aspect ratio
  2149. VECTOR2I currentImageSize = bitmap->GetSize();
  2150. VECTOR2I expectedImageSize = elem.location - elem.corner;
  2151. double scaleX = std::abs( static_cast<double>( expectedImageSize.x ) / currentImageSize.x );
  2152. double scaleY = std::abs( static_cast<double>( expectedImageSize.y ) / currentImageSize.y );
  2153. bitmap->SetImageScale( std::min( scaleX, scaleY ) );
  2154. bitmap->SetFlags( IS_NEW );
  2155. screen->Append( bitmap.release() );
  2156. }
  2157. void SCH_ALTIUM_PLUGIN::ParseSheet( const std::map<wxString, wxString>& aProperties )
  2158. {
  2159. m_altiumSheet = std::make_unique<ASCH_SHEET>( aProperties );
  2160. SCH_SCREEN* screen = getCurrentScreen();
  2161. wxCHECK( screen, /* void */ );
  2162. PAGE_INFO pageInfo;
  2163. bool isPortrait = m_altiumSheet->sheetOrientation == ASCH_SHEET_WORKSPACEORIENTATION::PORTRAIT;
  2164. switch( m_altiumSheet->sheetSize )
  2165. {
  2166. default:
  2167. case ASCH_SHEET_SIZE::A4: pageInfo.SetType( "A4", isPortrait ); break;
  2168. case ASCH_SHEET_SIZE::A3: pageInfo.SetType( "A3", isPortrait ); break;
  2169. case ASCH_SHEET_SIZE::A2: pageInfo.SetType( "A2", isPortrait ); break;
  2170. case ASCH_SHEET_SIZE::A1: pageInfo.SetType( "A1", isPortrait ); break;
  2171. case ASCH_SHEET_SIZE::A0: pageInfo.SetType( "A0", isPortrait ); break;
  2172. case ASCH_SHEET_SIZE::A: pageInfo.SetType( "A", isPortrait ); break;
  2173. case ASCH_SHEET_SIZE::B: pageInfo.SetType( "B", isPortrait ); break;
  2174. case ASCH_SHEET_SIZE::C: pageInfo.SetType( "C", isPortrait ); break;
  2175. case ASCH_SHEET_SIZE::D: pageInfo.SetType( "D", isPortrait ); break;
  2176. case ASCH_SHEET_SIZE::E: pageInfo.SetType( "E", isPortrait ); break;
  2177. case ASCH_SHEET_SIZE::LETTER: pageInfo.SetType( "USLetter", isPortrait ); break;
  2178. case ASCH_SHEET_SIZE::LEGAL: pageInfo.SetType( "USLegal", isPortrait ); break;
  2179. case ASCH_SHEET_SIZE::TABLOID: pageInfo.SetType( "A3", isPortrait ); break;
  2180. case ASCH_SHEET_SIZE::ORCAD_A: pageInfo.SetType( "A", isPortrait ); break;
  2181. case ASCH_SHEET_SIZE::ORCAD_B: pageInfo.SetType( "B", isPortrait ); break;
  2182. case ASCH_SHEET_SIZE::ORCAD_C: pageInfo.SetType( "C", isPortrait ); break;
  2183. case ASCH_SHEET_SIZE::ORCAD_D: pageInfo.SetType( "D", isPortrait ); break;
  2184. case ASCH_SHEET_SIZE::ORCAD_E: pageInfo.SetType( "E", isPortrait ); break;
  2185. }
  2186. screen->SetPageSettings( pageInfo );
  2187. m_sheetOffset = { 0, pageInfo.GetHeightIU( schIUScale.IU_PER_MILS ) };
  2188. }
  2189. void SCH_ALTIUM_PLUGIN::ParseSheetName( const std::map<wxString, wxString>& aProperties )
  2190. {
  2191. ASCH_SHEET_NAME elem( aProperties );
  2192. const auto& sheetIt = m_sheets.find( elem.ownerindex );
  2193. if( sheetIt == m_sheets.end() )
  2194. {
  2195. m_reporter->Report( wxString::Format( wxT( "Sheetname's owner (%d) not found." ),
  2196. elem.ownerindex ),
  2197. RPT_SEVERITY_DEBUG );
  2198. return;
  2199. }
  2200. SCH_FIELD& sheetNameField = sheetIt->second->GetFields()[SHEETNAME];
  2201. sheetNameField.SetPosition( elem.location + m_sheetOffset );
  2202. sheetNameField.SetText( elem.text );
  2203. sheetNameField.SetVisible( !elem.isHidden );
  2204. SetTextPositioning( &sheetNameField, ASCH_LABEL_JUSTIFICATION::BOTTOM_LEFT, elem.orientation );
  2205. }
  2206. void SCH_ALTIUM_PLUGIN::ParseFileName( const std::map<wxString, wxString>& aProperties )
  2207. {
  2208. ASCH_FILE_NAME elem( aProperties );
  2209. const auto& sheetIt = m_sheets.find( elem.ownerindex );
  2210. if( sheetIt == m_sheets.end() )
  2211. {
  2212. m_reporter->Report( wxString::Format( wxT( "Filename's owner (%d) not found." ),
  2213. elem.ownerindex ),
  2214. RPT_SEVERITY_DEBUG );
  2215. return;
  2216. }
  2217. SCH_FIELD& filenameField = sheetIt->second->GetFields()[SHEETFILENAME];
  2218. filenameField.SetPosition( elem.location + m_sheetOffset );
  2219. // Keep the filename of the Altium file until after the file is actually loaded.
  2220. filenameField.SetText( elem.text );
  2221. filenameField.SetVisible( !elem.isHidden );
  2222. SetTextPositioning( &filenameField, ASCH_LABEL_JUSTIFICATION::BOTTOM_LEFT, elem.orientation );
  2223. }
  2224. void SCH_ALTIUM_PLUGIN::ParseDesignator( const std::map<wxString, wxString>& aProperties )
  2225. {
  2226. ASCH_DESIGNATOR elem( aProperties );
  2227. const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
  2228. if( libSymbolIt == m_libSymbols.end() )
  2229. {
  2230. // TODO: e.g. can depend on Template (RECORD=39
  2231. m_reporter->Report( wxString::Format( wxT( "Designator's owner (%d) not found." ),
  2232. elem.ownerindex ),
  2233. RPT_SEVERITY_DEBUG );
  2234. return;
  2235. }
  2236. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  2237. SCH_SHEET_PATH sheetpath;
  2238. SCH_SCREEN* screen = getCurrentScreen();
  2239. wxCHECK( screen, /* void */ );
  2240. // Graphics symbols have no reference. '#GRAPHIC' allows them to not have footprint associated.
  2241. // Note: not all unnamed imported symbols are necessarily graphics.
  2242. bool emptyRef = elem.text.IsEmpty();
  2243. symbol->SetRef( &m_sheetPath, emptyRef ? "#GRAPHIC" : elem.text );
  2244. // I am not sure value and ref should be invisible just because emptyRef is true
  2245. // I have examples with this criteria fully incorrect.
  2246. bool visible = !emptyRef;
  2247. symbol->GetField( VALUE_FIELD )->SetVisible( visible );
  2248. symbol->GetField( REFERENCE_FIELD )->SetVisible( visible );
  2249. SCH_FIELD* field = symbol->GetField( REFERENCE_FIELD );
  2250. field->SetPosition( elem.location + m_sheetOffset );
  2251. SetTextPositioning( field, elem.justification, elem.orientation );
  2252. }
  2253. void SCH_ALTIUM_PLUGIN::ParseBusEntry( const std::map<wxString, wxString>& aProperties )
  2254. {
  2255. ASCH_BUS_ENTRY elem( aProperties );
  2256. SCH_SCREEN* screen = getCurrentScreen();
  2257. wxCHECK( screen, /* void */ );
  2258. SCH_BUS_WIRE_ENTRY* busWireEntry = new SCH_BUS_WIRE_ENTRY( elem.location + m_sheetOffset );
  2259. VECTOR2I vector = elem.corner - elem.location;
  2260. busWireEntry->SetSize( { vector.x, vector.y } );
  2261. busWireEntry->SetFlags( IS_NEW );
  2262. screen->Append( busWireEntry );
  2263. }
  2264. void SCH_ALTIUM_PLUGIN::ParseParameter( const std::map<wxString, wxString>& aProperties )
  2265. {
  2266. ASCH_PARAMETER elem( aProperties );
  2267. SCH_SCREEN* screen = getCurrentScreen();
  2268. wxCHECK( screen, /* void */ );
  2269. // TODO: fill in replacements from variant, sheet and project
  2270. std::map<wxString, wxString> variableMap = {
  2271. { "COMMENT", "VALUE" },
  2272. { "VALUE", "ALTIUM_VALUE" },
  2273. };
  2274. if( elem.ownerindex <= 0 && elem.ownerpartid == ALTIUM_COMPONENT_NONE )
  2275. {
  2276. // This is some sheet parameter
  2277. if( elem.text == "*" )
  2278. return; // indicates parameter not set?
  2279. wxString paramName = elem.name.Upper();
  2280. if( paramName == "SHEETNUMBER" )
  2281. {
  2282. m_sheetPath.SetPageNumber( elem.text );
  2283. }
  2284. else if( paramName == "TITLE" )
  2285. {
  2286. m_currentTitleBlock->SetTitle( elem.text );
  2287. }
  2288. else if( paramName == "REVISION" )
  2289. {
  2290. m_currentTitleBlock->SetRevision( elem.text );
  2291. }
  2292. else if( paramName == "DATE" )
  2293. {
  2294. m_currentTitleBlock->SetDate( elem.text );
  2295. }
  2296. else if( paramName == "COMPANYNAME" )
  2297. {
  2298. m_currentTitleBlock->SetCompany( elem.text );
  2299. }
  2300. else
  2301. {
  2302. m_schematic->Prj().GetTextVars()[ paramName ] = elem.text;
  2303. }
  2304. }
  2305. else
  2306. {
  2307. const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
  2308. if( libSymbolIt == m_libSymbols.end() )
  2309. {
  2310. // TODO: e.g. can depend on Template (RECORD=39
  2311. return;
  2312. }
  2313. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  2314. SCH_FIELD* field = nullptr;
  2315. wxString upperName = elem.name.Upper();
  2316. if( upperName == "COMMENT" )
  2317. {
  2318. field = symbol->GetField( VALUE_FIELD );
  2319. }
  2320. else
  2321. {
  2322. int fieldIdx = symbol->GetFieldCount();
  2323. wxString fieldName = elem.name.Upper();
  2324. if( fieldName.IsEmpty() )
  2325. {
  2326. int disambiguate = 1;
  2327. do
  2328. {
  2329. fieldName = wxString::Format( "ALTIUM_UNNAMED_%d", disambiguate++ );
  2330. } while( !symbol->GetFieldText( fieldName ).IsEmpty() );
  2331. }
  2332. else if( fieldName == "VALUE" )
  2333. {
  2334. fieldName = "ALTIUM_VALUE";
  2335. }
  2336. field = symbol->AddField( SCH_FIELD( VECTOR2I(), fieldIdx, symbol, fieldName ) );
  2337. }
  2338. wxString kicadText = AltiumSpecialStringsToKiCadVariables( elem.text, variableMap );
  2339. field->SetText( kicadText );
  2340. field->SetPosition( elem.location + m_sheetOffset );
  2341. field->SetVisible( !elem.isHidden );
  2342. SetTextPositioning( field, elem.justification, elem.orientation );
  2343. }
  2344. }
  2345. void SCH_ALTIUM_PLUGIN::ParseImplementationList( int aIndex,
  2346. const std::map<wxString, wxString>& aProperties )
  2347. {
  2348. ASCH_IMPLEMENTATION_LIST elem( aProperties );
  2349. m_altiumImplementationList.emplace( aIndex, elem.ownerindex );
  2350. }
  2351. void SCH_ALTIUM_PLUGIN::ParseImplementation( const std::map<wxString, wxString>& aProperties )
  2352. {
  2353. ASCH_IMPLEMENTATION elem( aProperties );
  2354. // Only get footprint, currently assigned only
  2355. if( ( elem.type == "PCBLIB" ) && ( elem.isCurrent ) )
  2356. {
  2357. const auto& implementationOwnerIt = m_altiumImplementationList.find( elem.ownerindex );
  2358. if( implementationOwnerIt == m_altiumImplementationList.end() )
  2359. {
  2360. m_reporter->Report( wxString::Format( wxT( "Implementation's owner (%d) not found." ),
  2361. elem.ownerindex ),
  2362. RPT_SEVERITY_DEBUG );
  2363. return;
  2364. }
  2365. const auto& libSymbolIt = m_libSymbols.find( implementationOwnerIt->second );
  2366. if( libSymbolIt == m_libSymbols.end() )
  2367. {
  2368. m_reporter->Report( wxString::Format( wxT( "Footprint's owner (%d) not found." ),
  2369. implementationOwnerIt->second ),
  2370. RPT_SEVERITY_DEBUG );
  2371. return;
  2372. }
  2373. LIB_ID fpLibId = AltiumToKiCadLibID( elem.libname, elem.name );
  2374. wxArrayString fpFilters;
  2375. fpFilters.Add( fpLibId.Format() );
  2376. libSymbolIt->second->SetFPFilters( fpFilters ); // TODO: not ideal as we overwrite it
  2377. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  2378. symbol->SetFootprint( fpLibId.Format() );
  2379. }
  2380. }