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.

3531 lines
122 KiB

3 years ago
2 years ago
3 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
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
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
6 years ago
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
6 years ago
2 years ago
3 years ago
2 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
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2017 CERN
  5. * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * @author Alejandro García Montoro <alejandro.garciamontoro@gmail.com>
  8. * @author Maciej Suminski <maciej.suminski@cern.ch>
  9. * @author Russell Oliver <roliver8143@gmail.com>
  10. *
  11. * This program is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU General Public License
  13. * as published by the Free Software Foundation; either version 3
  14. * of the License, or (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License along
  22. * with this program. If not, see <http://www.gnu.org/licenses/>.
  23. */
  24. #include <sch_io/eagle/sch_io_eagle.h>
  25. #include <locale_io.h>
  26. #include <algorithm>
  27. #include <memory>
  28. #include <wx/filename.h>
  29. #include <wx/string.h>
  30. #include <wx/tokenzr.h>
  31. #include <wx/wfstream.h>
  32. #include <wx/txtstrm.h>
  33. #include <wx/xml/xml.h>
  34. #include <font/fontconfig.h>
  35. #include <io/eagle/eagle_parser.h>
  36. #include <lib_id.h>
  37. #include <progress_reporter.h>
  38. #include <project.h>
  39. #include <project/net_settings.h>
  40. #include <project_sch.h>
  41. #include <sch_bus_entry.h>
  42. #include <sch_edit_frame.h>
  43. #include <sch_io/kicad_sexpr/sch_io_kicad_sexpr.h>
  44. #include <sch_junction.h>
  45. #include <sch_label.h>
  46. #include <sch_marker.h>
  47. #include <sch_pin.h>
  48. #include <sch_screen.h>
  49. #include <sch_shape.h>
  50. #include <sch_sheet.h>
  51. #include <sch_sheet_path.h>
  52. #include <sch_sheet_pin.h>
  53. #include <sch_symbol.h>
  54. #include <schematic.h>
  55. #include <string_utils.h>
  56. #include <symbol_lib_table.h>
  57. #include <wildcards_and_files_ext.h>
  58. // Eagle schematic axes are aligned with x increasing left to right and Y increasing bottom to top
  59. // KiCad schematic axes are aligned with x increasing left to right and Y increasing top to bottom.
  60. using namespace std;
  61. /**
  62. * Map of EAGLE pin type values to KiCad pin type values
  63. */
  64. static const std::map<wxString, ELECTRICAL_PINTYPE> pinDirectionsMap = {
  65. { wxT( "sup" ), ELECTRICAL_PINTYPE::PT_POWER_IN },
  66. { wxT( "pas" ), ELECTRICAL_PINTYPE::PT_PASSIVE },
  67. { wxT( "out" ), ELECTRICAL_PINTYPE::PT_OUTPUT },
  68. { wxT( "in" ), ELECTRICAL_PINTYPE::PT_INPUT },
  69. { wxT( "nc" ), ELECTRICAL_PINTYPE::PT_NC },
  70. { wxT( "io" ), ELECTRICAL_PINTYPE::PT_BIDI },
  71. { wxT( "oc" ), ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR },
  72. { wxT( "hiz" ), ELECTRICAL_PINTYPE::PT_TRISTATE },
  73. { wxT( "pwr" ), ELECTRICAL_PINTYPE::PT_POWER_IN },
  74. };
  75. ///< Compute a bounding box for all items in a schematic sheet
  76. static BOX2I getSheetBbox( SCH_SHEET* aSheet )
  77. {
  78. BOX2I bbox;
  79. for( SCH_ITEM* item : aSheet->GetScreen()->Items() )
  80. bbox.Merge( item->GetBoundingBox() );
  81. return bbox;
  82. }
  83. ///< Extract the net name part from a pin name (e.g. return 'GND' for pin named 'GND@2')
  84. static inline wxString extractNetName( const wxString& aPinName )
  85. {
  86. return aPinName.BeforeFirst( '@' );
  87. }
  88. SCH_SHEET* SCH_IO_EAGLE::getCurrentSheet()
  89. {
  90. return m_sheetPath.Last();
  91. }
  92. SCH_SCREEN* SCH_IO_EAGLE::getCurrentScreen()
  93. {
  94. SCH_SHEET* currentSheet = m_sheetPath.Last();
  95. wxCHECK( currentSheet, nullptr );
  96. return currentSheet->GetScreen();
  97. }
  98. wxString SCH_IO_EAGLE::getLibName()
  99. {
  100. if( m_libName.IsEmpty() )
  101. {
  102. // Try to come up with a meaningful name
  103. m_libName = m_schematic->Prj().GetProjectName();
  104. if( m_libName.IsEmpty() )
  105. {
  106. wxFileName fn( m_rootSheet->GetFileName() );
  107. m_libName = fn.GetName();
  108. }
  109. if( m_libName.IsEmpty() )
  110. m_libName = wxT( "noname" );
  111. m_libName += wxT( "-eagle-import" );
  112. m_libName = LIB_ID::FixIllegalChars( m_libName, true ).wx_str();
  113. }
  114. return m_libName;
  115. }
  116. wxFileName SCH_IO_EAGLE::getLibFileName()
  117. {
  118. wxFileName fn;
  119. wxCHECK( m_schematic, fn );
  120. fn.Assign( m_schematic->Prj().GetProjectPath(), getLibName(),
  121. FILEEXT::KiCadSymbolLibFileExtension );
  122. return fn;
  123. }
  124. void SCH_IO_EAGLE::loadLayerDefs( const std::vector<std::unique_ptr<ELAYER>>& aLayers )
  125. {
  126. // match layers based on their names
  127. for( const std::unique_ptr<ELAYER>& elayer : aLayers )
  128. {
  129. /**
  130. * Layers in KiCad schematics are not actually layers, but abstract groups mainly used to
  131. * decide item colors.
  132. *
  133. * <layers>
  134. * <layer number="90" name="Modules" color="5" fill="1" visible="yes" active="yes"/>
  135. * <layer number="91" name="Nets" color="2" fill="1" visible="yes" active="yes"/>
  136. * <layer number="92" name="Busses" color="1" fill="1" visible="yes" active="yes"/>
  137. * <layer number="93" name="Pins" color="2" fill="1" visible="no" active="yes"/>
  138. * <layer number="94" name="Symbols" color="4" fill="1" visible="yes" active="yes"/>
  139. * <layer number="95" name="Names" color="7" fill="1" visible="yes" active="yes"/>
  140. * <layer number="96" name="Values" color="7" fill="1" visible="yes" active="yes"/>
  141. * <layer number="97" name="Info" color="7" fill="1" visible="yes" active="yes"/>
  142. * <layer number="98" name="Guide" color="6" fill="1" visible="yes" active="yes"/>
  143. * </layers>
  144. */
  145. switch ( elayer->number)
  146. {
  147. case 91:
  148. m_layerMap[elayer->number] = LAYER_WIRE;
  149. break;
  150. case 92:
  151. m_layerMap[elayer->number] = LAYER_BUS;
  152. break;
  153. case 97:
  154. case 98:
  155. m_layerMap[elayer->number] = LAYER_NOTES;
  156. break;
  157. default:
  158. break;
  159. }
  160. }
  161. }
  162. SCH_LAYER_ID SCH_IO_EAGLE::kiCadLayer( int aEagleLayer )
  163. {
  164. auto it = m_layerMap.find( aEagleLayer );
  165. return it == m_layerMap.end() ? LAYER_NOTES : it->second;
  166. }
  167. // Return the KiCad symbol orientation based on eagle rotation degrees.
  168. static SYMBOL_ORIENTATION_T kiCadComponentRotation( float eagleDegrees )
  169. {
  170. int roti = int( eagleDegrees );
  171. switch( roti )
  172. {
  173. case 0: return SYM_ORIENT_0;
  174. case 90: return SYM_ORIENT_90;
  175. case 180: return SYM_ORIENT_180;
  176. case 270: return SYM_ORIENT_270;
  177. default:
  178. wxASSERT_MSG( false, wxString::Format( wxT( "Unhandled orientation (%d degrees)" ),
  179. roti ) );
  180. return SYM_ORIENT_0;
  181. }
  182. }
  183. // Calculate text alignment based on the given Eagle text alignment parameters.
  184. static void eagleToKicadAlignment( EDA_TEXT* aText, int aEagleAlignment, int aRelDegress,
  185. bool aMirror, bool aSpin, int aAbsDegress )
  186. {
  187. int align = aEagleAlignment;
  188. if( aRelDegress == 90 )
  189. {
  190. aText->SetTextAngle( ANGLE_VERTICAL );
  191. }
  192. else if( aRelDegress == 180 )
  193. {
  194. align = -align;
  195. }
  196. else if( aRelDegress == 270 )
  197. {
  198. aText->SetTextAngle( ANGLE_VERTICAL );
  199. align = -align;
  200. }
  201. if( aMirror == true )
  202. {
  203. if( aAbsDegress == 90 || aAbsDegress == 270 )
  204. {
  205. if( align == ETEXT::BOTTOM_RIGHT )
  206. align = ETEXT::TOP_RIGHT;
  207. else if( align == ETEXT::BOTTOM_LEFT )
  208. align = ETEXT::TOP_LEFT;
  209. else if( align == ETEXT::TOP_LEFT )
  210. align = ETEXT::BOTTOM_LEFT;
  211. else if( align == ETEXT::TOP_RIGHT )
  212. align = ETEXT::BOTTOM_RIGHT;
  213. }
  214. else if( aAbsDegress == 0 || aAbsDegress == 180 )
  215. {
  216. if( align == ETEXT::BOTTOM_RIGHT )
  217. align = ETEXT::BOTTOM_LEFT;
  218. else if( align == ETEXT::BOTTOM_LEFT )
  219. align = ETEXT::BOTTOM_RIGHT;
  220. else if( align == ETEXT::TOP_LEFT )
  221. align = ETEXT::TOP_RIGHT;
  222. else if( align == ETEXT::TOP_RIGHT )
  223. align = ETEXT::TOP_LEFT;
  224. else if( align == ETEXT::CENTER_LEFT )
  225. align = ETEXT::CENTER_RIGHT;
  226. else if( align == ETEXT::CENTER_RIGHT )
  227. align = ETEXT::CENTER_LEFT;
  228. }
  229. }
  230. switch( align )
  231. {
  232. case ETEXT::CENTER:
  233. aText->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
  234. aText->SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
  235. break;
  236. case ETEXT::CENTER_LEFT:
  237. aText->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
  238. aText->SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
  239. break;
  240. case ETEXT::CENTER_RIGHT:
  241. aText->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
  242. aText->SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
  243. break;
  244. case ETEXT::TOP_CENTER:
  245. aText->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
  246. aText->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
  247. break;
  248. case ETEXT::TOP_LEFT:
  249. aText->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
  250. aText->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
  251. break;
  252. case ETEXT::TOP_RIGHT:
  253. aText->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
  254. aText->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
  255. break;
  256. case ETEXT::BOTTOM_CENTER:
  257. aText->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
  258. aText->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
  259. break;
  260. case ETEXT::BOTTOM_LEFT:
  261. aText->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
  262. aText->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
  263. break;
  264. case ETEXT::BOTTOM_RIGHT:
  265. aText->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
  266. aText->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
  267. break;
  268. default:
  269. aText->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
  270. aText->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
  271. break;
  272. }
  273. }
  274. SCH_IO_EAGLE::SCH_IO_EAGLE() : SCH_IO( wxS( "EAGLE" ) ),
  275. m_rootSheet( nullptr ),
  276. m_schematic( nullptr ),
  277. m_sheetIndex( 1 )
  278. {
  279. m_reporter = &WXLOG_REPORTER::GetInstance();
  280. }
  281. SCH_IO_EAGLE::~SCH_IO_EAGLE()
  282. {
  283. }
  284. int SCH_IO_EAGLE::GetModifyHash() const
  285. {
  286. return 0;
  287. }
  288. SCH_SHEET* SCH_IO_EAGLE::LoadSchematicFile( const wxString& aFileName, SCHEMATIC* aSchematic,
  289. SCH_SHEET* aAppendToMe,
  290. const std::map<std::string, UTF8>* aProperties )
  291. {
  292. wxASSERT( !aFileName || aSchematic != nullptr );
  293. LOCALE_IO toggle; // toggles on, then off, the C locale.
  294. // Show the font substitution warnings
  295. fontconfig::FONTCONFIG::SetReporter( &WXLOG_REPORTER::GetInstance() );
  296. m_filename = aFileName;
  297. m_schematic = aSchematic;
  298. if( m_progressReporter )
  299. {
  300. m_progressReporter->Report( wxString::Format( _( "Loading %s..." ), aFileName ) );
  301. if( !m_progressReporter->KeepRefreshing() )
  302. THROW_IO_ERROR( ( "Open canceled by user." ) );
  303. }
  304. // Load the document
  305. wxXmlDocument xmlDocument = loadXmlDocument( m_filename.GetFullPath() );
  306. // Retrieve the root as current node
  307. wxXmlNode* currentNode = xmlDocument.GetRoot();
  308. if( m_progressReporter )
  309. m_progressReporter->SetNumPhases( static_cast<int>( GetNodeCount( currentNode ) ) );
  310. // Delete on exception, if I own m_rootSheet, according to aAppendToMe
  311. unique_ptr<SCH_SHEET> deleter( aAppendToMe ? nullptr : m_rootSheet );
  312. wxFileName newFilename( m_filename );
  313. newFilename.SetExt( FILEEXT::KiCadSchematicFileExtension );
  314. if( aAppendToMe )
  315. {
  316. wxCHECK_MSG( aSchematic->IsValid(), nullptr,
  317. wxT( "Can't append to a schematic with no root!" ) );
  318. m_rootSheet = &aSchematic->Root();
  319. // We really should be passing the SCH_SHEET_PATH object to the aAppendToMe attribute
  320. // instead of the SCH_SHEET. The full path is needed to properly generate instance
  321. // data.
  322. SCH_SHEET_LIST hierarchy( m_rootSheet );
  323. for( const SCH_SHEET_PATH& sheetPath : hierarchy )
  324. {
  325. if( sheetPath.Last() == aAppendToMe )
  326. {
  327. m_sheetPath = sheetPath;
  328. break;
  329. }
  330. }
  331. }
  332. else
  333. {
  334. m_rootSheet = new SCH_SHEET( aSchematic );
  335. m_rootSheet->SetFileName( newFilename.GetFullPath() );
  336. aSchematic->SetRoot( m_rootSheet );
  337. }
  338. if( !m_rootSheet->GetScreen() )
  339. {
  340. SCH_SCREEN* screen = new SCH_SCREEN( m_schematic );
  341. screen->SetFileName( newFilename.GetFullPath() );
  342. m_rootSheet->SetScreen( screen );
  343. // Virtual root sheet UUID must be the same as the schematic file UUID.
  344. const_cast<KIID&>( m_rootSheet->m_Uuid ) = screen->GetUuid();
  345. // There is always at least a root sheet.
  346. m_sheetPath.push_back( m_rootSheet );
  347. m_sheetPath.SetPageNumber( wxT( "1" ) );
  348. }
  349. SYMBOL_LIB_TABLE* libTable = PROJECT_SCH::SchSymbolLibTable( &m_schematic->Prj() );
  350. wxCHECK_MSG( libTable, nullptr, wxT( "Could not load symbol lib table." ) );
  351. m_pi.reset( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
  352. /// @note No check is being done here to see if the existing symbol library exists so this
  353. /// will overwrite the existing one.
  354. if( !libTable->HasLibrary( getLibName() ) )
  355. {
  356. // Create a new empty symbol library.
  357. m_pi->CreateLibrary( getLibFileName().GetFullPath() );
  358. wxString libTableUri = wxT( "${KIPRJMOD}/" ) + getLibFileName().GetFullName();
  359. // Add the new library to the project symbol library table.
  360. libTable->InsertRow( new SYMBOL_LIB_TABLE_ROW( getLibName(), libTableUri,
  361. wxT( "KiCad" ) ) );
  362. // Save project symbol library table.
  363. wxFileName fn( m_schematic->Prj().GetProjectPath(),
  364. SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
  365. // So output formatter goes out of scope and closes the file before reloading.
  366. {
  367. FILE_OUTPUTFORMATTER formatter( fn.GetFullPath() );
  368. libTable->Format( &formatter, 0 );
  369. }
  370. // Reload the symbol library table.
  371. m_schematic->Prj().SetElem( PROJECT::ELEM::SYMBOL_LIB_TABLE, nullptr );
  372. PROJECT_SCH::SchSymbolLibTable( &m_schematic->Prj() );
  373. }
  374. m_eagleDoc = std::make_unique<EAGLE_DOC>( currentNode, this );
  375. // If the attribute is found, store the Eagle version;
  376. // otherwise, store the dummy "0.0" version.
  377. m_version = ( m_eagleDoc->version.IsEmpty() ) ? wxString( wxS( "0.0" ) ) : m_eagleDoc->version;
  378. // Load drawing
  379. loadDrawing( m_eagleDoc->drawing );
  380. m_pi->SaveLibrary( getLibFileName().GetFullPath() );
  381. SCH_SCREENS allSheets( m_rootSheet );
  382. allSheets.UpdateSymbolLinks(); // Update all symbol library links for all sheets.
  383. return m_rootSheet;
  384. }
  385. void SCH_IO_EAGLE::EnumerateSymbolLib( wxArrayString& aSymbolNameList,
  386. const wxString& aLibraryPath,
  387. const std::map<std::string, UTF8>* aProperties )
  388. {
  389. m_filename = aLibraryPath;
  390. m_libName = m_filename.GetName();
  391. ensureLoadedLibrary( aLibraryPath );
  392. auto it = m_eagleLibs.find( m_libName );
  393. if( it != m_eagleLibs.end() )
  394. {
  395. for( const auto& [symName, libSymbol] : it->second.KiCadSymbols )
  396. aSymbolNameList.push_back( symName );
  397. }
  398. }
  399. void SCH_IO_EAGLE::EnumerateSymbolLib( std::vector<LIB_SYMBOL*>& aSymbolList,
  400. const wxString& aLibraryPath,
  401. const std::map<std::string, UTF8>* aProperties )
  402. {
  403. m_filename = aLibraryPath;
  404. m_libName = m_filename.GetName();
  405. ensureLoadedLibrary( aLibraryPath );
  406. auto it = m_eagleLibs.find( m_libName );
  407. if( it != m_eagleLibs.end() )
  408. {
  409. for( const auto& [symName, libSymbol] : it->second.KiCadSymbols )
  410. aSymbolList.push_back( libSymbol.get() );
  411. }
  412. }
  413. LIB_SYMBOL* SCH_IO_EAGLE::LoadSymbol( const wxString& aLibraryPath, const wxString& aAliasName,
  414. const std::map<std::string, UTF8>* aProperties )
  415. {
  416. m_filename = aLibraryPath;
  417. m_libName = m_filename.GetName();
  418. ensureLoadedLibrary( aLibraryPath );
  419. auto it = m_eagleLibs.find( m_libName );
  420. if( it != m_eagleLibs.end() )
  421. {
  422. auto it2 = it->second.KiCadSymbols.find( aAliasName );
  423. if( it2 != it->second.KiCadSymbols.end() )
  424. return it2->second.get();
  425. }
  426. return nullptr;
  427. }
  428. long long SCH_IO_EAGLE::getLibraryTimestamp( const wxString& aLibraryPath ) const
  429. {
  430. wxFileName fn( aLibraryPath );
  431. if( fn.IsFileReadable() && fn.GetModificationTime().IsValid() )
  432. return fn.GetModificationTime().GetValue().GetValue();
  433. else
  434. return wxDateTime( 0.0 ).GetValue().GetValue();
  435. }
  436. void SCH_IO_EAGLE::ensureLoadedLibrary( const wxString& aLibraryPath )
  437. {
  438. // Suppress font substitution warnings
  439. fontconfig::FONTCONFIG::SetReporter( nullptr );
  440. if( m_eagleLibs.find( m_libName ) != m_eagleLibs.end() )
  441. {
  442. wxCHECK( m_timestamps.count( m_libName ), /*void*/ );
  443. if( m_timestamps.at( m_libName ) == getLibraryTimestamp( aLibraryPath ) )
  444. return;
  445. }
  446. LOCALE_IO toggle; // toggles on, then off, the C locale.
  447. if( m_progressReporter )
  448. {
  449. m_progressReporter->Report( wxString::Format( _( "Loading %s..." ), aLibraryPath ) );
  450. if( !m_progressReporter->KeepRefreshing() )
  451. THROW_IO_ERROR( ( "Open canceled by user." ) );
  452. }
  453. // Load the document
  454. wxXmlDocument xmlDocument = loadXmlDocument( m_filename.GetFullPath() );
  455. // Retrieve the root as current node
  456. std::unique_ptr<EAGLE_DOC> doc = std::make_unique<EAGLE_DOC>( xmlDocument.GetRoot(), this );
  457. // If the attribute is found, store the Eagle version;
  458. // otherwise, store the dummy "0.0" version.
  459. m_version = ( doc->version.IsEmpty() ) ? wxString( wxS( "0.0" ) ) : doc->version;
  460. // Load drawing
  461. loadDrawing( doc->drawing );
  462. // Remember timestamp
  463. m_timestamps[m_libName] = getLibraryTimestamp( aLibraryPath );
  464. }
  465. wxXmlDocument SCH_IO_EAGLE::loadXmlDocument( const wxString& aFileName )
  466. {
  467. wxXmlDocument xmlDocument;
  468. wxFFileInputStream stream( m_filename.GetFullPath() );
  469. if( !stream.IsOk() )
  470. {
  471. THROW_IO_ERROR(
  472. wxString::Format( _( "Unable to read file '%s'." ), m_filename.GetFullPath() ) );
  473. }
  474. // read first line to check for Eagle XML format file
  475. wxTextInputStream text( stream );
  476. wxString line = text.ReadLine();
  477. if( !line.StartsWith( wxT( "<?xml" ) ) && !line.StartsWith( wxT( "<!--" ) ) )
  478. {
  479. THROW_IO_ERROR( wxString::Format( _( "'%s' is an Eagle binary-format file; "
  480. "only Eagle XML-format files can be imported." ),
  481. m_filename.GetFullPath() ) );
  482. }
  483. if( !xmlDocument.Load( stream ) )
  484. {
  485. THROW_IO_ERROR(
  486. wxString::Format( _( "Unable to read file '%s'." ), m_filename.GetFullPath() ) );
  487. }
  488. return xmlDocument;
  489. }
  490. void SCH_IO_EAGLE::loadDrawing( const std::unique_ptr<EDRAWING>& aDrawing )
  491. {
  492. wxCHECK( aDrawing, /* void */ );
  493. loadLayerDefs( aDrawing->layers );
  494. if( aDrawing->library )
  495. {
  496. EAGLE_LIBRARY& elib = m_eagleLibs[m_libName];
  497. elib.name = m_libName;
  498. loadLibrary( &aDrawing->library.value(), &elib );
  499. }
  500. if( aDrawing->schematic )
  501. loadSchematic( *aDrawing->schematic );
  502. }
  503. void SCH_IO_EAGLE::countNets( const ESCHEMATIC& aSchematic )
  504. {
  505. for( const std::unique_ptr<ESHEET>& esheet : aSchematic.sheets )
  506. {
  507. for( const std::unique_ptr<ENET>& enet : esheet->nets )
  508. {
  509. wxString netName = enet->netname;
  510. if( m_netCounts.count( netName ) )
  511. m_netCounts[netName] = m_netCounts[netName] + 1;
  512. else
  513. m_netCounts[netName] = 1;
  514. }
  515. }
  516. for( const auto& [modname, emodule] : aSchematic.modules )
  517. {
  518. for( const std::unique_ptr<ESHEET>& esheet : emodule->sheets )
  519. {
  520. for( const std::unique_ptr<ENET>& enet : esheet->nets )
  521. {
  522. wxString netName = enet->netname;
  523. if( m_netCounts.count( netName ) )
  524. m_netCounts[netName] = m_netCounts[netName] + 1;
  525. else
  526. m_netCounts[netName] = 1;
  527. }
  528. }
  529. }
  530. }
  531. void SCH_IO_EAGLE::loadSchematic( const ESCHEMATIC& aSchematic )
  532. {
  533. // Map all children into a readable dictionary
  534. if( aSchematic.sheets.empty() )
  535. return;
  536. // N.B. Eagle parts are case-insensitive in matching but we keep the display case
  537. for( const auto& [name, epart] : aSchematic.parts )
  538. m_partlist[name.Upper()] = epart.get();
  539. for( const auto& [modName, emodule] : aSchematic.modules )
  540. {
  541. for( const auto& [partName, epart] : emodule->parts )
  542. m_partlist[partName.Upper()] = epart.get();
  543. }
  544. if( !aSchematic.libraries.empty() )
  545. {
  546. for( const auto& [libName, elibrary] : aSchematic.libraries )
  547. {
  548. EAGLE_LIBRARY* elib = &m_eagleLibs[elibrary->GetName()];
  549. elib->name = elibrary->GetName();
  550. loadLibrary( elibrary.get(), &m_eagleLibs[elibrary->GetName()] );
  551. }
  552. m_pi->SaveLibrary( getLibFileName().GetFullPath() );
  553. }
  554. // find all nets and count how many sheets they appear on.
  555. // local labels will be used for nets found only on that sheet.
  556. countNets( aSchematic );
  557. size_t sheetCount = aSchematic.sheets.size();
  558. if( sheetCount > 1 )
  559. {
  560. int x, y;
  561. x = 1;
  562. y = 1;
  563. for( const std::unique_ptr<ESHEET>& esheet : aSchematic.sheets )
  564. {
  565. VECTOR2I pos = VECTOR2I( x * schIUScale.MilsToIU( 1000 ),
  566. y * schIUScale.MilsToIU( 1000 ) );
  567. // Eagle schematics are never more than one sheet deep so the parent sheet is
  568. // always the root sheet.
  569. std::unique_ptr<SCH_SHEET> sheet = std::make_unique<SCH_SHEET>( m_rootSheet, pos );
  570. SCH_SCREEN* screen = new SCH_SCREEN( m_schematic );
  571. sheet->SetScreen( screen );
  572. screen->SetFileName( sheet->GetFileName() );
  573. wxCHECK2( sheet && screen, continue );
  574. wxString pageNo = wxString::Format( wxT( "%d" ), m_sheetIndex );
  575. m_sheetPath.push_back( sheet.get() );
  576. loadSheet( esheet );
  577. m_sheetPath.SetPageNumber( pageNo );
  578. m_sheetPath.pop_back();
  579. SCH_SCREEN* currentScreen = m_rootSheet->GetScreen();
  580. wxCHECK2( currentScreen, continue );
  581. sheet->SetParent( m_sheetPath.Last() );
  582. currentScreen->Append( sheet.release() );
  583. x += 2;
  584. if( x > 10 ) // Start next row of sheets.
  585. {
  586. x = 1;
  587. y += 2;
  588. }
  589. m_sheetIndex++;
  590. }
  591. }
  592. else
  593. {
  594. for( const std::unique_ptr<ESHEET>& esheet : aSchematic.sheets )
  595. loadSheet( esheet );
  596. }
  597. // Handle the missing symbol units that need to be instantiated
  598. // to create the missing implicit connections
  599. // Calculate the already placed items bounding box and the page size to determine
  600. // placement for the new symbols
  601. VECTOR2I pageSizeIU = m_rootSheet->GetScreen()->GetPageSettings().GetSizeIU( schIUScale.IU_PER_MILS );
  602. BOX2I sheetBbox = getSheetBbox( m_rootSheet );
  603. VECTOR2I newCmpPosition( sheetBbox.GetLeft(), sheetBbox.GetBottom() );
  604. int maxY = sheetBbox.GetY();
  605. SCH_SHEET_PATH sheetpath;
  606. m_rootSheet->LocatePathOfScreen( m_rootSheet->GetScreen(), &sheetpath );
  607. for( auto& cmp : m_missingCmps )
  608. {
  609. const SCH_SYMBOL* origSymbol = cmp.second.cmp;
  610. for( auto& unitEntry : cmp.second.units )
  611. {
  612. if( unitEntry.second == false )
  613. continue; // unit has been already processed
  614. // Instantiate the missing symbol unit
  615. int unit = unitEntry.first;
  616. const wxString reference = origSymbol->GetField( FIELD_T::REFERENCE )->GetText();
  617. std::unique_ptr<SCH_SYMBOL> symbol( (SCH_SYMBOL*) origSymbol->Duplicate( IGNORE_PARENT_GROUP ) );
  618. symbol->SetUnitSelection( &sheetpath, unit );
  619. symbol->SetUnit( unit );
  620. symbol->SetOrientation( 0 );
  621. symbol->AddHierarchicalReference( sheetpath.Path(), reference, unit );
  622. // Calculate the placement position
  623. BOX2I cmpBbox = symbol->GetBoundingBox();
  624. int posY = newCmpPosition.y + cmpBbox.GetHeight();
  625. symbol->SetPosition( VECTOR2I( newCmpPosition.x, posY ) );
  626. newCmpPosition.x += cmpBbox.GetWidth();
  627. maxY = std::max( maxY, posY );
  628. if( newCmpPosition.x >= pageSizeIU.x ) // reached the page boundary?
  629. newCmpPosition = VECTOR2I( sheetBbox.GetLeft(), maxY ); // then start a new row
  630. // Add the global net labels to recreate the implicit connections
  631. addImplicitConnections( symbol.get(), m_rootSheet->GetScreen(), false );
  632. m_rootSheet->GetScreen()->Append( symbol.release() );
  633. }
  634. }
  635. m_missingCmps.clear();
  636. }
  637. void SCH_IO_EAGLE::loadSheet( const std::unique_ptr<ESHEET>& aSheet )
  638. {
  639. SCH_SHEET* sheet = getCurrentSheet();
  640. SCH_SCREEN* screen = getCurrentScreen();
  641. wxCHECK( sheet && screen, /* void */ );
  642. if( m_modules.empty() )
  643. {
  644. std::string filename;
  645. wxFileName fn = m_filename;
  646. fn.SetExt( FILEEXT::KiCadSchematicFileExtension );
  647. filename = wxString::Format( wxT( "%s_%d" ), m_filename.GetName(), m_sheetIndex );
  648. sheet->SetName( filename );
  649. ReplaceIllegalFileNameChars( &filename );
  650. replace( filename.begin(), filename.end(), ' ', '_' );
  651. fn.SetName( filename );
  652. sheet->SetFileName( fn.GetFullName() );
  653. screen->SetFileName( fn.GetFullPath() );
  654. }
  655. for( const auto& [name, moduleinst] : aSheet->moduleinsts )
  656. loadModuleInstance( moduleinst );
  657. sheet->AutoplaceFields( screen, AUTOPLACE_AUTO );
  658. if( aSheet->plain )
  659. {
  660. for( const std::unique_ptr<EPOLYGON>& epoly : aSheet->plain->polygons )
  661. screen->Append( loadPolyLine( epoly ) );
  662. for( const std::unique_ptr<EWIRE>& ewire : aSheet->plain->wires )
  663. {
  664. SEG endpoints;
  665. screen->Append( loadWire( ewire, endpoints ) );
  666. }
  667. for( const std::unique_ptr<ETEXT>& etext : aSheet->plain->texts )
  668. screen->Append( loadPlainText( etext ) );
  669. for( const std::unique_ptr<ECIRCLE>& ecircle : aSheet->plain->circles )
  670. screen->Append( loadCircle( ecircle ) );
  671. for( const std::unique_ptr<ERECT>& erectangle : aSheet->plain->rectangles )
  672. screen->Append( loadRectangle( erectangle ) );
  673. for( const std::unique_ptr<EFRAME>& eframe : aSheet->plain->frames )
  674. {
  675. std::vector<SCH_ITEM*> frameItems;
  676. loadFrame( eframe, frameItems );
  677. for( SCH_ITEM* item : frameItems )
  678. screen->Append( item );
  679. }
  680. // Holes and splines currently not handled. Not sure hole has any meaning in scheamtics.
  681. }
  682. for( const std::unique_ptr<EINSTANCE>& einstance : aSheet->instances )
  683. loadInstance( einstance, ( m_modules.size() ) ? m_modules.back()->parts
  684. : m_eagleDoc->drawing->schematic->parts );
  685. // Loop through all buses
  686. // From the DTD: "Buses receive names which determine which signals they include.
  687. // A bus is a drawing object. It does not create any electrical connections.
  688. // These are always created by means of the nets and their names."
  689. for( const std::unique_ptr<EBUS>& ebus : aSheet->busses )
  690. {
  691. // Get the bus name
  692. wxString busName = translateEagleBusName( ebus->name );
  693. // Load segments of this bus
  694. loadSegments( ebus->segments, busName, wxString() );
  695. }
  696. for( const std::unique_ptr<ENET>& enet : aSheet->nets )
  697. {
  698. // Get the net name and class
  699. wxString netName = enet->netname;
  700. wxString netClass = wxString::Format( wxS( "%i" ), enet->netcode );
  701. // Load segments of this net
  702. loadSegments( enet->segments, netName, netClass );
  703. }
  704. adjustNetLabels(); // needs to be called before addBusEntries()
  705. addBusEntries();
  706. // Calculate the new sheet size.
  707. BOX2I sheetBoundingBox = getSheetBbox( sheet );
  708. VECTOR2I targetSheetSize = sheetBoundingBox.GetSize();
  709. targetSheetSize += VECTOR2I( schIUScale.MilsToIU( 1500 ), schIUScale.MilsToIU( 1500 ) );
  710. // Get current Eeschema sheet size.
  711. VECTOR2I pageSizeIU = screen->GetPageSettings().GetSizeIU( schIUScale.IU_PER_MILS );
  712. PAGE_INFO pageInfo = screen->GetPageSettings();
  713. // Increase if necessary
  714. if( pageSizeIU.x < targetSheetSize.x )
  715. pageInfo.SetWidthMils( schIUScale.IUToMils( targetSheetSize.x ) );
  716. if( pageSizeIU.y < targetSheetSize.y )
  717. pageInfo.SetHeightMils( schIUScale.IUToMils( targetSheetSize.y ) );
  718. // Set the new sheet size.
  719. screen->SetPageSettings( pageInfo );
  720. pageSizeIU = screen->GetPageSettings().GetSizeIU( schIUScale.IU_PER_MILS );
  721. VECTOR2I sheetcentre( pageSizeIU.x / 2, pageSizeIU.y / 2 );
  722. VECTOR2I itemsCentre = sheetBoundingBox.Centre();
  723. // round the translation to nearest 100mil to place it on the grid.
  724. VECTOR2I translation = sheetcentre - itemsCentre;
  725. translation.x = translation.x - translation.x % schIUScale.MilsToIU( 100 );
  726. translation.y = translation.y - translation.y % schIUScale.MilsToIU( 100 );
  727. // Add global net labels for the named power input pins in this sheet
  728. for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
  729. {
  730. SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
  731. addImplicitConnections( symbol, screen, true );
  732. }
  733. m_connPoints.clear();
  734. // Translate the items.
  735. std::vector<SCH_ITEM*> allItems;
  736. std::copy( screen->Items().begin(), screen->Items().end(), std::back_inserter( allItems ) );
  737. for( SCH_ITEM* item : allItems )
  738. {
  739. item->SetPosition( item->GetPosition() + translation );
  740. // We don't read positions of Eagle label fields (primarily intersheet refs), so we
  741. // need to autoplace them after applying the translation.
  742. if( SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( item ) )
  743. label->AutoplaceFields( screen, AUTOPLACE_AUTO );
  744. item->ClearFlags();
  745. screen->Update( item );
  746. }
  747. }
  748. void SCH_IO_EAGLE::loadModuleInstance( const std::unique_ptr<EMODULEINST>& aModuleInstance )
  749. {
  750. SCH_SHEET* currentSheet = getCurrentSheet();
  751. SCH_SCREEN* currentScreen = getCurrentScreen();
  752. wxCHECK( currentSheet &&currentScreen, /* void */ );
  753. m_sheetIndex++;
  754. // Eagle document has already be checked for drawing and schematic nodes so this
  755. // should not segfault.
  756. auto it = m_eagleDoc->drawing->schematic->modules.find( aModuleInstance->moduleinst );
  757. // Find the module referenced by the module instance.
  758. if( it == m_eagleDoc->drawing->schematic->modules.end() )
  759. {
  760. THROW_IO_ERROR( wxString::Format( _( "No module instance '%s' found in schematic "
  761. "file:\n%s" ),
  762. aModuleInstance->name, m_filename.GetFullPath() ) );
  763. }
  764. wxFileName fn = m_filename;
  765. fn.SetName( aModuleInstance->moduleinst );
  766. fn.SetExt( FILEEXT::KiCadSchematicFileExtension );
  767. VECTOR2I portExtWireEndpoint;
  768. VECTOR2I size( it->second->dx.ToSchUnits(), it->second->dy.ToSchUnits() );
  769. int halfX = KiROUND( size.x / 2.0 );
  770. int halfY = KiROUND( size.y / 2.0 );
  771. int portExtWireLength = schIUScale.mmToIU( 5.08 );
  772. VECTOR2I pos( aModuleInstance->x.ToSchUnits() - halfX,
  773. -aModuleInstance->y.ToSchUnits() - halfY );
  774. std::unique_ptr<SCH_SHEET> newSheet = std::make_unique<SCH_SHEET>( currentSheet, pos, size );
  775. // The Eagle module for this instance (SCH_SCREEN in KiCad) may have already been loaded.
  776. SCH_SCREEN* newScreen = nullptr;
  777. SCH_SCREENS schFiles( m_rootSheet );
  778. for( SCH_SCREEN* schFile = schFiles.GetFirst(); schFile; schFile = schFiles.GetNext() )
  779. {
  780. if( schFile->GetFileName() == fn.GetFullPath() )
  781. {
  782. newScreen = schFile;
  783. break;
  784. }
  785. }
  786. bool isNewSchFile = ( newScreen == nullptr );
  787. if( !newScreen )
  788. {
  789. newScreen = new SCH_SCREEN( m_schematic );
  790. newScreen->SetFileName( fn.GetFullPath() );
  791. }
  792. wxCHECK( newSheet && newScreen, /* void */ );
  793. newSheet->SetScreen( newScreen );
  794. newSheet->SetFileName( fn.GetFullName() );
  795. newSheet->SetName( aModuleInstance->name );
  796. for( const auto& [portName, port] : it->second->ports )
  797. {
  798. VECTOR2I pinPos( 0, 0 );
  799. int pinOffset = port->coord.ToSchUnits();
  800. SHEET_SIDE side = SHEET_SIDE::LEFT;
  801. if( port->side == "left" )
  802. {
  803. side = SHEET_SIDE::LEFT;
  804. pinPos.x = pos.x;
  805. pinPos.y = pos.y + halfY - pinOffset;
  806. portExtWireEndpoint = pinPos;
  807. portExtWireEndpoint.x -= portExtWireLength;
  808. }
  809. else if( port->side == "right" )
  810. {
  811. side = SHEET_SIDE::RIGHT;
  812. pinPos.x = pos.x + size.x;
  813. pinPos.y = pos.y + halfY - pinOffset;
  814. portExtWireEndpoint = pinPos;
  815. portExtWireEndpoint.x += portExtWireLength;
  816. }
  817. else if( port->side == "top" )
  818. {
  819. side = SHEET_SIDE::TOP;
  820. pinPos.x = pos.x + halfX + pinOffset;
  821. pinPos.y = pos.y;
  822. portExtWireEndpoint = pinPos;
  823. portExtWireEndpoint.y -= portExtWireLength;
  824. }
  825. else if( port->side == "bottom" )
  826. {
  827. side = SHEET_SIDE::BOTTOM;
  828. pinPos.x = pos.x + halfX + pinOffset;
  829. pinPos.y = pos.y + size.y;
  830. portExtWireEndpoint = pinPos;
  831. portExtWireEndpoint.y += portExtWireLength;
  832. }
  833. SCH_LINE* portExtWire = new SCH_LINE( pinPos, LAYER_WIRE );
  834. portExtWire->SetEndPoint( portExtWireEndpoint );
  835. currentScreen->Append( portExtWire );
  836. LABEL_FLAG_SHAPE pinType = LABEL_FLAG_SHAPE::L_UNSPECIFIED;
  837. if( port->direction )
  838. {
  839. if( *port->direction == "in" )
  840. pinType = LABEL_FLAG_SHAPE::L_INPUT;
  841. else if( *port->direction == "out" )
  842. pinType = LABEL_FLAG_SHAPE::L_OUTPUT;
  843. else if( *port->direction == "io" )
  844. pinType = LABEL_FLAG_SHAPE::L_BIDI;
  845. else if( *port->direction == "hiz" )
  846. pinType = LABEL_FLAG_SHAPE::L_TRISTATE;
  847. else
  848. pinType = LABEL_FLAG_SHAPE::L_UNSPECIFIED;
  849. // KiCad does not support passive, power, open collector, or no-connect sheet
  850. // pins that Eagle ports support. They are set to unspecified to minimize
  851. // ERC issues.
  852. }
  853. SCH_SHEET_PIN* sheetPin = new SCH_SHEET_PIN( newSheet.get(), VECTOR2I( 0, 0 ), portName );
  854. sheetPin->SetShape( pinType );
  855. sheetPin->SetPosition( pinPos );
  856. sheetPin->SetSide( side );
  857. newSheet->AddPin( sheetPin );
  858. }
  859. wxString pageNo = wxString::Format( wxT( "%d" ), m_sheetIndex );
  860. newSheet->SetParent( currentSheet );
  861. m_sheetPath.push_back( newSheet.get() );
  862. m_sheetPath.SetPageNumber( pageNo );
  863. currentScreen->Append( newSheet.release() );
  864. m_modules.push_back( it->second.get() );
  865. m_moduleInstances.push_back( aModuleInstance.get() );
  866. // Do not reload shared modules that are already loaded.
  867. if( isNewSchFile )
  868. {
  869. for( const std::unique_ptr<ESHEET>& esheet : it->second->sheets )
  870. loadSheet( esheet );
  871. }
  872. else
  873. {
  874. // Add instances for shared schematics.
  875. wxString refPrefix;
  876. for( const EMODULEINST* emoduleInst : m_moduleInstances )
  877. {
  878. wxCHECK2( emoduleInst, continue );
  879. refPrefix += emoduleInst->name + wxS( ":" );
  880. }
  881. SCH_SCREEN* sharedScreen = m_sheetPath.LastScreen();
  882. if( sharedScreen )
  883. {
  884. for( SCH_ITEM* schItem : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
  885. {
  886. SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( schItem );
  887. wxCHECK2( symbol && !symbol->GetInstances().empty(), continue );
  888. SCH_SYMBOL_INSTANCE inst = symbol->GetInstances().at( 0 );
  889. wxString newReference = refPrefix + inst.m_Reference.AfterLast( ':' );
  890. symbol->AddHierarchicalReference( m_sheetPath.Path(), newReference, inst.m_Unit );
  891. }
  892. }
  893. }
  894. m_moduleInstances.pop_back();
  895. m_modules.pop_back();
  896. m_sheetPath.pop_back();
  897. }
  898. void SCH_IO_EAGLE::loadFrame( const std::unique_ptr<EFRAME>& aFrame,
  899. std::vector<SCH_ITEM*>& aItems )
  900. {
  901. int xMin = aFrame->x1.ToSchUnits();
  902. int xMax = aFrame->x2.ToSchUnits();
  903. int yMin = -aFrame->y1.ToSchUnits();
  904. int yMax = -aFrame->y2.ToSchUnits();
  905. if( xMin > xMax )
  906. std::swap( xMin, xMax );
  907. if( yMin > yMax )
  908. std::swap( yMin, yMax );
  909. SCH_SHAPE* lines = new SCH_SHAPE( SHAPE_T::POLY );
  910. lines->AddPoint( VECTOR2I( xMin, yMin ) );
  911. lines->AddPoint( VECTOR2I( xMax, yMin ) );
  912. lines->AddPoint( VECTOR2I( xMax, yMax ) );
  913. lines->AddPoint( VECTOR2I( xMin, yMax ) );
  914. lines->AddPoint( VECTOR2I( xMin, yMin ) );
  915. aItems.push_back( lines );
  916. if( !( aFrame->border_left == false ) )
  917. {
  918. lines = new SCH_SHAPE( SHAPE_T::POLY );
  919. lines->AddPoint( VECTOR2I( xMin + schIUScale.MilsToIU( 150 ),
  920. yMin + schIUScale.MilsToIU( 150 ) ) );
  921. lines->AddPoint( VECTOR2I( xMin + schIUScale.MilsToIU( 150 ),
  922. yMax - schIUScale.MilsToIU( 150 ) ) );
  923. aItems.push_back( lines );
  924. int i;
  925. int height = yMax - yMin;
  926. int x1 = xMin;
  927. int x2 = x1 + schIUScale.MilsToIU( 150 );
  928. int legendPosX = xMin + schIUScale.MilsToIU( 75 );
  929. double rowSpacing = height / double( aFrame->rows );
  930. double legendPosY = yMin + ( rowSpacing / 2 );
  931. for( i = 1; i < aFrame->rows; i++ )
  932. {
  933. int newY = KiROUND( yMin + ( rowSpacing * (double) i ) );
  934. lines = new SCH_SHAPE( SHAPE_T::POLY );
  935. lines->AddPoint( VECTOR2I( x1, newY ) );
  936. lines->AddPoint( VECTOR2I( x2, newY ) );
  937. aItems.push_back( lines );
  938. }
  939. char legendChar = 'A';
  940. for( i = 0; i < aFrame->rows; i++ )
  941. {
  942. SCH_TEXT* legendText = new SCH_TEXT();
  943. legendText->SetPosition( VECTOR2I( legendPosX, KiROUND( legendPosY ) ) );
  944. legendText->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
  945. legendText->SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
  946. legendText->SetText( wxString( legendChar ) );
  947. legendText->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 90 ),
  948. schIUScale.MilsToIU( 100 ) ) );
  949. aItems.push_back( legendText );
  950. legendChar++;
  951. legendPosY += rowSpacing;
  952. }
  953. }
  954. if( !( aFrame->border_right == false ) )
  955. {
  956. lines = new SCH_SHAPE( SHAPE_T::POLY );
  957. lines->AddPoint( VECTOR2I( xMax - schIUScale.MilsToIU( 150 ),
  958. yMin + schIUScale.MilsToIU( 150 ) ) );
  959. lines->AddPoint( VECTOR2I( xMax - schIUScale.MilsToIU( 150 ),
  960. yMax - schIUScale.MilsToIU( 150 ) ) );
  961. aItems.push_back( lines );
  962. int i;
  963. int height = yMax - yMin;
  964. int x1 = xMax - schIUScale.MilsToIU( 150 );
  965. int x2 = xMax;
  966. int legendPosX = xMax - schIUScale.MilsToIU( 75 );
  967. double rowSpacing = height / double( aFrame->rows );
  968. double legendPosY = yMin + ( rowSpacing / 2 );
  969. for( i = 1; i < aFrame->rows; i++ )
  970. {
  971. int newY = KiROUND( yMin + ( rowSpacing * (double) i ) );
  972. lines = new SCH_SHAPE( SHAPE_T::POLY );
  973. lines->AddPoint( VECTOR2I( x1, newY ) );
  974. lines->AddPoint( VECTOR2I( x2, newY ) );
  975. aItems.push_back( lines );
  976. }
  977. char legendChar = 'A';
  978. for( i = 0; i < aFrame->rows; i++ )
  979. {
  980. SCH_TEXT* legendText = new SCH_TEXT();
  981. legendText->SetPosition( VECTOR2I( legendPosX, KiROUND( legendPosY ) ) );
  982. legendText->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
  983. legendText->SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
  984. legendText->SetText( wxString( legendChar ) );
  985. legendText->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 90 ),
  986. schIUScale.MilsToIU( 100 ) ) );
  987. aItems.push_back( legendText );
  988. legendChar++;
  989. legendPosY += rowSpacing;
  990. }
  991. }
  992. if( !( aFrame->border_top == false ) )
  993. {
  994. lines = new SCH_SHAPE( SHAPE_T::POLY );
  995. lines->AddPoint( VECTOR2I( xMax - schIUScale.MilsToIU( 150 ),
  996. yMin + schIUScale.MilsToIU( 150 ) ) );
  997. lines->AddPoint( VECTOR2I( xMin + schIUScale.MilsToIU( 150 ),
  998. yMin + schIUScale.MilsToIU( 150 ) ) );
  999. aItems.push_back( lines );
  1000. int i;
  1001. int width = xMax - xMin;
  1002. int y1 = yMin;
  1003. int y2 = yMin + schIUScale.MilsToIU( 150 );
  1004. int legendPosY = yMin + schIUScale.MilsToIU( 75 );
  1005. double columnSpacing = width / double( aFrame->columns );
  1006. double legendPosX = xMin + ( columnSpacing / 2 );
  1007. for( i = 1; i < aFrame->columns; i++ )
  1008. {
  1009. int newX = KiROUND( xMin + ( columnSpacing * (double) i ) );
  1010. lines = new SCH_SHAPE( SHAPE_T::POLY );
  1011. lines->AddPoint( VECTOR2I( newX, y1 ) );
  1012. lines->AddPoint( VECTOR2I( newX, y2 ) );
  1013. aItems.push_back( lines );
  1014. }
  1015. char legendChar = '1';
  1016. for( i = 0; i < aFrame->columns; i++ )
  1017. {
  1018. SCH_TEXT* legendText = new SCH_TEXT();
  1019. legendText->SetPosition( VECTOR2I( KiROUND( legendPosX ), legendPosY ) );
  1020. legendText->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
  1021. legendText->SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
  1022. legendText->SetText( wxString( legendChar ) );
  1023. legendText->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 90 ),
  1024. schIUScale.MilsToIU( 100 ) ) );
  1025. aItems.push_back( legendText );
  1026. legendChar++;
  1027. legendPosX += columnSpacing;
  1028. }
  1029. }
  1030. if( !( aFrame->border_bottom == false ) )
  1031. {
  1032. lines = new SCH_SHAPE( SHAPE_T::POLY );
  1033. lines->AddPoint( VECTOR2I( xMax - schIUScale.MilsToIU( 150 ),
  1034. yMax - schIUScale.MilsToIU( 150 ) ) );
  1035. lines->AddPoint( VECTOR2I( xMin + schIUScale.MilsToIU( 150 ),
  1036. yMax - schIUScale.MilsToIU( 150 ) ) );
  1037. aItems.push_back( lines );
  1038. int i;
  1039. int width = xMax - xMin;
  1040. int y1 = yMax - schIUScale.MilsToIU( 150 );
  1041. int y2 = yMax;
  1042. int legendPosY = yMax - schIUScale.MilsToIU( 75 );
  1043. double columnSpacing = width / double( aFrame->columns );
  1044. double legendPosX = xMin + ( columnSpacing / 2 );
  1045. for( i = 1; i < aFrame->columns; i++ )
  1046. {
  1047. int newX = KiROUND( xMin + ( columnSpacing * (double) i ) );
  1048. lines = new SCH_SHAPE( SHAPE_T::POLY );
  1049. lines->AddPoint( VECTOR2I( newX, y1 ) );
  1050. lines->AddPoint( VECTOR2I( newX, y2 ) );
  1051. aItems.push_back( lines );
  1052. }
  1053. char legendChar = '1';
  1054. for( i = 0; i < aFrame->columns; i++ )
  1055. {
  1056. SCH_TEXT* legendText = new SCH_TEXT();
  1057. legendText->SetPosition( VECTOR2I( KiROUND( legendPosX ), legendPosY ) );
  1058. legendText->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
  1059. legendText->SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
  1060. legendText->SetText( wxString( legendChar ) );
  1061. legendText->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 90 ),
  1062. schIUScale.MilsToIU( 100 ) ) );
  1063. aItems.push_back( legendText );
  1064. legendChar++;
  1065. legendPosX += columnSpacing;
  1066. }
  1067. }
  1068. }
  1069. void SCH_IO_EAGLE::loadSegments( const std::vector<std::unique_ptr<ESEGMENT>>& aSegments,
  1070. const wxString& netName,
  1071. const wxString& aNetClass )
  1072. {
  1073. // Loop through all segments
  1074. SCH_SCREEN* screen = getCurrentScreen();
  1075. wxCHECK( screen, /* void */ );
  1076. size_t segmentCount = aSegments.size();
  1077. for( const std::unique_ptr<ESEGMENT>& esegment : aSegments )
  1078. {
  1079. bool labelled = false; // has a label been added to this continuously connected segment
  1080. bool firstWireFound = false;
  1081. SEG firstWire;
  1082. m_segments.emplace_back();
  1083. SEG_DESC& segDesc = m_segments.back();
  1084. for( const std::unique_ptr<EWIRE>& ewire : esegment->wires )
  1085. {
  1086. // TODO: Check how intersections used in adjustNetLabels should be
  1087. // calculated - for now we pretend that all wires are line segments.
  1088. SEG thisWire;
  1089. SCH_ITEM* wire = loadWire( ewire, thisWire );
  1090. m_connPoints[thisWire.A].emplace( wire );
  1091. m_connPoints[thisWire.B].emplace( wire );
  1092. if( !firstWireFound )
  1093. {
  1094. firstWire = thisWire;
  1095. firstWireFound = true;
  1096. }
  1097. // Test for intersections with other wires
  1098. for( SEG_DESC& desc : m_segments )
  1099. {
  1100. if( !desc.labels.empty() && desc.labels.front()->GetText() == netName )
  1101. continue; // no point in saving intersections of the same net
  1102. for( const SEG& seg : desc.segs )
  1103. {
  1104. OPT_VECTOR2I intersection = thisWire.Intersect( seg, true );
  1105. if( intersection )
  1106. m_wireIntersections.push_back( *intersection );
  1107. }
  1108. }
  1109. segDesc.segs.push_back( thisWire );
  1110. screen->Append( wire );
  1111. }
  1112. for( const std::unique_ptr<EJUNCTION>& ejunction : esegment->junctions )
  1113. screen->Append( loadJunction( ejunction ) );
  1114. for( const std::unique_ptr<ELABEL>& elabel : esegment->labels )
  1115. {
  1116. SCH_TEXT* label = loadLabel( elabel, netName );
  1117. screen->Append( label );
  1118. wxASSERT( segDesc.labels.empty()
  1119. || segDesc.labels.front()->GetText() == label->GetText() );
  1120. segDesc.labels.push_back( label );
  1121. labelled = true;
  1122. }
  1123. for( const std::unique_ptr<EPINREF>& epinref : esegment->pinRefs )
  1124. {
  1125. wxString part = epinref->part;
  1126. wxString pin = epinref->pin;
  1127. auto powerPort = m_powerPorts.find( wxT( "#" ) + part );
  1128. if( powerPort != m_powerPorts.end()
  1129. && powerPort->second == EscapeString( pin, CTX_NETNAME ) )
  1130. {
  1131. labelled = true;
  1132. }
  1133. }
  1134. // Add a small label to the net segment if it hasn't been labeled already or is not
  1135. // connect to a power symbol with a pin on the same net. This preserves the named net
  1136. // feature of Eagle schematics.
  1137. if( !labelled && firstWireFound )
  1138. {
  1139. std::unique_ptr<SCH_LABEL_BASE> label;
  1140. // Add a global label if the net appears on more than one Eagle sheet
  1141. if( m_netCounts[netName.ToStdString()] > 1 )
  1142. label.reset( new SCH_GLOBALLABEL );
  1143. else if( segmentCount > 1 )
  1144. label.reset( new SCH_LABEL );
  1145. if( label )
  1146. {
  1147. label->SetPosition( firstWire.A );
  1148. label->SetText( escapeName( netName ) );
  1149. label->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 40 ),
  1150. schIUScale.MilsToIU( 40 ) ) );
  1151. if( firstWire.B.x > firstWire.A.x )
  1152. label->SetSpinStyle( SPIN_STYLE::LEFT );
  1153. else
  1154. label->SetSpinStyle( SPIN_STYLE::RIGHT );
  1155. screen->Append( label.release() );
  1156. }
  1157. }
  1158. }
  1159. }
  1160. SCH_SHAPE* SCH_IO_EAGLE::loadPolyLine( const std::unique_ptr<EPOLYGON>& aPolygon )
  1161. {
  1162. std::unique_ptr<SCH_SHAPE> poly = std::make_unique<SCH_SHAPE>( SHAPE_T::POLY );
  1163. VECTOR2I pt, prev_pt;
  1164. opt_double prev_curve;
  1165. for( const std::unique_ptr<EVERTEX>& evertex : aPolygon->vertices )
  1166. {
  1167. pt = VECTOR2I( evertex->x.ToSchUnits(), -evertex->y.ToSchUnits() );
  1168. if( prev_curve )
  1169. {
  1170. SHAPE_ARC arc;
  1171. arc.ConstructFromStartEndAngle( prev_pt, pt, -EDA_ANGLE( *prev_curve, DEGREES_T ) );
  1172. poly->GetPolyShape().Append( arc, -1, -1, ARC_ACCURACY );
  1173. }
  1174. else
  1175. {
  1176. poly->AddPoint( pt );
  1177. }
  1178. prev_pt = pt;
  1179. prev_curve = evertex->curve;
  1180. }
  1181. poly->SetLayer( kiCadLayer( aPolygon->layer ) );
  1182. poly->SetStroke( STROKE_PARAMS( aPolygon->width.ToSchUnits(), LINE_STYLE::SOLID ) );
  1183. poly->SetFillMode( FILL_T::FILLED_SHAPE );
  1184. return poly.release();
  1185. }
  1186. SCH_ITEM* SCH_IO_EAGLE::loadWire( const std::unique_ptr<EWIRE>& aWire, SEG& endpoints )
  1187. {
  1188. VECTOR2I start, end;
  1189. start.x = aWire->x1.ToSchUnits();
  1190. start.y = -aWire->y1.ToSchUnits();
  1191. end.x = aWire->x2.ToSchUnits();
  1192. end.y = -aWire->y2.ToSchUnits();
  1193. // For segment wires.
  1194. endpoints = SEG( start, end );
  1195. if( aWire->curve )
  1196. {
  1197. std::unique_ptr<SCH_SHAPE> arc = std::make_unique<SCH_SHAPE>( SHAPE_T::ARC );
  1198. VECTOR2I center = ConvertArcCenter( start, end, *aWire->curve );
  1199. arc->SetCenter( center );
  1200. arc->SetStart( start );
  1201. // KiCad rotates the other way.
  1202. arc->SetArcAngleAndEnd( -EDA_ANGLE( *aWire->curve, DEGREES_T ), true );
  1203. arc->SetLayer( kiCadLayer( aWire->layer ) );
  1204. arc->SetStroke( STROKE_PARAMS( aWire->width.ToSchUnits(), LINE_STYLE::SOLID ) );
  1205. return arc.release();
  1206. }
  1207. else
  1208. {
  1209. std::unique_ptr<SCH_LINE> line = std::make_unique<SCH_LINE>();
  1210. line->SetStartPoint( start );
  1211. line->SetEndPoint( end );
  1212. line->SetLayer( kiCadLayer( aWire->layer ) );
  1213. line->SetStroke( STROKE_PARAMS( aWire->width.ToSchUnits(), LINE_STYLE::SOLID ) );
  1214. return line.release();
  1215. }
  1216. }
  1217. SCH_SHAPE* SCH_IO_EAGLE::loadCircle( const std::unique_ptr<ECIRCLE>& aCircle )
  1218. {
  1219. std::unique_ptr<SCH_SHAPE> circle = std::make_unique<SCH_SHAPE>( SHAPE_T::CIRCLE );
  1220. VECTOR2I center( aCircle->x.ToSchUnits(), -aCircle->y.ToSchUnits() );
  1221. circle->SetLayer( kiCadLayer( aCircle->layer ) );
  1222. circle->SetPosition( center );
  1223. circle->SetEnd( VECTOR2I( center.x + aCircle->radius.ToSchUnits(), center.y ) );
  1224. circle->SetStroke( STROKE_PARAMS( aCircle->width.ToSchUnits(), LINE_STYLE::SOLID ) );
  1225. return circle.release();
  1226. }
  1227. SCH_SHAPE* SCH_IO_EAGLE::loadRectangle( const std::unique_ptr<ERECT>& aRectangle )
  1228. {
  1229. std::unique_ptr<SCH_SHAPE> rectangle = std::make_unique<SCH_SHAPE>( SHAPE_T::RECTANGLE );
  1230. rectangle->SetLayer( kiCadLayer( aRectangle->layer ) );
  1231. rectangle->SetPosition( VECTOR2I( aRectangle->x1.ToSchUnits(), -aRectangle->y1.ToSchUnits() ) );
  1232. rectangle->SetEnd( VECTOR2I( aRectangle->x2.ToSchUnits(), -aRectangle->y2.ToSchUnits() ) );
  1233. if( aRectangle->rot )
  1234. {
  1235. VECTOR2I pos( rectangle->GetPosition() );
  1236. VECTOR2I end( rectangle->GetEnd() );
  1237. VECTOR2I center( rectangle->GetCenter() );
  1238. RotatePoint( pos, center, EDA_ANGLE( aRectangle->rot->degrees, DEGREES_T ) );
  1239. RotatePoint( end, center, EDA_ANGLE( aRectangle->rot->degrees, DEGREES_T ) );
  1240. rectangle->SetPosition( pos );
  1241. rectangle->SetEnd( end );
  1242. }
  1243. // Eagle rectangles are filled by definition.
  1244. rectangle->SetFillMode( FILL_T::FILLED_SHAPE );
  1245. return rectangle.release();
  1246. }
  1247. SCH_JUNCTION* SCH_IO_EAGLE::loadJunction( const std::unique_ptr<EJUNCTION>& aJunction )
  1248. {
  1249. std::unique_ptr<SCH_JUNCTION> junction = std::make_unique<SCH_JUNCTION>();
  1250. VECTOR2I pos( aJunction->x.ToSchUnits(), -aJunction->y.ToSchUnits() );
  1251. junction->SetPosition( pos );
  1252. return junction.release();
  1253. }
  1254. SCH_TEXT* SCH_IO_EAGLE::loadLabel( const std::unique_ptr<ELABEL>& aLabel,
  1255. const wxString& aNetName )
  1256. {
  1257. VECTOR2I elabelpos( aLabel->x.ToSchUnits(), -aLabel->y.ToSchUnits() );
  1258. // Determine if the label is local or global depending on
  1259. // the number of sheets the net appears in
  1260. bool global = m_netCounts[aNetName] > 1;
  1261. std::unique_ptr<SCH_LABEL_BASE> label;
  1262. VECTOR2I textSize = VECTOR2I( KiROUND( aLabel->size.ToSchUnits() * 0.7 ),
  1263. KiROUND( aLabel->size.ToSchUnits() * 0.7 ) );
  1264. if( m_modules.size() )
  1265. {
  1266. if( m_modules.back()->ports.find( aNetName ) != m_modules.back()->ports.end() )
  1267. {
  1268. label = std::make_unique<SCH_HIERLABEL>();
  1269. label->SetText( escapeName( aNetName ) );
  1270. const auto it = m_modules.back()->ports.find( aNetName );
  1271. LABEL_SHAPE type;
  1272. if( it->second->direction )
  1273. {
  1274. wxString direction = *it->second->direction;
  1275. if( direction == "in" )
  1276. type = LABEL_SHAPE::LABEL_INPUT;
  1277. else if( direction == "out" )
  1278. type = LABEL_SHAPE::LABEL_OUTPUT;
  1279. else if( direction == "io" )
  1280. type = LABEL_SHAPE::LABEL_BIDI;
  1281. else if( direction == "hiz" )
  1282. type = LABEL_SHAPE::LABEL_TRISTATE;
  1283. else
  1284. type = LABEL_SHAPE::LABEL_PASSIVE;
  1285. // KiCad does not support passive, power, open collector, or no-connect sheet
  1286. // pins that Eagle ports support. They are set to unspecified to minimize
  1287. // ERC issues.
  1288. label->SetLabelShape( type );
  1289. }
  1290. }
  1291. else
  1292. {
  1293. label = std::make_unique<SCH_LABEL>();
  1294. label->SetText( escapeName( aNetName ) );
  1295. }
  1296. }
  1297. else if( global )
  1298. {
  1299. label = std::make_unique<SCH_GLOBALLABEL>();
  1300. label->SetText( escapeName( aNetName ) );
  1301. }
  1302. else
  1303. {
  1304. label = std::make_unique<SCH_LABEL>();
  1305. label->SetText( escapeName( aNetName ) );
  1306. }
  1307. label->SetPosition( elabelpos );
  1308. label->SetTextSize( textSize );
  1309. label->SetSpinStyle( SPIN_STYLE::RIGHT );
  1310. if( aLabel->rot )
  1311. {
  1312. for( int i = 0; i < KiROUND( aLabel->rot->degrees / 90 ) %4; ++i )
  1313. label->Rotate90( false );
  1314. if( aLabel->rot->mirror )
  1315. label->MirrorSpinStyle( false );
  1316. }
  1317. return label.release();
  1318. }
  1319. std::pair<VECTOR2I, const SEG*>
  1320. SCH_IO_EAGLE::findNearestLinePoint( const VECTOR2I& aPoint,
  1321. const std::vector<SEG>& aLines ) const
  1322. {
  1323. VECTOR2I nearestPoint;
  1324. const SEG* nearestLine = nullptr;
  1325. double d, mindistance = std::numeric_limits<double>::max();
  1326. // Find the nearest start, middle or end of a line from the list of lines.
  1327. for( const SEG& line : aLines )
  1328. {
  1329. VECTOR2I testpoint = line.A;
  1330. d = aPoint.Distance( testpoint );
  1331. if( d < mindistance )
  1332. {
  1333. mindistance = d;
  1334. nearestPoint = testpoint;
  1335. nearestLine = &line;
  1336. }
  1337. testpoint = line.Center();
  1338. d = aPoint.Distance( testpoint );
  1339. if( d < mindistance )
  1340. {
  1341. mindistance = d;
  1342. nearestPoint = testpoint;
  1343. nearestLine = &line;
  1344. }
  1345. testpoint = line.B;
  1346. d = aPoint.Distance( testpoint );
  1347. if( d < mindistance )
  1348. {
  1349. mindistance = d;
  1350. nearestPoint = testpoint;
  1351. nearestLine = &line;
  1352. }
  1353. }
  1354. return std::make_pair( nearestPoint, nearestLine );
  1355. }
  1356. void SCH_IO_EAGLE::loadInstance( const std::unique_ptr<EINSTANCE>& aInstance,
  1357. const std::map<wxString, std::unique_ptr<EPART>>& aParts )
  1358. {
  1359. wxCHECK( aInstance, /* void */ );
  1360. SCH_SCREEN* screen = getCurrentScreen();
  1361. wxCHECK( screen, /* void */ );
  1362. const auto partIt = aParts.find( aInstance->part );
  1363. if( partIt == aParts.end() )
  1364. {
  1365. Report( wxString::Format( _( "Error parsing Eagle file. Could not find '%s' "
  1366. "instance but it is referenced in the schematic." ),
  1367. aInstance->part ),
  1368. RPT_SEVERITY_ERROR );
  1369. return;
  1370. }
  1371. const std::unique_ptr<EPART>& epart = partIt->second;
  1372. wxString libName = epart->library;
  1373. // Correctly handle versioned libraries.
  1374. if( epart->libraryUrn )
  1375. libName += wxS( "_" ) + epart->libraryUrn->assetId;
  1376. wxString gatename = epart->deviceset + wxS( "_" ) + epart->device + wxS( "_" ) +
  1377. aInstance->gate;
  1378. wxString symbolname = wxString( epart->deviceset + epart->device );
  1379. symbolname.Replace( wxT( "*" ), wxEmptyString );
  1380. wxString kisymbolname = EscapeString( symbolname, CTX_LIBID );
  1381. // Eagle schematics can have multiple libraries containing symbols with duplicate symbol
  1382. // names. Because this parser stores all of the symbols in a single library, the
  1383. // loadSymbol() function, prefixed the original Eagle library name to the symbol name
  1384. // in case of a name clash. Check for the prefixed symbol first. This ensures that
  1385. // the correct library symbol gets mapped on load.
  1386. wxString altSymbolName = libName + wxT( "_" ) + symbolname;
  1387. altSymbolName = EscapeString( altSymbolName, CTX_LIBID );
  1388. wxString libIdSymbolName = altSymbolName;
  1389. const auto libIt = m_eagleLibs.find( libName );
  1390. if( libIt == m_eagleLibs.end() )
  1391. {
  1392. Report( wxString::Format( wxS( "Eagle library '%s' not found while looking up symbol for "
  1393. "deviceset '%s', device '%s', and gate '%s." ),
  1394. libName, epart->deviceset, epart->device, aInstance->gate ) );
  1395. return;
  1396. }
  1397. const auto gateIt = libIt->second.GateToUnitMap.find( gatename );
  1398. if( gateIt == libIt->second.GateToUnitMap.end() )
  1399. {
  1400. Report( wxString::Format( wxS( "Symbol not found for deviceset '%s', device '%s', and "
  1401. "gate '%s in library '%s'." ),
  1402. epart->deviceset, epart->device, aInstance->gate, libName ) );
  1403. return;
  1404. }
  1405. int unit = gateIt->second;
  1406. wxString package;
  1407. EAGLE_LIBRARY* elib = &m_eagleLibs[libName];
  1408. auto p = elib->package.find( kisymbolname );
  1409. if( p != elib->package.end() )
  1410. package = p->second;
  1411. // set properties to prevent save file on every symbol save
  1412. std::map<std::string, UTF8> properties;
  1413. properties.emplace( SCH_IO_KICAD_SEXPR::PropBuffering, wxEmptyString );
  1414. LIB_SYMBOL* part = m_pi->LoadSymbol( getLibFileName().GetFullPath(), altSymbolName, &properties );
  1415. if( !part )
  1416. {
  1417. part = m_pi->LoadSymbol( getLibFileName().GetFullPath(), kisymbolname, &properties );
  1418. libIdSymbolName = kisymbolname;
  1419. }
  1420. if( !part )
  1421. {
  1422. Report( wxString::Format( _( "Could not find '%s' in the imported library." ),
  1423. UnescapeString( kisymbolname ) ),
  1424. RPT_SEVERITY_ERROR );
  1425. return;
  1426. }
  1427. LIB_ID libId( getLibName(), libIdSymbolName );
  1428. std::unique_ptr<SCH_SYMBOL> symbol = std::make_unique<SCH_SYMBOL>();
  1429. symbol->SetLibId( libId );
  1430. symbol->SetUnit( unit );
  1431. symbol->SetPosition( VECTOR2I( aInstance->x.ToSchUnits(), -aInstance->y.ToSchUnits() ) );
  1432. // assume that footprint library is identical to project name
  1433. if( !package.IsEmpty() )
  1434. {
  1435. wxString footprint = m_schematic->Prj().GetProjectName() + wxT( ":" ) + package;
  1436. symbol->GetField( FIELD_T::FOOTPRINT )->SetText( footprint );
  1437. }
  1438. if( aInstance->rot )
  1439. {
  1440. symbol->SetOrientation( kiCadComponentRotation( aInstance->rot->degrees ) );
  1441. if( aInstance->rot->mirror )
  1442. symbol->MirrorHorizontally( aInstance->x.ToSchUnits() );
  1443. }
  1444. std::vector<SCH_FIELD*> partFields;
  1445. part->GetFields( partFields );
  1446. for( const SCH_FIELD* partField : partFields )
  1447. {
  1448. SCH_FIELD* symbolField;
  1449. if( partField->IsMandatory() )
  1450. symbolField = symbol->GetField( partField->GetId() );
  1451. else
  1452. symbolField = symbol->GetField( partField->GetName() );
  1453. symbolField->ImportValues( *partField );
  1454. symbolField->SetTextPos( symbol->GetPosition() + partField->GetTextPos() );
  1455. }
  1456. // If there is no footprint assigned, then prepend the reference value
  1457. // with a hash character to mute netlist updater complaints
  1458. wxString reference = package.IsEmpty() ? '#' + aInstance->part : aInstance->part;
  1459. // reference must end with a number but EAGLE does not enforce this
  1460. if( reference.find_last_not_of( wxT( "0123456789" ) ) == ( reference.Length()-1 ) )
  1461. reference.Append( wxT( "0" ) );
  1462. // EAGLE allows references to be single digits. This breaks KiCad netlisting, which requires
  1463. // parts to have non-digit + digit annotation. If the reference begins with a number,
  1464. // we prepend 'UNK' (unknown) for the symbol designator
  1465. if( reference.find_first_not_of( wxT( "0123456789" ) ) != 0 )
  1466. reference.Prepend( wxT( "UNK" ) );
  1467. // EAGLE allows designator to start with # but that is used in KiCad
  1468. // for symbols which do not have a footprint
  1469. if( aInstance->part.find_first_not_of( wxT( "#" ) ) != 0 )
  1470. reference.Prepend( wxT( "UNK" ) );
  1471. SCH_FIELD* referenceField = symbol->GetField( FIELD_T::REFERENCE );
  1472. referenceField->SetText( reference );
  1473. SCH_FIELD* valueField = symbol->GetField( FIELD_T::VALUE );
  1474. bool userValue = m_userValue.at( libIdSymbolName );
  1475. if( part->GetUnitCount() > 1 )
  1476. {
  1477. getEagleSymbolFieldAttributes( aInstance, wxS( ">NAME" ), referenceField );
  1478. getEagleSymbolFieldAttributes( aInstance, wxS( ">VALUE" ), valueField );
  1479. }
  1480. if( epart->value && !epart->value.CGet().IsEmpty() )
  1481. {
  1482. valueField->SetText( *epart->value );
  1483. }
  1484. else
  1485. {
  1486. valueField->SetText( kisymbolname );
  1487. if( userValue )
  1488. valueField->SetVisible( false );
  1489. }
  1490. for( const auto& [ attrName, attr ] : epart->attributes )
  1491. {
  1492. SCH_FIELD newField( symbol.get(), FIELD_T::USER );
  1493. newField.SetName( attrName );
  1494. if( !symbol->GetFields().empty() )
  1495. newField.SetTextPos( symbol->GetFields().back().GetPosition() );
  1496. if( attr->value )
  1497. newField.SetText( *attr->value );
  1498. newField.SetVisible( ( attr->display == EATTR::Off ) ? false : true );
  1499. symbol->AddField( newField );
  1500. }
  1501. for( const auto& [variantName, variant] : epart->variants )
  1502. {
  1503. SCH_FIELD* field = symbol->AddField( *symbol->GetField( FIELD_T::VALUE ) );
  1504. field->SetName( wxT( "VARIANT_" ) + variant->name );
  1505. if( variant->value )
  1506. field->SetText( *variant->value );
  1507. field->SetVisible( false );
  1508. }
  1509. bool valueAttributeFound = false;
  1510. bool nameAttributeFound = false;
  1511. // Parse attributes for the instance
  1512. for( auto& [name, eattr] : aInstance->attributes )
  1513. {
  1514. SCH_FIELD* field = nullptr;
  1515. if( eattr->name.Lower() == wxT( "name" ) )
  1516. {
  1517. field = symbol->GetField( FIELD_T::REFERENCE );
  1518. nameAttributeFound = true;
  1519. }
  1520. else if( eattr->name.Lower() == wxT( "value" ) )
  1521. {
  1522. field = symbol->GetField( FIELD_T::VALUE );
  1523. valueAttributeFound = true;
  1524. }
  1525. else
  1526. {
  1527. field = symbol->GetField( eattr->name );
  1528. if( field )
  1529. field->SetVisible( false );
  1530. }
  1531. if( field )
  1532. {
  1533. field->SetPosition( VECTOR2I( eattr->x->ToSchUnits(), -eattr->y->ToSchUnits() ) );
  1534. int align = eattr->align ? *eattr->align : ETEXT::BOTTOM_LEFT;
  1535. int absdegrees = eattr->rot ? eattr->rot->degrees : 0;
  1536. bool mirror = eattr->rot ? eattr->rot->mirror : false;
  1537. if( aInstance->rot && aInstance->rot->mirror )
  1538. mirror = !mirror;
  1539. bool spin = eattr->rot ? eattr->rot->spin : false;
  1540. if( eattr->display == EATTR::Off || eattr->display == EATTR::NAME )
  1541. field->SetVisible( false );
  1542. int rotation = aInstance->rot ? aInstance->rot->degrees : 0;
  1543. int reldegrees = ( absdegrees - rotation + 360.0 );
  1544. reldegrees %= 360;
  1545. eagleToKicadAlignment( field, align, reldegrees, mirror, spin, absdegrees );
  1546. }
  1547. }
  1548. // Use the instance attribute to determine the reference and value field visibility.
  1549. if( aInstance->smashed && aInstance->smashed.Get() )
  1550. {
  1551. symbol->GetField( FIELD_T::VALUE )->SetVisible( valueAttributeFound );
  1552. symbol->GetField( FIELD_T::REFERENCE )->SetVisible( nameAttributeFound );
  1553. }
  1554. // Eagle has a brain dead module reference scheme where the module names separated by colons
  1555. // are prefixed to the symbol references. This will get blown away in KiCad the first time
  1556. // any annotation is performed. It is required for the initial synchronization between the
  1557. // schematic and the board.
  1558. wxString refPrefix;
  1559. for( const EMODULEINST* emoduleInst : m_moduleInstances )
  1560. {
  1561. wxCHECK2( emoduleInst, continue );
  1562. refPrefix += emoduleInst->name + wxS( ":" );
  1563. }
  1564. symbol->AddHierarchicalReference( m_sheetPath.Path(), refPrefix + reference, unit );
  1565. // Save the pin positions
  1566. SYMBOL_LIB_TABLE& schLibTable = *PROJECT_SCH::SchSymbolLibTable( &m_schematic->Prj() );
  1567. LIB_SYMBOL* libSymbol = schLibTable.LoadSymbol( symbol->GetLibId() );
  1568. wxCHECK( libSymbol, /*void*/ );
  1569. symbol->SetLibSymbol( new LIB_SYMBOL( *libSymbol ) );
  1570. for( const SCH_PIN* pin : symbol->GetLibPins() )
  1571. m_connPoints[symbol->GetPinPhysicalPosition( pin )].emplace( pin );
  1572. if( part->IsGlobalPower() )
  1573. m_powerPorts[ reference ] = symbol->GetField( FIELD_T::VALUE )->GetText();
  1574. symbol->ClearFlags();
  1575. screen->Append( symbol.release() );
  1576. }
  1577. EAGLE_LIBRARY* SCH_IO_EAGLE::loadLibrary( const ELIBRARY* aLibrary, EAGLE_LIBRARY* aEagleLibrary )
  1578. {
  1579. wxCHECK( aLibrary && aEagleLibrary, nullptr );
  1580. // Loop through the device sets and load each of them
  1581. for( const auto& [name, edeviceset] : aLibrary->devicesets )
  1582. {
  1583. // Get Device set information
  1584. wxString prefix = edeviceset->prefix ? edeviceset->prefix.Get() : wxString( wxT( "" ) );
  1585. wxString deviceSetDescr;
  1586. if( edeviceset->description )
  1587. deviceSetDescr = convertDescription( UnescapeHTML( edeviceset->description->text ) );
  1588. // For each device in the device set:
  1589. for( const std::unique_ptr<EDEVICE>& edevice : edeviceset->devices )
  1590. {
  1591. // Create symbol name from deviceset and device names.
  1592. wxString symbolName = edeviceset->name + edevice->name;
  1593. symbolName.Replace( wxT( "*" ), wxEmptyString );
  1594. wxASSERT( !symbolName.IsEmpty() );
  1595. symbolName = EscapeString( symbolName, CTX_LIBID );
  1596. if( edevice->package )
  1597. aEagleLibrary->package[symbolName] = edevice->package.Get();
  1598. // Create KiCad symbol.
  1599. std::unique_ptr<LIB_SYMBOL> libSymbol = std::make_unique<LIB_SYMBOL>( symbolName );
  1600. // Process each gate in the deviceset for this device.
  1601. int gate_count = static_cast<int>( edeviceset->gates.size() );
  1602. libSymbol->SetUnitCount( gate_count );
  1603. libSymbol->LockUnits( true );
  1604. SCH_FIELD* reference = libSymbol->GetField( FIELD_T::REFERENCE );
  1605. if( prefix.length() == 0 )
  1606. {
  1607. reference->SetVisible( false );
  1608. }
  1609. else
  1610. {
  1611. // If there is no footprint assigned, then prepend the reference value
  1612. // with a hash character to mute netlist updater complaints
  1613. reference->SetText( edevice->package ? prefix : '#' + prefix );
  1614. }
  1615. libSymbol->GetValueField().SetVisible( true );
  1616. int gateindex = 1;
  1617. bool ispower = false;
  1618. for( const auto& [gateName, egate] : edeviceset->gates )
  1619. {
  1620. const auto it = aLibrary->symbols.find( egate->symbol );
  1621. if( it == aLibrary->symbols.end() )
  1622. {
  1623. Report( wxString::Format( wxS( "Eagle symbol '%s' not found in library '%s'." ),
  1624. egate->symbol, aLibrary->GetName() ) );
  1625. continue;
  1626. }
  1627. wxString gateMapName = edeviceset->name + wxS( "_" ) + edevice->name +
  1628. wxS( "_" ) + egate->name;
  1629. aEagleLibrary->GateToUnitMap[gateMapName] = gateindex;
  1630. ispower = loadSymbol( it->second, libSymbol, edevice, gateindex, egate->name );
  1631. gateindex++;
  1632. }
  1633. libSymbol->SetUnitCount( gate_count );
  1634. if( gate_count == 1 && ispower )
  1635. libSymbol->SetGlobalPower();
  1636. // Don't set the footprint field if no package is defined in the Eagle schematic.
  1637. if( edevice->package )
  1638. {
  1639. wxString libName;
  1640. if( m_schematic )
  1641. {
  1642. // assume that footprint library is identical to project name
  1643. libName = m_schematic->Prj().GetProjectName();
  1644. }
  1645. else
  1646. {
  1647. libName = m_libName;
  1648. }
  1649. wxString packageString = libName + wxT( ":" ) + aEagleLibrary->package[symbolName];
  1650. libSymbol->GetFootprintField().SetText( packageString );
  1651. }
  1652. wxString libName = libSymbol->GetName();
  1653. libSymbol->SetName( libName );
  1654. libSymbol->SetDescription( deviceSetDescr );
  1655. if( m_pi )
  1656. {
  1657. // If duplicate symbol names exist in multiple Eagle symbol libraries, prefix the
  1658. // Eagle symbol library name to the symbol which should ensure that it is unique.
  1659. try
  1660. {
  1661. if( m_pi->LoadSymbol( getLibFileName().GetFullPath(), libName ) )
  1662. {
  1663. libName = aEagleLibrary->name + wxT( "_" ) + libName;
  1664. libName = EscapeString( libName, CTX_LIBID );
  1665. libSymbol->SetName( libName );
  1666. }
  1667. // set properties to prevent save file on every symbol save
  1668. std::map<std::string, UTF8> properties;
  1669. properties.emplace( SCH_IO_KICAD_SEXPR::PropBuffering, wxEmptyString );
  1670. m_pi->SaveSymbol( getLibFileName().GetFullPath(), new LIB_SYMBOL( *libSymbol.get() ),
  1671. &properties );
  1672. }
  1673. catch(...)
  1674. {
  1675. // A library symbol cannot be loaded for some reason.
  1676. // Just skip this symbol creating an issue.
  1677. // The issue will be reported later by the Reporter
  1678. }
  1679. }
  1680. aEagleLibrary->KiCadSymbols[ libName ] = std::move( libSymbol );
  1681. // Store information on whether the value of FIELD_T::VALUE for a part should be
  1682. // part/@value or part/@deviceset + part/@device.
  1683. m_userValue.emplace( std::make_pair( libName, edeviceset->uservalue == true ) );
  1684. }
  1685. }
  1686. return aEagleLibrary;
  1687. }
  1688. bool SCH_IO_EAGLE::loadSymbol( const std::unique_ptr<ESYMBOL>& aEsymbol,
  1689. std::unique_ptr<LIB_SYMBOL>& aSymbol,
  1690. const std::unique_ptr<EDEVICE>& aDevice, int aGateNumber,
  1691. const wxString& aGateName )
  1692. {
  1693. wxCHECK( aEsymbol && aSymbol && aDevice, false );
  1694. wxString symbolName = aEsymbol->name;
  1695. std::vector<SCH_ITEM*> items;
  1696. bool showRefDes = false;
  1697. bool showValue = false;
  1698. bool ispower = false;
  1699. int pincount = 0;
  1700. for( const std::unique_ptr<ECIRCLE>& ecircle : aEsymbol->circles )
  1701. aSymbol->AddDrawItem( loadSymbolCircle( aSymbol, ecircle, aGateNumber ) );
  1702. for( const std::unique_ptr<EPIN>& epin : aEsymbol->pins )
  1703. {
  1704. std::unique_ptr<SCH_PIN> pin( loadPin( aSymbol, epin, aGateNumber ) );
  1705. pincount++;
  1706. pin->SetType( ELECTRICAL_PINTYPE::PT_BIDI );
  1707. if( epin->direction )
  1708. {
  1709. for( const auto& pinDir : pinDirectionsMap )
  1710. {
  1711. if( epin->direction->Lower() == pinDir.first )
  1712. {
  1713. pin->SetType( pinDir.second );
  1714. if( pinDir.first == wxT( "sup" ) ) // power supply symbol
  1715. ispower = true;
  1716. break;
  1717. }
  1718. }
  1719. }
  1720. if( aDevice->connects.size() != 0 )
  1721. {
  1722. for( const std::unique_ptr<ECONNECT>& connect : aDevice->connects )
  1723. {
  1724. if( connect->gate == aGateName && pin->GetName() == connect->pin )
  1725. {
  1726. wxArrayString pads = wxSplit( wxString( connect->pad ), ' ' );
  1727. pin->SetUnit( aGateNumber );
  1728. pin->SetName( escapeName( pin->GetName() ) );
  1729. if( pads.GetCount() > 1 )
  1730. {
  1731. pin->SetNumberTextSize( 0 );
  1732. }
  1733. for( unsigned i = 0; i < pads.GetCount(); i++ )
  1734. {
  1735. SCH_PIN* apin = new SCH_PIN( *pin );
  1736. wxString padname( pads[i] );
  1737. apin->SetNumber( padname );
  1738. aSymbol->AddDrawItem( apin );
  1739. }
  1740. break;
  1741. }
  1742. }
  1743. }
  1744. else
  1745. {
  1746. pin->SetUnit( aGateNumber );
  1747. pin->SetNumber( wxString::Format( wxT( "%i" ), pincount ) );
  1748. aSymbol->AddDrawItem( pin.release() );
  1749. }
  1750. }
  1751. for( const std::unique_ptr<EPOLYGON>& epolygon : aEsymbol->polygons )
  1752. aSymbol->AddDrawItem( loadSymbolPolyLine( aSymbol, epolygon, aGateNumber ) );
  1753. for( const std::unique_ptr<ERECT>& erectangle : aEsymbol->rectangles )
  1754. aSymbol->AddDrawItem( loadSymbolRectangle( aSymbol, erectangle, aGateNumber ) );
  1755. for( const std::unique_ptr<ETEXT>& etext : aEsymbol->texts )
  1756. {
  1757. std::unique_ptr<SCH_TEXT> libtext( loadSymbolText( aSymbol, etext, aGateNumber ) );
  1758. if( libtext->GetText() == wxT( "${REFERENCE}" ) )
  1759. {
  1760. // Move text & attributes to Reference field and discard LIB_TEXT item
  1761. loadFieldAttributes( &aSymbol->GetReferenceField(), libtext.get() );
  1762. // Show Reference field if Eagle reference was uppercase
  1763. showRefDes = etext->text == wxT( ">NAME" );
  1764. }
  1765. else if( libtext->GetText() == wxT( "${VALUE}" ) )
  1766. {
  1767. // Move text & attributes to Value field and discard LIB_TEXT item
  1768. loadFieldAttributes( &aSymbol->GetValueField(), libtext.get() );
  1769. // Show Value field if Eagle reference was uppercase
  1770. showValue = etext->text == wxT( ">VALUE" );
  1771. }
  1772. else
  1773. {
  1774. aSymbol->AddDrawItem( libtext.release() );
  1775. }
  1776. }
  1777. for( const std::unique_ptr<EWIRE>& ewire : aEsymbol->wires )
  1778. aSymbol->AddDrawItem( loadSymbolWire( aSymbol, ewire, aGateNumber ) );
  1779. for( const std::unique_ptr<EFRAME>& eframe : aEsymbol->frames )
  1780. {
  1781. std::vector<SCH_ITEM*> frameItems;
  1782. loadFrame( eframe, frameItems );
  1783. for( SCH_ITEM* item : frameItems )
  1784. {
  1785. item->SetParent( aSymbol.get() );
  1786. item->SetUnit( aGateNumber );
  1787. aSymbol->AddDrawItem( item );
  1788. }
  1789. }
  1790. aSymbol->GetReferenceField().SetVisible( showRefDes );
  1791. aSymbol->GetValueField().SetVisible( showValue );
  1792. return pincount == 1 ? ispower : false;
  1793. }
  1794. SCH_SHAPE* SCH_IO_EAGLE::loadSymbolCircle( std::unique_ptr<LIB_SYMBOL>& aSymbol,
  1795. const std::unique_ptr<ECIRCLE>& aCircle,
  1796. int aGateNumber )
  1797. {
  1798. wxCHECK( aSymbol && aCircle, nullptr );
  1799. // Parse the circle properties
  1800. SCH_SHAPE* circle = new SCH_SHAPE( SHAPE_T::CIRCLE );
  1801. VECTOR2I center( aCircle->x.ToSchUnits(), -aCircle->y.ToSchUnits() );
  1802. circle->SetParent( aSymbol.get() );
  1803. circle->SetPosition( center );
  1804. circle->SetEnd( VECTOR2I( center.x + aCircle->radius.ToSchUnits(), center.y ) );
  1805. circle->SetStroke( STROKE_PARAMS( aCircle->width.ToSchUnits(), LINE_STYLE::SOLID ) );
  1806. circle->SetUnit( aGateNumber );
  1807. return circle;
  1808. }
  1809. SCH_SHAPE* SCH_IO_EAGLE::loadSymbolRectangle( std::unique_ptr<LIB_SYMBOL>& aSymbol,
  1810. const std::unique_ptr<ERECT>& aRectangle,
  1811. int aGateNumber )
  1812. {
  1813. wxCHECK( aSymbol && aRectangle, nullptr );
  1814. SCH_SHAPE* rectangle = new SCH_SHAPE( SHAPE_T::RECTANGLE );
  1815. rectangle->SetParent( aSymbol.get() );
  1816. rectangle->SetPosition( VECTOR2I( aRectangle->x1.ToSchUnits(), -aRectangle->y1.ToSchUnits() ) );
  1817. rectangle->SetEnd( VECTOR2I( aRectangle->x2.ToSchUnits(), -aRectangle->y2.ToSchUnits() ) );
  1818. if( aRectangle->rot )
  1819. {
  1820. VECTOR2I pos( rectangle->GetPosition() );
  1821. VECTOR2I end( rectangle->GetEnd() );
  1822. VECTOR2I center( rectangle->GetCenter() );
  1823. RotatePoint( pos, center, EDA_ANGLE( aRectangle->rot->degrees, DEGREES_T ) );
  1824. RotatePoint( end, center, EDA_ANGLE( aRectangle->rot->degrees, DEGREES_T ) );
  1825. rectangle->SetPosition( pos );
  1826. rectangle->SetEnd( end );
  1827. }
  1828. rectangle->SetUnit( aGateNumber );
  1829. // Eagle rectangles are filled by definition.
  1830. rectangle->SetFillMode( FILL_T::FILLED_SHAPE );
  1831. return rectangle;
  1832. }
  1833. SCH_ITEM* SCH_IO_EAGLE::loadSymbolWire( std::unique_ptr<LIB_SYMBOL>& aSymbol,
  1834. const std::unique_ptr<EWIRE>& aWire, int aGateNumber )
  1835. {
  1836. wxCHECK( aSymbol && aWire, nullptr );
  1837. VECTOR2I begin, end;
  1838. begin.x = aWire->x1.ToSchUnits();
  1839. begin.y = -aWire->y1.ToSchUnits();
  1840. end.x = aWire->x2.ToSchUnits();
  1841. end.y = -aWire->y2.ToSchUnits();
  1842. if( begin == end )
  1843. return nullptr;
  1844. // if the wire is an arc
  1845. if( aWire->curve )
  1846. {
  1847. SCH_SHAPE* arc = new SCH_SHAPE( SHAPE_T::ARC, LAYER_DEVICE );
  1848. VECTOR2I center = ConvertArcCenter( begin, end, *aWire->curve );
  1849. double radius = sqrt( ( ( center.x - begin.x ) * ( center.x - begin.x ) ) +
  1850. ( ( center.y - begin.y ) * ( center.y - begin.y ) ) );
  1851. arc->SetParent( aSymbol.get() );
  1852. // this emulates the filled semicircles created by a thick arc with flat ends caps.
  1853. if( aWire->cap == EWIRE::FLAT && aWire->width.ToSchUnits() >= 2 * radius )
  1854. {
  1855. VECTOR2I centerStartVector = ( begin - center ) *
  1856. ( aWire->width.ToSchUnits() / radius );
  1857. begin = center + centerStartVector;
  1858. arc->SetStroke( STROKE_PARAMS( 1, LINE_STYLE::SOLID ) );
  1859. arc->SetFillMode( FILL_T::FILLED_SHAPE );
  1860. }
  1861. else
  1862. {
  1863. arc->SetStroke( STROKE_PARAMS( aWire->width.ToSchUnits(), LINE_STYLE::SOLID ) );
  1864. }
  1865. arc->SetCenter( center );
  1866. arc->SetStart( begin );
  1867. // KiCad rotates the other way.
  1868. arc->SetArcAngleAndEnd( -EDA_ANGLE( *aWire->curve, DEGREES_T ), true );
  1869. arc->SetUnit( aGateNumber );
  1870. return arc;
  1871. }
  1872. else
  1873. {
  1874. SCH_SHAPE* poly = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
  1875. poly->AddPoint( begin );
  1876. poly->AddPoint( end );
  1877. poly->SetUnit( aGateNumber );
  1878. poly->SetStroke( STROKE_PARAMS( aWire->width.ToSchUnits(), LINE_STYLE::SOLID ) );
  1879. return poly;
  1880. }
  1881. }
  1882. SCH_SHAPE* SCH_IO_EAGLE::loadSymbolPolyLine( std::unique_ptr<LIB_SYMBOL>& aSymbol,
  1883. const std::unique_ptr<EPOLYGON>& aPolygon,
  1884. int aGateNumber )
  1885. {
  1886. wxCHECK( aSymbol && aPolygon, nullptr );
  1887. SCH_SHAPE* poly = new SCH_SHAPE( SHAPE_T::POLY );
  1888. VECTOR2I pt, prev_pt;
  1889. opt_double prev_curve;
  1890. poly->SetParent( aSymbol.get() );
  1891. for( const std::unique_ptr<EVERTEX>& evertex : aPolygon->vertices )
  1892. {
  1893. pt = VECTOR2I( evertex->x.ToSchUnits(), evertex->y.ToSchUnits() );
  1894. if( prev_curve )
  1895. {
  1896. SHAPE_ARC arc;
  1897. arc.ConstructFromStartEndAngle( prev_pt, pt, -EDA_ANGLE( *prev_curve, DEGREES_T ) );
  1898. poly->GetPolyShape().Append( arc, -1, -1, ARC_ACCURACY );
  1899. }
  1900. else
  1901. {
  1902. poly->AddPoint( pt );
  1903. }
  1904. prev_pt = pt;
  1905. prev_curve = evertex->curve;
  1906. }
  1907. poly->SetStroke( STROKE_PARAMS( aPolygon->width.ToSchUnits(), LINE_STYLE::SOLID ) );
  1908. poly->SetFillMode( FILL_T::FILLED_SHAPE );
  1909. poly->SetUnit( aGateNumber );
  1910. return poly;
  1911. }
  1912. SCH_PIN* SCH_IO_EAGLE::loadPin( std::unique_ptr<LIB_SYMBOL>& aSymbol,
  1913. const std::unique_ptr<EPIN>& aPin, int aGateNumber )
  1914. {
  1915. wxCHECK( aSymbol && aPin, nullptr );
  1916. std::unique_ptr<SCH_PIN> pin = std::make_unique<SCH_PIN>( aSymbol.get() );
  1917. pin->SetPosition( VECTOR2I( aPin->x.ToSchUnits(), -aPin->y.ToSchUnits() ) );
  1918. pin->SetName( aPin->name );
  1919. pin->SetUnit( aGateNumber );
  1920. int roti = aPin->rot ? aPin->rot->degrees : 0;
  1921. switch( roti )
  1922. {
  1923. case 0: pin->SetOrientation( PIN_ORIENTATION::PIN_RIGHT ); break;
  1924. case 90: pin->SetOrientation( PIN_ORIENTATION::PIN_UP ); break;
  1925. case 180: pin->SetOrientation( PIN_ORIENTATION::PIN_LEFT ); break;
  1926. case 270: pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN ); break;
  1927. default: wxFAIL_MSG( wxString::Format( wxT( "Unhandled orientation (%d degrees)." ), roti ) );
  1928. }
  1929. pin->SetLength( schIUScale.MilsToIU( 300 ) ); // Default pin length when not defined.
  1930. if( aPin->length )
  1931. {
  1932. wxString length = aPin->length.Get();
  1933. if( length == wxT( "short" ) )
  1934. pin->SetLength( schIUScale.MilsToIU( 100 ) );
  1935. else if( length == wxT( "middle" ) )
  1936. pin->SetLength( schIUScale.MilsToIU( 200 ) );
  1937. else if( length == wxT( "long" ) )
  1938. pin->SetLength( schIUScale.MilsToIU( 300 ) );
  1939. else if( length == wxT( "point" ) )
  1940. pin->SetLength( schIUScale.MilsToIU( 0 ) );
  1941. }
  1942. // Pin names and numbers are fixed size in Eagle.
  1943. pin->SetNumberTextSize( schIUScale.MilsToIU( 60 ) );
  1944. pin->SetNameTextSize( schIUScale.MilsToIU( 60 ) );
  1945. // emulate the visibility of pin elements
  1946. if( aPin->visible )
  1947. {
  1948. wxString visible = aPin->visible.Get();
  1949. if( visible == wxT( "off" ) )
  1950. {
  1951. pin->SetNameTextSize( 0 );
  1952. pin->SetNumberTextSize( 0 );
  1953. }
  1954. else if( visible == wxT( "pad" ) )
  1955. {
  1956. pin->SetNameTextSize( 0 );
  1957. }
  1958. else if( visible == wxT( "pin" ) )
  1959. {
  1960. pin->SetNumberTextSize( 0 );
  1961. }
  1962. /*
  1963. * else if( visible == wxT( "both" ) )
  1964. * {
  1965. * }
  1966. */
  1967. }
  1968. if( aPin->function )
  1969. {
  1970. wxString function = aPin->function.Get();
  1971. if( function == wxT( "dot" ) )
  1972. pin->SetShape( GRAPHIC_PINSHAPE::INVERTED );
  1973. else if( function == wxT( "clk" ) )
  1974. pin->SetShape( GRAPHIC_PINSHAPE::CLOCK );
  1975. else if( function == wxT( "dotclk" ) )
  1976. pin->SetShape( GRAPHIC_PINSHAPE::INVERTED_CLOCK );
  1977. }
  1978. return pin.release();
  1979. }
  1980. SCH_TEXT* SCH_IO_EAGLE::loadSymbolText( std::unique_ptr<LIB_SYMBOL>& aSymbol,
  1981. const std::unique_ptr<ETEXT>& aText, int aGateNumber )
  1982. {
  1983. wxCHECK( aSymbol && aText, nullptr );
  1984. std::unique_ptr<SCH_TEXT> libtext = std::make_unique<SCH_TEXT>();
  1985. libtext->SetParent( aSymbol.get() );
  1986. libtext->SetUnit( aGateNumber );
  1987. libtext->SetPosition( VECTOR2I( aText->x.ToSchUnits(), -aText->y.ToSchUnits() ) );
  1988. const wxString& eagleText = aText->text;
  1989. wxString adjustedText;
  1990. wxStringTokenizer tokenizer( eagleText, "\r\n" );
  1991. // Strip the whitespace from both ends of each line.
  1992. while( tokenizer.HasMoreTokens() )
  1993. {
  1994. wxString tmp = interpretText( tokenizer.GetNextToken().Trim( true ).Trim( false ) );
  1995. if( tokenizer.HasMoreTokens() )
  1996. tmp += wxT( "\n" );
  1997. adjustedText += tmp;
  1998. }
  1999. libtext->SetText( adjustedText.IsEmpty() ? wxString( wxS( "~" ) ) : adjustedText );
  2000. loadTextAttributes( libtext.get(), aText );
  2001. return libtext.release();
  2002. }
  2003. SCH_TEXT* SCH_IO_EAGLE::loadPlainText( const std::unique_ptr<ETEXT>& aText )
  2004. {
  2005. wxCHECK( aText, nullptr );
  2006. std::unique_ptr<SCH_TEXT> schtext = std::make_unique<SCH_TEXT>();
  2007. const wxString& eagleText = aText->text;
  2008. wxString adjustedText;
  2009. wxStringTokenizer tokenizer( eagleText, "\r\n" );
  2010. // Strip the whitespace from both ends of each line.
  2011. while( tokenizer.HasMoreTokens() )
  2012. {
  2013. wxString tmp = interpretText( tokenizer.GetNextToken().Trim( true ).Trim( false ) );
  2014. if( tokenizer.HasMoreTokens() )
  2015. tmp += wxT( "\n" );
  2016. adjustedText += tmp;
  2017. }
  2018. schtext->SetText( adjustedText.IsEmpty() ? wxString( wxS( "\" \"" ) )
  2019. : escapeName( adjustedText ) );
  2020. schtext->SetPosition( VECTOR2I( aText->x.ToSchUnits(), -aText->y.ToSchUnits() ) );
  2021. loadTextAttributes( schtext.get(), aText );
  2022. schtext->SetItalic( false );
  2023. return schtext.release();
  2024. }
  2025. void SCH_IO_EAGLE::loadTextAttributes( EDA_TEXT* aText,
  2026. const std::unique_ptr<ETEXT>& aAttributes ) const
  2027. {
  2028. wxCHECK( aText && aAttributes, /* void */ );
  2029. aText->SetTextSize( aAttributes->ConvertSize() );
  2030. // Must come after SetTextSize()
  2031. if( aAttributes->ratio && aAttributes->ratio.CGet() > 12 )
  2032. aText->SetBold( true );
  2033. int align = aAttributes->align ? *aAttributes->align : ETEXT::BOTTOM_LEFT;
  2034. int degrees = aAttributes->rot ? aAttributes->rot->degrees : 0;
  2035. bool mirror = aAttributes->rot ? aAttributes->rot->mirror : false;
  2036. bool spin = aAttributes->rot ? aAttributes->rot->spin : false;
  2037. eagleToKicadAlignment( aText, align, degrees, mirror, spin, 0 );
  2038. }
  2039. void SCH_IO_EAGLE::loadFieldAttributes( SCH_FIELD* aField, const SCH_TEXT* aText ) const
  2040. {
  2041. wxCHECK( aField && aText, /* void */ );
  2042. aField->SetTextPos( aText->GetPosition() );
  2043. aField->SetTextSize( aText->GetTextSize() );
  2044. aField->SetTextAngle( aText->GetTextAngle() );
  2045. // Must come after SetTextSize()
  2046. aField->SetBold( aText->IsBold() );
  2047. aField->SetItalic( false );
  2048. aField->SetVertJustify( aText->GetVertJustify() );
  2049. aField->SetHorizJustify( aText->GetHorizJustify() );
  2050. }
  2051. void SCH_IO_EAGLE::adjustNetLabels()
  2052. {
  2053. // Eagle supports detached labels, so a label does not need to be placed on a wire
  2054. // to be associated with it. KiCad needs to move them, so the labels actually touch the
  2055. // corresponding wires.
  2056. // Sort the intersection points to speed up the search process
  2057. std::sort( m_wireIntersections.begin(), m_wireIntersections.end() );
  2058. auto onIntersection =
  2059. [&]( const VECTOR2I& aPos )
  2060. {
  2061. return std::binary_search( m_wireIntersections.begin(),
  2062. m_wireIntersections.end(), aPos );
  2063. };
  2064. for( SEG_DESC& segDesc : m_segments )
  2065. {
  2066. for( SCH_TEXT* label : segDesc.labels )
  2067. {
  2068. VECTOR2I labelPos( label->GetPosition() );
  2069. const SEG* segAttached = segDesc.LabelAttached( label );
  2070. if( segAttached && !onIntersection( labelPos ) )
  2071. continue; // label is placed correctly
  2072. // Move the label to the nearest wire
  2073. if( !segAttached )
  2074. {
  2075. std::tie( labelPos, segAttached ) = findNearestLinePoint( label->GetPosition(),
  2076. segDesc.segs );
  2077. if( !segAttached ) // we cannot do anything
  2078. continue;
  2079. }
  2080. // Create a vector pointing in the direction of the wire, 50 mils long
  2081. VECTOR2I wireDirection( segAttached->B - segAttached->A );
  2082. wireDirection = wireDirection.Resize( schIUScale.MilsToIU( 50 ) );
  2083. const VECTOR2I origPos( labelPos );
  2084. // Flags determining the search direction
  2085. bool checkPositive = true, checkNegative = true, move = false;
  2086. int trial = 0;
  2087. // Be sure the label is not placed on a wire intersection
  2088. while( ( !move || onIntersection( labelPos ) ) && ( checkPositive || checkNegative ) )
  2089. {
  2090. move = false;
  2091. // Move along the attached wire to find the new label position
  2092. if( trial % 2 == 1 )
  2093. {
  2094. labelPos = VECTOR2I( origPos + wireDirection * trial / 2 );
  2095. move = checkPositive = segAttached->Contains( labelPos );
  2096. }
  2097. else
  2098. {
  2099. labelPos = VECTOR2I( origPos - wireDirection * trial / 2 );
  2100. move = checkNegative = segAttached->Contains( labelPos );
  2101. }
  2102. ++trial;
  2103. }
  2104. if( move )
  2105. label->SetPosition( VECTOR2I( labelPos ) );
  2106. }
  2107. }
  2108. m_segments.clear();
  2109. m_wireIntersections.clear();
  2110. }
  2111. bool SCH_IO_EAGLE::CanReadSchematicFile( const wxString& aFileName ) const
  2112. {
  2113. if( !SCH_IO::CanReadSchematicFile( aFileName ) )
  2114. return false;
  2115. return checkHeader( aFileName );
  2116. }
  2117. bool SCH_IO_EAGLE::CanReadLibrary( const wxString& aFileName ) const
  2118. {
  2119. if( !SCH_IO::CanReadLibrary( aFileName ) )
  2120. return false;
  2121. return checkHeader( aFileName );
  2122. }
  2123. bool SCH_IO_EAGLE::checkHeader( const wxString& aFileName ) const
  2124. {
  2125. wxFileInputStream input( aFileName );
  2126. if( !input.IsOk() )
  2127. return false;
  2128. wxTextInputStream text( input );
  2129. for( int i = 0; i < 8; i++ )
  2130. {
  2131. if( input.Eof() )
  2132. return false;
  2133. if( text.ReadLine().Contains( wxS( "<eagle" ) ) )
  2134. return true;
  2135. }
  2136. return false;
  2137. }
  2138. void SCH_IO_EAGLE::moveLabels( SCH_LINE* aWire, const VECTOR2I& aNewEndPoint )
  2139. {
  2140. wxCHECK( aWire, /* void */ );
  2141. SCH_SCREEN* screen = getCurrentScreen();
  2142. wxCHECK( screen, /* void */ );
  2143. for( SCH_ITEM* item : screen->Items().Overlapping( aWire->GetBoundingBox() ) )
  2144. {
  2145. if( !item->IsType( { SCH_LABEL_LOCATE_ANY_T } ) )
  2146. continue;
  2147. if( TestSegmentHit( item->GetPosition(), aWire->GetStartPoint(), aWire->GetEndPoint(), 0 ) )
  2148. item->SetPosition( aNewEndPoint );
  2149. }
  2150. }
  2151. void SCH_IO_EAGLE::addBusEntries()
  2152. {
  2153. // Add bus entry symbols
  2154. // TODO: Cleanup this function and break into pieces
  2155. // for each wire segment, compare each end with all busses.
  2156. // If the wire end is found to end on a bus segment, place a bus entry symbol.
  2157. std::vector<SCH_LINE*> buses;
  2158. std::vector<SCH_LINE*> wires;
  2159. SCH_SCREEN* screen = getCurrentScreen();
  2160. wxCHECK( screen, /* void */ );
  2161. for( SCH_ITEM* ii : screen->Items().OfType( SCH_LINE_T ) )
  2162. {
  2163. SCH_LINE* line = static_cast<SCH_LINE*>( ii );
  2164. if( line->IsBus() )
  2165. buses.push_back( line );
  2166. else if( line->IsWire() )
  2167. wires.push_back( line );
  2168. }
  2169. for( SCH_LINE* wire : wires )
  2170. {
  2171. VECTOR2I wireStart = wire->GetStartPoint();
  2172. VECTOR2I wireEnd = wire->GetEndPoint();
  2173. for( SCH_LINE* bus : buses )
  2174. {
  2175. VECTOR2I busStart = bus->GetStartPoint();
  2176. VECTOR2I busEnd = bus->GetEndPoint();
  2177. auto entrySize =
  2178. []( int signX, int signY ) -> VECTOR2I
  2179. {
  2180. return VECTOR2I( schIUScale.MilsToIU( DEFAULT_SCH_ENTRY_SIZE ) * signX,
  2181. schIUScale.MilsToIU( DEFAULT_SCH_ENTRY_SIZE ) * signY );
  2182. };
  2183. auto testBusHit =
  2184. [&]( const VECTOR2I& aPt ) -> bool
  2185. {
  2186. return TestSegmentHit( aPt, busStart, busEnd, 0 );
  2187. };
  2188. if( wireStart.y == wireEnd.y && busStart.x == busEnd.x )
  2189. {
  2190. // Horizontal wire and vertical bus
  2191. if( testBusHit( wireStart ) )
  2192. {
  2193. // Wire start is on the vertical bus
  2194. if( wireEnd.x < busStart.x )
  2195. {
  2196. /* the end of the wire is to the left of the bus
  2197. *
  2198. *
  2199. *
  2200. */
  2201. VECTOR2I p = wireStart + entrySize( -1, 0 );
  2202. if( testBusHit( wireStart + entrySize( 0, -1 ) ) )
  2203. {
  2204. /* there is room above the wire for the bus entry
  2205. *
  2206. * _____/
  2207. *
  2208. */
  2209. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
  2210. busEntry->SetFlags( IS_NEW );
  2211. screen->Append( busEntry );
  2212. moveLabels( wire, p );
  2213. wire->SetStartPoint( p );
  2214. }
  2215. else if( testBusHit( wireStart + entrySize( 0, 1 ) ) )
  2216. {
  2217. /* there is room below the wire for the bus entry
  2218. * _____
  2219. * \
  2220. *
  2221. */
  2222. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
  2223. busEntry->SetFlags( IS_NEW );
  2224. screen->Append( busEntry );
  2225. moveLabels( wire, p );
  2226. wire->SetStartPoint( p );
  2227. }
  2228. else
  2229. {
  2230. std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
  2231. screen->Append( new SCH_MARKER( std::move( ercItem ), wireStart ) );
  2232. }
  2233. }
  2234. else
  2235. {
  2236. /* the wire end is to the right of the bus
  2237. *
  2238. *
  2239. *
  2240. */
  2241. VECTOR2I p = wireStart + entrySize( 1, 0 );
  2242. if( testBusHit( wireStart + entrySize( 0, -1 ) ) )
  2243. {
  2244. /* There is room above the wire for the bus entry
  2245. *
  2246. * \_____
  2247. *
  2248. */
  2249. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p , 4 );
  2250. busEntry->SetFlags( IS_NEW );
  2251. screen->Append( busEntry );
  2252. moveLabels( wire, p );
  2253. wire->SetStartPoint( p );
  2254. }
  2255. else if( testBusHit( wireStart + entrySize( 0, 1 ) ) )
  2256. {
  2257. /* There is room below the wire for the bus entry
  2258. * _____
  2259. * /
  2260. *
  2261. */
  2262. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
  2263. busEntry->SetFlags( IS_NEW );
  2264. screen->Append( busEntry );
  2265. moveLabels( wire, p );
  2266. wire->SetStartPoint( p );
  2267. }
  2268. else
  2269. {
  2270. std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
  2271. screen->Append( new SCH_MARKER( std::move( ercItem ), wireStart ) );
  2272. }
  2273. }
  2274. break;
  2275. }
  2276. else if( testBusHit( wireEnd ) )
  2277. {
  2278. // Wire end is on the vertical bus
  2279. if( wireStart.x < busStart.x )
  2280. {
  2281. /* start of the wire is to the left of the bus
  2282. *
  2283. *
  2284. *
  2285. */
  2286. VECTOR2I p = wireEnd + entrySize( -1, 0 );
  2287. if( testBusHit( wireEnd + entrySize( 0, -1 ) ) )
  2288. {
  2289. /* there is room above the wire for the bus entry
  2290. *
  2291. * _____/
  2292. *
  2293. */
  2294. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
  2295. busEntry->SetFlags( IS_NEW );
  2296. screen->Append( busEntry );
  2297. moveLabels( wire, p );
  2298. wire->SetEndPoint( p );
  2299. }
  2300. else if( testBusHit( wireEnd + entrySize( 0, -1 ) ) )
  2301. {
  2302. /* there is room below the wire for the bus entry
  2303. * _____
  2304. * \
  2305. *
  2306. */
  2307. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
  2308. busEntry->SetFlags( IS_NEW );
  2309. screen->Append( busEntry );
  2310. moveLabels( wire, wireEnd + entrySize( -1, 0 ) );
  2311. wire->SetEndPoint( wireEnd + entrySize( -1, 0 ) );
  2312. }
  2313. else
  2314. {
  2315. std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
  2316. screen->Append( new SCH_MARKER( std::move( ercItem ), wireEnd ) );
  2317. }
  2318. }
  2319. else
  2320. {
  2321. /* the start of the wire is to the right of the bus
  2322. *
  2323. *
  2324. *
  2325. */
  2326. VECTOR2I p = wireEnd + entrySize( 1, 0 );
  2327. if( testBusHit( wireEnd + entrySize( 0, -1 ) ) )
  2328. {
  2329. /* There is room above the wire for the bus entry
  2330. *
  2331. * \_____
  2332. *
  2333. */
  2334. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
  2335. busEntry->SetFlags( IS_NEW );
  2336. screen->Append( busEntry );
  2337. moveLabels( wire, p );
  2338. wire->SetEndPoint( p );
  2339. }
  2340. else if( testBusHit( wireEnd + entrySize( 0, 1 ) ) )
  2341. {
  2342. /* There is room below the wire for the bus entry
  2343. * _____
  2344. * /
  2345. *
  2346. */
  2347. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
  2348. busEntry->SetFlags( IS_NEW );
  2349. screen->Append( busEntry );
  2350. moveLabels( wire, p );
  2351. wire->SetEndPoint( p );
  2352. }
  2353. else
  2354. {
  2355. std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
  2356. screen->Append( new SCH_MARKER( std::move( ercItem ), wireEnd ) );
  2357. }
  2358. }
  2359. break;
  2360. }
  2361. }
  2362. else if( wireStart.x == wireEnd.x && busStart.y == busEnd.y )
  2363. {
  2364. // Vertical wire and horizontal bus
  2365. if( testBusHit( wireStart ) )
  2366. {
  2367. // Wire start is on the bus
  2368. if( wireEnd.y < busStart.y )
  2369. {
  2370. /* the end of the wire is above the bus
  2371. * |
  2372. * |
  2373. * |
  2374. * =======
  2375. */
  2376. VECTOR2I p = wireStart + entrySize( 0, -1 );
  2377. if( testBusHit( wireStart + entrySize( -1, 0 ) ) )
  2378. {
  2379. /* there is room to the left of the wire for the bus entry
  2380. * |
  2381. * |
  2382. * /
  2383. * =======
  2384. */
  2385. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
  2386. busEntry->SetFlags( IS_NEW );
  2387. screen->Append( busEntry );
  2388. moveLabels( wire, p );
  2389. wire->SetStartPoint( p );
  2390. }
  2391. else if( testBusHit( wireStart + entrySize( 1, 0 ) ) )
  2392. {
  2393. /* there is room to the right of the wire for the bus entry
  2394. * |
  2395. * |
  2396. * \
  2397. * =======
  2398. */
  2399. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
  2400. busEntry->SetFlags( IS_NEW );
  2401. screen->Append( busEntry );
  2402. moveLabels( wire, p );
  2403. wire->SetStartPoint( p );
  2404. }
  2405. else
  2406. {
  2407. std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
  2408. screen->Append( new SCH_MARKER( std::move( ercItem ), wireStart ) );
  2409. }
  2410. }
  2411. else
  2412. {
  2413. /* wire end is below the bus
  2414. * =======
  2415. * |
  2416. * |
  2417. * |
  2418. */
  2419. VECTOR2I p = wireStart + entrySize( 0, 1 );
  2420. if( testBusHit( wireStart + entrySize( -1, 0 ) ) )
  2421. {
  2422. /* there is room to the left of the wire for the bus entry
  2423. * =======
  2424. * \
  2425. * |
  2426. * |
  2427. */
  2428. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
  2429. busEntry->SetFlags( IS_NEW );
  2430. screen->Append( busEntry );
  2431. moveLabels( wire, p );
  2432. wire->SetStartPoint( p );
  2433. }
  2434. else if( testBusHit( wireStart + entrySize( 1, 0 ) ) )
  2435. {
  2436. /* there is room to the right of the wire for the bus entry
  2437. * =======
  2438. * /
  2439. * |
  2440. * |
  2441. */
  2442. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
  2443. busEntry->SetFlags( IS_NEW );
  2444. screen->Append( busEntry );
  2445. moveLabels( wire, p );
  2446. wire->SetStartPoint( p );
  2447. }
  2448. else
  2449. {
  2450. std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
  2451. screen->Append( new SCH_MARKER( std::move( ercItem ), wireStart ) );
  2452. }
  2453. }
  2454. break;
  2455. }
  2456. else if( testBusHit( wireEnd ) )
  2457. {
  2458. // Wire end is on the bus
  2459. if( wireStart.y < busStart.y )
  2460. {
  2461. /* the start of the wire is above the bus
  2462. * |
  2463. * |
  2464. * |
  2465. * =======
  2466. */
  2467. VECTOR2I p = wireEnd + entrySize( 0, -1 );
  2468. if( testBusHit( wireEnd + entrySize( -1, 0 ) ) )
  2469. {
  2470. /* there is room to the left of the wire for the bus entry
  2471. * |
  2472. * |
  2473. * /
  2474. * =======
  2475. */
  2476. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
  2477. busEntry->SetFlags( IS_NEW );
  2478. screen->Append( busEntry );
  2479. moveLabels( wire, p );
  2480. wire->SetEndPoint( p );
  2481. }
  2482. else if( testBusHit( wireEnd + entrySize( 1, 0 ) ) )
  2483. {
  2484. /* there is room to the right of the wire for the bus entry
  2485. * |
  2486. * |
  2487. * \
  2488. * =======
  2489. */
  2490. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
  2491. busEntry->SetFlags( IS_NEW );
  2492. screen->Append( busEntry );
  2493. moveLabels( wire, p );
  2494. wire->SetEndPoint( p );
  2495. }
  2496. else
  2497. {
  2498. std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
  2499. screen->Append( new SCH_MARKER( std::move( ercItem ), wireEnd ) );
  2500. }
  2501. }
  2502. else
  2503. {
  2504. /* wire start is below the bus
  2505. * =======
  2506. * |
  2507. * |
  2508. * |
  2509. */
  2510. VECTOR2I p = wireEnd + entrySize( 0, 1 );
  2511. if( testBusHit( wireEnd + entrySize( -1, 0 ) ) )
  2512. {
  2513. /* there is room to the left of the wire for the bus entry
  2514. * =======
  2515. * \
  2516. * |
  2517. * |
  2518. */
  2519. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
  2520. busEntry->SetFlags( IS_NEW );
  2521. screen->Append( busEntry );
  2522. moveLabels( wire, p );
  2523. wire->SetEndPoint( p );
  2524. }
  2525. else if( testBusHit( wireEnd + entrySize( 1, 0 ) ) )
  2526. {
  2527. /* there is room to the right of the wire for the bus entry
  2528. * =======
  2529. * /
  2530. * |
  2531. * |
  2532. */
  2533. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
  2534. busEntry->SetFlags( IS_NEW );
  2535. screen->Append( busEntry );
  2536. moveLabels( wire, p );
  2537. wire->SetEndPoint( p );
  2538. }
  2539. else
  2540. {
  2541. std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
  2542. screen->Append( new SCH_MARKER( std::move( ercItem ), wireEnd ) );
  2543. }
  2544. }
  2545. break;
  2546. }
  2547. }
  2548. else
  2549. {
  2550. // Wire isn't horizontal or vertical
  2551. if( testBusHit( wireStart ) )
  2552. {
  2553. VECTOR2I wirevector = wireStart - wireEnd;
  2554. if( wirevector.x > 0 )
  2555. {
  2556. if( wirevector.y > 0 )
  2557. {
  2558. VECTOR2I p = wireStart + entrySize( -1, -1 );
  2559. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
  2560. busEntry->SetFlags( IS_NEW );
  2561. screen->Append( busEntry );
  2562. moveLabels( wire, p );
  2563. wire->SetStartPoint( p );
  2564. }
  2565. else
  2566. {
  2567. VECTOR2I p = wireStart + entrySize( -1, 1 );
  2568. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
  2569. busEntry->SetFlags( IS_NEW );
  2570. screen->Append( busEntry );
  2571. moveLabels( wire, p );
  2572. wire->SetStartPoint( p );
  2573. }
  2574. }
  2575. else
  2576. {
  2577. if( wirevector.y > 0 )
  2578. {
  2579. VECTOR2I p = wireStart + entrySize( 1, -1 );
  2580. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
  2581. busEntry->SetFlags( IS_NEW );
  2582. screen->Append( busEntry );
  2583. moveLabels( wire, p );
  2584. wire->SetStartPoint( p );
  2585. }
  2586. else
  2587. {
  2588. VECTOR2I p = wireStart + entrySize( 1, 1 );
  2589. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
  2590. busEntry->SetFlags( IS_NEW );
  2591. screen->Append( busEntry );
  2592. moveLabels( wire, p );
  2593. wire->SetStartPoint( p );
  2594. }
  2595. }
  2596. break;
  2597. }
  2598. else if( testBusHit( wireEnd ) )
  2599. {
  2600. VECTOR2I wirevector = wireStart - wireEnd;
  2601. if( wirevector.x > 0 )
  2602. {
  2603. if( wirevector.y > 0 )
  2604. {
  2605. VECTOR2I p = wireEnd + entrySize( 1, 1 );
  2606. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
  2607. busEntry->SetFlags( IS_NEW );
  2608. screen->Append( busEntry );
  2609. moveLabels( wire, p );
  2610. wire->SetEndPoint( p );
  2611. }
  2612. else
  2613. {
  2614. VECTOR2I p = wireEnd + entrySize( 1, -1 );
  2615. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
  2616. busEntry->SetFlags( IS_NEW );
  2617. screen->Append( busEntry );
  2618. moveLabels( wire, p );
  2619. wire->SetEndPoint( p );
  2620. }
  2621. }
  2622. else
  2623. {
  2624. if( wirevector.y > 0 )
  2625. {
  2626. VECTOR2I p = wireEnd + entrySize( -1, 1 );
  2627. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
  2628. busEntry->SetFlags( IS_NEW );
  2629. screen->Append( busEntry );
  2630. moveLabels( wire, p );
  2631. wire->SetEndPoint( p );
  2632. }
  2633. else
  2634. {
  2635. VECTOR2I p = wireEnd + entrySize( -1, -1 );
  2636. SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
  2637. busEntry->SetFlags( IS_NEW );
  2638. screen->Append( busEntry );
  2639. moveLabels( wire, p );
  2640. wire->SetEndPoint( p );
  2641. }
  2642. }
  2643. break;
  2644. }
  2645. }
  2646. }
  2647. }
  2648. }
  2649. const SEG* SCH_IO_EAGLE::SEG_DESC::LabelAttached( const SCH_TEXT* aLabel ) const
  2650. {
  2651. wxCHECK( aLabel, nullptr );
  2652. VECTOR2I labelPos( aLabel->GetPosition() );
  2653. for( const SEG& seg : segs )
  2654. {
  2655. if( seg.Contains( labelPos ) )
  2656. return &seg;
  2657. }
  2658. return nullptr;
  2659. }
  2660. // TODO could be used to place junctions, instead of IsJunctionNeeded()
  2661. // (see SCH_EDIT_FRAME::importFile())
  2662. bool SCH_IO_EAGLE::checkConnections( const SCH_SYMBOL* aSymbol, const SCH_PIN* aPin ) const
  2663. {
  2664. wxCHECK( aSymbol && aPin, false );
  2665. VECTOR2I pinPosition = aSymbol->GetPinPhysicalPosition( aPin );
  2666. auto pointIt = m_connPoints.find( pinPosition );
  2667. if( pointIt == m_connPoints.end() )
  2668. return false;
  2669. const auto& items = pointIt->second;
  2670. wxCHECK( items.find( aPin ) != items.end(), false );
  2671. return items.size() > 1;
  2672. }
  2673. void SCH_IO_EAGLE::addImplicitConnections( SCH_SYMBOL* aSymbol, SCH_SCREEN* aScreen,
  2674. bool aUpdateSet )
  2675. {
  2676. wxCHECK( aSymbol && aScreen && aSymbol->GetLibSymbolRef(), /*void*/ );
  2677. // Normally power parts also have power input pins,
  2678. // but they already force net names on the attached wires
  2679. if( aSymbol->GetLibSymbolRef()->IsGlobalPower() )
  2680. return;
  2681. int unit = aSymbol->GetUnit();
  2682. const wxString reference = aSymbol->GetField( FIELD_T::REFERENCE )->GetText();
  2683. std::vector<SCH_PIN*> pins = aSymbol->GetLibSymbolRef()->GetPins();
  2684. std::set<int> missingUnits;
  2685. // Search all units for pins creating implicit connections
  2686. for( const SCH_PIN* pin : pins )
  2687. {
  2688. if( pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN )
  2689. {
  2690. bool pinInUnit = !unit || pin->GetUnit() == unit; // pin belongs to the tested unit
  2691. // Create a global net label only if there are no other wires/pins attached
  2692. if( pinInUnit )
  2693. {
  2694. if( !checkConnections( aSymbol, pin ) )
  2695. {
  2696. // Create a net label to force the net name on the pin
  2697. SCH_GLOBALLABEL* netLabel = new SCH_GLOBALLABEL;
  2698. netLabel->SetPosition( aSymbol->GetPinPhysicalPosition( pin ) );
  2699. netLabel->SetText( extractNetName( pin->GetName() ) );
  2700. netLabel->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 40 ),
  2701. schIUScale.MilsToIU( 40 ) ) );
  2702. switch( pin->GetOrientation() )
  2703. {
  2704. default:
  2705. case PIN_ORIENTATION::PIN_RIGHT:
  2706. netLabel->SetSpinStyle( SPIN_STYLE::LEFT );
  2707. break;
  2708. case PIN_ORIENTATION::PIN_LEFT:
  2709. netLabel->SetSpinStyle( SPIN_STYLE::RIGHT );
  2710. break;
  2711. case PIN_ORIENTATION::PIN_UP:
  2712. netLabel->SetSpinStyle( SPIN_STYLE::UP );
  2713. break;
  2714. case PIN_ORIENTATION::PIN_DOWN:
  2715. netLabel->SetSpinStyle( SPIN_STYLE::BOTTOM );
  2716. break;
  2717. }
  2718. aScreen->Append( netLabel );
  2719. }
  2720. }
  2721. else if( aUpdateSet )
  2722. {
  2723. // Found a pin creating implicit connection information in another unit.
  2724. // Such units will be instantiated if they do not appear in another sheet and
  2725. // processed later.
  2726. wxASSERT( pin->GetUnit() );
  2727. missingUnits.insert( pin->GetUnit() );
  2728. }
  2729. }
  2730. }
  2731. if( aUpdateSet && aSymbol->GetLibSymbolRef()->GetUnitCount() > 1 )
  2732. {
  2733. auto cmpIt = m_missingCmps.find( reference );
  2734. // The first unit found has always already been processed.
  2735. if( cmpIt == m_missingCmps.end() )
  2736. {
  2737. EAGLE_MISSING_CMP& entry = m_missingCmps[reference];
  2738. entry.cmp = aSymbol;
  2739. entry.units.emplace( unit, false );
  2740. }
  2741. else
  2742. {
  2743. // Set the flag indicating this unit has been processed.
  2744. cmpIt->second.units[unit] = false;
  2745. }
  2746. if( !missingUnits.empty() ) // Save the units that need later processing
  2747. {
  2748. EAGLE_MISSING_CMP& entry = m_missingCmps[reference];
  2749. entry.cmp = aSymbol;
  2750. // Add units that haven't already been processed.
  2751. for( int i : missingUnits )
  2752. {
  2753. if( entry.units.find( i ) != entry.units.end() )
  2754. entry.units.emplace( i, true );
  2755. }
  2756. }
  2757. }
  2758. }
  2759. wxString SCH_IO_EAGLE::translateEagleBusName( const wxString& aEagleName ) const
  2760. {
  2761. if( NET_SETTINGS::ParseBusVector( aEagleName, nullptr, nullptr ) )
  2762. return aEagleName;
  2763. wxString ret = wxT( "{" );
  2764. wxStringTokenizer tokenizer( aEagleName, wxT( "," ) );
  2765. while( tokenizer.HasMoreTokens() )
  2766. {
  2767. wxString member = tokenizer.GetNextToken();
  2768. // In Eagle, overbar text is automatically stopped at the end of the net name, even when
  2769. // that net name is part of a bus definition. In KiCad, we don't (currently) do that, so
  2770. // if there is an odd number of overbar markers in this net name, we need to append one
  2771. // to close it out before appending the space.
  2772. if( member.Freq( '!' ) % 2 > 0 )
  2773. member << wxT( "!" );
  2774. ret << member << wxS( " " );
  2775. }
  2776. ret.Trim( true );
  2777. ret << wxT( "}" );
  2778. return ret;
  2779. }
  2780. const ESYMBOL* SCH_IO_EAGLE::getEagleSymbol( const std::unique_ptr<EINSTANCE>& aInstance )
  2781. {
  2782. wxCHECK( m_eagleDoc && m_eagleDoc->drawing && m_eagleDoc->drawing->schematic && aInstance,
  2783. nullptr );
  2784. std::unique_ptr<EPART>& epart = m_eagleDoc->drawing->schematic->parts[aInstance->part];
  2785. if( !epart || epart->deviceset.IsEmpty() )
  2786. return nullptr;
  2787. std::unique_ptr<ELIBRARY>& elibrary = m_eagleDoc->drawing->schematic->libraries[epart->library];
  2788. if( !elibrary )
  2789. return nullptr;
  2790. std::unique_ptr<EDEVICE_SET>& edeviceset = elibrary->devicesets[epart->deviceset];
  2791. if( !edeviceset )
  2792. return nullptr;
  2793. std::unique_ptr<EGATE>& egate = edeviceset->gates[aInstance->gate];
  2794. if( !egate )
  2795. return nullptr;
  2796. std::unique_ptr<ESYMBOL>& esymbol = elibrary->symbols[egate->symbol];
  2797. if( esymbol )
  2798. return esymbol.get();
  2799. return nullptr;
  2800. }
  2801. void SCH_IO_EAGLE::getEagleSymbolFieldAttributes( const std::unique_ptr<EINSTANCE>& aInstance,
  2802. const wxString& aEagleFieldName,
  2803. SCH_FIELD* aField )
  2804. {
  2805. wxCHECK( aField && !aEagleFieldName.IsEmpty(), /* void */ );
  2806. const ESYMBOL* esymbol = getEagleSymbol( aInstance );
  2807. if( esymbol )
  2808. {
  2809. for( const std::unique_ptr<ETEXT>& text : esymbol->texts )
  2810. {
  2811. if( text->text == aEagleFieldName )
  2812. {
  2813. aField->SetVisible( true );
  2814. VECTOR2I pos( text->x.ToSchUnits() + aInstance->x.ToSchUnits(),
  2815. -text->y.ToSchUnits() - aInstance->y.ToSchUnits() );
  2816. bool mirror = text->rot ? text->rot->mirror : false;
  2817. if( aInstance->rot && aInstance->rot->mirror )
  2818. mirror = !mirror;
  2819. if( mirror )
  2820. pos.y = -aInstance->y.ToSchUnits() + text->y.ToSchUnits();
  2821. aField->SetPosition( pos );
  2822. }
  2823. }
  2824. }
  2825. }