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.

2590 lines
82 KiB

13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  5. * Copyright (C) 2012-2019 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. /*
  25. Pcbnew PLUGIN for Eagle 6.x XML *.brd and footprint format.
  26. XML parsing and converting:
  27. Getting line numbers and byte offsets from the source XML file is not
  28. possible using currently available XML libraries within KiCad project:
  29. wxXmlDocument and boost::property_tree.
  30. property_tree will give line numbers but no byte offsets, and only during
  31. document loading. This means that if we have a problem after the document is
  32. successfully loaded, there is no way to correlate back to line number and byte
  33. offset of the problem. So a different approach is taken, one which relies on the
  34. XML elements themselves using an XPATH type of reporting mechanism. The path to
  35. the problem is reported in the error messages. This means keeping track of that
  36. path as we traverse the XML document for the sole purpose of accurate error
  37. reporting.
  38. User can load the source XML file into firefox or other xml browser and follow
  39. our error message.
  40. Load() TODO's
  41. *) verify zone fill clearances are correct
  42. */
  43. #include <cerrno>
  44. #include <wx/string.h>
  45. #include <wx/xml/xml.h>
  46. #include <common.h>
  47. #include <convert_basic_shapes_to_polygon.h>
  48. #include <fctsys.h>
  49. #include <geometry/geometry_utils.h>
  50. #include <kicad_string.h>
  51. #include <macros.h>
  52. #include <properties.h>
  53. #include <trigo.h>
  54. #include <wx/filename.h>
  55. #include <math/util.h> // for KiROUND
  56. #include <class_board.h>
  57. #include <class_module.h>
  58. #include <class_track.h>
  59. #include <class_edge_mod.h>
  60. #include <class_zone.h>
  61. #include <class_pcb_text.h>
  62. #include <class_dimension.h>
  63. #include <eagle_plugin.h>
  64. using namespace std;
  65. typedef MODULE_MAP::iterator MODULE_ITER;
  66. typedef MODULE_MAP::const_iterator MODULE_CITER;
  67. /// Parse an eagle distance which is either mm, or mils if there is "mil" suffix.
  68. /// Return is in BIU.
  69. static int parseEagle( const wxString& aDistance )
  70. {
  71. ECOORD::EAGLE_UNIT unit = ( aDistance.npos != aDistance.find( "mil" ) )
  72. ? ECOORD::EAGLE_UNIT::EU_MIL : ECOORD::EAGLE_UNIT::EU_MM;
  73. ECOORD coord( aDistance, unit );
  74. return coord.ToPcbUnits();
  75. }
  76. // In Eagle one can specify DRC rules where min value > max value,
  77. // in such case the max value has the priority
  78. template<typename T>
  79. static T eagleClamp( T aMin, T aValue, T aMax )
  80. {
  81. T ret = std::max( aMin, aValue );
  82. return std::min( aMax, ret );
  83. }
  84. /// Assemble a two part key as a simple concatenation of aFirst and aSecond parts,
  85. /// using a separator.
  86. static wxString makeKey( const wxString& aFirst, const wxString& aSecond )
  87. {
  88. wxString key = aFirst + '\x02' + aSecond;
  89. return key;
  90. }
  91. void ERULES::parse( wxXmlNode* aRules )
  92. {
  93. wxXmlNode* child = aRules->GetChildren();
  94. while( child )
  95. {
  96. if( child->GetName() == "param" )
  97. {
  98. const wxString& name = child->GetAttribute( "name" );
  99. const wxString& value = child->GetAttribute( "value" );
  100. if( name == "psElongationLong" )
  101. psElongationLong = wxAtoi( value );
  102. else if( name == "psElongationOffset" )
  103. psElongationOffset = wxAtoi( value );
  104. else if( name == "mvStopFrame" )
  105. value.ToDouble( &mvStopFrame );
  106. else if( name == "mvCreamFrame" )
  107. value.ToDouble( &mvCreamFrame );
  108. else if( name == "mlMinStopFrame" )
  109. mlMinStopFrame = parseEagle( value );
  110. else if( name == "mlMaxStopFrame" )
  111. mlMaxStopFrame = parseEagle( value );
  112. else if( name == "mlMinCreamFrame" )
  113. mlMinCreamFrame = parseEagle( value );
  114. else if( name == "mlMaxCreamFrame" )
  115. mlMaxCreamFrame = parseEagle( value );
  116. else if( name == "srRoundness" )
  117. value.ToDouble( &srRoundness );
  118. else if( name == "srMinRoundness" )
  119. srMinRoundness = parseEagle( value );
  120. else if( name == "srMaxRoundness" )
  121. srMaxRoundness = parseEagle( value );
  122. else if( name == "psTop" )
  123. psTop = wxAtoi( value );
  124. else if( name == "psBottom" )
  125. psBottom = wxAtoi( value );
  126. else if( name == "psFirst" )
  127. psFirst = wxAtoi( value );
  128. else if( name == "rvPadTop" )
  129. value.ToDouble( &rvPadTop );
  130. else if( name == "rlMinPadTop" )
  131. rlMinPadTop = parseEagle( value );
  132. else if( name == "rlMaxPadTop" )
  133. rlMaxPadTop = parseEagle( value );
  134. else if( name == "rvViaOuter" )
  135. value.ToDouble( &rvViaOuter );
  136. else if( name == "rlMinViaOuter" )
  137. rlMinViaOuter = parseEagle( value );
  138. else if( name == "rlMaxViaOuter" )
  139. rlMaxViaOuter = parseEagle( value );
  140. else if( name == "mdWireWire" )
  141. mdWireWire = parseEagle( value );
  142. }
  143. child = child->GetNext();
  144. }
  145. }
  146. EAGLE_PLUGIN::EAGLE_PLUGIN() :
  147. m_rules( new ERULES() ),
  148. m_xpath( new XPATH() ),
  149. m_mod_time( wxDateTime::Now() )
  150. {
  151. init( NULL );
  152. clear_cu_map();
  153. }
  154. EAGLE_PLUGIN::~EAGLE_PLUGIN()
  155. {
  156. deleteTemplates();
  157. delete m_rules;
  158. delete m_xpath;
  159. }
  160. const wxString EAGLE_PLUGIN::PluginName() const
  161. {
  162. return wxT( "Eagle" );
  163. }
  164. const wxString EAGLE_PLUGIN::GetFileExtension() const
  165. {
  166. return wxT( "brd" );
  167. }
  168. wxSize inline EAGLE_PLUGIN::kicad_fontz( const ECOORD& d ) const
  169. {
  170. // texts seem to better match eagle when scaled down by 0.95
  171. int kz = d.ToPcbUnits() * 95 / 100;
  172. return wxSize( kz, kz );
  173. }
  174. BOARD* EAGLE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties )
  175. {
  176. LOCALE_IO toggle; // toggles on, then off, the C locale.
  177. wxXmlNode* doc;
  178. init( aProperties );
  179. m_board = aAppendToMe ? aAppendToMe : new BOARD();
  180. // Give the filename to the board if it's new
  181. if( !aAppendToMe )
  182. m_board->SetFileName( aFileName );
  183. // delete on exception, if I own m_board, according to aAppendToMe
  184. unique_ptr<BOARD> deleter( aAppendToMe ? NULL : m_board );
  185. try
  186. {
  187. // Load the document
  188. wxXmlDocument xmlDocument;
  189. wxFileName fn = aFileName;
  190. if( !xmlDocument.Load( fn.GetFullPath() ) )
  191. THROW_IO_ERROR( wxString::Format( _( "Unable to read file \"%s\"" ),
  192. fn.GetFullPath() ) );
  193. doc = xmlDocument.GetRoot();
  194. m_min_trace = INT_MAX;
  195. m_min_via = INT_MAX;
  196. m_min_via_hole = INT_MAX;
  197. loadAllSections( doc );
  198. BOARD_DESIGN_SETTINGS& designSettings = m_board->GetDesignSettings();
  199. if( m_min_trace < designSettings.m_TrackMinWidth )
  200. designSettings.m_TrackMinWidth = m_min_trace;
  201. if( m_min_via < designSettings.m_ViasMinSize )
  202. designSettings.m_ViasMinSize = m_min_via;
  203. if( m_min_via_hole < designSettings.m_ViasMinDrill )
  204. designSettings.m_ViasMinDrill = m_min_via_hole;
  205. if( m_rules->mdWireWire )
  206. {
  207. NETCLASSPTR defaultNetclass = designSettings.GetDefault();
  208. int clearance = KiROUND( m_rules->mdWireWire );
  209. if( clearance < defaultNetclass->GetClearance() )
  210. defaultNetclass->SetClearance( clearance );
  211. }
  212. // should be empty, else missing m_xpath->pop()
  213. wxASSERT( m_xpath->Contents().size() == 0 );
  214. }
  215. // Catch all exceptions thrown from the parser.
  216. catch( const XML_PARSER_ERROR &exc )
  217. {
  218. wxString errmsg = exc.what();
  219. errmsg += "\n@ ";
  220. errmsg += m_xpath->Contents();
  221. THROW_IO_ERROR( errmsg );
  222. }
  223. // IO_ERROR exceptions are left uncaught, they pass upwards from here.
  224. // Ensure the copper layers count is a multiple of 2
  225. // Pcbnew does not like boards with odd layers count
  226. // (these boards cannot exist. they actually have a even layers count)
  227. int lyrcnt = m_board->GetCopperLayerCount();
  228. if( (lyrcnt % 2) != 0 )
  229. {
  230. lyrcnt++;
  231. m_board->SetCopperLayerCount( lyrcnt );
  232. }
  233. centerBoard();
  234. deleter.release();
  235. return m_board;
  236. }
  237. void EAGLE_PLUGIN::init( const PROPERTIES* aProperties )
  238. {
  239. m_hole_count = 0;
  240. m_min_trace = 0;
  241. m_min_via = 0;
  242. m_min_via_hole = 0;
  243. m_xpath->clear();
  244. m_pads_to_nets.clear();
  245. m_board = NULL;
  246. m_props = aProperties;
  247. delete m_rules;
  248. m_rules = new ERULES();
  249. }
  250. void EAGLE_PLUGIN::clear_cu_map()
  251. {
  252. // All cu layers are invalid until we see them in the <layers> section while
  253. // loading either a board or library. See loadLayerDefs().
  254. for( unsigned i = 0; i < arrayDim(m_cu_map); ++i )
  255. m_cu_map[i] = -1;
  256. }
  257. void EAGLE_PLUGIN::loadAllSections( wxXmlNode* aDoc )
  258. {
  259. wxXmlNode* drawing = MapChildren( aDoc )["drawing"];
  260. NODE_MAP drawingChildren = MapChildren( drawing );
  261. wxXmlNode* board = drawingChildren["board"];
  262. NODE_MAP boardChildren = MapChildren( board );
  263. m_xpath->push( "eagle.drawing" );
  264. {
  265. m_xpath->push( "board" );
  266. wxXmlNode* designrules = boardChildren["designrules"];
  267. loadDesignRules( designrules );
  268. m_xpath->pop();
  269. }
  270. {
  271. m_xpath->push( "layers" );
  272. wxXmlNode* layers = drawingChildren["layers"];
  273. loadLayerDefs( layers );
  274. m_xpath->pop();
  275. }
  276. {
  277. m_xpath->push( "board" );
  278. wxXmlNode* plain = boardChildren["plain"];
  279. loadPlain( plain );
  280. wxXmlNode* signals = boardChildren["signals"];
  281. loadSignals( signals );
  282. wxXmlNode* libs = boardChildren["libraries"];
  283. loadLibraries( libs );
  284. wxXmlNode* elems = boardChildren["elements"];
  285. loadElements( elems );
  286. m_xpath->pop(); // "board"
  287. }
  288. m_xpath->pop(); // "eagle.drawing"
  289. }
  290. void EAGLE_PLUGIN::loadDesignRules( wxXmlNode* aDesignRules )
  291. {
  292. if( aDesignRules )
  293. {
  294. m_xpath->push( "designrules" );
  295. m_rules->parse( aDesignRules );
  296. m_xpath->pop(); // "designrules"
  297. }
  298. }
  299. void EAGLE_PLUGIN::loadLayerDefs( wxXmlNode* aLayers )
  300. {
  301. if( !aLayers )
  302. return;
  303. ELAYERS cu; // copper layers
  304. // Get the first layer and iterate
  305. wxXmlNode* layerNode = aLayers->GetChildren();
  306. m_eagleLayers.clear();
  307. while( layerNode )
  308. {
  309. ELAYER elayer( layerNode );
  310. m_eagleLayers.insert( std::make_pair( elayer.number, elayer ) );
  311. // find the subset of layers that are copper and active
  312. if( elayer.number >= 1 && elayer.number <= 16 && ( !elayer.active || *elayer.active ) )
  313. {
  314. cu.push_back( elayer );
  315. }
  316. layerNode = layerNode->GetNext();
  317. }
  318. // establish cu layer map:
  319. int ki_layer_count = 0;
  320. for( EITER it = cu.begin(); it != cu.end(); ++it, ++ki_layer_count )
  321. {
  322. if( ki_layer_count == 0 )
  323. m_cu_map[it->number] = F_Cu;
  324. else if( ki_layer_count == int( cu.size()-1 ) )
  325. m_cu_map[it->number] = B_Cu;
  326. else
  327. {
  328. // some eagle boards do not have contiguous layer number sequences.
  329. #if 0 // pre PCB_LAYER_ID & LSET:
  330. m_cu_map[it->number] = cu.size() - 1 - ki_layer_count;
  331. #else
  332. m_cu_map[it->number] = ki_layer_count;
  333. #endif
  334. }
  335. }
  336. #if 0 && defined(DEBUG)
  337. printf( "m_cu_map:\n" );
  338. for( unsigned i=0; i<arrayDim(m_cu_map); ++i )
  339. {
  340. printf( "\t[%d]:%d\n", i, m_cu_map[i] );
  341. }
  342. #endif
  343. // Set the layer names and cu count if we're loading a board.
  344. if( m_board )
  345. {
  346. m_board->SetCopperLayerCount( cu.size() );
  347. for( EITER it = cu.begin(); it != cu.end(); ++it )
  348. {
  349. PCB_LAYER_ID layer = kicad_layer( it->number );
  350. // these function provide their own protection against UNDEFINED_LAYER:
  351. m_board->SetLayerName( layer, FROM_UTF8( it->name.c_str() ) );
  352. m_board->SetLayerType( layer, LT_SIGNAL );
  353. // could map the colors here
  354. }
  355. }
  356. }
  357. #define DIMENSION_PRECISION 1 // 0.001 mm
  358. void EAGLE_PLUGIN::loadPlain( wxXmlNode* aGraphics )
  359. {
  360. if( !aGraphics )
  361. return;
  362. m_xpath->push( "plain" );
  363. // Get the first graphic and iterate
  364. wxXmlNode* gr = aGraphics->GetChildren();
  365. // (polygon | wire | text | circle | rectangle | frame | hole)*
  366. while( gr )
  367. {
  368. wxString grName = gr->GetName();
  369. if( grName == "wire" )
  370. {
  371. m_xpath->push( "wire" );
  372. EWIRE w( gr );
  373. PCB_LAYER_ID layer = kicad_layer( w.layer );
  374. wxPoint start( kicad_x( w.x1 ), kicad_y( w.y1 ) );
  375. wxPoint end( kicad_x( w.x2 ), kicad_y( w.y2 ) );
  376. if( layer != UNDEFINED_LAYER )
  377. {
  378. DRAWSEGMENT* dseg = new DRAWSEGMENT( m_board );
  379. int width = w.width.ToPcbUnits();
  380. // KiCad cannot handle zero or negative line widths
  381. if( width <= 0 )
  382. width = m_board->GetDesignSettings().GetLineThickness( layer );
  383. m_board->Add( dseg, ADD_MODE::APPEND );
  384. if( !w.curve )
  385. {
  386. dseg->SetStart( start );
  387. dseg->SetEnd( end );
  388. }
  389. else
  390. {
  391. wxPoint center = ConvertArcCenter( start, end, *w.curve );
  392. dseg->SetShape( S_ARC );
  393. dseg->SetStart( center );
  394. dseg->SetEnd( start );
  395. dseg->SetAngle( *w.curve * -10.0 ); // KiCad rotates the other way
  396. }
  397. dseg->SetTimeStamp( EagleTimeStamp( gr ) );
  398. dseg->SetLayer( layer );
  399. dseg->SetWidth( width );
  400. }
  401. m_xpath->pop();
  402. }
  403. else if( grName == "text" )
  404. {
  405. m_xpath->push( "text" );
  406. ETEXT t( gr );
  407. PCB_LAYER_ID layer = kicad_layer( t.layer );
  408. if( layer != UNDEFINED_LAYER )
  409. {
  410. TEXTE_PCB* pcbtxt = new TEXTE_PCB( m_board );
  411. m_board->Add( pcbtxt, ADD_MODE::APPEND );
  412. pcbtxt->SetLayer( layer );
  413. pcbtxt->SetTimeStamp( EagleTimeStamp( gr ) );
  414. pcbtxt->SetText( FROM_UTF8( t.text.c_str() ) );
  415. pcbtxt->SetTextPos( wxPoint( kicad_x( t.x ), kicad_y( t.y ) ) );
  416. pcbtxt->SetTextSize( kicad_fontz( t.size ) );
  417. double ratio = t.ratio ? *t.ratio : 8; // DTD says 8 is default
  418. pcbtxt->SetThickness( t.size.ToPcbUnits() * ratio / 100 );
  419. int align = t.align ? *t.align : ETEXT::BOTTOM_LEFT;
  420. if( t.rot )
  421. {
  422. int sign = t.rot->mirror ? -1 : 1;
  423. pcbtxt->SetMirrored( t.rot->mirror );
  424. double degrees = t.rot->degrees;
  425. if( degrees == 90 || t.rot->spin )
  426. pcbtxt->SetTextAngle( sign * t.rot->degrees * 10 );
  427. else if( degrees == 180 )
  428. align = ETEXT::TOP_RIGHT;
  429. else if( degrees == 270 )
  430. {
  431. pcbtxt->SetTextAngle( sign * 90 * 10 );
  432. align = ETEXT::TOP_RIGHT;
  433. }
  434. else // Ok so text is not at 90,180 or 270 so do some funny stuff to get placement right
  435. {
  436. if( ( degrees > 0 ) && ( degrees < 90 ) )
  437. pcbtxt->SetTextAngle( sign * t.rot->degrees * 10 );
  438. else if( ( degrees > 90 ) && ( degrees < 180 ) )
  439. {
  440. pcbtxt->SetTextAngle( sign * ( t.rot->degrees + 180 ) * 10 );
  441. align = ETEXT::TOP_RIGHT;
  442. }
  443. else if( ( degrees > 180 ) && ( degrees < 270 ) )
  444. {
  445. pcbtxt->SetTextAngle( sign * ( t.rot->degrees - 180 ) * 10 );
  446. align = ETEXT::TOP_RIGHT;
  447. }
  448. else if( ( degrees > 270 ) && ( degrees < 360 ) )
  449. {
  450. pcbtxt->SetTextAngle( sign * t.rot->degrees * 10 );
  451. align = ETEXT::BOTTOM_LEFT;
  452. }
  453. }
  454. }
  455. switch( align )
  456. {
  457. case ETEXT::CENTER:
  458. // this was the default in pcbtxt's constructor
  459. break;
  460. case ETEXT::CENTER_LEFT:
  461. pcbtxt->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  462. break;
  463. case ETEXT::CENTER_RIGHT:
  464. pcbtxt->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  465. break;
  466. case ETEXT::TOP_CENTER:
  467. pcbtxt->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
  468. break;
  469. case ETEXT::TOP_LEFT:
  470. pcbtxt->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  471. pcbtxt->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
  472. break;
  473. case ETEXT::TOP_RIGHT:
  474. pcbtxt->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  475. pcbtxt->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
  476. break;
  477. case ETEXT::BOTTOM_CENTER:
  478. pcbtxt->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  479. break;
  480. case ETEXT::BOTTOM_LEFT:
  481. pcbtxt->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  482. pcbtxt->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  483. break;
  484. case ETEXT::BOTTOM_RIGHT:
  485. pcbtxt->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  486. pcbtxt->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  487. break;
  488. }
  489. }
  490. m_xpath->pop();
  491. }
  492. else if( grName == "circle" )
  493. {
  494. m_xpath->push( "circle" );
  495. ECIRCLE c( gr );
  496. PCB_LAYER_ID layer = kicad_layer( c.layer );
  497. if( layer != UNDEFINED_LAYER ) // unsupported layer
  498. {
  499. DRAWSEGMENT* dseg = new DRAWSEGMENT( m_board );
  500. m_board->Add( dseg, ADD_MODE::APPEND );
  501. int width = c.width.ToPcbUnits();
  502. int radius = c.radius.ToPcbUnits();
  503. // with == 0 means filled circle
  504. if( width <= 0 )
  505. {
  506. width = radius;
  507. radius = radius / 2;
  508. }
  509. dseg->SetShape( S_CIRCLE );
  510. dseg->SetTimeStamp( EagleTimeStamp( gr ) );
  511. dseg->SetLayer( layer );
  512. dseg->SetStart( wxPoint( kicad_x( c.x ), kicad_y( c.y ) ) );
  513. dseg->SetEnd( wxPoint( kicad_x( c.x ) + radius, kicad_y( c.y ) ) );
  514. dseg->SetWidth( width );
  515. }
  516. m_xpath->pop();
  517. }
  518. else if( grName == "rectangle" )
  519. {
  520. // This seems to be a simplified rectangular [copper] zone, cannot find any
  521. // net related info on it from the DTD.
  522. m_xpath->push( "rectangle" );
  523. ERECT r( gr );
  524. PCB_LAYER_ID layer = kicad_layer( r.layer );
  525. if( IsCopperLayer( layer ) )
  526. {
  527. // use a "netcode = 0" type ZONE:
  528. ZONE_CONTAINER* zone = new ZONE_CONTAINER( m_board );
  529. m_board->Add( zone, ADD_MODE::APPEND );
  530. zone->SetTimeStamp( EagleTimeStamp( gr ) );
  531. zone->SetLayer( layer );
  532. zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
  533. ZONE_HATCH_STYLE outline_hatch = ZONE_HATCH_STYLE::DIAGONAL_EDGE;
  534. const int outlineIdx = -1; // this is the id of the copper zone main outline
  535. zone->AppendCorner( wxPoint( kicad_x( r.x1 ), kicad_y( r.y1 ) ), outlineIdx );
  536. zone->AppendCorner( wxPoint( kicad_x( r.x2 ), kicad_y( r.y1 ) ), outlineIdx );
  537. zone->AppendCorner( wxPoint( kicad_x( r.x2 ), kicad_y( r.y2 ) ), outlineIdx );
  538. zone->AppendCorner( wxPoint( kicad_x( r.x1 ), kicad_y( r.y2 ) ), outlineIdx );
  539. if( r.rot )
  540. {
  541. zone->Rotate( zone->GetPosition(), r.rot->degrees * 10 );
  542. }
  543. // this is not my fault:
  544. zone->SetHatch( outline_hatch, zone->GetDefaultHatchPitch(), true );
  545. }
  546. m_xpath->pop();
  547. }
  548. else if( grName == "hole" )
  549. {
  550. m_xpath->push( "hole" );
  551. // Fabricate a MODULE with a single PAD_ATTRIB_HOLE_NOT_PLATED pad.
  552. // Use m_hole_count to gen up a unique name.
  553. MODULE* module = new MODULE( m_board );
  554. m_board->Add( module, ADD_MODE::APPEND );
  555. module->SetReference( wxString::Format( "@HOLE%d", m_hole_count++ ) );
  556. module->Reference().SetVisible( false );
  557. packageHole( module, gr, true );
  558. m_xpath->pop();
  559. }
  560. else if( grName == "frame" )
  561. {
  562. // picture this
  563. }
  564. else if( grName == "polygon" )
  565. {
  566. m_xpath->push( "polygon" );
  567. loadPolygon( gr );
  568. m_xpath->pop(); // "polygon"
  569. }
  570. else if( grName == "dimension" )
  571. {
  572. EDIMENSION d( gr );
  573. PCB_LAYER_ID layer = kicad_layer( d.layer );
  574. if( layer != UNDEFINED_LAYER )
  575. {
  576. const BOARD_DESIGN_SETTINGS& designSettings = m_board->GetDesignSettings();
  577. DIMENSION* dimension = new DIMENSION( m_board );
  578. m_board->Add( dimension, ADD_MODE::APPEND );
  579. if( d.dimensionType )
  580. {
  581. // Eagle dimension graphic arms may have different lengths, but they look
  582. // incorrect in KiCad (the graphic is tilted). Make them even length in such case.
  583. if( *d.dimensionType == "horizontal" )
  584. {
  585. int newY = ( d.y1.ToPcbUnits() + d.y2.ToPcbUnits() ) / 2;
  586. d.y1 = ECOORD( newY, ECOORD::EAGLE_UNIT::EU_NM );
  587. d.y2 = ECOORD( newY, ECOORD::EAGLE_UNIT::EU_NM );
  588. }
  589. else if( *d.dimensionType == "vertical" )
  590. {
  591. int newX = ( d.x1.ToPcbUnits() + d.x2.ToPcbUnits() ) / 2;
  592. d.x1 = ECOORD( newX, ECOORD::EAGLE_UNIT::EU_NM );
  593. d.x2 = ECOORD( newX, ECOORD::EAGLE_UNIT::EU_NM );
  594. }
  595. }
  596. dimension->SetLayer( layer );
  597. // The origin and end are assumed to always be in this order from eagle
  598. dimension->SetOrigin( wxPoint( kicad_x( d.x1 ), kicad_y( d.y1 ) ),
  599. DIMENSION_PRECISION );
  600. dimension->SetEnd( wxPoint( kicad_x( d.x2 ), kicad_y( d.y2 ) ),
  601. DIMENSION_PRECISION );
  602. dimension->Text().SetTextSize( designSettings.GetTextSize( layer ) );
  603. dimension->Text().SetThickness( designSettings.GetTextThickness( layer ) );
  604. dimension->SetWidth( designSettings.GetLineThickness( layer ) );
  605. dimension->SetUnits( EDA_UNITS::MILLIMETRES, false );
  606. // check which axis the dimension runs in
  607. // because the "height" of the dimension is perpendicular to that axis
  608. // Note the check is just if two axes are close enough to each other
  609. // Eagle appears to have some rounding errors
  610. if( abs( ( d.x1 - d.x2 ).ToPcbUnits() ) < 50000 ) // 50000 nm = 0.05 mm
  611. dimension->SetHeight( kicad_x( d.x3 - d.x1 ), DIMENSION_PRECISION );
  612. else
  613. dimension->SetHeight( kicad_y( d.y3 - d.y1 ), DIMENSION_PRECISION );
  614. dimension->AdjustDimensionDetails( DIMENSION_PRECISION );
  615. }
  616. }
  617. // Get next graphic
  618. gr = gr->GetNext();
  619. }
  620. m_xpath->pop();
  621. }
  622. void EAGLE_PLUGIN::loadLibrary( wxXmlNode* aLib, const wxString* aLibName )
  623. {
  624. if( !aLib )
  625. return;
  626. // library will have <xmlattr> node, skip that and get the single packages node
  627. wxXmlNode* packages = MapChildren( aLib )["packages"];
  628. if( !packages )
  629. return;
  630. m_xpath->push( "packages" );
  631. // Create a MODULE for all the eagle packages, for use later via a copy constructor
  632. // to instantiate needed MODULES in our BOARD. Save the MODULE templates in
  633. // a MODULE_MAP using a single lookup key consisting of libname+pkgname.
  634. // Get the first package and iterate
  635. wxXmlNode* package = packages->GetChildren();
  636. while( package )
  637. {
  638. m_xpath->push( "package", "name" );
  639. wxString pack_ref = package->GetAttribute( "name" );
  640. ReplaceIllegalFileNameChars( pack_ref, '_' );
  641. m_xpath->Value( pack_ref.ToUTF8() );
  642. wxString key = aLibName ? makeKey( *aLibName, pack_ref ) : pack_ref;
  643. MODULE* m = makeModule( package, pack_ref );
  644. // add the templating MODULE to the MODULE template factory "m_templates"
  645. std::pair<MODULE_ITER, bool> r = m_templates.insert( {key, m} );
  646. if( !r.second
  647. // && !( m_props && m_props->Value( "ignore_duplicates" ) )
  648. )
  649. {
  650. wxString lib = aLibName ? *aLibName : m_lib_path;
  651. const wxString& pkg = pack_ref;
  652. wxString emsg = wxString::Format(
  653. _( "<package> name: \"%s\" duplicated in eagle <library>: \"%s\"" ),
  654. GetChars( pkg ),
  655. GetChars( lib )
  656. );
  657. THROW_IO_ERROR( emsg );
  658. }
  659. m_xpath->pop();
  660. package = package->GetNext();
  661. }
  662. m_xpath->pop(); // "packages"
  663. }
  664. void EAGLE_PLUGIN::loadLibraries( wxXmlNode* aLibs )
  665. {
  666. if( !aLibs )
  667. return;
  668. m_xpath->push( "libraries.library", "name" );
  669. // Get the first library and iterate
  670. wxXmlNode* library = aLibs->GetChildren();
  671. while( library )
  672. {
  673. const wxString& lib_name = library->GetAttribute( "name" );
  674. m_xpath->Value( lib_name.c_str() );
  675. loadLibrary( library, &lib_name );
  676. library = library->GetNext();
  677. }
  678. m_xpath->pop();
  679. }
  680. void EAGLE_PLUGIN::loadElements( wxXmlNode* aElements )
  681. {
  682. if( !aElements )
  683. return;
  684. m_xpath->push( "elements.element", "name" );
  685. EATTR name;
  686. EATTR value;
  687. bool refanceNamePresetInPackageLayout;
  688. bool valueNamePresetInPackageLayout;
  689. // Get the first element and iterate
  690. wxXmlNode* element = aElements->GetChildren();
  691. while( element )
  692. {
  693. if( element->GetName() != "element" )
  694. {
  695. wxLogDebug( "expected: <element> read <%s>. Skip it", element->GetName() );
  696. // Get next item
  697. element = element->GetNext();
  698. continue;
  699. }
  700. EELEMENT e( element );
  701. // use "NULL-ness" as an indication of presence of the attribute:
  702. EATTR* nameAttr = 0;
  703. EATTR* valueAttr = 0;
  704. m_xpath->Value( e.name.c_str() );
  705. wxString pkg_key = makeKey( e.library, e.package );
  706. MODULE_CITER mi = m_templates.find( pkg_key );
  707. if( mi == m_templates.end() )
  708. {
  709. wxString emsg = wxString::Format( _( "No \"%s\" package in library \"%s\"" ),
  710. GetChars( FROM_UTF8( e.package.c_str() ) ),
  711. GetChars( FROM_UTF8( e.library.c_str() ) ) );
  712. THROW_IO_ERROR( emsg );
  713. }
  714. // copy constructor to clone the template
  715. MODULE* m = new MODULE( *mi->second );
  716. m_board->Add( m, ADD_MODE::APPEND );
  717. // update the nets within the pads of the clone
  718. for( auto pad : m->Pads() )
  719. {
  720. wxString pn_key = makeKey( e.name, pad->GetName() );
  721. NET_MAP_CITER ni = m_pads_to_nets.find( pn_key );
  722. if( ni != m_pads_to_nets.end() )
  723. {
  724. const ENET* enet = &ni->second;
  725. pad->SetNetCode( enet->netcode );
  726. }
  727. }
  728. refanceNamePresetInPackageLayout = true;
  729. valueNamePresetInPackageLayout = true;
  730. m->SetPosition( wxPoint( kicad_x( e.x ), kicad_y( e.y ) ) );
  731. // Is >NAME field set in package layout ?
  732. if( m->GetReference().size() == 0 )
  733. {
  734. m->Reference().SetVisible( false ); // No so no show
  735. refanceNamePresetInPackageLayout = false;
  736. }
  737. // Is >VALUE field set in package layout
  738. if( m->GetValue().size() == 0 )
  739. {
  740. m->Value().SetVisible( false ); // No so no show
  741. valueNamePresetInPackageLayout = false;
  742. }
  743. m->SetReference( FROM_UTF8( e.name.c_str() ) );
  744. m->SetValue( FROM_UTF8( e.value.c_str() ) );
  745. if( !e.smashed )
  746. { // Not smashed so show NAME & VALUE
  747. if( valueNamePresetInPackageLayout )
  748. m->Value().SetVisible( true ); // Only if place holder in package layout
  749. if( refanceNamePresetInPackageLayout )
  750. m->Reference().SetVisible( true ); // Only if place holder in package layout
  751. }
  752. else if( *e.smashed == true )
  753. { // Smashed so set default to no show for NAME and VALUE
  754. m->Value().SetVisible( false );
  755. m->Reference().SetVisible( false );
  756. // initialize these to default values in case the <attribute> elements are not present.
  757. m_xpath->push( "attribute", "name" );
  758. // VALUE and NAME can have something like our text "effects" overrides
  759. // in SWEET and new schematic. Eagle calls these XML elements "attribute".
  760. // There can be one for NAME and/or VALUE both. Features present in the
  761. // EATTR override the ones established in the package only if they are
  762. // present here (except for rot, which if not present means angle zero).
  763. // So the logic is a bit different than in packageText() and in plain text.
  764. // Get the first attribute and iterate
  765. wxXmlNode* attribute = element->GetChildren();
  766. while( attribute )
  767. {
  768. if( attribute->GetName() != "attribute" )
  769. {
  770. wxLogDebug( "expected: <attribute> read <%s>. Skip it", attribute->GetName() );
  771. attribute = attribute->GetNext();
  772. continue;
  773. }
  774. EATTR a( attribute );
  775. if( a.name == "NAME" )
  776. {
  777. name = a;
  778. nameAttr = &name;
  779. // do we have a display attribute ?
  780. if( a.display )
  781. {
  782. // Yes!
  783. switch( *a.display )
  784. {
  785. case EATTR::VALUE :
  786. {
  787. wxString reference = e.name;
  788. // EAGLE allows references to be single digits. This breaks KiCad netlisting, which requires
  789. // parts to have non-digit + digit annotation. If the reference begins with a number,
  790. // we prepend 'UNK' (unknown) for the symbol designator
  791. if( reference.find_first_not_of( "0123456789" ) == wxString::npos )
  792. reference.Prepend( "UNK" );
  793. nameAttr->name = reference;
  794. m->SetReference( reference );
  795. if( refanceNamePresetInPackageLayout )
  796. m->Reference().SetVisible( true );
  797. break;
  798. }
  799. case EATTR::NAME :
  800. if( refanceNamePresetInPackageLayout )
  801. {
  802. m->SetReference( "NAME" );
  803. m->Reference().SetVisible( true );
  804. }
  805. break;
  806. case EATTR::BOTH :
  807. if( refanceNamePresetInPackageLayout )
  808. m->Reference().SetVisible( true );
  809. nameAttr->name = nameAttr->name + " = " + e.name;
  810. m->SetReference( "NAME = " + e.name );
  811. break;
  812. case EATTR::Off :
  813. m->Reference().SetVisible( false );
  814. break;
  815. default:
  816. nameAttr->name = e.name;
  817. if( refanceNamePresetInPackageLayout )
  818. m->Reference().SetVisible( true );
  819. }
  820. }
  821. else
  822. // No display, so default is visible, and show value of NAME
  823. m->Reference().SetVisible( true );
  824. }
  825. else if( a.name == "VALUE" )
  826. {
  827. value = a;
  828. valueAttr = &value;
  829. if( a.display )
  830. {
  831. // Yes!
  832. switch( *a.display )
  833. {
  834. case EATTR::VALUE :
  835. valueAttr->value = opt_wxString( e.value );
  836. m->SetValue( e.value );
  837. if( valueNamePresetInPackageLayout )
  838. m->Value().SetVisible( true );
  839. break;
  840. case EATTR::NAME :
  841. if( valueNamePresetInPackageLayout )
  842. m->Value().SetVisible( true );
  843. m->SetValue( "VALUE" );
  844. break;
  845. case EATTR::BOTH :
  846. if( valueNamePresetInPackageLayout )
  847. m->Value().SetVisible( true );
  848. valueAttr->value = opt_wxString( "VALUE = " + e.value );
  849. m->SetValue( "VALUE = " + e.value );
  850. break;
  851. case EATTR::Off :
  852. m->Value().SetVisible( false );
  853. break;
  854. default:
  855. valueAttr->value = opt_wxString( e.value );
  856. if( valueNamePresetInPackageLayout )
  857. m->Value().SetVisible( true );
  858. }
  859. }
  860. else
  861. // No display, so default is visible, and show value of NAME
  862. m->Value().SetVisible( true );
  863. }
  864. attribute = attribute->GetNext();
  865. }
  866. m_xpath->pop(); // "attribute"
  867. }
  868. orientModuleAndText( m, e, nameAttr, valueAttr );
  869. // Set the local coordinates for the footprint text items
  870. m->Reference().SetLocalCoord();
  871. m->Value().SetLocalCoord();
  872. // Get next element
  873. element = element->GetNext();
  874. }
  875. m_xpath->pop(); // "elements.element"
  876. }
  877. ZONE_CONTAINER* EAGLE_PLUGIN::loadPolygon( wxXmlNode* aPolyNode )
  878. {
  879. EPOLYGON p( aPolyNode );
  880. PCB_LAYER_ID layer = kicad_layer( p.layer );
  881. ZONE_CONTAINER* zone = nullptr;
  882. bool keepout = ( p.layer == EAGLE_LAYER::TRESTRICT || p.layer == EAGLE_LAYER::BRESTRICT );
  883. if( !IsCopperLayer( layer ) && !keepout )
  884. return nullptr;
  885. // use a "netcode = 0" type ZONE:
  886. zone = new ZONE_CONTAINER( m_board );
  887. zone->SetTimeStamp( EagleTimeStamp( aPolyNode ) );
  888. m_board->Add( zone, ADD_MODE::APPEND );
  889. if( p.layer == EAGLE_LAYER::TRESTRICT ) // front layer keepout
  890. zone->SetLayer( F_Cu );
  891. else if( p.layer == EAGLE_LAYER::BRESTRICT ) // bottom layer keepout
  892. zone->SetLayer( B_Cu );
  893. else
  894. zone->SetLayer( layer );
  895. if( keepout )
  896. {
  897. zone->SetIsKeepout( true );
  898. zone->SetDoNotAllowVias( true );
  899. zone->SetDoNotAllowTracks( true );
  900. zone->SetDoNotAllowCopperPour( true );
  901. }
  902. // Get the first vertex and iterate
  903. wxXmlNode* vertex = aPolyNode->GetChildren();
  904. std::vector<EVERTEX> vertices;
  905. // Create a circular vector of vertices
  906. // The "curve" parameter indicates a curve from the current
  907. // to the next vertex, so we keep the first at the end as well
  908. // to allow the curve to link back
  909. while( vertex )
  910. {
  911. if( vertex->GetName() == "vertex" )
  912. vertices.emplace_back( vertex );
  913. vertex = vertex->GetNext();
  914. }
  915. vertices.push_back( vertices[0] );
  916. SHAPE_POLY_SET polygon;
  917. polygon.NewOutline();
  918. for( size_t i = 0; i < vertices.size() - 1; i++ )
  919. {
  920. EVERTEX v1 = vertices[i];
  921. // Append the corner
  922. polygon.Append( kicad_x( v1.x ), kicad_y( v1.y ) );
  923. if( v1.curve )
  924. {
  925. EVERTEX v2 = vertices[i + 1];
  926. wxPoint center = ConvertArcCenter(
  927. wxPoint( kicad_x( v1.x ), kicad_y( v1.y ) ),
  928. wxPoint( kicad_x( v2.x ), kicad_y( v2.y ) ), *v1.curve );
  929. double angle = DEG2RAD( *v1.curve );
  930. double end_angle = atan2( kicad_y( v2.y ) - center.y,
  931. kicad_x( v2.x ) - center.x );
  932. double radius = sqrt( pow( center.x - kicad_x( v1.x ), 2 )
  933. + pow( center.y - kicad_y( v1.y ), 2 ) );
  934. // If we are curving, we need at least 2 segments otherwise
  935. // delta_angle == angle
  936. double delta_angle = angle / std::max(
  937. 2, GetArcToSegmentCount( KiROUND( radius ),
  938. ARC_HIGH_DEF, *v1.curve ) - 1 );
  939. for( double a = end_angle + angle;
  940. fabs( a - end_angle ) > fabs( delta_angle );
  941. a -= delta_angle )
  942. {
  943. polygon.Append( KiROUND( radius * cos( a ) ) + center.x,
  944. KiROUND( radius * sin( a ) ) + center.y );
  945. }
  946. }
  947. }
  948. // Eagle traces the zone such that half of the pen width is outside the polygon.
  949. // We trace the zone such that the copper is completely inside.
  950. if( p.width.ToPcbUnits() > 0 )
  951. {
  952. polygon.Inflate( p.width.ToPcbUnits() / 2, 32, SHAPE_POLY_SET::ALLOW_ACUTE_CORNERS );
  953. polygon.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
  954. }
  955. zone->AddPolygon( polygon.COutline( 0 ) );
  956. // If the pour is a cutout it needs to be set to a keepout
  957. if( p.pour == EPOLYGON::CUTOUT )
  958. {
  959. zone->SetIsKeepout( true );
  960. zone->SetDoNotAllowCopperPour( true );
  961. zone->SetHatchStyle( ZONE_HATCH_STYLE::NO_HATCH );
  962. }
  963. else if( p.pour == EPOLYGON::HATCH )
  964. {
  965. int spacing = p.spacing ? p.spacing->ToPcbUnits() : 50 * IU_PER_MILS;
  966. zone->SetFillMode( ZONE_FILL_MODE::HATCH_PATTERN );
  967. zone->SetHatchFillTypeThickness( p.width.ToPcbUnits() );
  968. zone->SetHatchFillTypeGap( spacing - p.width.ToPcbUnits() );
  969. zone->SetHatchFillTypeOrientation( 0 );
  970. }
  971. // We divide the thickness by half because we are tracing _inside_ the zone outline
  972. // This means the radius of curvature will be twice the size for an equivalent EAGLE zone
  973. zone->SetMinThickness(
  974. std::max<int>( ZONE_THICKNESS_MIN_VALUE_MIL * IU_PER_MILS, p.width.ToPcbUnits() / 2 ) );
  975. if( p.isolate )
  976. zone->SetZoneClearance( p.isolate->ToPcbUnits() );
  977. else
  978. zone->SetZoneClearance( 1 ); // @todo: set minimum clearance value based on board settings
  979. // missing == yes per DTD.
  980. bool thermals = !p.thermals || *p.thermals;
  981. zone->SetPadConnection( thermals ? ZONE_CONNECTION::THERMAL : ZONE_CONNECTION::FULL );
  982. if( thermals )
  983. {
  984. // FIXME: eagle calculates dimensions for thermal spokes
  985. // based on what the zone is connecting to.
  986. // (i.e. width of spoke is half of the smaller side of an smd pad)
  987. // This is a basic workaround
  988. zone->SetThermalReliefGap( p.width.ToPcbUnits() + 50000 ); // 50000nm == 0.05mm
  989. zone->SetThermalReliefCopperBridge( p.width.ToPcbUnits() + 50000 );
  990. }
  991. int rank = p.rank ? (p.max_priority - *p.rank) : p.max_priority;
  992. zone->SetPriority( rank );
  993. return zone;
  994. }
  995. void EAGLE_PLUGIN::orientModuleAndText( MODULE* m, const EELEMENT& e, const EATTR* nameAttr,
  996. const EATTR* valueAttr )
  997. {
  998. if( e.rot )
  999. {
  1000. if( e.rot->mirror )
  1001. {
  1002. double orientation = e.rot->degrees + 180.0;
  1003. m->SetOrientation( orientation * 10 );
  1004. m->Flip( m->GetPosition(), false );
  1005. }
  1006. else
  1007. m->SetOrientation( e.rot->degrees * 10 );
  1008. }
  1009. orientModuleText( m, e, &m->Reference(), nameAttr );
  1010. orientModuleText( m, e, &m->Value(), valueAttr );
  1011. }
  1012. void EAGLE_PLUGIN::orientModuleText( MODULE* m, const EELEMENT& e,
  1013. TEXTE_MODULE* txt, const EATTR* aAttr )
  1014. {
  1015. // Smashed part ?
  1016. if( aAttr )
  1017. { // Yes
  1018. const EATTR& a = *aAttr;
  1019. if( a.value )
  1020. {
  1021. txt->SetText( FROM_UTF8( a.value->c_str() ) );
  1022. }
  1023. if( a.x && a.y ) // OPT
  1024. {
  1025. wxPoint pos( kicad_x( *a.x ), kicad_y( *a.y ) );
  1026. txt->SetTextPos( pos );
  1027. }
  1028. // Even though size and ratio are both optional, I am not seeing
  1029. // a case where ratio is present but size is not.
  1030. double ratio = 8;
  1031. wxSize fontz = txt->GetTextSize();
  1032. if( a.size )
  1033. {
  1034. fontz = kicad_fontz( *a.size );
  1035. txt->SetTextSize( fontz );
  1036. if( a.ratio )
  1037. ratio = *a.ratio;
  1038. }
  1039. int lw = int( fontz.y * ratio / 100 );
  1040. txt->SetThickness( lw );
  1041. int align = ETEXT::BOTTOM_LEFT; // bottom-left is eagle default
  1042. if( a.align )
  1043. align = a.align;
  1044. // The "rot" in a EATTR seems to be assumed to be zero if it is not
  1045. // present, and this zero rotation becomes an override to the
  1046. // package's text field. If they did not want zero, they specify
  1047. // what they want explicitly.
  1048. double degrees = a.rot ? a.rot->degrees : 0;
  1049. double orient; // relative to parent
  1050. int sign = 1;
  1051. bool spin = false;
  1052. if( a.rot )
  1053. {
  1054. spin = a.rot->spin;
  1055. sign = a.rot->mirror ? -1 : 1;
  1056. txt->SetMirrored( a.rot->mirror );
  1057. }
  1058. if( degrees == 90 || degrees == 0 || spin )
  1059. {
  1060. orient = degrees - m->GetOrientation() / 10;
  1061. txt->SetTextAngle( sign * orient * 10 );
  1062. }
  1063. else if( degrees == 180 )
  1064. {
  1065. orient = 0 - m->GetOrientation() / 10;
  1066. txt->SetTextAngle( sign * orient * 10 );
  1067. align = -align;
  1068. }
  1069. else if( degrees == 270 )
  1070. {
  1071. orient = 90 - m->GetOrientation() / 10;
  1072. align = -align;
  1073. txt->SetTextAngle( sign * orient * 10 );
  1074. }
  1075. else
  1076. {
  1077. orient = 90 - degrees - m->GetOrientation() / 10;
  1078. txt->SetTextAngle( sign * orient * 10 );
  1079. }
  1080. switch( align )
  1081. {
  1082. case ETEXT::TOP_RIGHT:
  1083. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  1084. txt->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
  1085. break;
  1086. case ETEXT::BOTTOM_LEFT:
  1087. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  1088. txt->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  1089. break;
  1090. case ETEXT::TOP_LEFT:
  1091. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  1092. txt->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
  1093. break;
  1094. case ETEXT::BOTTOM_RIGHT:
  1095. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  1096. txt->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  1097. break;
  1098. case ETEXT::TOP_CENTER:
  1099. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_CENTER );
  1100. txt->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
  1101. break;
  1102. case ETEXT::BOTTOM_CENTER:
  1103. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_CENTER );
  1104. txt->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  1105. break;
  1106. default:
  1107. ;
  1108. }
  1109. }
  1110. else // Part is not smash so use Lib default for NAME/VALUE // the text is per the original package, sans <attribute>
  1111. {
  1112. double degrees = ( txt->GetTextAngle() + m->GetOrientation() ) / 10;
  1113. // @todo there are a few more cases than these to contend with:
  1114. if( (!txt->IsMirrored() && ( abs( degrees ) == 180 || abs( degrees ) == 270 ))
  1115. || ( txt->IsMirrored() && ( degrees == 360 ) ) )
  1116. {
  1117. // ETEXT::TOP_RIGHT:
  1118. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  1119. txt->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
  1120. }
  1121. }
  1122. }
  1123. MODULE* EAGLE_PLUGIN::makeModule( wxXmlNode* aPackage, const wxString& aPkgName ) const
  1124. {
  1125. std::unique_ptr<MODULE> m( new MODULE( m_board ) );
  1126. LIB_ID fpID;
  1127. fpID.Parse( aPkgName, LIB_ID::ID_PCB, true );
  1128. m->SetFPID( fpID );
  1129. // Get the first package item and iterate
  1130. wxXmlNode* packageItem = aPackage->GetChildren();
  1131. while( packageItem )
  1132. {
  1133. const wxString& itemName = packageItem->GetName();
  1134. if( itemName == "description" )
  1135. m->SetDescription( FROM_UTF8( packageItem->GetNodeContent().c_str() ) );
  1136. else if( itemName == "wire" )
  1137. packageWire( m.get(), packageItem );
  1138. else if( itemName == "pad" )
  1139. packagePad( m.get(), packageItem );
  1140. else if( itemName == "text" )
  1141. packageText( m.get(), packageItem );
  1142. else if( itemName == "rectangle" )
  1143. packageRectangle( m.get(), packageItem );
  1144. else if( itemName == "polygon" )
  1145. packagePolygon( m.get(), packageItem );
  1146. else if( itemName == "circle" )
  1147. packageCircle( m.get(), packageItem );
  1148. else if( itemName == "hole" )
  1149. packageHole( m.get(), packageItem, false );
  1150. else if( itemName == "smd" )
  1151. packageSMD( m.get(), packageItem );
  1152. packageItem = packageItem->GetNext();
  1153. }
  1154. return m.release();
  1155. }
  1156. void EAGLE_PLUGIN::packageWire( MODULE* aModule, wxXmlNode* aTree ) const
  1157. {
  1158. EWIRE w( aTree );
  1159. PCB_LAYER_ID layer = kicad_layer( w.layer );
  1160. wxPoint start( kicad_x( w.x1 ), kicad_y( w.y1 ) );
  1161. wxPoint end( kicad_x( w.x2 ), kicad_y( w.y2 ) );
  1162. int width = w.width.ToPcbUnits();
  1163. // KiCad cannot handle zero or negative line widths which apparently have meaning in Eagle.
  1164. if( width <= 0 )
  1165. {
  1166. BOARD* board = aModule->GetBoard();
  1167. if( board )
  1168. {
  1169. width = board->GetDesignSettings().GetLineThickness( layer );
  1170. }
  1171. else
  1172. {
  1173. // When loading footprint libraries, there is no board so use the default KiCad
  1174. // line widths.
  1175. switch( layer )
  1176. {
  1177. case Edge_Cuts:
  1178. width = Millimeter2iu( DEFAULT_EDGE_WIDTH );
  1179. break;
  1180. case F_SilkS:
  1181. case B_SilkS:
  1182. width = Millimeter2iu( DEFAULT_SILK_LINE_WIDTH );
  1183. break;
  1184. case F_CrtYd:
  1185. case B_CrtYd:
  1186. width = Millimeter2iu( DEFAULT_COURTYARD_WIDTH );
  1187. break;
  1188. default:
  1189. width = Millimeter2iu( DEFAULT_LINE_WIDTH );
  1190. }
  1191. }
  1192. }
  1193. // FIXME: the cap attribute is ignored because KiCad can't create lines
  1194. // with flat ends.
  1195. EDGE_MODULE* dwg;
  1196. if( !w.curve )
  1197. {
  1198. dwg = new EDGE_MODULE( aModule, S_SEGMENT );
  1199. dwg->SetStart0( start );
  1200. dwg->SetEnd0( end );
  1201. }
  1202. else
  1203. {
  1204. dwg = new EDGE_MODULE( aModule, S_ARC );
  1205. wxPoint center = ConvertArcCenter( start, end, *w.curve );
  1206. dwg->SetStart0( center );
  1207. dwg->SetEnd0( start );
  1208. dwg->SetAngle( *w.curve * -10.0 ); // KiCad rotates the other way
  1209. }
  1210. dwg->SetLayer( layer );
  1211. dwg->SetWidth( width );
  1212. dwg->SetDrawCoord();
  1213. aModule->Add( dwg );
  1214. }
  1215. void EAGLE_PLUGIN::packagePad( MODULE* aModule, wxXmlNode* aTree ) const
  1216. {
  1217. // this is thru hole technology here, no SMDs
  1218. EPAD e( aTree );
  1219. int shape = EPAD::UNDEF;
  1220. D_PAD* pad = new D_PAD( aModule );
  1221. aModule->Add( pad );
  1222. transferPad( e, pad );
  1223. if( e.first && *e.first && m_rules->psFirst != EPAD::UNDEF )
  1224. shape = m_rules->psFirst;
  1225. else if( aModule->GetLayer() == F_Cu && m_rules->psTop != EPAD::UNDEF )
  1226. shape = m_rules->psTop;
  1227. else if( aModule->GetLayer() == B_Cu && m_rules->psBottom != EPAD::UNDEF )
  1228. shape = m_rules->psBottom;
  1229. pad->SetDrillSize( wxSize( e.drill.ToPcbUnits(), e.drill.ToPcbUnits() ) );
  1230. pad->SetLayerSet( LSET::AllCuMask() );
  1231. // Solder mask
  1232. if( !e.stop || *e.stop == true ) // enabled by default
  1233. pad->SetLayerSet( pad->GetLayerSet().set( B_Mask ).set( F_Mask ) );
  1234. if( shape == EPAD::ROUND || shape == EPAD::SQUARE || shape == EPAD::OCTAGON )
  1235. e.shape = shape;
  1236. if( e.shape )
  1237. {
  1238. switch( *e.shape )
  1239. {
  1240. case EPAD::ROUND:
  1241. pad->SetShape( PAD_SHAPE_CIRCLE );
  1242. break;
  1243. case EPAD::OCTAGON:
  1244. // no KiCad octagonal pad shape, use PAD_CIRCLE for now.
  1245. // pad->SetShape( PAD_OCTAGON );
  1246. wxASSERT( pad->GetShape() == PAD_SHAPE_CIRCLE ); // verify set in D_PAD constructor
  1247. pad->SetShape( PAD_SHAPE_CHAMFERED_RECT );
  1248. pad->SetChamferPositions( RECT_CHAMFER_ALL );
  1249. pad->SetChamferRectRatio( 0.25 );
  1250. break;
  1251. case EPAD::LONG:
  1252. pad->SetShape( PAD_SHAPE_OVAL );
  1253. break;
  1254. case EPAD::SQUARE:
  1255. pad->SetShape( PAD_SHAPE_RECT );
  1256. break;
  1257. case EPAD::OFFSET:
  1258. pad->SetShape( PAD_SHAPE_OVAL );
  1259. break;
  1260. }
  1261. }
  1262. else
  1263. {
  1264. // if shape is not present, our default is circle and that matches their default "round"
  1265. }
  1266. if( e.diameter )
  1267. {
  1268. int diameter = e.diameter->ToPcbUnits();
  1269. pad->SetSize( wxSize( diameter, diameter ) );
  1270. }
  1271. else
  1272. {
  1273. double drillz = pad->GetDrillSize().x;
  1274. double annulus = drillz * m_rules->rvPadTop; // copper annulus, eagle "restring"
  1275. annulus = eagleClamp( m_rules->rlMinPadTop, annulus, m_rules->rlMaxPadTop );
  1276. int diameter = KiROUND( drillz + 2 * annulus );
  1277. pad->SetSize( wxSize( KiROUND( diameter ), KiROUND( diameter ) ) );
  1278. }
  1279. if( pad->GetShape() == PAD_SHAPE_OVAL )
  1280. {
  1281. // The Eagle "long" pad is wider than it is tall,
  1282. // m_elongation is percent elongation
  1283. wxSize sz = pad->GetSize();
  1284. sz.x = ( sz.x * ( 100 + m_rules->psElongationLong ) ) / 100;
  1285. pad->SetSize( sz );
  1286. if( e.shape && *e.shape == EPAD::OFFSET )
  1287. {
  1288. int offset = KiROUND( ( sz.x - sz.y ) / 2.0 );
  1289. pad->SetOffset( wxPoint( offset, 0 ) );
  1290. }
  1291. }
  1292. if( e.rot )
  1293. {
  1294. pad->SetOrientation( e.rot->degrees * 10 );
  1295. }
  1296. }
  1297. void EAGLE_PLUGIN::packageText( MODULE* aModule, wxXmlNode* aTree ) const
  1298. {
  1299. ETEXT t( aTree );
  1300. PCB_LAYER_ID layer = kicad_layer( t.layer );
  1301. if( layer == UNDEFINED_LAYER )
  1302. {
  1303. layer = Cmts_User;
  1304. }
  1305. TEXTE_MODULE* txt;
  1306. if( t.text == ">NAME" || t.text == ">name" )
  1307. txt = &aModule->Reference();
  1308. else if( t.text == ">VALUE" || t.text == ">value" )
  1309. txt = &aModule->Value();
  1310. else
  1311. {
  1312. // FIXME: graphical text items are rotated for some reason.
  1313. txt = new TEXTE_MODULE( aModule );
  1314. aModule->Add( txt );
  1315. }
  1316. txt->SetTimeStamp( EagleTimeStamp( aTree ) );
  1317. txt->SetText( FROM_UTF8( t.text.c_str() ) );
  1318. wxPoint pos( kicad_x( t.x ), kicad_y( t.y ) );
  1319. txt->SetTextPos( pos );
  1320. txt->SetPos0( pos - aModule->GetPosition() );
  1321. txt->SetLayer( layer );
  1322. txt->SetTextSize( kicad_fontz( t.size ) );
  1323. double ratio = t.ratio ? *t.ratio : 8; // DTD says 8 is default
  1324. txt->SetThickness( t.size.ToPcbUnits() * ratio / 100 );
  1325. int align = t.align ? *t.align : ETEXT::BOTTOM_LEFT; // bottom-left is eagle default
  1326. // An eagle package is never rotated, the DTD does not allow it.
  1327. // angle -= aModule->GetOrienation();
  1328. if( t.rot )
  1329. {
  1330. int sign = t.rot->mirror ? -1 : 1;
  1331. txt->SetMirrored( t.rot->mirror );
  1332. double degrees = t.rot->degrees;
  1333. if( degrees == 90 || t.rot->spin )
  1334. txt->SetTextAngle( sign * degrees * 10 );
  1335. else if( degrees == 180 )
  1336. align = ETEXT::TOP_RIGHT;
  1337. else if( degrees == 270 )
  1338. {
  1339. align = ETEXT::TOP_RIGHT;
  1340. txt->SetTextAngle( sign * 90 * 10 );
  1341. }
  1342. }
  1343. switch( align )
  1344. {
  1345. case ETEXT::CENTER:
  1346. // this was the default in pcbtxt's constructor
  1347. break;
  1348. case ETEXT::CENTER_LEFT:
  1349. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  1350. break;
  1351. case ETEXT::CENTER_RIGHT:
  1352. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  1353. break;
  1354. case ETEXT::TOP_CENTER:
  1355. txt->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
  1356. break;
  1357. case ETEXT::TOP_LEFT:
  1358. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  1359. txt->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
  1360. break;
  1361. case ETEXT::TOP_RIGHT:
  1362. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  1363. txt->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
  1364. break;
  1365. case ETEXT::BOTTOM_CENTER:
  1366. txt->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  1367. break;
  1368. case ETEXT::BOTTOM_LEFT:
  1369. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  1370. txt->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  1371. break;
  1372. case ETEXT::BOTTOM_RIGHT:
  1373. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  1374. txt->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  1375. break;
  1376. }
  1377. }
  1378. void EAGLE_PLUGIN::packageRectangle( MODULE* aModule, wxXmlNode* aTree ) const
  1379. {
  1380. ERECT r( aTree );
  1381. PCB_LAYER_ID layer = kicad_layer( r.layer );
  1382. EDGE_MODULE* dwg = new EDGE_MODULE( aModule, S_POLYGON );
  1383. aModule->Add( dwg );
  1384. dwg->SetLayer( layer );
  1385. dwg->SetWidth( 0 );
  1386. dwg->SetTimeStamp( EagleTimeStamp( aTree ) );
  1387. std::vector<wxPoint> pts;
  1388. wxPoint start( wxPoint( kicad_x( r.x1 ), kicad_y( r.y1 ) ) );
  1389. wxPoint end( wxPoint( kicad_x( r.x1 ), kicad_y( r.y2 ) ) );
  1390. pts.push_back( start );
  1391. pts.emplace_back( kicad_x( r.x2 ), kicad_y( r.y1 ) );
  1392. pts.emplace_back( kicad_x( r.x2 ), kicad_y( r.y2 ) );
  1393. pts.push_back( end );
  1394. dwg->SetPolyPoints( pts );
  1395. dwg->SetStart0( start );
  1396. dwg->SetEnd0( end );
  1397. if( r.rot )
  1398. {
  1399. dwg->Rotate( dwg->GetCenter(), r.rot->degrees * 10 );
  1400. }
  1401. }
  1402. void EAGLE_PLUGIN::packagePolygon( MODULE* aModule, wxXmlNode* aTree ) const
  1403. {
  1404. EPOLYGON p( aTree );
  1405. PCB_LAYER_ID layer = kicad_layer( p.layer );
  1406. EDGE_MODULE* dwg = new EDGE_MODULE( aModule, S_POLYGON );
  1407. aModule->Add( dwg );
  1408. dwg->SetWidth( 0 ); // it's filled, no need for boundary width
  1409. dwg->SetLayer( layer );
  1410. dwg->SetTimeStamp( EagleTimeStamp( aTree ) );
  1411. std::vector<wxPoint> pts;
  1412. // Get the first vertex and iterate
  1413. wxXmlNode* vertex = aTree->GetChildren();
  1414. std::vector<EVERTEX> vertices;
  1415. // Create a circular vector of vertices
  1416. // The "curve" parameter indicates a curve from the current
  1417. // to the next vertex, so we keep the first at the end as well
  1418. // to allow the curve to link back
  1419. while( vertex )
  1420. {
  1421. if( vertex->GetName() == "vertex" )
  1422. vertices.emplace_back( vertex );
  1423. vertex = vertex->GetNext();
  1424. }
  1425. vertices.push_back( vertices[0] );
  1426. for( size_t i = 0; i < vertices.size() - 1; i++ )
  1427. {
  1428. EVERTEX v1 = vertices[i];
  1429. // Append the corner
  1430. pts.emplace_back( kicad_x( v1.x ), kicad_y( v1.y ) );
  1431. if( v1.curve )
  1432. {
  1433. EVERTEX v2 = vertices[i + 1];
  1434. wxPoint center = ConvertArcCenter(
  1435. wxPoint( kicad_x( v1.x ), kicad_y( v1.y ) ),
  1436. wxPoint( kicad_x( v2.x ), kicad_y( v2.y ) ), *v1.curve );
  1437. double angle = DEG2RAD( *v1.curve );
  1438. double end_angle = atan2( kicad_y( v2.y ) - center.y,
  1439. kicad_x( v2.x ) - center.x );
  1440. double radius = sqrt( pow( center.x - kicad_x( v1.x ), 2 )
  1441. + pow( center.y - kicad_y( v1.y ), 2 ) );
  1442. // Don't allow a zero-radius curve
  1443. if( KiROUND( radius ) == 0 )
  1444. radius = 1.0;
  1445. int segCount = GetArcToSegmentCount( KiROUND( radius ), ARC_HIGH_DEF, *v1.curve ) - 1;
  1446. // If we are curving, we need at least 2 segments otherwise delta == angle
  1447. if( segCount < 2 )
  1448. segCount = 2;
  1449. double delta = angle / segCount;
  1450. for( double a = end_angle + angle; fabs( a - end_angle ) > fabs( delta ); a -= delta )
  1451. {
  1452. pts.push_back(
  1453. wxPoint( KiROUND( radius * cos( a ) ),
  1454. KiROUND( radius * sin( a ) ) ) + center );
  1455. }
  1456. }
  1457. }
  1458. dwg->SetPolyPoints( pts );
  1459. dwg->SetStart0( *pts.begin() );
  1460. dwg->SetEnd0( pts.back() );
  1461. dwg->SetDrawCoord();
  1462. dwg->GetPolyShape().Inflate( p.width.ToPcbUnits() / 2, 32,
  1463. SHAPE_POLY_SET::ALLOW_ACUTE_CORNERS );
  1464. }
  1465. void EAGLE_PLUGIN::packageCircle( MODULE* aModule, wxXmlNode* aTree ) const
  1466. {
  1467. ECIRCLE e( aTree );
  1468. PCB_LAYER_ID layer = kicad_layer( e.layer );
  1469. EDGE_MODULE* gr = new EDGE_MODULE( aModule, S_CIRCLE );
  1470. int width = e.width.ToPcbUnits();
  1471. int radius = e.radius.ToPcbUnits();
  1472. // with == 0 means filled circle
  1473. if( width <= 0 )
  1474. {
  1475. width = radius;
  1476. radius = radius / 2;
  1477. }
  1478. aModule->Add( gr );
  1479. gr->SetWidth( width );
  1480. switch ( (int) layer )
  1481. {
  1482. case UNDEFINED_LAYER:
  1483. layer = Cmts_User;
  1484. break;
  1485. default:
  1486. break;
  1487. }
  1488. gr->SetLayer( layer );
  1489. gr->SetTimeStamp( EagleTimeStamp( aTree ) );
  1490. gr->SetStart0( wxPoint( kicad_x( e.x ), kicad_y( e.y ) ) );
  1491. gr->SetEnd0( wxPoint( kicad_x( e.x ) + radius, kicad_y( e.y ) ) );
  1492. gr->SetDrawCoord();
  1493. }
  1494. void EAGLE_PLUGIN::packageHole( MODULE* aModule, wxXmlNode* aTree, bool aCenter ) const
  1495. {
  1496. EHOLE e( aTree );
  1497. // we add a PAD_ATTRIB_HOLE_NOT_PLATED pad to this module.
  1498. D_PAD* pad = new D_PAD( aModule );
  1499. aModule->Add( pad );
  1500. pad->SetShape( PAD_SHAPE_CIRCLE );
  1501. pad->SetAttribute( PAD_ATTRIB_HOLE_NOT_PLATED );
  1502. // Mechanical purpose only:
  1503. // no offset, no net name, no pad name allowed
  1504. // pad->SetOffset( wxPoint( 0, 0 ) );
  1505. // pad->SetName( wxEmptyString );
  1506. wxPoint padpos( kicad_x( e.x ), kicad_y( e.y ) );
  1507. if( aCenter )
  1508. {
  1509. pad->SetPos0( wxPoint( 0, 0 ) );
  1510. aModule->SetPosition( padpos );
  1511. pad->SetPosition( padpos );
  1512. }
  1513. else
  1514. {
  1515. pad->SetPos0( padpos );
  1516. pad->SetPosition( padpos + aModule->GetPosition() );
  1517. }
  1518. wxSize sz( e.drill.ToPcbUnits(), e.drill.ToPcbUnits() );
  1519. pad->SetDrillSize( sz );
  1520. pad->SetSize( sz );
  1521. pad->SetLayerSet( LSET::AllCuMask().set( B_Mask ).set( F_Mask ) );
  1522. }
  1523. void EAGLE_PLUGIN::packageSMD( MODULE* aModule, wxXmlNode* aTree ) const
  1524. {
  1525. ESMD e( aTree );
  1526. PCB_LAYER_ID layer = kicad_layer( e.layer );
  1527. if( !IsCopperLayer( layer ) )
  1528. return;
  1529. bool shape_set = false;
  1530. int shape = EPAD::UNDEF;
  1531. D_PAD* pad = new D_PAD( aModule );
  1532. aModule->Add( pad );
  1533. transferPad( e, pad );
  1534. if( pad->GetName() == wxT( "1" ) && m_rules->psFirst != EPAD::UNDEF )
  1535. shape = m_rules->psFirst;
  1536. else if( layer == F_Cu && m_rules->psTop != EPAD::UNDEF )
  1537. shape = m_rules->psTop;
  1538. else if( layer == B_Cu && m_rules->psBottom != EPAD::UNDEF )
  1539. shape = m_rules->psBottom;
  1540. switch( shape )
  1541. {
  1542. case EPAD::ROUND:
  1543. case EPAD::OCTAGON:
  1544. shape_set = true;
  1545. pad->SetShape( PAD_SHAPE_CIRCLE );
  1546. break;
  1547. case EPAD::SQUARE:
  1548. shape_set = true;
  1549. pad->SetShape( PAD_SHAPE_RECT );
  1550. break;
  1551. default:
  1552. pad->SetShape( PAD_SHAPE_RECT );
  1553. }
  1554. pad->SetAttribute( PAD_ATTRIB_SMD );
  1555. wxSize padSize( e.dx.ToPcbUnits(), e.dy.ToPcbUnits() );
  1556. pad->SetSize( padSize );
  1557. pad->SetLayer( layer );
  1558. const LSET front( 3, F_Cu, F_Paste, F_Mask );
  1559. const LSET back( 3, B_Cu, B_Paste, B_Mask );
  1560. if( layer == F_Cu )
  1561. pad->SetLayerSet( front );
  1562. else if( layer == B_Cu )
  1563. pad->SetLayerSet( back );
  1564. int minPadSize = std::min( padSize.x, padSize.y );
  1565. // Rounded rectangle pads
  1566. int roundRadius = eagleClamp( m_rules->srMinRoundness * 2,
  1567. (int)( minPadSize * m_rules->srRoundness ), m_rules->srMaxRoundness * 2 );
  1568. if( !shape_set && ( e.roundness || roundRadius > 0 ) )
  1569. {
  1570. double roundRatio = (double) roundRadius / minPadSize / 2.0;
  1571. // Eagle uses a different definition of roundness, hence division by 200
  1572. if( e.roundness )
  1573. roundRatio = std::fmax( *e.roundness / 200.0, roundRatio );
  1574. pad->SetShape( PAD_SHAPE_ROUNDRECT );
  1575. pad->SetRoundRectRadiusRatio( roundRatio );
  1576. }
  1577. if( e.rot )
  1578. {
  1579. pad->SetOrientation( e.rot->degrees * 10 );
  1580. }
  1581. pad->SetLocalSolderPasteMargin( -eagleClamp( m_rules->mlMinCreamFrame,
  1582. (int) ( m_rules->mvCreamFrame * minPadSize ),
  1583. m_rules->mlMaxCreamFrame ) );
  1584. // Solder mask
  1585. if( e.stop && *e.stop == false ) // enabled by default
  1586. {
  1587. if( layer == F_Cu )
  1588. pad->SetLayerSet( pad->GetLayerSet().set( F_Mask, false ) );
  1589. else if( layer == B_Cu )
  1590. pad->SetLayerSet( pad->GetLayerSet().set( B_Mask, false ) );
  1591. }
  1592. // Solder paste (only for SMD pads)
  1593. if( e.cream && *e.cream == false ) // enabled by default
  1594. {
  1595. if( layer == F_Cu )
  1596. pad->SetLayerSet( pad->GetLayerSet().set( F_Paste, false ) );
  1597. else if( layer == B_Cu )
  1598. pad->SetLayerSet( pad->GetLayerSet().set( B_Paste, false ) );
  1599. }
  1600. }
  1601. void EAGLE_PLUGIN::transferPad( const EPAD_COMMON& aEaglePad, D_PAD* aPad ) const
  1602. {
  1603. aPad->SetName( FROM_UTF8( aEaglePad.name.c_str() ) );
  1604. // pad's "Position" is not relative to the module's,
  1605. // whereas Pos0 is relative to the module's but is the unrotated coordinate.
  1606. wxPoint padPos( kicad_x( aEaglePad.x ), kicad_y( aEaglePad.y ) );
  1607. aPad->SetPos0( padPos );
  1608. // Solder mask
  1609. const wxSize& padSize( aPad->GetSize() );
  1610. aPad->SetLocalSolderMaskMargin( eagleClamp( m_rules->mlMinStopFrame,
  1611. (int)( m_rules->mvStopFrame * std::min( padSize.x, padSize.y ) ),
  1612. m_rules->mlMaxStopFrame ) );
  1613. // Solid connection to copper zones
  1614. if( aEaglePad.thermals && !*aEaglePad.thermals )
  1615. aPad->SetZoneConnection( ZONE_CONNECTION::FULL );
  1616. MODULE* module = aPad->GetParent();
  1617. wxCHECK( module, /* void */ );
  1618. RotatePoint( &padPos, module->GetOrientation() );
  1619. aPad->SetPosition( padPos + module->GetPosition() );
  1620. }
  1621. void EAGLE_PLUGIN::deleteTemplates()
  1622. {
  1623. for( auto& t : m_templates )
  1624. delete t.second;
  1625. m_templates.clear();
  1626. }
  1627. void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals )
  1628. {
  1629. ZONES zones; // per net
  1630. m_xpath->push( "signals.signal", "name" );
  1631. int netCode = 1;
  1632. // Get the first signal and iterate
  1633. wxXmlNode* net = aSignals->GetChildren();
  1634. while( net )
  1635. {
  1636. bool sawPad = false;
  1637. zones.clear();
  1638. const wxString& netName = escapeName( net->GetAttribute( "name" ) );
  1639. m_board->Add( new NETINFO_ITEM( m_board, netName, netCode ) );
  1640. m_xpath->Value( netName.c_str() );
  1641. // Get the first net item and iterate
  1642. wxXmlNode* netItem = net->GetChildren();
  1643. // (contactref | polygon | wire | via)*
  1644. while( netItem )
  1645. {
  1646. const wxString& itemName = netItem->GetName();
  1647. if( itemName == "wire" )
  1648. {
  1649. m_xpath->push( "wire" );
  1650. EWIRE w( netItem );
  1651. PCB_LAYER_ID layer = kicad_layer( w.layer );
  1652. if( IsCopperLayer( layer ) )
  1653. {
  1654. wxPoint start( kicad_x( w.x1 ), kicad_y( w.y1 ) );
  1655. double angle = 0.0;
  1656. double end_angle = 0.0;
  1657. double radius = 0.0;
  1658. double delta_angle = 0.0;
  1659. wxPoint center;
  1660. int width = w.width.ToPcbUnits();
  1661. if( width < m_min_trace )
  1662. m_min_trace = width;
  1663. if( w.curve )
  1664. {
  1665. center = ConvertArcCenter(
  1666. wxPoint( kicad_x( w.x1 ), kicad_y( w.y1 ) ),
  1667. wxPoint( kicad_x( w.x2 ), kicad_y( w.y2 ) ),
  1668. *w.curve );
  1669. angle = DEG2RAD( *w.curve );
  1670. end_angle = atan2( kicad_y( w.y2 ) - center.y,
  1671. kicad_x( w.x2 ) - center.x );
  1672. radius = sqrt( pow( center.x - kicad_x( w.x1 ), 2 ) +
  1673. pow( center.y - kicad_y( w.y1 ), 2 ) );
  1674. // If we are curving, we need at least 2 segments otherwise
  1675. // delta_angle == angle
  1676. int segments = std::max( 2, GetArcToSegmentCount( KiROUND( radius ),
  1677. ARC_HIGH_DEF, *w.curve ) - 1 );
  1678. delta_angle = angle / segments;
  1679. }
  1680. while( fabs( angle ) > fabs( delta_angle ) )
  1681. {
  1682. wxASSERT( radius > 0.0 );
  1683. wxPoint end( KiROUND( radius * cos( end_angle + angle ) + center.x ),
  1684. KiROUND( radius * sin( end_angle + angle ) + center.y ) );
  1685. TRACK* t = new TRACK( m_board );
  1686. t->SetTimeStamp( EagleTimeStamp( netItem ) + int( RAD2DEG( angle ) ) );
  1687. t->SetPosition( start );
  1688. t->SetEnd( end );
  1689. t->SetWidth( width );
  1690. t->SetLayer( layer );
  1691. t->SetNetCode( netCode );
  1692. m_board->Add( t );
  1693. start = end;
  1694. angle -= delta_angle;
  1695. }
  1696. TRACK* t = new TRACK( m_board );
  1697. t->SetTimeStamp( EagleTimeStamp( netItem ) );
  1698. t->SetPosition( start );
  1699. t->SetEnd( wxPoint( kicad_x( w.x2 ), kicad_y( w.y2 ) ) );
  1700. t->SetWidth( width );
  1701. t->SetLayer( layer );
  1702. t->SetNetCode( netCode );
  1703. m_board->Add( t );
  1704. }
  1705. else
  1706. {
  1707. // put non copper wires where the sun don't shine.
  1708. }
  1709. m_xpath->pop();
  1710. }
  1711. else if( itemName == "via" )
  1712. {
  1713. m_xpath->push( "via" );
  1714. EVIA v( netItem );
  1715. PCB_LAYER_ID layer_front_most = kicad_layer( v.layer_front_most );
  1716. PCB_LAYER_ID layer_back_most = kicad_layer( v.layer_back_most );
  1717. if( IsCopperLayer( layer_front_most ) &&
  1718. IsCopperLayer( layer_back_most ) )
  1719. {
  1720. int kidiam;
  1721. int drillz = v.drill.ToPcbUnits();
  1722. VIA* via = new VIA( m_board );
  1723. m_board->Add( via );
  1724. via->SetLayerPair( layer_front_most, layer_back_most );
  1725. if( v.diam )
  1726. {
  1727. kidiam = v.diam->ToPcbUnits();
  1728. via->SetWidth( kidiam );
  1729. }
  1730. else
  1731. {
  1732. double annulus = drillz * m_rules->rvViaOuter; // eagle "restring"
  1733. annulus = eagleClamp( m_rules->rlMinViaOuter, annulus,
  1734. m_rules->rlMaxViaOuter );
  1735. kidiam = KiROUND( drillz + 2 * annulus );
  1736. via->SetWidth( kidiam );
  1737. }
  1738. via->SetDrill( drillz );
  1739. // make sure the via diameter respects the restring rules
  1740. if( !v.diam || via->GetWidth() <= via->GetDrill() )
  1741. {
  1742. double annulus = eagleClamp( m_rules->rlMinViaOuter,
  1743. (double)( via->GetWidth() / 2 - via->GetDrill() ),
  1744. m_rules->rlMaxViaOuter );
  1745. via->SetWidth( drillz + 2 * annulus );
  1746. }
  1747. if( kidiam < m_min_via )
  1748. m_min_via = kidiam;
  1749. if( drillz < m_min_via_hole )
  1750. m_min_via_hole = drillz;
  1751. if( layer_front_most == F_Cu && layer_back_most == B_Cu )
  1752. via->SetViaType( VIATYPE::THROUGH );
  1753. else if( layer_front_most == F_Cu || layer_back_most == B_Cu )
  1754. via->SetViaType( VIATYPE::MICROVIA );
  1755. else
  1756. via->SetViaType( VIATYPE::BLIND_BURIED );
  1757. via->SetTimeStamp( EagleTimeStamp( netItem ) );
  1758. wxPoint pos( kicad_x( v.x ), kicad_y( v.y ) );
  1759. via->SetPosition( pos );
  1760. via->SetEnd( pos );
  1761. via->SetNetCode( netCode );
  1762. }
  1763. m_xpath->pop();
  1764. }
  1765. else if( itemName == "contactref" )
  1766. {
  1767. m_xpath->push( "contactref" );
  1768. // <contactref element="RN1" pad="7"/>
  1769. const wxString& reference = netItem->GetAttribute( "element" );
  1770. const wxString& pad = netItem->GetAttribute( "pad" );
  1771. wxString key = makeKey( reference, pad ) ;
  1772. // D(printf( "adding refname:'%s' pad:'%s' netcode:%d netname:'%s'\n", reference.c_str(), pad.c_str(), netCode, netName.c_str() );)
  1773. m_pads_to_nets[ key ] = ENET( netCode, netName );
  1774. m_xpath->pop();
  1775. sawPad = true;
  1776. }
  1777. else if( itemName == "polygon" )
  1778. {
  1779. m_xpath->push( "polygon" );
  1780. auto* zone = loadPolygon( netItem );
  1781. if( zone )
  1782. {
  1783. zones.push_back( zone );
  1784. if( !zone->GetIsKeepout() )
  1785. zone->SetNetCode( netCode );
  1786. }
  1787. m_xpath->pop(); // "polygon"
  1788. }
  1789. netItem = netItem->GetNext();
  1790. }
  1791. if( zones.size() && !sawPad )
  1792. {
  1793. // KiCad does not support an unconnected zone with its own non-zero netcode,
  1794. // but only when assigned netcode = 0 w/o a name...
  1795. for( ZONES::iterator it = zones.begin(); it != zones.end(); ++it )
  1796. (*it)->SetNetCode( NETINFO_LIST::UNCONNECTED );
  1797. // therefore omit this signal/net.
  1798. }
  1799. else
  1800. netCode++;
  1801. // Get next signal
  1802. net = net->GetNext();
  1803. }
  1804. m_xpath->pop(); // "signals.signal"
  1805. }
  1806. PCB_LAYER_ID EAGLE_PLUGIN::kicad_layer( int aEagleLayer ) const
  1807. {
  1808. int kiLayer;
  1809. // eagle copper layer:
  1810. if( aEagleLayer >= 1 && aEagleLayer < int( arrayDim( m_cu_map ) ) )
  1811. {
  1812. kiLayer = m_cu_map[aEagleLayer];
  1813. }
  1814. else
  1815. {
  1816. // translate non-copper eagle layer to pcbnew layer
  1817. switch( aEagleLayer )
  1818. {
  1819. // Eagle says "Dimension" layer, but it's for board perimeter
  1820. case EAGLE_LAYER::MILLING: kiLayer = Edge_Cuts; break;
  1821. case EAGLE_LAYER::DIMENSION: kiLayer = Edge_Cuts; break;
  1822. case EAGLE_LAYER::TPLACE: kiLayer = F_SilkS; break;
  1823. case EAGLE_LAYER::BPLACE: kiLayer = B_SilkS; break;
  1824. case EAGLE_LAYER::TNAMES: kiLayer = F_SilkS; break;
  1825. case EAGLE_LAYER::BNAMES: kiLayer = B_SilkS; break;
  1826. case EAGLE_LAYER::TVALUES: kiLayer = F_Fab; break;
  1827. case EAGLE_LAYER::BVALUES: kiLayer = B_Fab; break;
  1828. case EAGLE_LAYER::TSTOP: kiLayer = F_Mask; break;
  1829. case EAGLE_LAYER::BSTOP: kiLayer = B_Mask; break;
  1830. case EAGLE_LAYER::TCREAM: kiLayer = F_Paste; break;
  1831. case EAGLE_LAYER::BCREAM: kiLayer = B_Paste; break;
  1832. case EAGLE_LAYER::TFINISH: kiLayer = F_Mask; break;
  1833. case EAGLE_LAYER::BFINISH: kiLayer = B_Mask; break;
  1834. case EAGLE_LAYER::TGLUE: kiLayer = F_Adhes; break;
  1835. case EAGLE_LAYER::BGLUE: kiLayer = B_Adhes; break;
  1836. case EAGLE_LAYER::DOCUMENT: kiLayer = Cmts_User; break;
  1837. case EAGLE_LAYER::REFERENCELC: kiLayer = Cmts_User; break;
  1838. case EAGLE_LAYER::REFERENCELS: kiLayer = Cmts_User; break;
  1839. // Packages show the future chip pins on SMD parts using layer 51.
  1840. // This is an area slightly smaller than the PAD/SMD copper area.
  1841. // Carry those visual aids into the MODULE on the fabrication layer,
  1842. // not silkscreen. This is perhaps not perfect, but there is not a lot
  1843. // of other suitable paired layers
  1844. case EAGLE_LAYER::TDOCU: kiLayer = F_Fab; break;
  1845. case EAGLE_LAYER::BDOCU: kiLayer = B_Fab; break;
  1846. // these layers are defined as user layers. put them on ECO layers
  1847. case EAGLE_LAYER::USERLAYER1: kiLayer = Eco1_User; break;
  1848. case EAGLE_LAYER::USERLAYER2: kiLayer = Eco2_User; break;
  1849. // these will also appear in the ratsnest, so there's no need for a warning
  1850. case EAGLE_LAYER::UNROUTED: kiLayer = Dwgs_User; break;
  1851. case EAGLE_LAYER::TKEEPOUT:
  1852. case EAGLE_LAYER::BKEEPOUT:
  1853. case EAGLE_LAYER::TTEST:
  1854. case EAGLE_LAYER::BTEST:
  1855. case EAGLE_LAYER::HOLES:
  1856. default:
  1857. // some layers do not map to KiCad
  1858. wxLogMessage( wxString::Format( _( "Unsupported Eagle layer '%s' (%d), converted to Dwgs.User layer" ),
  1859. eagle_layer_name( aEagleLayer ), aEagleLayer ) );
  1860. kiLayer = Dwgs_User;
  1861. break;
  1862. }
  1863. }
  1864. return PCB_LAYER_ID( kiLayer );
  1865. }
  1866. const wxString& EAGLE_PLUGIN::eagle_layer_name( int aLayer ) const
  1867. {
  1868. static const wxString unknown( "unknown" );
  1869. auto it = m_eagleLayers.find( aLayer );
  1870. return it == m_eagleLayers.end() ? unknown : it->second.name;
  1871. }
  1872. void EAGLE_PLUGIN::centerBoard()
  1873. {
  1874. if( m_props )
  1875. {
  1876. UTF8 page_width;
  1877. UTF8 page_height;
  1878. if( m_props->Value( "page_width", &page_width ) &&
  1879. m_props->Value( "page_height", &page_height ) )
  1880. {
  1881. EDA_RECT bbbox = m_board->GetBoardEdgesBoundingBox();
  1882. int w = atoi( page_width.c_str() );
  1883. int h = atoi( page_height.c_str() );
  1884. int desired_x = ( w - bbbox.GetWidth() ) / 2;
  1885. int desired_y = ( h - bbbox.GetHeight() ) / 2;
  1886. DBG(printf( "bbox.width:%d bbox.height:%d w:%d h:%d desired_x:%d desired_y:%d\n",
  1887. bbbox.GetWidth(), bbbox.GetHeight(), w, h, desired_x, desired_y );)
  1888. m_board->Move( wxPoint( desired_x - bbbox.GetX(), desired_y - bbbox.GetY() ) );
  1889. }
  1890. }
  1891. }
  1892. wxDateTime EAGLE_PLUGIN::getModificationTime( const wxString& aPath )
  1893. {
  1894. // File hasn't been loaded yet.
  1895. if( aPath.IsEmpty() )
  1896. return wxDateTime::Now();
  1897. wxFileName fn( aPath );
  1898. if( fn.IsFileReadable() )
  1899. return fn.GetModificationTime();
  1900. else
  1901. return wxDateTime( 0.0 );
  1902. }
  1903. void EAGLE_PLUGIN::cacheLib( const wxString& aLibPath )
  1904. {
  1905. try
  1906. {
  1907. wxDateTime modtime = getModificationTime( aLibPath );
  1908. // Fixes assertions in wxWidgets debug builds for the wxDateTime object. Refresh the
  1909. // cache if either of the wxDateTime objects are invalid or the last file modification
  1910. // time differs from the current file modification time.
  1911. bool load = !m_mod_time.IsValid() || !modtime.IsValid() || m_mod_time != modtime;
  1912. if( aLibPath != m_lib_path || load )
  1913. {
  1914. wxXmlNode* doc;
  1915. LOCALE_IO toggle; // toggles on, then off, the C locale.
  1916. deleteTemplates();
  1917. // Set this before completion of loading, since we rely on it for
  1918. // text of an exception. Delay setting m_mod_time until after successful load
  1919. // however.
  1920. m_lib_path = aLibPath;
  1921. // 8 bit "filename" should be encoded according to disk filename encoding,
  1922. // (maybe this is current locale, maybe not, its a filesystem issue),
  1923. // and is not necessarily utf8.
  1924. string filename = (const char*) aLibPath.char_str( wxConvFile );
  1925. // Load the document
  1926. wxXmlDocument xmlDocument;
  1927. wxFileName fn( filename );
  1928. if( !xmlDocument.Load( fn.GetFullPath() ) )
  1929. THROW_IO_ERROR( wxString::Format( _( "Unable to read file \"%s\"" ),
  1930. fn.GetFullPath() ) );
  1931. doc = xmlDocument.GetRoot();
  1932. wxXmlNode* drawing = MapChildren( doc )["drawing"];
  1933. NODE_MAP drawingChildren = MapChildren( drawing );
  1934. // clear the cu map and then rebuild it.
  1935. clear_cu_map();
  1936. m_xpath->push( "eagle.drawing.layers" );
  1937. wxXmlNode* layers = drawingChildren["layers"];
  1938. loadLayerDefs( layers );
  1939. m_xpath->pop();
  1940. m_xpath->push( "eagle.drawing.library" );
  1941. wxXmlNode* library = drawingChildren["library"];
  1942. loadLibrary( library, NULL );
  1943. m_xpath->pop();
  1944. m_mod_time = modtime;
  1945. }
  1946. }
  1947. catch(...){}
  1948. // TODO: Handle exceptions
  1949. // catch( file_parser_error fpe )
  1950. // {
  1951. // // for xml_parser_error, what() has the line number in it,
  1952. // // but no byte offset. That should be an adequate error message.
  1953. // THROW_IO_ERROR( fpe.what() );
  1954. // }
  1955. //
  1956. // // Class ptree_error is a base class for xml_parser_error & file_parser_error,
  1957. // // so one catch should be OK for all errors.
  1958. // catch( ptree_error pte )
  1959. // {
  1960. // string errmsg = pte.what();
  1961. //
  1962. // errmsg += " @\n";
  1963. // errmsg += m_xpath->Contents();
  1964. //
  1965. // THROW_IO_ERROR( errmsg );
  1966. // }
  1967. }
  1968. void EAGLE_PLUGIN::FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibraryPath,
  1969. bool aBestEfforts, const PROPERTIES* aProperties )
  1970. {
  1971. wxString errorMsg;
  1972. init( aProperties );
  1973. try
  1974. {
  1975. cacheLib( aLibraryPath );
  1976. }
  1977. catch( const IO_ERROR& ioe )
  1978. {
  1979. errorMsg = ioe.What();
  1980. }
  1981. // Some of the files may have been parsed correctly so we want to add the valid files to
  1982. // the library.
  1983. for( MODULE_CITER it = m_templates.begin(); it != m_templates.end(); ++it )
  1984. aFootprintNames.Add( FROM_UTF8( it->first.c_str() ) );
  1985. if( !errorMsg.IsEmpty() && !aBestEfforts )
  1986. THROW_IO_ERROR( errorMsg );
  1987. }
  1988. MODULE* EAGLE_PLUGIN::FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
  1989. const PROPERTIES* aProperties )
  1990. {
  1991. init( aProperties );
  1992. cacheLib( aLibraryPath );
  1993. MODULE_CITER mi = m_templates.find( aFootprintName );
  1994. if( mi == m_templates.end() )
  1995. return NULL;
  1996. // copy constructor to clone the template
  1997. MODULE* ret = new MODULE( *mi->second );
  1998. return ret;
  1999. }
  2000. void EAGLE_PLUGIN::FootprintLibOptions( PROPERTIES* aListToAppendTo ) const
  2001. {
  2002. PLUGIN::FootprintLibOptions( aListToAppendTo );
  2003. /*
  2004. (*aListToAppendTo)["ignore_duplicates"] = UTF8( _(
  2005. "Ignore duplicately named footprints within the same Eagle library. "
  2006. "Only the first similarly named footprint will be loaded."
  2007. ));
  2008. */
  2009. }
  2010. /*
  2011. void EAGLE_PLUGIN::Save( const wxString& aFileName, BOARD* aBoard, const PROPERTIES* aProperties )
  2012. {
  2013. // Eagle lovers apply here.
  2014. }
  2015. void EAGLE_PLUGIN::FootprintSave( const wxString& aLibraryPath, const MODULE* aFootprint, const PROPERTIES* aProperties )
  2016. {
  2017. }
  2018. void EAGLE_PLUGIN::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName )
  2019. {
  2020. }
  2021. void EAGLE_PLUGIN::FootprintLibCreate( const wxString& aLibraryPath, const PROPERTIES* aProperties )
  2022. {
  2023. }
  2024. bool EAGLE_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties )
  2025. {
  2026. }
  2027. bool EAGLE_PLUGIN::IsFootprintLibWritable( const wxString& aLibraryPath )
  2028. {
  2029. return true;
  2030. }
  2031. */