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.

2431 lines
84 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 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_sheet.h>
  44. #include <sch_sheet_pin.h>
  45. #include <sch_text.h>
  46. #include <bezier_curves.h>
  47. #include <compoundfilereader.h>
  48. #include <string_utils.h>
  49. #include <sch_edit_frame.h>
  50. #include <trigo.h>
  51. #include <wildcards_and_files_ext.h>
  52. #include <wx/mstream.h>
  53. #include <wx/log.h>
  54. #include <wx/zstream.h>
  55. #include <wx/wfstream.h>
  56. #include <trigo.h>
  57. static const VECTOR2I GetRelativePosition( const VECTOR2I& aPosition, const SCH_SYMBOL* aSymbol )
  58. {
  59. TRANSFORM t = aSymbol->GetTransform().InverseTransform();
  60. return t.TransformCoordinate( aPosition - aSymbol->GetPosition() );
  61. }
  62. static COLOR4D GetColorFromInt( int color )
  63. {
  64. int red = color & 0x0000FF;
  65. int green = ( color & 0x00FF00 ) >> 8;
  66. int blue = ( color & 0xFF0000 ) >> 16;
  67. return COLOR4D().FromCSSRGBA( red, green, blue, 1.0 );
  68. }
  69. static PLOT_DASH_TYPE GetPlotDashType( const ASCH_POLYLINE_LINESTYLE linestyle )
  70. {
  71. switch( linestyle )
  72. {
  73. case ASCH_POLYLINE_LINESTYLE::SOLID: return PLOT_DASH_TYPE::SOLID;
  74. case ASCH_POLYLINE_LINESTYLE::DASHED: return PLOT_DASH_TYPE::DASH;
  75. case ASCH_POLYLINE_LINESTYLE::DOTTED: return PLOT_DASH_TYPE::DOT;
  76. case ASCH_POLYLINE_LINESTYLE::DASH_DOTTED: return PLOT_DASH_TYPE::DASHDOT;
  77. default: return PLOT_DASH_TYPE::DEFAULT;
  78. }
  79. }
  80. static void SetSchShapeFillAndColor( const ASCH_SHAPE_INTERFACE& elem, SCH_SHAPE* shape )
  81. {
  82. shape->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) );
  83. if( !elem.isSolid )
  84. {
  85. shape->SetFillMode( FILL_T::NO_FILL );
  86. }
  87. else
  88. {
  89. shape->SetFillMode( FILL_T::FILLED_WITH_COLOR );
  90. shape->SetFillColor( GetColorFromInt( elem.areacolor ) );
  91. }
  92. }
  93. static void SetLibShapeFillAndColor( const ASCH_SHAPE_INTERFACE& elem, LIB_SHAPE* shape )
  94. {
  95. shape->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) );
  96. if( !elem.isSolid )
  97. {
  98. shape->SetFillMode( FILL_T::NO_FILL );
  99. }
  100. else if( elem.color == elem.areacolor )
  101. {
  102. shape->SetFillMode( FILL_T::FILLED_SHAPE );
  103. }
  104. else
  105. {
  106. shape->SetFillMode( FILL_T::FILLED_WITH_BG_BODYCOLOR );
  107. }
  108. }
  109. SCH_ALTIUM_PLUGIN::SCH_ALTIUM_PLUGIN()
  110. {
  111. m_rootSheet = nullptr;
  112. m_currentSheet = nullptr;
  113. m_schematic = nullptr;
  114. m_reporter = &WXLOG_REPORTER::GetInstance();
  115. }
  116. SCH_ALTIUM_PLUGIN::~SCH_ALTIUM_PLUGIN()
  117. {
  118. }
  119. const wxString SCH_ALTIUM_PLUGIN::GetName() const
  120. {
  121. return "Altium";
  122. }
  123. const wxString SCH_ALTIUM_PLUGIN::GetFileExtension() const
  124. {
  125. return "SchDoc";
  126. }
  127. const wxString SCH_ALTIUM_PLUGIN::GetLibraryFileExtension() const
  128. {
  129. return "SchLib";
  130. }
  131. int SCH_ALTIUM_PLUGIN::GetModifyHash() const
  132. {
  133. return 0;
  134. }
  135. bool SCH_ALTIUM_PLUGIN::CheckHeader( const wxString& aFileName )
  136. {
  137. // TODO
  138. return true;
  139. }
  140. wxString SCH_ALTIUM_PLUGIN::getLibName()
  141. {
  142. if( m_libName.IsEmpty() )
  143. {
  144. // Try to come up with a meaningful name
  145. m_libName = m_schematic->Prj().GetProjectName();
  146. if( m_libName.IsEmpty() )
  147. {
  148. wxFileName fn( m_rootSheet->GetFileName() );
  149. m_libName = fn.GetName();
  150. }
  151. if( m_libName.IsEmpty() )
  152. m_libName = "noname";
  153. m_libName += "-altium-import";
  154. m_libName = LIB_ID::FixIllegalChars( m_libName, true );
  155. }
  156. return m_libName;
  157. }
  158. wxFileName SCH_ALTIUM_PLUGIN::getLibFileName()
  159. {
  160. wxFileName fn( m_schematic->Prj().GetProjectPath(), getLibName(), KiCadSymbolLibFileExtension );
  161. return fn;
  162. }
  163. SCH_SHEET* SCH_ALTIUM_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchematic,
  164. SCH_SHEET* aAppendToMe, const PROPERTIES* aProperties )
  165. {
  166. wxASSERT( !aFileName || aSchematic != nullptr );
  167. wxFileName fileName( aFileName );
  168. fileName.SetExt( KiCadSchematicFileExtension );
  169. m_schematic = aSchematic;
  170. // Delete on exception, if I own m_rootSheet, according to aAppendToMe
  171. std::unique_ptr<SCH_SHEET> deleter( aAppendToMe ? nullptr : m_rootSheet );
  172. if( aAppendToMe )
  173. {
  174. wxCHECK_MSG( aSchematic->IsValid(), nullptr, "Can't append to a schematic with no root!" );
  175. m_rootSheet = &aSchematic->Root();
  176. }
  177. else
  178. {
  179. m_rootSheet = new SCH_SHEET( aSchematic );
  180. m_rootSheet->SetFileName( fileName.GetFullPath() );
  181. aSchematic->SetRoot( m_rootSheet );
  182. SCH_SHEET_PATH sheetpath;
  183. sheetpath.push_back( m_rootSheet );
  184. m_rootSheet->AddInstance( sheetpath );
  185. m_rootSheet->SetPageNumber( sheetpath, "#" ); // We'll update later if we find a
  186. // pageNumber record for it
  187. }
  188. if( !m_rootSheet->GetScreen() )
  189. {
  190. SCH_SCREEN* screen = new SCH_SCREEN( m_schematic );
  191. screen->SetFileName( aFileName );
  192. m_rootSheet->SetScreen( screen );
  193. }
  194. SYMBOL_LIB_TABLE* libTable = m_schematic->Prj().SchSymbolLibTable();
  195. wxCHECK_MSG( libTable, nullptr, "Could not load symbol lib table." );
  196. m_pi.set( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
  197. /// @note No check is being done here to see if the existing symbol library exists so this
  198. /// will overwrite the existing one.
  199. if( !libTable->HasLibrary( getLibName() ) )
  200. {
  201. // Create a new empty symbol library.
  202. m_pi->CreateSymbolLib( getLibFileName().GetFullPath() );
  203. wxString libTableUri = "${KIPRJMOD}/" + getLibFileName().GetFullName();
  204. // Add the new library to the project symbol library table.
  205. libTable->InsertRow( new SYMBOL_LIB_TABLE_ROW( getLibName(), libTableUri,
  206. wxString( "KiCad" ) ) );
  207. // Save project symbol library table.
  208. wxFileName fn( m_schematic->Prj().GetProjectPath(),
  209. SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
  210. // So output formatter goes out of scope and closes the file before reloading.
  211. {
  212. FILE_OUTPUTFORMATTER formatter( fn.GetFullPath() );
  213. libTable->Format( &formatter, 0 );
  214. }
  215. // Reload the symbol library table.
  216. m_schematic->Prj().SetElem( PROJECT::ELEM_SYMBOL_LIB_TABLE, nullptr );
  217. m_schematic->Prj().SchSymbolLibTable();
  218. }
  219. m_currentSheet = m_rootSheet;
  220. ParseAltiumSch( aFileName );
  221. m_pi->SaveLibrary( getLibFileName().GetFullPath() );
  222. SCH_SCREENS allSheets( m_rootSheet );
  223. allSheets.UpdateSymbolLinks(); // Update all symbol library links for all sheets.
  224. allSheets.ClearEditFlags();
  225. return m_rootSheet;
  226. }
  227. void SCH_ALTIUM_PLUGIN::ParseAltiumSch( const wxString& aFileName )
  228. {
  229. // Open file
  230. FILE* fp = wxFopen( aFileName, "rb" );
  231. if( fp == nullptr )
  232. {
  233. m_reporter->Report( wxString::Format( _( "Cannot open file '%s'." ), aFileName ),
  234. RPT_SEVERITY_ERROR );
  235. return;
  236. }
  237. fseek( fp, 0, SEEK_END );
  238. long len = ftell( fp );
  239. if( len < 0 )
  240. {
  241. fclose( fp );
  242. THROW_IO_ERROR( "Read error, cannot determine length of file." );
  243. }
  244. std::unique_ptr<unsigned char[]> buffer( new unsigned char[len] );
  245. fseek( fp, 0, SEEK_SET );
  246. size_t bytesRead = fread( buffer.get(), sizeof( unsigned char ), len, fp );
  247. fclose( fp );
  248. if( static_cast<size_t>( len ) != bytesRead )
  249. THROW_IO_ERROR( "Read error." );
  250. try
  251. {
  252. CFB::CompoundFileReader reader( buffer.get(), bytesRead );
  253. ParseStorage( reader ); // we need this before parsing the FileHeader
  254. ParseFileHeader( reader );
  255. }
  256. catch( CFB::CFBException& exception )
  257. {
  258. THROW_IO_ERROR( exception.what() );
  259. }
  260. }
  261. void SCH_ALTIUM_PLUGIN::ParseStorage( const CFB::CompoundFileReader& aReader )
  262. {
  263. const CFB::COMPOUND_FILE_ENTRY* file = FindStream( aReader, "Storage" );
  264. if( file == nullptr )
  265. return;
  266. ALTIUM_PARSER reader( aReader, file );
  267. std::map<wxString, wxString> properties = reader.ReadProperties();
  268. wxString header = ALTIUM_PARSER::ReadString( properties, "HEADER", "" );
  269. int weight = ALTIUM_PARSER::ReadInt( properties, "WEIGHT", 0 );
  270. if( weight < 0 )
  271. THROW_IO_ERROR( "Storage weight is negative!" );
  272. for( int i = 0; i < weight; i++ )
  273. {
  274. m_altiumStorage.emplace_back( reader );
  275. }
  276. if( reader.HasParsingError() )
  277. THROW_IO_ERROR( "stream was not parsed correctly!" );
  278. // TODO pointhi: is it possible to have multiple headers in one Storage file? Otherwise
  279. // throw IO Error.
  280. if( reader.GetRemainingBytes() != 0 )
  281. {
  282. m_reporter->Report( wxString::Format( _( "Storage file not fully parsed "
  283. "(%d bytes remaining)." ),
  284. reader.GetRemainingBytes() ),
  285. RPT_SEVERITY_ERROR );
  286. }
  287. }
  288. void SCH_ALTIUM_PLUGIN::ParseFileHeader( const CFB::CompoundFileReader& aReader )
  289. {
  290. const CFB::COMPOUND_FILE_ENTRY* file = FindStream( aReader, "FileHeader" );
  291. if( file == nullptr )
  292. THROW_IO_ERROR( "FileHeader not found" );
  293. ALTIUM_PARSER reader( aReader, file );
  294. if( reader.GetRemainingBytes() <= 0 )
  295. {
  296. THROW_IO_ERROR( "FileHeader does not contain any data" );
  297. }
  298. else
  299. {
  300. std::map<wxString, wxString> properties = reader.ReadProperties();
  301. int recordId = ALTIUM_PARSER::ReadInt( properties, "RECORD", 0 );
  302. ALTIUM_SCH_RECORD record = static_cast<ALTIUM_SCH_RECORD>( recordId );
  303. if( record != ALTIUM_SCH_RECORD::HEADER )
  304. THROW_IO_ERROR( "Header expected" );
  305. }
  306. // Prepare some local variables
  307. wxASSERT( m_altiumPortsCurrentSheet.empty() );
  308. wxASSERT( !m_currentTitleBlock );
  309. m_currentTitleBlock = std::make_unique<TITLE_BLOCK>();
  310. // index is required to resolve OWNERINDEX
  311. for( int index = 0; reader.GetRemainingBytes() > 0; index++ )
  312. {
  313. std::map<wxString, wxString> properties = reader.ReadProperties();
  314. int recordId = ALTIUM_PARSER::ReadInt( properties, "RECORD", 0 );
  315. ALTIUM_SCH_RECORD record = static_cast<ALTIUM_SCH_RECORD>( recordId );
  316. // see: https://github.com/vadmium/python-altium/blob/master/format.md
  317. switch( record )
  318. {
  319. case ALTIUM_SCH_RECORD::HEADER:
  320. THROW_IO_ERROR( "Header already parsed" );
  321. case ALTIUM_SCH_RECORD::COMPONENT:
  322. ParseComponent( index, properties );
  323. break;
  324. case ALTIUM_SCH_RECORD::PIN:
  325. ParsePin( properties );
  326. break;
  327. case ALTIUM_SCH_RECORD::IEEE_SYMBOL:
  328. break;
  329. case ALTIUM_SCH_RECORD::LABEL:
  330. ParseLabel( properties );
  331. break;
  332. case ALTIUM_SCH_RECORD::BEZIER:
  333. ParseBezier( properties );
  334. break;
  335. case ALTIUM_SCH_RECORD::POLYLINE:
  336. ParsePolyline( properties );
  337. break;
  338. case ALTIUM_SCH_RECORD::POLYGON:
  339. ParsePolygon( properties );
  340. break;
  341. case ALTIUM_SCH_RECORD::ELLIPSE:
  342. break;
  343. case ALTIUM_SCH_RECORD::PIECHART:
  344. break;
  345. case ALTIUM_SCH_RECORD::ROUND_RECTANGLE:
  346. ParseRoundRectangle( properties );
  347. break;
  348. case ALTIUM_SCH_RECORD::ELLIPTICAL_ARC:
  349. break;
  350. case ALTIUM_SCH_RECORD::ARC:
  351. ParseArc( properties );
  352. break;
  353. case ALTIUM_SCH_RECORD::LINE:
  354. ParseLine( properties );
  355. break;
  356. case ALTIUM_SCH_RECORD::RECTANGLE:
  357. ParseRectangle( properties );
  358. break;
  359. case ALTIUM_SCH_RECORD::SHEET_SYMBOL:
  360. ParseSheetSymbol( index, properties );
  361. break;
  362. case ALTIUM_SCH_RECORD::SHEET_ENTRY:
  363. ParseSheetEntry( properties );
  364. break;
  365. case ALTIUM_SCH_RECORD::POWER_PORT:
  366. ParsePowerPort( properties );
  367. break;
  368. case ALTIUM_SCH_RECORD::PORT:
  369. // Ports are parsed after the sheet was parsed
  370. // This is required because we need all electrical connection points before placing.
  371. m_altiumPortsCurrentSheet.emplace_back( properties );
  372. break;
  373. case ALTIUM_SCH_RECORD::NO_ERC:
  374. ParseNoERC( properties );
  375. break;
  376. case ALTIUM_SCH_RECORD::NET_LABEL:
  377. ParseNetLabel( properties );
  378. break;
  379. case ALTIUM_SCH_RECORD::BUS:
  380. ParseBus( properties );
  381. break;
  382. case ALTIUM_SCH_RECORD::WIRE:
  383. ParseWire( properties );
  384. break;
  385. case ALTIUM_SCH_RECORD::TEXT_FRAME:
  386. ParseTextFrame( properties );
  387. break;
  388. case ALTIUM_SCH_RECORD::JUNCTION:
  389. ParseJunction( properties );
  390. break;
  391. case ALTIUM_SCH_RECORD::IMAGE:
  392. ParseImage( properties );
  393. break;
  394. case ALTIUM_SCH_RECORD::SHEET:
  395. ParseSheet( properties );
  396. break;
  397. case ALTIUM_SCH_RECORD::SHEET_NAME:
  398. ParseSheetName( properties );
  399. break;
  400. case ALTIUM_SCH_RECORD::FILE_NAME:
  401. ParseFileName( properties );
  402. break;
  403. case ALTIUM_SCH_RECORD::DESIGNATOR:
  404. ParseDesignator( properties );
  405. break;
  406. case ALTIUM_SCH_RECORD::BUS_ENTRY:
  407. ParseBusEntry( properties );
  408. break;
  409. case ALTIUM_SCH_RECORD::TEMPLATE:
  410. break;
  411. case ALTIUM_SCH_RECORD::PARAMETER:
  412. ParseParameter( properties );
  413. break;
  414. case ALTIUM_SCH_RECORD::WARNING_SIGN:
  415. break;
  416. case ALTIUM_SCH_RECORD::IMPLEMENTATION_LIST:
  417. ParseImplementationList( index, properties );
  418. break;
  419. case ALTIUM_SCH_RECORD::IMPLEMENTATION:
  420. ParseImplementation( properties );
  421. break;
  422. case ALTIUM_SCH_RECORD::RECORD_46:
  423. break;
  424. case ALTIUM_SCH_RECORD::RECORD_47:
  425. break;
  426. case ALTIUM_SCH_RECORD::RECORD_48:
  427. break;
  428. case ALTIUM_SCH_RECORD::NOTE:
  429. ParseNote( properties );
  430. break;
  431. case ALTIUM_SCH_RECORD::COMPILE_MASK:
  432. m_reporter->Report( _( "Compile mask not currently supported." ), RPT_SEVERITY_ERROR );
  433. break;
  434. case ALTIUM_SCH_RECORD::RECORD_215:
  435. break;
  436. case ALTIUM_SCH_RECORD::RECORD_216:
  437. break;
  438. case ALTIUM_SCH_RECORD::RECORD_217:
  439. break;
  440. case ALTIUM_SCH_RECORD::RECORD_218:
  441. break;
  442. case ALTIUM_SCH_RECORD::RECORD_226:
  443. break;
  444. default:
  445. m_reporter->Report( wxString::Format( _( "Unknown Record id: %d." ), recordId ),
  446. RPT_SEVERITY_ERROR );
  447. break;
  448. }
  449. }
  450. if( reader.HasParsingError() )
  451. THROW_IO_ERROR( "stream was not parsed correctly!" );
  452. if( reader.GetRemainingBytes() != 0 )
  453. THROW_IO_ERROR( "stream is not fully parsed" );
  454. // assign LIB_SYMBOL -> COMPONENT
  455. for( std::pair<const int, SCH_SYMBOL*>& symbol : m_symbols )
  456. {
  457. auto libSymbolIt = m_libSymbols.find( symbol.first );
  458. if( libSymbolIt == m_libSymbols.end() )
  459. THROW_IO_ERROR( "every symbol should have a symbol attached" );
  460. m_pi->SaveSymbol( getLibFileName().GetFullPath(),
  461. new LIB_SYMBOL( *( libSymbolIt->second ) ), m_properties.get() );
  462. symbol.second->SetLibSymbol( libSymbolIt->second );
  463. }
  464. // Handle title blocks
  465. m_currentSheet->GetScreen()->SetTitleBlock( *m_currentTitleBlock );
  466. m_currentTitleBlock.reset();
  467. // Handle Ports
  468. for( const ASCH_PORT& port : m_altiumPortsCurrentSheet )
  469. ParsePort( port );
  470. m_altiumPortsCurrentSheet.clear();
  471. m_symbols.clear();
  472. m_libSymbols.clear();
  473. // Otherwise we cannot save the imported sheet?
  474. m_currentSheet->SetModified();
  475. }
  476. bool SCH_ALTIUM_PLUGIN::IsComponentPartVisible( int aOwnerindex, int aOwnerpartdisplaymode ) const
  477. {
  478. const auto& component = m_altiumComponents.find( aOwnerindex );
  479. if( component == m_altiumComponents.end() )
  480. return false;
  481. return component->second.displaymode == aOwnerpartdisplaymode;
  482. }
  483. const ASCH_STORAGE_FILE* SCH_ALTIUM_PLUGIN::GetFileFromStorage( const wxString& aFilename ) const
  484. {
  485. const ASCH_STORAGE_FILE* nonExactMatch = nullptr;
  486. for( const ASCH_STORAGE_FILE& file : m_altiumStorage )
  487. {
  488. if( file.filename.IsSameAs( aFilename ) )
  489. return &file;
  490. if( file.filename.EndsWith( aFilename ) )
  491. nonExactMatch = &file;
  492. }
  493. return nonExactMatch;
  494. }
  495. void SCH_ALTIUM_PLUGIN::ParseComponent( int aIndex,
  496. const std::map<wxString, wxString>& aProperties )
  497. {
  498. auto pair = m_altiumComponents.insert( { aIndex, ASCH_SYMBOL( aProperties ) } );
  499. const ASCH_SYMBOL& elem = pair.first->second;
  500. // TODO: this is a hack until we correctly apply all transformations to every element
  501. wxString name = wxString::Format( "%d%s_%s",
  502. elem.orientation,
  503. elem.isMirrored ? "_mirrored" : "",
  504. elem.libreference );
  505. LIB_ID libId = AltiumToKiCadLibID( getLibName(), name );
  506. LIB_SYMBOL* ksymbol = new LIB_SYMBOL( wxEmptyString );
  507. ksymbol->SetName( name );
  508. ksymbol->SetDescription( elem.componentdescription );
  509. ksymbol->SetLibId( libId );
  510. m_libSymbols.insert( { aIndex, ksymbol } );
  511. // each component has its own symbol for now
  512. SCH_SYMBOL* symbol = new SCH_SYMBOL();
  513. symbol->SetPosition( elem.location + m_sheetOffset );
  514. // TODO: keep it simple for now, and only set position.
  515. //component->SetOrientation( elem.orientation );
  516. symbol->SetLibId( libId );
  517. symbol->SetUnit( elem.currentpartid );
  518. m_currentSheet->GetScreen()->Append( symbol );
  519. m_symbols.insert( { aIndex, symbol } );
  520. }
  521. void SCH_ALTIUM_PLUGIN::ParsePin( const std::map<wxString, wxString>& aProperties )
  522. {
  523. ASCH_PIN elem( aProperties );
  524. const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
  525. if( libSymbolIt == m_libSymbols.end() )
  526. {
  527. // TODO: e.g. can depend on Template (RECORD=39
  528. m_reporter->Report( wxString::Format( _( "Pin's owner (%d) not found." ), elem.ownerindex ),
  529. RPT_SEVERITY_ERROR );
  530. return;
  531. }
  532. if( !IsComponentPartVisible( elem.ownerindex, elem.ownerpartdisplaymode ) )
  533. return;
  534. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  535. LIB_PIN* pin = new LIB_PIN( libSymbolIt->second );
  536. libSymbolIt->second->AddDrawItem( pin );
  537. pin->SetUnit( elem.ownerpartid );
  538. pin->SetName( elem.name );
  539. pin->SetNumber( elem.designator );
  540. pin->SetLength( elem.pinlength );
  541. if( !elem.showDesignator )
  542. pin->SetNumberTextSize( 0 );
  543. if( !elem.showPinName )
  544. pin->SetNameTextSize( 0 );
  545. VECTOR2I pinLocation = elem.location; // the location given is not the connection point!
  546. switch( elem.orientation )
  547. {
  548. case ASCH_RECORD_ORIENTATION::RIGHTWARDS:
  549. pin->SetOrientation( DrawPinOrient::PIN_LEFT );
  550. pinLocation.x += elem.pinlength;
  551. break;
  552. case ASCH_RECORD_ORIENTATION::UPWARDS:
  553. pin->SetOrientation( DrawPinOrient::PIN_DOWN );
  554. pinLocation.y -= elem.pinlength;
  555. break;
  556. case ASCH_RECORD_ORIENTATION::LEFTWARDS:
  557. pin->SetOrientation( DrawPinOrient::PIN_RIGHT );
  558. pinLocation.x -= elem.pinlength;
  559. break;
  560. case ASCH_RECORD_ORIENTATION::DOWNWARDS:
  561. pin->SetOrientation( DrawPinOrient::PIN_UP );
  562. pinLocation.y += elem.pinlength;
  563. break;
  564. default:
  565. m_reporter->Report( _( "Pin has unexpected orientation." ), RPT_SEVERITY_WARNING );
  566. break;
  567. }
  568. // TODO: position can be sometimes off a little bit!
  569. pin->SetPosition( GetRelativePosition( pinLocation + m_sheetOffset, symbol ) );
  570. // TODO: the following fix is even worse for now?
  571. // pin->SetPosition( GetRelativePosition( elem.kicadLocation, symbol ) );
  572. switch( elem.electrical )
  573. {
  574. case ASCH_PIN_ELECTRICAL::INPUT:
  575. pin->SetType( ELECTRICAL_PINTYPE::PT_INPUT );
  576. break;
  577. case ASCH_PIN_ELECTRICAL::BIDI:
  578. pin->SetType( ELECTRICAL_PINTYPE::PT_BIDI );
  579. break;
  580. case ASCH_PIN_ELECTRICAL::OUTPUT:
  581. pin->SetType( ELECTRICAL_PINTYPE::PT_OUTPUT );
  582. break;
  583. case ASCH_PIN_ELECTRICAL::OPEN_COLLECTOR:
  584. pin->SetType( ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR );
  585. break;
  586. case ASCH_PIN_ELECTRICAL::PASSIVE:
  587. pin->SetType( ELECTRICAL_PINTYPE::PT_PASSIVE );
  588. break;
  589. case ASCH_PIN_ELECTRICAL::TRISTATE:
  590. pin->SetType( ELECTRICAL_PINTYPE::PT_TRISTATE );
  591. break;
  592. case ASCH_PIN_ELECTRICAL::OPEN_EMITTER:
  593. pin->SetType( ELECTRICAL_PINTYPE::PT_OPENEMITTER );
  594. break;
  595. case ASCH_PIN_ELECTRICAL::POWER:
  596. pin->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN );
  597. break;
  598. case ASCH_PIN_ELECTRICAL::UNKNOWN:
  599. default:
  600. pin->SetType( ELECTRICAL_PINTYPE::PT_UNSPECIFIED );
  601. m_reporter->Report( _( "Pin has unexpected electrical type." ), RPT_SEVERITY_WARNING );
  602. break;
  603. }
  604. if( elem.symbolOuterEdge == ASCH_PIN_SYMBOL_OUTEREDGE::UNKNOWN )
  605. m_reporter->Report( _( "Pin has unexpected outer edge type." ), RPT_SEVERITY_WARNING );
  606. if( elem.symbolInnerEdge == ASCH_PIN_SYMBOL_INNEREDGE::UNKNOWN )
  607. m_reporter->Report( _( "Pin has unexpected inner edge type." ), RPT_SEVERITY_WARNING );
  608. if( elem.symbolOuterEdge == ASCH_PIN_SYMBOL_OUTEREDGE::NEGATED )
  609. {
  610. switch( elem.symbolInnerEdge )
  611. {
  612. case ASCH_PIN_SYMBOL_INNEREDGE::CLOCK:
  613. pin->SetShape( GRAPHIC_PINSHAPE::INVERTED_CLOCK );
  614. break;
  615. default:
  616. pin->SetShape( GRAPHIC_PINSHAPE::INVERTED );
  617. break;
  618. }
  619. }
  620. else if( elem.symbolOuterEdge == ASCH_PIN_SYMBOL_OUTEREDGE::LOW_INPUT )
  621. {
  622. switch( elem.symbolInnerEdge )
  623. {
  624. case ASCH_PIN_SYMBOL_INNEREDGE::CLOCK:
  625. pin->SetShape( GRAPHIC_PINSHAPE::CLOCK_LOW );
  626. break;
  627. default:
  628. pin->SetShape( GRAPHIC_PINSHAPE::INPUT_LOW );
  629. break;
  630. }
  631. }
  632. else if( elem.symbolOuterEdge == ASCH_PIN_SYMBOL_OUTEREDGE::LOW_OUTPUT )
  633. {
  634. pin->SetShape( GRAPHIC_PINSHAPE::OUTPUT_LOW );
  635. }
  636. else
  637. {
  638. switch( elem.symbolInnerEdge )
  639. {
  640. case ASCH_PIN_SYMBOL_INNEREDGE::CLOCK:
  641. pin->SetShape( GRAPHIC_PINSHAPE::CLOCK );
  642. break;
  643. default:
  644. pin->SetShape( GRAPHIC_PINSHAPE::LINE ); // nothing to do
  645. break;
  646. }
  647. }
  648. }
  649. void SetTextPositioning( EDA_TEXT* text, ASCH_LABEL_JUSTIFICATION justification,
  650. ASCH_RECORD_ORIENTATION orientation )
  651. {
  652. int vjustify, hjustify;
  653. EDA_ANGLE angle = ANGLE_HORIZONTAL;
  654. switch( justification )
  655. {
  656. default:
  657. case ASCH_LABEL_JUSTIFICATION::UNKNOWN:
  658. case ASCH_LABEL_JUSTIFICATION::BOTTOM_LEFT:
  659. case ASCH_LABEL_JUSTIFICATION::BOTTOM_CENTER:
  660. case ASCH_LABEL_JUSTIFICATION::BOTTOM_RIGHT:
  661. vjustify = GR_TEXT_V_ALIGN_BOTTOM;
  662. break;
  663. case ASCH_LABEL_JUSTIFICATION::CENTER_LEFT:
  664. case ASCH_LABEL_JUSTIFICATION::CENTER_CENTER:
  665. case ASCH_LABEL_JUSTIFICATION::CENTER_RIGHT:
  666. vjustify = GR_TEXT_V_ALIGN_CENTER;
  667. break;
  668. case ASCH_LABEL_JUSTIFICATION::TOP_LEFT:
  669. case ASCH_LABEL_JUSTIFICATION::TOP_CENTER:
  670. case ASCH_LABEL_JUSTIFICATION::TOP_RIGHT:
  671. vjustify = GR_TEXT_V_ALIGN_TOP;
  672. break;
  673. }
  674. switch( justification )
  675. {
  676. default:
  677. case ASCH_LABEL_JUSTIFICATION::UNKNOWN:
  678. case ASCH_LABEL_JUSTIFICATION::BOTTOM_LEFT:
  679. case ASCH_LABEL_JUSTIFICATION::CENTER_LEFT:
  680. case ASCH_LABEL_JUSTIFICATION::TOP_LEFT:
  681. hjustify = GR_TEXT_H_ALIGN_LEFT;
  682. break;
  683. case ASCH_LABEL_JUSTIFICATION::BOTTOM_CENTER:
  684. case ASCH_LABEL_JUSTIFICATION::CENTER_CENTER:
  685. case ASCH_LABEL_JUSTIFICATION::TOP_CENTER:
  686. hjustify = GR_TEXT_H_ALIGN_CENTER;
  687. break;
  688. case ASCH_LABEL_JUSTIFICATION::BOTTOM_RIGHT:
  689. case ASCH_LABEL_JUSTIFICATION::CENTER_RIGHT:
  690. case ASCH_LABEL_JUSTIFICATION::TOP_RIGHT:
  691. hjustify = GR_TEXT_H_ALIGN_RIGHT;
  692. break;
  693. }
  694. switch( orientation )
  695. {
  696. case ASCH_RECORD_ORIENTATION::RIGHTWARDS:
  697. angle = ANGLE_HORIZONTAL;
  698. break;
  699. case ASCH_RECORD_ORIENTATION::LEFTWARDS:
  700. vjustify *= -1;
  701. hjustify *= -1;
  702. angle = ANGLE_HORIZONTAL;
  703. break;
  704. case ASCH_RECORD_ORIENTATION::UPWARDS:
  705. angle = ANGLE_VERTICAL;
  706. break;
  707. case ASCH_RECORD_ORIENTATION::DOWNWARDS:
  708. vjustify *= -1;
  709. hjustify *= -1;
  710. angle = ANGLE_VERTICAL;
  711. break;
  712. }
  713. text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( vjustify ) );
  714. text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( hjustify ) );
  715. text->SetTextAngle( angle );
  716. }
  717. void SCH_ALTIUM_PLUGIN::ParseLabel( const std::map<wxString, wxString>& aProperties )
  718. {
  719. ASCH_LABEL elem( aProperties );
  720. if( elem.ownerpartid == ALTIUM_COMPONENT_NONE )
  721. {
  722. std::map<wxString, wxString> variableMap = {
  723. { "APPLICATION_BUILDNUMBER", "KICAD_VERSION" },
  724. { "SHEETNUMBER", "#" },
  725. { "SHEETTOTAL", "##" },
  726. { "TITLE", "TITLE" }, // 1:1 maps are sort of useless, but it makes it
  727. { "REVISION", "REVISION" }, // easier to see that the list is complete
  728. { "DATE", "ISSUE_DATE" },
  729. { "CURRENTDATE", "CURRENT_DATE" },
  730. { "COMPANYNAME", "COMPANY" },
  731. { "DOCUMENTNAME", "FILENAME" },
  732. { "PROJECTNAME", "PROJECTNAME" },
  733. };
  734. wxString kicadText = AltiumSpecialStringsToKiCadVariables( elem.text, variableMap );
  735. SCH_TEXT* textItem = new SCH_TEXT( elem.location + m_sheetOffset, kicadText );
  736. SetTextPositioning( textItem, elem.justification, elem.orientation );
  737. size_t fontId = static_cast<int>( elem.fontId );
  738. if( m_altiumSheet && fontId > 0 && fontId <= m_altiumSheet->fonts.size() )
  739. {
  740. const ASCH_SHEET_FONT& font = m_altiumSheet->fonts.at( fontId - 1 );
  741. textItem->SetItalic( font.italic );
  742. textItem->SetBold( font.bold );
  743. textItem->SetTextSize( { font.size / 2, font.size / 2 } );
  744. }
  745. textItem->SetFlags(IS_NEW );
  746. m_currentSheet->GetScreen()->Append( textItem );
  747. }
  748. else
  749. {
  750. const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
  751. if( libSymbolIt == m_libSymbols.end() )
  752. {
  753. // TODO: e.g. can depend on Template (RECORD=39
  754. m_reporter->Report( wxString::Format( _( "Label's owner (%d) not found." ),
  755. elem.ownerindex ),
  756. RPT_SEVERITY_ERROR );
  757. return;
  758. }
  759. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  760. LIB_TEXT* textItem = new LIB_TEXT( libSymbolIt->second );
  761. libSymbolIt->second->AddDrawItem( textItem );
  762. textItem->SetUnit( elem.ownerpartid );
  763. textItem->SetPosition( GetRelativePosition( elem.location + m_sheetOffset, symbol ) );
  764. textItem->SetText( elem.text );
  765. SetTextPositioning( textItem, elem.justification, elem.orientation );
  766. size_t fontId = static_cast<int>( elem.fontId );
  767. if( m_altiumSheet && fontId > 0 && fontId <= m_altiumSheet->fonts.size() )
  768. {
  769. const ASCH_SHEET_FONT& font = m_altiumSheet->fonts.at( fontId - 1 );
  770. textItem->SetItalic( font.italic );
  771. textItem->SetBold( font.bold );
  772. textItem->SetTextSize( { font.size / 2, font.size / 2 } );
  773. }
  774. }
  775. }
  776. void SCH_ALTIUM_PLUGIN::ParseTextFrame( const std::map<wxString, wxString>& aProperties )
  777. {
  778. ASCH_TEXT_FRAME elem( aProperties );
  779. SCH_TEXT* text = new SCH_TEXT( elem.location + m_sheetOffset, elem.text );
  780. switch( elem.alignment )
  781. {
  782. default:
  783. case ASCH_TEXT_FRAME_ALIGNMENT::LEFT:
  784. text->SetLabelSpinStyle( LABEL_SPIN_STYLE::SPIN::RIGHT );
  785. break;
  786. case ASCH_TEXT_FRAME_ALIGNMENT::CENTER:
  787. // No support for centered text in Eeschema yet...
  788. text->SetLabelSpinStyle( LABEL_SPIN_STYLE::SPIN::RIGHT );
  789. break;
  790. case ASCH_TEXT_FRAME_ALIGNMENT::RIGHT:
  791. text->SetLabelSpinStyle( LABEL_SPIN_STYLE::SPIN::LEFT );
  792. break;
  793. }
  794. // TODO: set size and word-wrap once KiCad supports wrapped text.
  795. // TODO: set border and background color once KiCad supports them.
  796. size_t fontId = static_cast<int>( elem.fontId );
  797. if( m_altiumSheet && fontId > 0 && fontId <= m_altiumSheet->fonts.size() )
  798. {
  799. const ASCH_SHEET_FONT& font = m_altiumSheet->fonts.at( fontId - 1 );
  800. text->SetItalic( font.italic );
  801. text->SetBold( font.bold );
  802. text->SetTextSize( { font.size / 2, font.size / 2 } );
  803. }
  804. text->SetFlags( IS_NEW );
  805. m_currentSheet->GetScreen()->Append( text );
  806. }
  807. void SCH_ALTIUM_PLUGIN::ParseNote( const std::map<wxString, wxString>& aProperties )
  808. {
  809. ASCH_NOTE elem( aProperties );
  810. SCH_TEXT* text = new SCH_TEXT( elem.location + m_sheetOffset, elem.text );
  811. switch( elem.alignment )
  812. {
  813. default:
  814. case ASCH_TEXT_FRAME_ALIGNMENT::LEFT:
  815. text->SetLabelSpinStyle( LABEL_SPIN_STYLE::SPIN::RIGHT );
  816. break;
  817. case ASCH_TEXT_FRAME_ALIGNMENT::CENTER:
  818. // No support for centered text in Eeschema yet...
  819. text->SetLabelSpinStyle( LABEL_SPIN_STYLE::SPIN::RIGHT );
  820. break;
  821. case ASCH_TEXT_FRAME_ALIGNMENT::RIGHT:
  822. text->SetLabelSpinStyle( LABEL_SPIN_STYLE::SPIN::LEFT );
  823. break;
  824. }
  825. // TODO: set size and word-wrap once KiCad supports wrapped text.
  826. // TODO: set border and background color once KiCad supports them.
  827. // TODO: need some sort of property system for storing author....
  828. size_t fontId = static_cast<int>( elem.fontId );
  829. if( m_altiumSheet && fontId > 0 && fontId <= m_altiumSheet->fonts.size() )
  830. {
  831. const ASCH_SHEET_FONT& font = m_altiumSheet->fonts.at( fontId - 1 );
  832. text->SetItalic( font.italic );
  833. text->SetBold( font.bold );
  834. text->SetTextSize( { font.size / 2, font.size / 2 } );
  835. }
  836. text->SetFlags( IS_NEW );
  837. m_currentSheet->GetScreen()->Append( text );
  838. }
  839. void SCH_ALTIUM_PLUGIN::ParseBezier( const std::map<wxString, wxString>& aProperties )
  840. {
  841. ASCH_BEZIER elem( aProperties );
  842. if( elem.points.size() < 2 )
  843. {
  844. m_reporter->Report( wxString::Format( _( "Bezier has %d control points. At least 2 are "
  845. "expected." ),
  846. static_cast<int>( elem.points.size() ) ),
  847. RPT_SEVERITY_WARNING );
  848. return;
  849. }
  850. if( elem.ownerpartid == ALTIUM_COMPONENT_NONE )
  851. {
  852. for( size_t i = 0; i + 1 < elem.points.size(); i += 3 )
  853. {
  854. if( i + 2 == elem.points.size() )
  855. {
  856. // special case: single line
  857. SCH_LINE* line = new SCH_LINE( elem.points.at( i ) + m_sheetOffset,
  858. SCH_LAYER_ID::LAYER_NOTES );
  859. line->SetEndPoint( elem.points.at( i + 1 ) + m_sheetOffset );
  860. line->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) );
  861. line->SetFlags( IS_NEW );
  862. m_currentSheet->GetScreen()->Append( line );
  863. }
  864. else
  865. {
  866. // simulate Bezier using line segments
  867. std::vector<VECTOR2I> bezierPoints;
  868. std::vector<VECTOR2I> polyPoints;
  869. for( size_t j = i; j < elem.points.size() && j < i + 4; j++ )
  870. bezierPoints.push_back( elem.points.at( j ) );
  871. BEZIER_POLY converter( bezierPoints );
  872. converter.GetPoly( polyPoints );
  873. for( size_t k = 0; k + 1 < polyPoints.size(); k++ )
  874. {
  875. SCH_LINE* line = new SCH_LINE( polyPoints.at( k ) + m_sheetOffset,
  876. SCH_LAYER_ID::LAYER_NOTES );
  877. line->SetEndPoint( polyPoints.at( k + 1 ) + m_sheetOffset );
  878. line->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) );
  879. line->SetFlags( IS_NEW );
  880. m_currentSheet->GetScreen()->Append( line );
  881. }
  882. }
  883. }
  884. }
  885. else
  886. {
  887. const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
  888. if( libSymbolIt == m_libSymbols.end() )
  889. {
  890. // TODO: e.g. can depend on Template (RECORD=39
  891. m_reporter->Report( wxString::Format( _( "Bezier's owner (%d) not found." ),
  892. elem.ownerindex ),
  893. RPT_SEVERITY_ERROR );
  894. return;
  895. }
  896. if( !IsComponentPartVisible( elem.ownerindex, elem.ownerpartdisplaymode ) )
  897. return;
  898. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  899. for( size_t i = 0; i + 1 < elem.points.size(); i += 3 )
  900. {
  901. if( i + 2 == elem.points.size() )
  902. {
  903. // special case: single line
  904. LIB_SHAPE* line = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::POLY );
  905. libSymbolIt->second->AddDrawItem( line );
  906. line->SetUnit( elem.ownerpartid );
  907. for( size_t j = i; j < elem.points.size() && j < i + 2; j++ )
  908. {
  909. line->AddPoint( GetRelativePosition( elem.points.at( j ) + m_sheetOffset,
  910. symbol ) );
  911. }
  912. line->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) );
  913. }
  914. else if( i + 3 == elem.points.size() )
  915. {
  916. // TODO: special case of a single line with an extra point?
  917. // I haven't a clue what this is all about, but the sample document we have in
  918. // https://gitlab.com/kicad/code/kicad/-/issues/8974 responds best by treating it
  919. // as another single line special case.
  920. LIB_SHAPE* line = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::POLY );
  921. libSymbolIt->second->AddDrawItem( line );
  922. line->SetUnit( elem.ownerpartid );
  923. for( size_t j = i; j < elem.points.size() && j < i + 2; j++ )
  924. {
  925. line->AddPoint( GetRelativePosition( elem.points.at( j ) + m_sheetOffset,
  926. symbol ) );
  927. }
  928. line->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) );
  929. }
  930. else
  931. {
  932. // Bezier always has exactly 4 control points
  933. LIB_SHAPE* bezier = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::BEZIER );
  934. libSymbolIt->second->AddDrawItem( bezier );
  935. bezier->SetUnit( elem.ownerpartid );
  936. for( size_t j = i; j < elem.points.size() && j < i + 4; j++ )
  937. {
  938. VECTOR2I pos =
  939. GetRelativePosition( elem.points.at( j ) + m_sheetOffset, symbol );
  940. switch( j - i )
  941. {
  942. case 0: bezier->SetStart( pos ); break;
  943. case 1: bezier->SetBezierC1( pos ); break;
  944. case 2: bezier->SetBezierC2( pos ); break;
  945. case 3: bezier->SetEnd( pos ); break;
  946. default: break; // Can't get here but silence warnings
  947. }
  948. }
  949. bezier->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) );
  950. }
  951. }
  952. }
  953. }
  954. void SCH_ALTIUM_PLUGIN::ParsePolyline( const std::map<wxString, wxString>& aProperties )
  955. {
  956. ASCH_POLYLINE elem( aProperties );
  957. if( elem.ownerpartid == ALTIUM_COMPONENT_NONE )
  958. {
  959. SCH_SHAPE* poly = new SCH_SHAPE( SHAPE_T::POLY, SCH_LAYER_ID::LAYER_NOTES );
  960. for( VECTOR2I& point : elem.points )
  961. poly->AddPoint( point + m_sheetOffset );
  962. poly->SetStroke( STROKE_PARAMS( elem.lineWidth, GetPlotDashType( elem.linestyle ) ) );
  963. poly->SetFlags( IS_NEW );
  964. m_currentSheet->GetScreen()->Append( poly );
  965. }
  966. else
  967. {
  968. const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
  969. if( libSymbolIt == m_libSymbols.end() )
  970. {
  971. // TODO: e.g. can depend on Template (RECORD=39
  972. m_reporter->Report( wxString::Format( _( "Polyline's owner (%d) not found." ),
  973. elem.ownerindex ),
  974. RPT_SEVERITY_ERROR );
  975. return;
  976. }
  977. if( !IsComponentPartVisible( elem.ownerindex, elem.ownerpartdisplaymode ) )
  978. return;
  979. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  980. LIB_SHAPE* line = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::POLY );
  981. libSymbolIt->second->AddDrawItem( line );
  982. line->SetUnit( elem.ownerpartid );
  983. for( VECTOR2I& point : elem.points )
  984. line->AddPoint( GetRelativePosition( point + m_sheetOffset, symbol ) );
  985. line->SetStroke( STROKE_PARAMS( elem.lineWidth, GetPlotDashType( elem.linestyle ) ) );
  986. }
  987. }
  988. void SCH_ALTIUM_PLUGIN::ParsePolygon( const std::map<wxString, wxString>& aProperties )
  989. {
  990. ASCH_POLYGON elem( aProperties );
  991. if( elem.ownerpartid == ALTIUM_COMPONENT_NONE )
  992. {
  993. SCH_SHAPE* poly = new SCH_SHAPE( SHAPE_T::POLY, SCH_LAYER_ID::LAYER_NOTES );
  994. for( VECTOR2I& point : elem.points )
  995. poly->AddPoint( point + m_sheetOffset );
  996. poly->AddPoint( elem.points.front() + m_sheetOffset );
  997. SetSchShapeFillAndColor( elem, poly );
  998. poly->SetFlags( IS_NEW );
  999. m_currentSheet->GetScreen()->Append( poly );
  1000. }
  1001. else
  1002. {
  1003. const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
  1004. if( libSymbolIt == m_libSymbols.end() )
  1005. {
  1006. // TODO: e.g. can depend on Template (RECORD=39
  1007. m_reporter->Report( wxString::Format( _( "Polygon's owner (%d) not found." ),
  1008. elem.ownerindex ),
  1009. RPT_SEVERITY_ERROR );
  1010. return;
  1011. }
  1012. if( !IsComponentPartVisible( elem.ownerindex, elem.ownerpartdisplaymode ) )
  1013. return;
  1014. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  1015. LIB_SHAPE* line = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::POLY );
  1016. libSymbolIt->second->AddDrawItem( line );
  1017. line->SetUnit( elem.ownerpartid );
  1018. for( VECTOR2I& point : elem.points )
  1019. line->AddPoint( GetRelativePosition( point + m_sheetOffset, symbol ) );
  1020. line->AddPoint( GetRelativePosition( elem.points.front() + m_sheetOffset, symbol ) );
  1021. SetLibShapeFillAndColor( elem, line );
  1022. }
  1023. }
  1024. void SCH_ALTIUM_PLUGIN::ParseRoundRectangle( const std::map<wxString, wxString>& aProperties )
  1025. {
  1026. ASCH_ROUND_RECTANGLE elem( aProperties );
  1027. VECTOR2I sheetTopRight = elem.topRight + m_sheetOffset;
  1028. VECTOR2I sheetBottomLeft = elem.bottomLeft + m_sheetOffset;
  1029. if( elem.ownerpartid == ALTIUM_COMPONENT_NONE )
  1030. {
  1031. // TODO: misses rounded edges
  1032. SCH_SHAPE* rect = new SCH_SHAPE( SHAPE_T::RECT, SCH_LAYER_ID::LAYER_NOTES );
  1033. rect->SetPosition( sheetTopRight );
  1034. rect->SetEnd( sheetBottomLeft );
  1035. SetSchShapeFillAndColor( elem, rect );
  1036. rect->SetFlags( IS_NEW );
  1037. m_currentSheet->GetScreen()->Append( rect );
  1038. }
  1039. else
  1040. {
  1041. const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
  1042. if( libSymbolIt == m_libSymbols.end() )
  1043. {
  1044. // TODO: e.g. can depend on Template (RECORD=39
  1045. m_reporter->Report( wxString::Format( _( "Rounded rectangle's owner (%d) not found." ),
  1046. elem.ownerindex ),
  1047. RPT_SEVERITY_ERROR );
  1048. return;
  1049. }
  1050. if( !IsComponentPartVisible( elem.ownerindex, elem.ownerpartdisplaymode ) )
  1051. return;
  1052. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  1053. // TODO: misses rounded edges
  1054. LIB_SHAPE* rect = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::RECT );
  1055. libSymbolIt->second->AddDrawItem( rect );
  1056. rect->SetUnit( elem.ownerpartid );
  1057. rect->SetPosition( GetRelativePosition( elem.topRight + m_sheetOffset, symbol ) );
  1058. rect->SetEnd( GetRelativePosition( elem.bottomLeft + m_sheetOffset, symbol ) );
  1059. SetLibShapeFillAndColor( elem, rect );
  1060. }
  1061. }
  1062. void SCH_ALTIUM_PLUGIN::ParseArc( const std::map<wxString, wxString>& aProperties )
  1063. {
  1064. ASCH_ARC elem( aProperties );
  1065. if( elem.ownerpartid == ALTIUM_COMPONENT_NONE )
  1066. {
  1067. if( elem.startAngle == 0 && ( elem.endAngle == 0 || elem.endAngle == 360 ) )
  1068. {
  1069. SCH_SHAPE* circle = new SCH_SHAPE( SHAPE_T::CIRCLE, SCH_LAYER_ID::LAYER_NOTES );
  1070. circle->SetPosition( elem.center + m_sheetOffset );
  1071. circle->SetEnd( circle->GetPosition() + VECTOR2I( elem.radius, 0 ) );
  1072. circle->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) );
  1073. m_currentSheet->GetScreen()->Append( circle );
  1074. }
  1075. else
  1076. {
  1077. SCH_SHAPE* arc = new SCH_SHAPE( SHAPE_T::ARC, SCH_LAYER_ID::LAYER_NOTES );
  1078. EDA_ANGLE includedAngle( elem.endAngle - elem.startAngle, DEGREES_T );
  1079. EDA_ANGLE startAngle( elem.endAngle, DEGREES_T );
  1080. VECTOR2I startOffset( KiROUND( elem.radius * startAngle.Cos() ),
  1081. -KiROUND( elem.radius * startAngle.Sin() ) );
  1082. arc->SetCenter( elem.center + m_sheetOffset );
  1083. arc->SetStart( elem.center + startOffset + m_sheetOffset );
  1084. arc->SetArcAngleAndEnd( includedAngle.Normalize(), true );
  1085. arc->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) );
  1086. m_currentSheet->GetScreen()->Append( arc );
  1087. }
  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( _( "Arc's owner (%d) not found." ),
  1096. elem.ownerindex ),
  1097. RPT_SEVERITY_ERROR );
  1098. return;
  1099. }
  1100. if( !IsComponentPartVisible( elem.ownerindex, elem.ownerpartdisplaymode ) )
  1101. return;
  1102. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  1103. if( elem.startAngle == 0 && ( elem.endAngle == 0 || elem.endAngle == 360 ) )
  1104. {
  1105. LIB_SHAPE* circle = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::CIRCLE );
  1106. libSymbolIt->second->AddDrawItem( circle );
  1107. circle->SetUnit( elem.ownerpartid );
  1108. circle->SetPosition( GetRelativePosition( elem.center + m_sheetOffset, symbol ) );
  1109. circle->SetEnd( circle->GetPosition() + VECTOR2I( elem.radius, 0 ) );
  1110. circle->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) );
  1111. }
  1112. else
  1113. {
  1114. LIB_SHAPE* arc = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::ARC );
  1115. libSymbolIt->second->AddDrawItem( arc );
  1116. arc->SetUnit( elem.ownerpartid );
  1117. arc->SetCenter( GetRelativePosition( elem.center + m_sheetOffset, symbol ) );
  1118. VECTOR2I arcStart( elem.radius, 0 );
  1119. RotatePoint( &arcStart.x, &arcStart.y, -elem.startAngle * 10.0 );
  1120. arcStart += arc->GetCenter();
  1121. arc->SetStart( arcStart );
  1122. VECTOR2I arcEnd( elem.radius, 0 );
  1123. RotatePoint( &arcEnd.x, &arcEnd.y, -elem.endAngle * 10.0 );
  1124. arcEnd += arc->GetCenter();
  1125. arc->SetEnd( arcEnd );
  1126. arc->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) );
  1127. }
  1128. }
  1129. }
  1130. void SCH_ALTIUM_PLUGIN::ParseLine( const std::map<wxString, wxString>& aProperties )
  1131. {
  1132. ASCH_LINE elem( aProperties );
  1133. if( elem.ownerpartid == ALTIUM_COMPONENT_NONE )
  1134. {
  1135. // close polygon
  1136. SCH_LINE* line = new SCH_LINE( elem.point1 + m_sheetOffset, SCH_LAYER_ID::LAYER_NOTES );
  1137. line->SetEndPoint( elem.point2 + m_sheetOffset );
  1138. line->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) ); // TODO?
  1139. line->SetFlags( IS_NEW );
  1140. m_currentSheet->GetScreen()->Append( line );
  1141. }
  1142. else
  1143. {
  1144. const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
  1145. if( libSymbolIt == m_libSymbols.end() )
  1146. {
  1147. // TODO: e.g. can depend on Template (RECORD=39
  1148. m_reporter->Report( wxString::Format( _( "Line's owner (%d) not found." ),
  1149. elem.ownerindex ),
  1150. RPT_SEVERITY_ERROR );
  1151. return;
  1152. }
  1153. if( !IsComponentPartVisible( elem.ownerindex, elem.ownerpartdisplaymode ) )
  1154. return;
  1155. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  1156. LIB_SHAPE* line = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::POLY );
  1157. libSymbolIt->second->AddDrawItem( line );
  1158. line->SetUnit( elem.ownerpartid );
  1159. line->AddPoint( GetRelativePosition( elem.point1 + m_sheetOffset, symbol ) );
  1160. line->AddPoint( GetRelativePosition( elem.point2 + m_sheetOffset, symbol ) );
  1161. line->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) );
  1162. }
  1163. }
  1164. void SCH_ALTIUM_PLUGIN::ParseRectangle( const std::map<wxString, wxString>& aProperties )
  1165. {
  1166. ASCH_RECTANGLE elem( aProperties );
  1167. VECTOR2I sheetTopRight = elem.topRight + m_sheetOffset;
  1168. VECTOR2I sheetBottomLeft = elem.bottomLeft + m_sheetOffset;
  1169. if( elem.ownerpartid == ALTIUM_COMPONENT_NONE )
  1170. {
  1171. SCH_SHAPE* rect = new SCH_SHAPE( SHAPE_T::RECT, SCH_LAYER_ID::LAYER_NOTES );
  1172. rect->SetPosition( sheetTopRight );
  1173. rect->SetEnd( sheetBottomLeft );
  1174. SetSchShapeFillAndColor( elem, rect );
  1175. rect->SetFlags( IS_NEW );
  1176. m_currentSheet->GetScreen()->Append( rect );
  1177. }
  1178. else
  1179. {
  1180. const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
  1181. if( libSymbolIt == m_libSymbols.end() )
  1182. {
  1183. // TODO: e.g. can depend on Template (RECORD=39
  1184. m_reporter->Report( wxString::Format( _( "Rectangle's owner (%d) not found." ),
  1185. elem.ownerindex ),
  1186. RPT_SEVERITY_ERROR );
  1187. return;
  1188. }
  1189. if( !IsComponentPartVisible( elem.ownerindex, elem.ownerpartdisplaymode ) )
  1190. return;
  1191. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  1192. LIB_SHAPE* rect = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::RECT );
  1193. libSymbolIt->second->AddDrawItem( rect );
  1194. rect->SetUnit( elem.ownerpartid );
  1195. rect->SetPosition( GetRelativePosition( sheetTopRight, symbol ) );
  1196. rect->SetEnd( GetRelativePosition( sheetBottomLeft, symbol ) );
  1197. SetLibShapeFillAndColor( elem, rect );
  1198. }
  1199. }
  1200. void SCH_ALTIUM_PLUGIN::ParseSheetSymbol( int aIndex,
  1201. const std::map<wxString, wxString>& aProperties )
  1202. {
  1203. ASCH_SHEET_SYMBOL elem( aProperties );
  1204. SCH_SHEET* sheet = new SCH_SHEET( m_currentSheet, elem.location + m_sheetOffset );
  1205. SCH_SCREEN* screen = new SCH_SCREEN( m_schematic );
  1206. sheet->SetSize( elem.size );
  1207. sheet->SetBorderColor( GetColorFromInt( elem.color ) );
  1208. if( elem.isSolid )
  1209. sheet->SetBackgroundColor( GetColorFromInt( elem.areacolor ) );
  1210. sheet->SetScreen( screen );
  1211. sheet->SetFlags( IS_NEW );
  1212. m_currentSheet->GetScreen()->Append( sheet );
  1213. SCH_SHEET_PATH sheetpath;
  1214. m_rootSheet->LocatePathOfScreen( m_currentSheet->GetScreen(), &sheetpath );
  1215. sheetpath.push_back( sheet );
  1216. sheet->AddInstance( sheetpath );
  1217. sheet->SetPageNumber( sheetpath, "#" ); // We'll update later if we find a pageNumber
  1218. // record for it
  1219. m_sheets.insert( { aIndex, sheet } );
  1220. }
  1221. void SCH_ALTIUM_PLUGIN::ParseSheetEntry( const std::map<wxString, wxString>& aProperties )
  1222. {
  1223. ASCH_SHEET_ENTRY elem( aProperties );
  1224. const auto& sheetIt = m_sheets.find( elem.ownerindex );
  1225. if( sheetIt == m_sheets.end() )
  1226. {
  1227. m_reporter->Report( wxString::Format( _( "Sheet entry's owner (%d) not found." ),
  1228. elem.ownerindex ),
  1229. RPT_SEVERITY_ERROR );
  1230. return;
  1231. }
  1232. SCH_SHEET_PIN* sheetPin = new SCH_SHEET_PIN( sheetIt->second );
  1233. sheetIt->second->AddPin( sheetPin );
  1234. sheetPin->SetText( elem.name );
  1235. sheetPin->SetShape( LABEL_FLAG_SHAPE::L_UNSPECIFIED );
  1236. //sheetPin->SetLabelSpinStyle( getSpinStyle( term.OrientAngle, false ) );
  1237. //sheetPin->SetPosition( getKiCadPoint( term.Position ) );
  1238. VECTOR2I pos = sheetIt->second->GetPosition();
  1239. wxSize size = sheetIt->second->GetSize();
  1240. switch( elem.side )
  1241. {
  1242. default:
  1243. case ASCH_SHEET_ENTRY_SIDE::LEFT:
  1244. sheetPin->SetPosition( { pos.x, pos.y + elem.distanceFromTop } );
  1245. sheetPin->SetLabelSpinStyle( LABEL_SPIN_STYLE::LEFT );
  1246. sheetPin->SetSide( SHEET_SIDE::LEFT );
  1247. break;
  1248. case ASCH_SHEET_ENTRY_SIDE::RIGHT:
  1249. sheetPin->SetPosition( { pos.x + size.x, pos.y + elem.distanceFromTop } );
  1250. sheetPin->SetLabelSpinStyle( LABEL_SPIN_STYLE::RIGHT );
  1251. sheetPin->SetSide( SHEET_SIDE::RIGHT );
  1252. break;
  1253. case ASCH_SHEET_ENTRY_SIDE::TOP:
  1254. sheetPin->SetPosition( { pos.x + elem.distanceFromTop, pos.y } );
  1255. sheetPin->SetLabelSpinStyle( LABEL_SPIN_STYLE::UP );
  1256. sheetPin->SetSide( SHEET_SIDE::TOP );
  1257. break;
  1258. case ASCH_SHEET_ENTRY_SIDE::BOTTOM:
  1259. sheetPin->SetPosition( { pos.x + elem.distanceFromTop, pos.y + size.y } );
  1260. sheetPin->SetLabelSpinStyle( LABEL_SPIN_STYLE::BOTTOM );
  1261. sheetPin->SetSide( SHEET_SIDE::BOTTOM );
  1262. break;
  1263. }
  1264. switch( elem.iotype )
  1265. {
  1266. default:
  1267. case ASCH_PORT_IOTYPE::UNSPECIFIED:
  1268. sheetPin->SetShape( LABEL_FLAG_SHAPE::L_UNSPECIFIED );
  1269. break;
  1270. case ASCH_PORT_IOTYPE::OUTPUT:
  1271. sheetPin->SetShape( LABEL_FLAG_SHAPE::L_OUTPUT );
  1272. break;
  1273. case ASCH_PORT_IOTYPE::INPUT:
  1274. sheetPin->SetShape( LABEL_FLAG_SHAPE::L_INPUT );
  1275. break;
  1276. case ASCH_PORT_IOTYPE::BIDI:
  1277. sheetPin->SetShape( LABEL_FLAG_SHAPE::L_BIDI );
  1278. break;
  1279. }
  1280. }
  1281. VECTOR2I HelperGeneratePowerPortGraphics( LIB_SYMBOL* aKsymbol, ASCH_POWER_PORT_STYLE aStyle,
  1282. REPORTER* aReporter )
  1283. {
  1284. if( aStyle == ASCH_POWER_PORT_STYLE::CIRCLE || aStyle == ASCH_POWER_PORT_STYLE::ARROW )
  1285. {
  1286. LIB_SHAPE* line1 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1287. aKsymbol->AddDrawItem( line1 );
  1288. line1->SetStroke( STROKE_PARAMS( Mils2iu( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1289. line1->AddPoint( { 0, 0 } );
  1290. line1->AddPoint( { 0, Mils2iu( -50 ) } );
  1291. if( aStyle == ASCH_POWER_PORT_STYLE::CIRCLE )
  1292. {
  1293. LIB_SHAPE* circle = new LIB_SHAPE( aKsymbol, SHAPE_T::CIRCLE );
  1294. aKsymbol->AddDrawItem( circle );
  1295. circle->SetStroke( STROKE_PARAMS( Mils2iu( 5 ), PLOT_DASH_TYPE::SOLID ) );
  1296. circle->SetPosition( { Mils2iu( 0 ), Mils2iu( -75 ) } );
  1297. circle->SetEnd( circle->GetPosition() + VECTOR2I( Mils2iu( 25 ), 0 ) );
  1298. }
  1299. else
  1300. {
  1301. LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1302. aKsymbol->AddDrawItem( line2 );
  1303. line2->SetStroke( STROKE_PARAMS( Mils2iu( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1304. line2->AddPoint( { Mils2iu( -25 ), Mils2iu( -50 ) } );
  1305. line2->AddPoint( { Mils2iu( 25 ), Mils2iu( -50 ) } );
  1306. line2->AddPoint( { Mils2iu( 0 ), Mils2iu( -100 ) } );
  1307. line2->AddPoint( { Mils2iu( -25 ), Mils2iu( -50 ) } );
  1308. }
  1309. return { 0, Mils2iu( 150 ) };
  1310. }
  1311. else if( aStyle == ASCH_POWER_PORT_STYLE::WAVE )
  1312. {
  1313. LIB_SHAPE* line = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1314. aKsymbol->AddDrawItem( line );
  1315. line->SetStroke( STROKE_PARAMS( Mils2iu( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1316. line->AddPoint( { 0, 0 } );
  1317. line->AddPoint( { 0, Mils2iu( -72 ) } );
  1318. LIB_SHAPE* bezier = new LIB_SHAPE( aKsymbol, SHAPE_T::BEZIER );
  1319. aKsymbol->AddDrawItem( bezier );
  1320. bezier->SetStroke( STROKE_PARAMS( Mils2iu( 5 ), PLOT_DASH_TYPE::SOLID ) );
  1321. bezier->AddPoint( { Mils2iu( 30 ), Mils2iu( -50 ) } );
  1322. bezier->AddPoint( { Mils2iu( 30 ), Mils2iu( -87 ) } );
  1323. bezier->AddPoint( { Mils2iu( -30 ), Mils2iu( -63 ) } );
  1324. bezier->AddPoint( { Mils2iu( -30 ), Mils2iu( -100 ) } );
  1325. return { 0, Mils2iu( 150 ) };
  1326. }
  1327. else if( aStyle == ASCH_POWER_PORT_STYLE::POWER_GROUND
  1328. || aStyle == ASCH_POWER_PORT_STYLE::SIGNAL_GROUND
  1329. || aStyle == ASCH_POWER_PORT_STYLE::EARTH
  1330. || aStyle == ASCH_POWER_PORT_STYLE::GOST_ARROW )
  1331. {
  1332. LIB_SHAPE* line1 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1333. aKsymbol->AddDrawItem( line1 );
  1334. line1->SetStroke( STROKE_PARAMS( Mils2iu( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1335. line1->AddPoint( { 0, 0 } );
  1336. line1->AddPoint( { 0, Mils2iu( -100 ) } );
  1337. if( aStyle == ASCH_POWER_PORT_STYLE::POWER_GROUND )
  1338. {
  1339. LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1340. aKsymbol->AddDrawItem( line2 );
  1341. line2->SetStroke( STROKE_PARAMS( Mils2iu( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1342. line2->AddPoint( { Mils2iu( -100 ), Mils2iu( -100 ) } );
  1343. line2->AddPoint( { Mils2iu( 100 ), Mils2iu( -100 ) } );
  1344. LIB_SHAPE* line3 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1345. aKsymbol->AddDrawItem( line3 );
  1346. line3->SetStroke( STROKE_PARAMS( Mils2iu( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1347. line3->AddPoint( { Mils2iu( -70 ), Mils2iu( -130 ) } );
  1348. line3->AddPoint( { Mils2iu( 70 ), Mils2iu( -130 ) } );
  1349. LIB_SHAPE* line4 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1350. aKsymbol->AddDrawItem( line4 );
  1351. line4->SetStroke( STROKE_PARAMS( Mils2iu( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1352. line4->AddPoint( { Mils2iu( -40 ), Mils2iu( -160 ) } );
  1353. line4->AddPoint( { Mils2iu( 40 ), Mils2iu( -160 ) } );
  1354. LIB_SHAPE* line5 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1355. aKsymbol->AddDrawItem( line5 );
  1356. line5->SetStroke( STROKE_PARAMS( Mils2iu( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1357. line5->AddPoint( { Mils2iu( -10 ), Mils2iu( -190 ) } );
  1358. line5->AddPoint( { Mils2iu( 10 ), Mils2iu( -190 ) } );
  1359. }
  1360. else if( aStyle == ASCH_POWER_PORT_STYLE::SIGNAL_GROUND )
  1361. {
  1362. LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1363. aKsymbol->AddDrawItem( line2 );
  1364. line2->SetStroke( STROKE_PARAMS( Mils2iu( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1365. line2->AddPoint( { Mils2iu( -100 ), Mils2iu( -100 ) } );
  1366. line2->AddPoint( { Mils2iu( 100 ), Mils2iu( -100 ) } );
  1367. line2->AddPoint( { Mils2iu( 0 ), Mils2iu( -200 ) } );
  1368. line2->AddPoint( { Mils2iu( -100 ), Mils2iu( -100 ) } );
  1369. }
  1370. else if( aStyle == ASCH_POWER_PORT_STYLE::EARTH )
  1371. {
  1372. LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1373. aKsymbol->AddDrawItem( line2 );
  1374. line2->SetStroke( STROKE_PARAMS( Mils2iu( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1375. line2->AddPoint( { Mils2iu( -150 ), Mils2iu( -200 ) } );
  1376. line2->AddPoint( { Mils2iu( -100 ), Mils2iu( -100 ) } );
  1377. line2->AddPoint( { Mils2iu( 100 ), Mils2iu( -100 ) } );
  1378. line2->AddPoint( { Mils2iu( 50 ), Mils2iu( -200 ) } );
  1379. LIB_SHAPE* line3 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1380. aKsymbol->AddDrawItem( line3 );
  1381. line3->SetStroke( STROKE_PARAMS( Mils2iu( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1382. line3->AddPoint( { Mils2iu( 0 ), Mils2iu( -100 ) } );
  1383. line3->AddPoint( { Mils2iu( -50 ), Mils2iu( -200 ) } );
  1384. }
  1385. else // ASCH_POWER_PORT_STYLE::GOST_ARROW
  1386. {
  1387. LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1388. aKsymbol->AddDrawItem( line2 );
  1389. line2->SetStroke( STROKE_PARAMS( Mils2iu( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1390. line2->AddPoint( { Mils2iu( -25 ), Mils2iu( -50 ) } );
  1391. line2->AddPoint( { Mils2iu( 0 ), Mils2iu( -100 ) } );
  1392. line2->AddPoint( { Mils2iu( 25 ), Mils2iu( -50 ) } );
  1393. return { 0, Mils2iu( 150 ) }; // special case
  1394. }
  1395. return { 0, Mils2iu( 250 ) };
  1396. }
  1397. else if( aStyle == ASCH_POWER_PORT_STYLE::GOST_POWER_GROUND
  1398. || aStyle == ASCH_POWER_PORT_STYLE::GOST_EARTH )
  1399. {
  1400. LIB_SHAPE* line1 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1401. aKsymbol->AddDrawItem( line1 );
  1402. line1->SetStroke( STROKE_PARAMS( Mils2iu( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1403. line1->AddPoint( { 0, 0 } );
  1404. line1->AddPoint( { 0, Mils2iu( -160 ) } );
  1405. LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1406. aKsymbol->AddDrawItem( line2 );
  1407. line2->SetStroke( STROKE_PARAMS( Mils2iu( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1408. line2->AddPoint( { Mils2iu( -100 ), Mils2iu( -160 ) } );
  1409. line2->AddPoint( { Mils2iu( 100 ), Mils2iu( -160 ) } );
  1410. LIB_SHAPE* line3 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1411. aKsymbol->AddDrawItem( line3 );
  1412. line3->SetStroke( STROKE_PARAMS( Mils2iu( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1413. line3->AddPoint( { Mils2iu( -60 ), Mils2iu( -200 ) } );
  1414. line3->AddPoint( { Mils2iu( 60 ), Mils2iu( -200 ) } );
  1415. LIB_SHAPE* line4 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1416. aKsymbol->AddDrawItem( line4 );
  1417. line4->SetStroke( STROKE_PARAMS( Mils2iu( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1418. line4->AddPoint( { Mils2iu( -20 ), Mils2iu( -240 ) } );
  1419. line4->AddPoint( { Mils2iu( 20 ), Mils2iu( -240 ) } );
  1420. if( aStyle == ASCH_POWER_PORT_STYLE::GOST_POWER_GROUND )
  1421. return { 0, Mils2iu( 300 ) };
  1422. LIB_SHAPE* circle = new LIB_SHAPE( aKsymbol, SHAPE_T::CIRCLE );
  1423. aKsymbol->AddDrawItem( circle );
  1424. circle->SetStroke( STROKE_PARAMS( Mils2iu( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1425. circle->SetPosition( { Mils2iu( 0 ), Mils2iu( -160 ) } );
  1426. circle->SetEnd( circle->GetPosition() + VECTOR2I( Mils2iu( 120 ), 0 ) );
  1427. return { 0, Mils2iu( 350 ) };
  1428. }
  1429. else if( aStyle == ASCH_POWER_PORT_STYLE::GOST_BAR )
  1430. {
  1431. LIB_SHAPE* line1 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1432. aKsymbol->AddDrawItem( line1 );
  1433. line1->SetStroke( STROKE_PARAMS( Mils2iu( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1434. line1->AddPoint( { 0, 0 } );
  1435. line1->AddPoint( { 0, Mils2iu( -200 ) } );
  1436. LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1437. aKsymbol->AddDrawItem( line2 );
  1438. line2->SetStroke( STROKE_PARAMS( Mils2iu( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1439. line2->AddPoint( { Mils2iu( -100 ), Mils2iu( -200 ) } );
  1440. line2->AddPoint( { Mils2iu( 100 ), Mils2iu( -200 ) } );
  1441. return { 0, Mils2iu( 250 ) };
  1442. }
  1443. else
  1444. {
  1445. if( aStyle != ASCH_POWER_PORT_STYLE::BAR )
  1446. {
  1447. aReporter->Report( _( "Power Port has unknown style, use bar instead." ),
  1448. RPT_SEVERITY_WARNING );
  1449. }
  1450. LIB_SHAPE* line1 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1451. aKsymbol->AddDrawItem( line1 );
  1452. line1->SetStroke( STROKE_PARAMS( Mils2iu( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1453. line1->AddPoint( { 0, 0 } );
  1454. line1->AddPoint( { 0, Mils2iu( -100 ) } );
  1455. LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
  1456. aKsymbol->AddDrawItem( line2 );
  1457. line2->SetStroke( STROKE_PARAMS( Mils2iu( 10 ), PLOT_DASH_TYPE::SOLID ) );
  1458. line2->AddPoint( { Mils2iu( -50 ), Mils2iu( -100 ) } );
  1459. line2->AddPoint( { Mils2iu( 50 ), Mils2iu( -100 ) } );
  1460. return { 0, Mils2iu( 150 ) };
  1461. }
  1462. }
  1463. void SCH_ALTIUM_PLUGIN::ParsePowerPort( const std::map<wxString, wxString>& aProperties )
  1464. {
  1465. ASCH_POWER_PORT elem( aProperties );
  1466. LIB_ID libId = AltiumToKiCadLibID( getLibName(), elem.text );
  1467. LIB_SYMBOL* libSymbol = nullptr;
  1468. const auto& powerSymbolIt = m_powerSymbols.find( elem.text );
  1469. if( powerSymbolIt != m_powerSymbols.end() )
  1470. {
  1471. libSymbol = powerSymbolIt->second; // cache hit
  1472. }
  1473. else
  1474. {
  1475. libSymbol = new LIB_SYMBOL( wxEmptyString );
  1476. libSymbol->SetPower();
  1477. libSymbol->SetName( elem.text );
  1478. libSymbol->GetReferenceField().SetText( "#PWR" );
  1479. libSymbol->GetValueField().SetText( elem.text );
  1480. libSymbol->GetValueField().SetVisible( true );
  1481. libSymbol->SetDescription( wxString::Format( _( "Power symbol creates a global "
  1482. "label with name '%s'" ), elem.text ) );
  1483. libSymbol->SetKeyWords( "power-flag" );
  1484. libSymbol->SetLibId( libId );
  1485. // generate graphic
  1486. LIB_PIN* pin = new LIB_PIN( libSymbol );
  1487. libSymbol->AddDrawItem( pin );
  1488. pin->SetName( elem.text );
  1489. pin->SetPosition( { 0, 0 } );
  1490. pin->SetLength( 0 );
  1491. // marks the pin as a global label
  1492. pin->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN );
  1493. pin->SetVisible( false );
  1494. VECTOR2I valueFieldPos =
  1495. HelperGeneratePowerPortGraphics( libSymbol, elem.style, m_reporter );
  1496. libSymbol->GetValueField().SetPosition( valueFieldPos );
  1497. // this has to be done after parsing the LIB_SYMBOL!
  1498. m_pi->SaveSymbol( getLibFileName().GetFullPath(), libSymbol, m_properties.get() );
  1499. m_powerSymbols.insert( { elem.text, libSymbol } );
  1500. }
  1501. SCH_SHEET_PATH sheetpath;
  1502. m_rootSheet->LocatePathOfScreen( m_currentSheet->GetScreen(), &sheetpath );
  1503. // each symbol has its own powerSymbolIt for now
  1504. SCH_SYMBOL* symbol = new SCH_SYMBOL();
  1505. symbol->SetRef( &sheetpath, "#PWR?" );
  1506. symbol->SetValue( elem.text );
  1507. symbol->SetLibId( libId );
  1508. symbol->SetLibSymbol( new LIB_SYMBOL( *libSymbol ) );
  1509. SCH_FIELD* valueField = symbol->GetField( VALUE_FIELD );
  1510. valueField->SetVisible( elem.showNetName );
  1511. // TODO: Why do I need to set this a second time?
  1512. valueField->SetPosition( libSymbol->GetValueField().GetPosition() );
  1513. symbol->SetPosition( elem.location + m_sheetOffset );
  1514. switch( elem.orientation )
  1515. {
  1516. case ASCH_RECORD_ORIENTATION::RIGHTWARDS:
  1517. symbol->SetOrientation( SYMBOL_ORIENTATION_T::SYM_ORIENT_90 );
  1518. valueField->SetTextAngle( ANGLE_VERTICAL );
  1519. valueField->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
  1520. break;
  1521. case ASCH_RECORD_ORIENTATION::UPWARDS:
  1522. symbol->SetOrientation( SYMBOL_ORIENTATION_T::SYM_ORIENT_180 );
  1523. valueField->SetTextAngle( ANGLE_HORIZONTAL );
  1524. valueField->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
  1525. break;
  1526. case ASCH_RECORD_ORIENTATION::LEFTWARDS:
  1527. symbol->SetOrientation( SYMBOL_ORIENTATION_T::SYM_ORIENT_270 );
  1528. valueField->SetTextAngle( ANGLE_VERTICAL );
  1529. valueField->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
  1530. break;
  1531. case ASCH_RECORD_ORIENTATION::DOWNWARDS:
  1532. symbol->SetOrientation( SYMBOL_ORIENTATION_T::SYM_ORIENT_0 );
  1533. valueField->SetTextAngle( ANGLE_HORIZONTAL );
  1534. valueField->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
  1535. break;
  1536. default:
  1537. m_reporter->Report( _( "Pin has unexpected orientation." ), RPT_SEVERITY_WARNING );
  1538. break;
  1539. }
  1540. m_currentSheet->GetScreen()->Append( symbol );
  1541. }
  1542. void SCH_ALTIUM_PLUGIN::ParsePort( const ASCH_PORT& aElem )
  1543. {
  1544. bool isHarness = !aElem.harnessType.IsEmpty();
  1545. VECTOR2I start = aElem.location + m_sheetOffset;
  1546. VECTOR2I end = start;
  1547. switch( aElem.style )
  1548. {
  1549. default:
  1550. case ASCH_PORT_STYLE::NONE_HORIZONTAL:
  1551. case ASCH_PORT_STYLE::LEFT:
  1552. case ASCH_PORT_STYLE::RIGHT:
  1553. case ASCH_PORT_STYLE::LEFT_RIGHT:
  1554. end.x += aElem.width;
  1555. break;
  1556. case ASCH_PORT_STYLE::NONE_VERTICAL:
  1557. case ASCH_PORT_STYLE::TOP:
  1558. case ASCH_PORT_STYLE::BOTTOM:
  1559. case ASCH_PORT_STYLE::TOP_BOTTOM:
  1560. end.y -= aElem.width;
  1561. break;
  1562. }
  1563. // Check which connection points exists in the schematic
  1564. SCH_SCREEN* screen = m_currentSheet->GetScreen();
  1565. bool startIsWireTerminal = screen->IsTerminalPoint( start, LAYER_WIRE );
  1566. bool startIsBusTerminal = screen->IsTerminalPoint( start, LAYER_BUS );
  1567. bool endIsWireTerminal = screen->IsTerminalPoint( end, LAYER_WIRE );
  1568. bool endIsBusTerminal = screen->IsTerminalPoint( end, LAYER_BUS );
  1569. // check if any of the points is a terminal point
  1570. // TODO: there seems a problem to detect approximated connections towards component pins?
  1571. bool connectionFound = startIsWireTerminal
  1572. || startIsBusTerminal
  1573. || endIsWireTerminal
  1574. || endIsBusTerminal;
  1575. if( !isHarness && !connectionFound )
  1576. {
  1577. m_reporter->Report( wxString::Format( _( "Port %s has no connections." ), aElem.name ),
  1578. RPT_SEVERITY_WARNING );
  1579. }
  1580. // Select label position. In case both match, we will add a line later.
  1581. VECTOR2I position = ( startIsWireTerminal || startIsBusTerminal ) ? start : end;
  1582. SCH_TEXT* label;
  1583. if( isHarness )
  1584. {
  1585. wxString name = wxT( "HARNESS: " ) + aElem.name;
  1586. if( aElem.harnessType != aElem.name )
  1587. name += wxString::Format( wxT( " (%s)" ), aElem.harnessType );
  1588. label = new SCH_TEXT( position, name );
  1589. }
  1590. // TODO: detect correct label type depending on sheet settings, etc.
  1591. //{
  1592. // label = new SCH_HIERLABEL( elem.location + m_sheetOffset, elem.name );
  1593. //}
  1594. else
  1595. {
  1596. label = new SCH_GLOBALLABEL( position, aElem.name );
  1597. }
  1598. switch( aElem.iotype )
  1599. {
  1600. default:
  1601. case ASCH_PORT_IOTYPE::UNSPECIFIED:
  1602. label->SetShape( LABEL_FLAG_SHAPE::L_UNSPECIFIED );
  1603. break;
  1604. case ASCH_PORT_IOTYPE::OUTPUT:
  1605. label->SetShape( LABEL_FLAG_SHAPE::L_OUTPUT );
  1606. break;
  1607. case ASCH_PORT_IOTYPE::INPUT:
  1608. label->SetShape( LABEL_FLAG_SHAPE::L_INPUT );
  1609. break;
  1610. case ASCH_PORT_IOTYPE::BIDI:
  1611. label->SetShape( LABEL_FLAG_SHAPE::L_BIDI );
  1612. break;
  1613. }
  1614. switch( aElem.style )
  1615. {
  1616. default:
  1617. case ASCH_PORT_STYLE::NONE_HORIZONTAL:
  1618. case ASCH_PORT_STYLE::LEFT:
  1619. case ASCH_PORT_STYLE::RIGHT:
  1620. case ASCH_PORT_STYLE::LEFT_RIGHT:
  1621. if( ( startIsWireTerminal || startIsBusTerminal ) )
  1622. label->SetLabelSpinStyle( LABEL_SPIN_STYLE::RIGHT );
  1623. else
  1624. label->SetLabelSpinStyle( LABEL_SPIN_STYLE::LEFT );
  1625. break;
  1626. case ASCH_PORT_STYLE::NONE_VERTICAL:
  1627. case ASCH_PORT_STYLE::TOP:
  1628. case ASCH_PORT_STYLE::BOTTOM:
  1629. case ASCH_PORT_STYLE::TOP_BOTTOM:
  1630. if( ( startIsWireTerminal || startIsBusTerminal ) )
  1631. label->SetLabelSpinStyle( LABEL_SPIN_STYLE::UP );
  1632. else
  1633. label->SetLabelSpinStyle( LABEL_SPIN_STYLE::BOTTOM );
  1634. break;
  1635. }
  1636. label->SetFlags( IS_NEW );
  1637. m_currentSheet->GetScreen()->Append( label );
  1638. // This is a hack, for the case both connection points are valid: add a small wire
  1639. if( ( startIsWireTerminal && endIsWireTerminal ) )
  1640. {
  1641. SCH_LINE* wire = new SCH_LINE( start, SCH_LAYER_ID::LAYER_WIRE );
  1642. wire->SetEndPoint( end );
  1643. wire->SetLineWidth( Mils2iu( 2 ) );
  1644. wire->SetFlags( IS_NEW );
  1645. m_currentSheet->GetScreen()->Append( wire );
  1646. }
  1647. else if( startIsBusTerminal && endIsBusTerminal )
  1648. {
  1649. SCH_LINE* wire = new SCH_LINE( start, SCH_LAYER_ID::LAYER_BUS );
  1650. wire->SetEndPoint( end );
  1651. wire->SetLineWidth( Mils2iu( 2 ) );
  1652. wire->SetFlags( IS_NEW );
  1653. m_currentSheet->GetScreen()->Append( wire );
  1654. }
  1655. }
  1656. void SCH_ALTIUM_PLUGIN::ParseNoERC( const std::map<wxString, wxString>& aProperties )
  1657. {
  1658. ASCH_NO_ERC elem( aProperties );
  1659. if( elem.isActive )
  1660. {
  1661. SCH_NO_CONNECT* noConnect = new SCH_NO_CONNECT( elem.location + m_sheetOffset );
  1662. noConnect->SetFlags( IS_NEW );
  1663. m_currentSheet->GetScreen()->Append( noConnect );
  1664. }
  1665. }
  1666. void SCH_ALTIUM_PLUGIN::ParseNetLabel( const std::map<wxString, wxString>& aProperties )
  1667. {
  1668. ASCH_NET_LABEL elem( aProperties );
  1669. SCH_LABEL* label = new SCH_LABEL( elem.location + m_sheetOffset, elem.text );
  1670. switch( elem.orientation )
  1671. {
  1672. case ASCH_RECORD_ORIENTATION::RIGHTWARDS:
  1673. label->SetLabelSpinStyle( LABEL_SPIN_STYLE::RIGHT );
  1674. break;
  1675. case ASCH_RECORD_ORIENTATION::UPWARDS:
  1676. label->SetLabelSpinStyle( LABEL_SPIN_STYLE::UP );
  1677. break;
  1678. case ASCH_RECORD_ORIENTATION::LEFTWARDS:
  1679. label->SetLabelSpinStyle( LABEL_SPIN_STYLE::LEFT );
  1680. break;
  1681. case ASCH_RECORD_ORIENTATION::DOWNWARDS:
  1682. label->SetLabelSpinStyle( LABEL_SPIN_STYLE::BOTTOM );
  1683. break;
  1684. default:
  1685. break;
  1686. }
  1687. label->SetFlags( IS_NEW );
  1688. m_currentSheet->GetScreen()->Append( label );
  1689. }
  1690. void SCH_ALTIUM_PLUGIN::ParseBus( const std::map<wxString, wxString>& aProperties )
  1691. {
  1692. ASCH_BUS elem( aProperties );
  1693. for( size_t i = 0; i + 1 < elem.points.size(); i++ )
  1694. {
  1695. SCH_LINE* bus = new SCH_LINE( elem.points.at( i ) + m_sheetOffset,
  1696. SCH_LAYER_ID::LAYER_BUS );
  1697. bus->SetEndPoint( elem.points.at( i + 1 ) + m_sheetOffset );
  1698. bus->SetLineWidth( elem.lineWidth );
  1699. bus->SetFlags( IS_NEW );
  1700. m_currentSheet->GetScreen()->Append( bus );
  1701. }
  1702. }
  1703. void SCH_ALTIUM_PLUGIN::ParseWire( const std::map<wxString, wxString>& aProperties )
  1704. {
  1705. ASCH_WIRE elem( aProperties );
  1706. for( size_t i = 0; i + 1 < elem.points.size(); i++ )
  1707. {
  1708. SCH_LINE* wire =
  1709. new SCH_LINE( elem.points.at( i ) + m_sheetOffset, SCH_LAYER_ID::LAYER_WIRE );
  1710. wire->SetEndPoint( elem.points.at( i + 1 ) + m_sheetOffset );
  1711. wire->SetLineWidth( elem.lineWidth );
  1712. wire->SetFlags( IS_NEW );
  1713. m_currentSheet->GetScreen()->Append( wire );
  1714. }
  1715. }
  1716. void SCH_ALTIUM_PLUGIN::ParseJunction( const std::map<wxString, wxString>& aProperties )
  1717. {
  1718. ASCH_JUNCTION elem( aProperties );
  1719. SCH_JUNCTION* junction = new SCH_JUNCTION( elem.location + m_sheetOffset );
  1720. junction->SetFlags( IS_NEW );
  1721. m_currentSheet->GetScreen()->Append( junction );
  1722. }
  1723. void SCH_ALTIUM_PLUGIN::ParseImage( const std::map<wxString, wxString>& aProperties )
  1724. {
  1725. ASCH_IMAGE elem( aProperties );
  1726. VECTOR2I center = ( elem.location + elem.corner ) / 2 + m_sheetOffset;
  1727. std::unique_ptr<SCH_BITMAP> bitmap = std::make_unique<SCH_BITMAP>( center );
  1728. if( elem.embedimage )
  1729. {
  1730. const ASCH_STORAGE_FILE* storageFile = GetFileFromStorage( elem.filename );
  1731. if( !storageFile )
  1732. {
  1733. wxString msg = wxString::Format( _( "Embedded file %s not found in storage." ),
  1734. elem.filename );
  1735. m_reporter->Report( msg, RPT_SEVERITY_ERROR );
  1736. return;
  1737. }
  1738. wxString storagePath = wxFileName::CreateTempFileName( "kicad_import_" );
  1739. // As wxZlibInputStream is not seekable, we need to write a temporary file
  1740. wxMemoryInputStream fileStream( storageFile->data.data(), storageFile->data.size() );
  1741. wxZlibInputStream zlibInputStream( fileStream );
  1742. wxFFileOutputStream outputStream( storagePath );
  1743. outputStream.Write( zlibInputStream );
  1744. outputStream.Close();
  1745. if( !bitmap->ReadImageFile( storagePath ) )
  1746. {
  1747. m_reporter->Report( wxString::Format( _( "Error reading image %s." ), storagePath ),
  1748. RPT_SEVERITY_ERROR );
  1749. return;
  1750. }
  1751. // Remove temporary file
  1752. wxRemoveFile( storagePath );
  1753. }
  1754. else
  1755. {
  1756. if( !wxFileExists( elem.filename ) )
  1757. {
  1758. m_reporter->Report( wxString::Format( _( "File not found %s." ), elem.filename ),
  1759. RPT_SEVERITY_ERROR );
  1760. return;
  1761. }
  1762. if( !bitmap->ReadImageFile( elem.filename ) )
  1763. {
  1764. m_reporter->Report( wxString::Format( _( "Error reading image %s." ), elem.filename ),
  1765. RPT_SEVERITY_ERROR );
  1766. return;
  1767. }
  1768. }
  1769. // we only support one scale, thus we need to select one in case it does not keep aspect ratio
  1770. wxSize currentImageSize = bitmap->GetSize();
  1771. VECTOR2I expectedImageSize = elem.location - elem.corner;
  1772. double scaleX = std::abs( static_cast<double>( expectedImageSize.x ) / currentImageSize.x );
  1773. double scaleY = std::abs( static_cast<double>( expectedImageSize.y ) / currentImageSize.y );
  1774. bitmap->SetImageScale( std::min( scaleX, scaleY ) );
  1775. bitmap->SetFlags( IS_NEW );
  1776. m_currentSheet->GetScreen()->Append( bitmap.release() );
  1777. }
  1778. void SCH_ALTIUM_PLUGIN::ParseSheet( const std::map<wxString, wxString>& aProperties )
  1779. {
  1780. m_altiumSheet = std::make_unique<ASCH_SHEET>( aProperties );
  1781. PAGE_INFO pageInfo;
  1782. bool isPortrait = m_altiumSheet->sheetOrientation == ASCH_SHEET_WORKSPACEORIENTATION::PORTRAIT;
  1783. switch( m_altiumSheet->sheetSize )
  1784. {
  1785. default:
  1786. case ASCH_SHEET_SIZE::A4: pageInfo.SetType( "A4", isPortrait ); break;
  1787. case ASCH_SHEET_SIZE::A3: pageInfo.SetType( "A3", isPortrait ); break;
  1788. case ASCH_SHEET_SIZE::A2: pageInfo.SetType( "A2", isPortrait ); break;
  1789. case ASCH_SHEET_SIZE::A1: pageInfo.SetType( "A1", isPortrait ); break;
  1790. case ASCH_SHEET_SIZE::A0: pageInfo.SetType( "A0", isPortrait ); break;
  1791. case ASCH_SHEET_SIZE::A: pageInfo.SetType( "A", isPortrait ); break;
  1792. case ASCH_SHEET_SIZE::B: pageInfo.SetType( "B", isPortrait ); break;
  1793. case ASCH_SHEET_SIZE::C: pageInfo.SetType( "C", isPortrait ); break;
  1794. case ASCH_SHEET_SIZE::D: pageInfo.SetType( "D", isPortrait ); break;
  1795. case ASCH_SHEET_SIZE::E: pageInfo.SetType( "E", isPortrait ); break;
  1796. case ASCH_SHEET_SIZE::LETTER: pageInfo.SetType( "USLetter", isPortrait ); break;
  1797. case ASCH_SHEET_SIZE::LEGAL: pageInfo.SetType( "USLegal", isPortrait ); break;
  1798. case ASCH_SHEET_SIZE::TABLOID: pageInfo.SetType( "A3", isPortrait ); break;
  1799. case ASCH_SHEET_SIZE::ORCAD_A: pageInfo.SetType( "A", isPortrait ); break;
  1800. case ASCH_SHEET_SIZE::ORCAD_B: pageInfo.SetType( "B", isPortrait ); break;
  1801. case ASCH_SHEET_SIZE::ORCAD_C: pageInfo.SetType( "C", isPortrait ); break;
  1802. case ASCH_SHEET_SIZE::ORCAD_D: pageInfo.SetType( "D", isPortrait ); break;
  1803. case ASCH_SHEET_SIZE::ORCAD_E: pageInfo.SetType( "E", isPortrait ); break;
  1804. }
  1805. m_currentSheet->GetScreen()->SetPageSettings( pageInfo );
  1806. m_sheetOffset = { 0, pageInfo.GetHeightIU() };
  1807. }
  1808. void SCH_ALTIUM_PLUGIN::ParseSheetName( const std::map<wxString, wxString>& aProperties )
  1809. {
  1810. ASCH_SHEET_NAME elem( aProperties );
  1811. const auto& sheetIt = m_sheets.find( elem.ownerindex );
  1812. if( sheetIt == m_sheets.end() )
  1813. {
  1814. m_reporter->Report( wxString::Format( _( "Sheetname's owner (%d) not found." ),
  1815. elem.ownerindex ),
  1816. RPT_SEVERITY_ERROR );
  1817. return;
  1818. }
  1819. SCH_FIELD& sheetNameField = sheetIt->second->GetFields()[SHEETNAME];
  1820. sheetNameField.SetPosition( elem.location + m_sheetOffset );
  1821. sheetNameField.SetText( elem.text );
  1822. sheetNameField.SetVisible( !elem.isHidden );
  1823. SetTextPositioning( &sheetNameField, ASCH_LABEL_JUSTIFICATION::BOTTOM_LEFT, elem.orientation );
  1824. }
  1825. void SCH_ALTIUM_PLUGIN::ParseFileName( const std::map<wxString, wxString>& aProperties )
  1826. {
  1827. ASCH_FILE_NAME elem( aProperties );
  1828. const auto& sheetIt = m_sheets.find( elem.ownerindex );
  1829. if( sheetIt == m_sheets.end() )
  1830. {
  1831. m_reporter->Report( wxString::Format( _( "Filename's owner (%d) not found." ),
  1832. elem.ownerindex ),
  1833. RPT_SEVERITY_ERROR );
  1834. return;
  1835. }
  1836. SCH_FIELD& filenameField = sheetIt->second->GetFields()[SHEETFILENAME];
  1837. filenameField.SetPosition( elem.location + m_sheetOffset );
  1838. // If last symbols are ".sChDoC", change them to ".kicad_sch"
  1839. if( ( elem.text.Right( GetFileExtension().length() + 1 ).Lower() )
  1840. == ( "." + GetFileExtension().Lower() ) )
  1841. {
  1842. elem.text.RemoveLast( GetFileExtension().length() );
  1843. elem.text += KiCadSchematicFileExtension;
  1844. }
  1845. filenameField.SetText( elem.text );
  1846. filenameField.SetVisible( !elem.isHidden );
  1847. SetTextPositioning( &filenameField, ASCH_LABEL_JUSTIFICATION::BOTTOM_LEFT, elem.orientation );
  1848. }
  1849. void SCH_ALTIUM_PLUGIN::ParseDesignator( const std::map<wxString, wxString>& aProperties )
  1850. {
  1851. ASCH_DESIGNATOR elem( aProperties );
  1852. const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
  1853. if( libSymbolIt == m_libSymbols.end() )
  1854. {
  1855. // TODO: e.g. can depend on Template (RECORD=39
  1856. m_reporter->Report( wxString::Format( _( "Designator's owner (%d) not found." ),
  1857. elem.ownerindex ),
  1858. RPT_SEVERITY_ERROR );
  1859. return;
  1860. }
  1861. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  1862. SCH_SHEET_PATH sheetpath;
  1863. m_rootSheet->LocatePathOfScreen( m_currentSheet->GetScreen(), &sheetpath );
  1864. symbol->SetRef( &sheetpath, elem.text );
  1865. SCH_FIELD* refField = symbol->GetField( REFERENCE_FIELD );
  1866. refField->SetPosition( elem.location + m_sheetOffset );
  1867. refField->SetVisible( true );
  1868. SetTextPositioning( refField, elem.justification, elem.orientation );
  1869. }
  1870. void SCH_ALTIUM_PLUGIN::ParseBusEntry( const std::map<wxString, wxString>& aProperties )
  1871. {
  1872. ASCH_BUS_ENTRY elem( aProperties );
  1873. SCH_BUS_WIRE_ENTRY* busWireEntry = new SCH_BUS_WIRE_ENTRY( elem.location + m_sheetOffset );
  1874. VECTOR2I vector = elem.corner - elem.location;
  1875. busWireEntry->SetSize( { vector.x, vector.y } );
  1876. busWireEntry->SetFlags( IS_NEW );
  1877. m_currentSheet->GetScreen()->Append( busWireEntry );
  1878. }
  1879. void SCH_ALTIUM_PLUGIN::ParseParameter( const std::map<wxString, wxString>& aProperties )
  1880. {
  1881. ASCH_PARAMETER elem( aProperties );
  1882. // TODO: fill in replacements from variant, sheet and project
  1883. std::map<wxString, wxString> variableMap = {
  1884. { "COMMENT", "VALUE" },
  1885. { "VALUE", "ALTIUM_VALUE" },
  1886. };
  1887. if( elem.ownerindex <= 0 && elem.ownerpartid == ALTIUM_COMPONENT_NONE )
  1888. {
  1889. // This is some sheet parameter
  1890. if( elem.text == "*" )
  1891. return; // indicates parameter not set?
  1892. wxString paramName = elem.name.Upper();
  1893. if( paramName == "SHEETNUMBER" )
  1894. {
  1895. SCH_SHEET_PATH sheetpath;
  1896. m_rootSheet->LocatePathOfScreen( m_currentSheet->GetScreen(), &sheetpath );
  1897. m_rootSheet->SetPageNumber( sheetpath, elem.text );
  1898. }
  1899. else if( paramName == "TITLE" )
  1900. {
  1901. m_currentTitleBlock->SetTitle( elem.text );
  1902. }
  1903. else if( paramName == "REVISION" )
  1904. {
  1905. m_currentTitleBlock->SetRevision( elem.text );
  1906. }
  1907. else if( paramName == "DATE" )
  1908. {
  1909. m_currentTitleBlock->SetDate( elem.text );
  1910. }
  1911. else if( paramName == "COMPANYNAME" )
  1912. {
  1913. m_currentTitleBlock->SetCompany( elem.text );
  1914. }
  1915. else
  1916. {
  1917. m_schematic->Prj().GetTextVars()[ paramName ] = elem.text;
  1918. }
  1919. }
  1920. else
  1921. {
  1922. const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
  1923. if( libSymbolIt == m_libSymbols.end() )
  1924. {
  1925. // TODO: e.g. can depend on Template (RECORD=39
  1926. return;
  1927. }
  1928. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  1929. SCH_FIELD* field = nullptr;
  1930. if( elem.name.Upper() == "COMMENT" )
  1931. field = symbol->GetField( VALUE_FIELD );
  1932. else
  1933. {
  1934. int fieldIdx = symbol->GetFieldCount();
  1935. wxString fieldName = elem.name.Upper();
  1936. if( fieldName == "VALUE" )
  1937. fieldName = "ALTIUM_VALUE";
  1938. field = symbol->AddField( SCH_FIELD( VECTOR2I(), fieldIdx, symbol, fieldName ) );
  1939. }
  1940. wxString kicadText = AltiumSpecialStringsToKiCadVariables( elem.text, variableMap );
  1941. field->SetText( kicadText );
  1942. field->SetPosition( elem.location + m_sheetOffset );
  1943. field->SetVisible( !elem.isHidden );
  1944. SetTextPositioning( field, elem.justification, elem.orientation );
  1945. }
  1946. }
  1947. void SCH_ALTIUM_PLUGIN::ParseImplementationList( int aIndex,
  1948. const std::map<wxString, wxString>& aProperties )
  1949. {
  1950. ASCH_IMPLEMENTATION_LIST elem( aProperties );
  1951. m_altiumImplementationList.emplace( aIndex, elem.ownerindex );
  1952. }
  1953. void SCH_ALTIUM_PLUGIN::ParseImplementation( const std::map<wxString, wxString>& aProperties )
  1954. {
  1955. ASCH_IMPLEMENTATION elem( aProperties );
  1956. // Only get footprint, currently assigned only
  1957. if( ( elem.type == "PCBLIB" ) && ( elem.isCurrent ) )
  1958. {
  1959. const auto& implementationOwnerIt = m_altiumImplementationList.find( elem.ownerindex );
  1960. if( implementationOwnerIt == m_altiumImplementationList.end() )
  1961. {
  1962. m_reporter->Report( wxString::Format( _( "Implementation's owner (%d) not found." ),
  1963. elem.ownerindex ),
  1964. RPT_SEVERITY_ERROR );
  1965. return;
  1966. }
  1967. const auto& libSymbolIt = m_libSymbols.find( implementationOwnerIt->second );
  1968. if( libSymbolIt == m_libSymbols.end() )
  1969. {
  1970. m_reporter->Report( wxString::Format( _( "Footprint's owner (%d) not found." ),
  1971. implementationOwnerIt->second ),
  1972. RPT_SEVERITY_ERROR );
  1973. return;
  1974. }
  1975. LIB_ID fpLibId = AltiumToKiCadLibID( elem.libname, elem.name );
  1976. wxArrayString fpFilters;
  1977. fpFilters.Add( fpLibId.Format() );
  1978. libSymbolIt->second->SetFPFilters( fpFilters ); // TODO: not ideal as we overwrite it
  1979. SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
  1980. symbol->SetFootprint( fpLibId.Format() );
  1981. }
  1982. }