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.

3192 lines
98 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
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
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-2016 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 <errno.h>
  44. #include <wx/string.h>
  45. #include <boost/property_tree/ptree.hpp>
  46. #include <boost/property_tree/xml_parser.hpp>
  47. #include <eagle_plugin.h>
  48. #include <common.h>
  49. #include <macros.h>
  50. #include <fctsys.h>
  51. #include <trigo.h>
  52. #include <macros.h>
  53. #include <kicad_string.h>
  54. #include <properties.h>
  55. #include <wx/filename.h>
  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. using namespace boost::property_tree;
  64. using namespace std;
  65. typedef EAGLE_PLUGIN::BIU BIU;
  66. typedef PTREE::const_assoc_iterator CA_ITER;
  67. typedef PTREE::const_iterator CITER;
  68. typedef std::pair<CA_ITER, CA_ITER> CA_ITER_RANGE;
  69. typedef MODULE_MAP::iterator MODULE_ITER;
  70. typedef MODULE_MAP::const_iterator MODULE_CITER;
  71. typedef boost::optional<string> opt_string;
  72. typedef boost::optional<int> opt_int;
  73. typedef boost::optional<double> opt_double;
  74. typedef boost::optional<bool> opt_bool;
  75. /// segment (element) of our XPATH into the Eagle XML document tree in PTREE form.
  76. struct TRIPLET
  77. {
  78. const char* element;
  79. const char* attribute;
  80. const char* value;
  81. TRIPLET( const char* aElement, const char* aAttribute = "", const char* aValue = "" ) :
  82. element( aElement ),
  83. attribute( aAttribute ),
  84. value( aValue )
  85. {}
  86. };
  87. /**
  88. * Class XPATH
  89. * keeps track of what we are working on within a PTREE.
  90. * Then if an exception is thrown, the place within the tree that gave us
  91. * grief can be reported almost accurately. To minimally impact
  92. * speed, merely assign const char* pointers during the tree walking
  93. * expedition. The const char* pointers must be to C strings residing either in
  94. * the data or code segment (i.e. "compiled in") or within the XML document, but
  95. * not on the stack, since the stack is unwound during the throwing of the
  96. * exception. The XML document will not immediately vanish since we capture
  97. * the xpath (using function Contents()) before the XML document tree (PTREE)
  98. * is destroyed.
  99. */
  100. class XPATH
  101. {
  102. std::vector<TRIPLET> p;
  103. public:
  104. void push( const char* aPathSegment, const char* aAttribute="" )
  105. {
  106. p.push_back( TRIPLET( aPathSegment, aAttribute ) );
  107. }
  108. void clear() { p.clear(); }
  109. void pop() { p.pop_back(); }
  110. /// modify the last path node's value
  111. void Value( const char* aValue )
  112. {
  113. p.back().value = aValue;
  114. }
  115. /// modify the last path node's attribute
  116. void Attribute( const char* aAttribute )
  117. {
  118. p.back().attribute = aAttribute;
  119. }
  120. /// return the contents of the XPATH as a single string
  121. string Contents()
  122. {
  123. typedef std::vector<TRIPLET>::const_iterator CITER_TRIPLET;
  124. string ret;
  125. for( CITER_TRIPLET it = p.begin(); it != p.end(); ++it )
  126. {
  127. if( it != p.begin() )
  128. ret += '.';
  129. ret += it->element;
  130. if( it->attribute[0] && it->value[0] )
  131. {
  132. ret += '[';
  133. ret += it->attribute;
  134. ret += '=';
  135. ret += it->value;
  136. ret += ']';
  137. }
  138. }
  139. return ret;
  140. }
  141. };
  142. /**
  143. * Function parseOptionalBool
  144. * returns an opt_bool and sets it true or false according to the presence
  145. * and value of an attribute within the CPTREE element.
  146. */
  147. static opt_bool parseOptionalBool( CPTREE& attribs, const char* aName )
  148. {
  149. opt_bool ret;
  150. opt_string stemp = attribs.get_optional<string>( aName );
  151. if( stemp )
  152. ret = !stemp->compare( "yes" );
  153. return ret;
  154. }
  155. // All of the 'E'STRUCTS below merely hold Eagle XML information verbatim, in binary.
  156. // For maintenance and troubleshooting purposes, it was thought that we'd need to
  157. // separate the conversion process into distinct steps. There is no intent to have KiCad
  158. // forms of information in these 'E'STRUCTS. They are only binary forms
  159. // of the Eagle information in the corresponding Eagle XML nodes.
  160. /// Eagle rotation
  161. struct EROT
  162. {
  163. bool mirror;
  164. bool spin;
  165. double degrees;
  166. EROT() :
  167. mirror( false ),
  168. spin( false ),
  169. degrees( 0 )
  170. {}
  171. EROT( double aDegrees ) :
  172. mirror( false ),
  173. spin( false ),
  174. degrees( aDegrees )
  175. {}
  176. };
  177. typedef boost::optional<EROT> opt_erot;
  178. /// parse an Eagle XML "rot" field. Unfortunately the DTD seems not to explain
  179. /// this format very well. [S][M]R<degrees>. Examples: "R90", "MR180", "SR180"
  180. static EROT erot( const string& aRot )
  181. {
  182. EROT rot;
  183. rot.spin = aRot.find( 'S' ) != aRot.npos;
  184. rot.mirror = aRot.find( 'M' ) != aRot.npos;
  185. rot.degrees = strtod( aRot.c_str()
  186. + 1 // skip leading 'R'
  187. + int( rot.spin ) // skip optional leading 'S'
  188. + int( rot.mirror ), // skip optional leading 'M'
  189. NULL );
  190. return rot;
  191. }
  192. /// Eagle "rot" fields are optional, handle that by returning opt_erot.
  193. static opt_erot parseOptionalEROT( CPTREE& attribs )
  194. {
  195. opt_erot ret;
  196. opt_string stemp = attribs.get_optional<string>( "rot" );
  197. if( stemp )
  198. ret = erot( *stemp );
  199. return ret;
  200. }
  201. /// Eagle wire
  202. struct EWIRE
  203. {
  204. double x1;
  205. double y1;
  206. double x2;
  207. double y2;
  208. double width;
  209. LAYER_NUM layer;
  210. // for style: (continuous | longdash | shortdash | dashdot)
  211. enum {
  212. CONTINUOUS,
  213. LONGDASH,
  214. SHORTDASH,
  215. DASHDOT,
  216. };
  217. opt_int style;
  218. opt_double curve; ///< range is -359.9..359.9
  219. // for cap: (flat | round)
  220. enum {
  221. FLAT,
  222. ROUND,
  223. };
  224. opt_int cap;
  225. EWIRE( CPTREE& aWire );
  226. };
  227. /**
  228. * Constructor EWIRE
  229. * converts a "wire"'s xml attributes ( &ltwire&gt )
  230. * to binary without additional conversion.
  231. * This result is an EWIRE with the &ltwire&gt textual data merely converted to binary.
  232. */
  233. EWIRE::EWIRE( CPTREE& aWire )
  234. {
  235. CPTREE& attribs = aWire.get_child( "<xmlattr>" );
  236. /*
  237. <!ELEMENT wire EMPTY>
  238. <!ATTLIST wire
  239. x1 %Coord; #REQUIRED
  240. y1 %Coord; #REQUIRED
  241. x2 %Coord; #REQUIRED
  242. y2 %Coord; #REQUIRED
  243. width %Dimension; #REQUIRED
  244. layer %Layer; #REQUIRED
  245. extent %Extent; #IMPLIED -- only applicable for airwires --
  246. style %WireStyle; "continuous"
  247. curve %WireCurve; "0"
  248. cap %WireCap; "round" -- only applicable if 'curve' is not zero --
  249. >
  250. */
  251. x1 = attribs.get<double>( "x1" );
  252. y1 = attribs.get<double>( "y1" );
  253. x2 = attribs.get<double>( "x2" );
  254. y2 = attribs.get<double>( "y2" );
  255. width = attribs.get<double>( "width" );
  256. layer = attribs.get<int>( "layer" );
  257. curve = attribs.get_optional<double>( "curve" );
  258. opt_string s = attribs.get_optional<string>( "style" );
  259. if( s )
  260. {
  261. if( !s->compare( "continuous" ) )
  262. style = EWIRE::CONTINUOUS;
  263. else if( !s->compare( "longdash" ) )
  264. style = EWIRE::LONGDASH;
  265. else if( !s->compare( "shortdash" ) )
  266. style = EWIRE::SHORTDASH;
  267. else if( !s->compare( "dashdot" ) )
  268. style = EWIRE::DASHDOT;
  269. }
  270. s = attribs.get_optional<string>( "cap" );
  271. if( s )
  272. {
  273. if( !s->compare( "round" ) )
  274. cap = EWIRE::ROUND;
  275. else if( !s->compare( "flat" ) )
  276. cap = EWIRE::FLAT;
  277. }
  278. // ignoring extent
  279. }
  280. /// Eagle via
  281. struct EVIA
  282. {
  283. double x;
  284. double y;
  285. int layer_front_most; /// < extent
  286. int layer_back_most; /// < inclusive
  287. double drill;
  288. opt_double diam;
  289. opt_string shape;
  290. EVIA( CPTREE& aVia );
  291. };
  292. EVIA::EVIA( CPTREE& aVia )
  293. {
  294. CPTREE& attribs = aVia.get_child( "<xmlattr>" );
  295. /*
  296. <!ELEMENT via EMPTY>
  297. <!ATTLIST via
  298. x %Coord; #REQUIRED
  299. y %Coord; #REQUIRED
  300. extent %Extent; #REQUIRED
  301. drill %Dimension; #REQUIRED
  302. diameter %Dimension; "0"
  303. shape %ViaShape; "round"
  304. alwaysstop %Bool; "no"
  305. >
  306. */
  307. x = attribs.get<double>( "x" );
  308. y = attribs.get<double>( "y" );
  309. string ext = attribs.get<string>( "extent" );
  310. sscanf( ext.c_str(), "%d-%d", &layer_front_most, &layer_back_most );
  311. drill = attribs.get<double>( "drill" );
  312. diam = attribs.get_optional<double>( "diameter" );
  313. shape = attribs.get_optional<string>( "shape" );
  314. }
  315. /// Eagle circle
  316. struct ECIRCLE
  317. {
  318. double x;
  319. double y;
  320. double radius;
  321. double width;
  322. LAYER_NUM layer;
  323. ECIRCLE( CPTREE& aCircle );
  324. };
  325. ECIRCLE::ECIRCLE( CPTREE& aCircle )
  326. {
  327. CPTREE& attribs = aCircle.get_child( "<xmlattr>" );
  328. /*
  329. <!ELEMENT circle EMPTY>
  330. <!ATTLIST circle
  331. x %Coord; #REQUIRED
  332. y %Coord; #REQUIRED
  333. radius %Coord; #REQUIRED
  334. width %Dimension; #REQUIRED
  335. layer %Layer; #REQUIRED
  336. >
  337. */
  338. x = attribs.get<double>( "x" );
  339. y = attribs.get<double>( "y" );
  340. radius = attribs.get<double>( "radius" );
  341. width = attribs.get<double>( "width" );
  342. layer = attribs.get<int>( "layer" );
  343. }
  344. /// Eagle XML rectangle in binary
  345. struct ERECT
  346. {
  347. double x1;
  348. double y1;
  349. double x2;
  350. double y2;
  351. int layer;
  352. opt_erot rot;
  353. ERECT( CPTREE& aRect );
  354. };
  355. ERECT::ERECT( CPTREE& aRect )
  356. {
  357. CPTREE& attribs = aRect.get_child( "<xmlattr>" );
  358. /*
  359. <!ELEMENT rectangle EMPTY>
  360. <!ATTLIST rectangle
  361. x1 %Coord; #REQUIRED
  362. y1 %Coord; #REQUIRED
  363. x2 %Coord; #REQUIRED
  364. y2 %Coord; #REQUIRED
  365. layer %Layer; #REQUIRED
  366. rot %Rotation; "R0"
  367. >
  368. */
  369. x1 = attribs.get<double>( "x1" );
  370. y1 = attribs.get<double>( "y1" );
  371. x2 = attribs.get<double>( "x2" );
  372. y2 = attribs.get<double>( "y2" );
  373. layer = attribs.get<int>( "layer" );
  374. rot = parseOptionalEROT( attribs );
  375. }
  376. /// Eagle "attribute" XML element, no foolin'.
  377. struct EATTR
  378. {
  379. string name;
  380. opt_string value;
  381. opt_double x;
  382. opt_double y;
  383. opt_double size;
  384. opt_int layer;
  385. opt_double ratio;
  386. opt_erot rot;
  387. enum { // for 'display'
  388. Off,
  389. VALUE,
  390. NAME,
  391. BOTH,
  392. };
  393. opt_int display;
  394. EATTR( CPTREE& aTree );
  395. EATTR() {}
  396. };
  397. /**
  398. * Constructor EATTR
  399. * parses an Eagle "attribute" XML element. Note that an attribute element
  400. * is different than an XML element attribute. The attribute element is a
  401. * full XML node in and of itself, and has attributes of its own. Blame Eagle.
  402. */
  403. EATTR::EATTR( CPTREE& aAttribute )
  404. {
  405. CPTREE& attribs = aAttribute.get_child( "<xmlattr>" );
  406. /*
  407. <!ELEMENT attribute EMPTY>
  408. <!ATTLIST attribute
  409. name %String; #REQUIRED
  410. value %String; #IMPLIED
  411. x %Coord; #IMPLIED
  412. y %Coord; #IMPLIED
  413. size %Dimension; #IMPLIED
  414. layer %Layer; #IMPLIED
  415. font %TextFont; #IMPLIED
  416. ratio %Int; #IMPLIED
  417. rot %Rotation; "R0"
  418. display %AttributeDisplay; "value" -- only in <element> or <instance> context --
  419. constant %Bool; "no" -- only in <device> context --
  420. >
  421. */
  422. name = attribs.get<string>( "name" ); // #REQUIRED
  423. value = attribs.get_optional<string>( "value" );
  424. x = attribs.get_optional<double>( "x" );
  425. y = attribs.get_optional<double>( "y" );
  426. size = attribs.get_optional<double>( "size" );
  427. // KiCad cannot currently put a TEXTE_MODULE on a different layer than the MODULE
  428. // Eagle can it seems.
  429. layer = attribs.get_optional<int>( "layer" );
  430. ratio = attribs.get_optional<double>( "ratio" );
  431. rot = parseOptionalEROT( attribs );
  432. opt_string stemp = attribs.get_optional<string>( "display" );
  433. if( stemp )
  434. {
  435. // (off | value | name | both)
  436. if( !stemp->compare( "off" ) )
  437. display = EATTR::Off;
  438. else if( !stemp->compare( "value" ) )
  439. display = EATTR::VALUE;
  440. else if( !stemp->compare( "name" ) )
  441. display = EATTR::NAME;
  442. else if( !stemp->compare( "both" ) )
  443. display = EATTR::BOTH;
  444. }
  445. }
  446. /// Eagle dimension element
  447. struct EDIMENSION
  448. {
  449. double x1;
  450. double y1;
  451. double x2;
  452. double y2;
  453. double x3;
  454. double y3;
  455. int layer;
  456. opt_string dimensionType;
  457. EDIMENSION( CPTREE& aDimension );
  458. };
  459. EDIMENSION::EDIMENSION( CPTREE& aDimension )
  460. {
  461. CPTREE& attribs = aDimension.get_child( "<xmlattr>" );
  462. /*
  463. <!ELEMENT dimension EMPTY>
  464. <!ATTLIST dimension
  465. x1 %Coord; #REQUIRED
  466. y1 %Coord; #REQUIRED
  467. x2 %Coord; #REQUIRED
  468. y2 %Coord; #REQUIRED
  469. x3 %Coord; #REQUIRED
  470. y3 %Coord; #REQUIRED
  471. layer %Layer; #REQUIRED
  472. dtype %DimensionType; "parallel"
  473. >
  474. */
  475. x1 = attribs.get<double>( "x1" );
  476. y1 = attribs.get<double>( "y1" );
  477. x2 = attribs.get<double>( "x2" );
  478. y2 = attribs.get<double>( "y2" );
  479. x3 = attribs.get<double>( "x3" );
  480. y3 = attribs.get<double>( "y3" );
  481. layer = attribs.get<int>( "layer" );
  482. opt_string dimType = attribs.get_optional<string>( "dtype" );
  483. if(!dimType)
  484. {
  485. // default type is parallel
  486. }
  487. }
  488. /// Eagle text element
  489. struct ETEXT
  490. {
  491. string text;
  492. double x;
  493. double y;
  494. double size;
  495. int layer;
  496. opt_string font;
  497. opt_double ratio;
  498. opt_erot rot;
  499. enum { // for align
  500. CENTER,
  501. CENTER_LEFT,
  502. TOP_CENTER,
  503. TOP_LEFT,
  504. TOP_RIGHT,
  505. // opposites are -1 x above, used by code tricks in here
  506. CENTER_RIGHT = -CENTER_LEFT,
  507. BOTTOM_CENTER = -TOP_CENTER,
  508. BOTTOM_LEFT = -TOP_RIGHT,
  509. BOTTOM_RIGHT = -TOP_LEFT,
  510. };
  511. opt_int align;
  512. ETEXT( CPTREE& aText );
  513. };
  514. ETEXT::ETEXT( CPTREE& aText )
  515. {
  516. CPTREE& attribs = aText.get_child( "<xmlattr>" );
  517. /*
  518. <!ELEMENT text (#PCDATA)>
  519. <!ATTLIST text
  520. x %Coord; #REQUIRED
  521. y %Coord; #REQUIRED
  522. size %Dimension; #REQUIRED
  523. layer %Layer; #REQUIRED
  524. font %TextFont; "proportional"
  525. ratio %Int; "8"
  526. rot %Rotation; "R0"
  527. align %Align; "bottom-left"
  528. >
  529. */
  530. text = aText.data();
  531. x = attribs.get<double>( "x" );
  532. y = attribs.get<double>( "y" );
  533. size = attribs.get<double>( "size" );
  534. layer = attribs.get<int>( "layer" );
  535. font = attribs.get_optional<string>( "font" );
  536. ratio = attribs.get_optional<double>( "ratio" );
  537. rot = parseOptionalEROT( attribs );
  538. opt_string stemp = attribs.get_optional<string>( "align" );
  539. if( stemp )
  540. {
  541. // (bottom-left | bottom-center | bottom-right | center-left |
  542. // center | center-right | top-left | top-center | top-right)
  543. if( !stemp->compare( "center" ) )
  544. align = ETEXT::CENTER;
  545. else if( !stemp->compare( "center-right" ) )
  546. align = ETEXT::CENTER_RIGHT;
  547. else if( !stemp->compare( "top-left" ) )
  548. align = ETEXT::TOP_LEFT;
  549. else if( !stemp->compare( "top-center" ) )
  550. align = ETEXT::TOP_CENTER;
  551. else if( !stemp->compare( "top-right" ) )
  552. align = ETEXT::TOP_RIGHT;
  553. else if( !stemp->compare( "bottom-left" ) )
  554. align = ETEXT::BOTTOM_LEFT;
  555. else if( !stemp->compare( "bottom-center" ) )
  556. align = ETEXT::BOTTOM_CENTER;
  557. else if( !stemp->compare( "bottom-right" ) )
  558. align = ETEXT::BOTTOM_RIGHT;
  559. else if( !stemp->compare( "center-left" ) )
  560. align = ETEXT::CENTER_LEFT;
  561. }
  562. }
  563. /// Eagle thru hol pad
  564. struct EPAD
  565. {
  566. string name;
  567. double x;
  568. double y;
  569. double drill;
  570. opt_double diameter;
  571. // for shape: (square | round | octagon | long | offset)
  572. enum {
  573. SQUARE,
  574. ROUND,
  575. OCTAGON,
  576. LONG,
  577. OFFSET,
  578. };
  579. opt_int shape;
  580. opt_erot rot;
  581. opt_bool stop;
  582. opt_bool thermals;
  583. opt_bool first;
  584. EPAD( CPTREE& aPad );
  585. };
  586. EPAD::EPAD( CPTREE& aPad )
  587. {
  588. CPTREE& attribs = aPad.get_child( "<xmlattr>" );
  589. /*
  590. <!ELEMENT pad EMPTY>
  591. <!ATTLIST pad
  592. name %String; #REQUIRED
  593. x %Coord; #REQUIRED
  594. y %Coord; #REQUIRED
  595. drill %Dimension; #REQUIRED
  596. diameter %Dimension; "0"
  597. shape %PadShape; "round"
  598. rot %Rotation; "R0"
  599. stop %Bool; "yes"
  600. thermals %Bool; "yes"
  601. first %Bool; "no"
  602. >
  603. */
  604. // #REQUIRED says DTD, throw exception if not found
  605. name = attribs.get<string>( "name" );
  606. x = attribs.get<double>( "x" );
  607. y = attribs.get<double>( "y" );
  608. drill = attribs.get<double>( "drill" );
  609. diameter = attribs.get_optional<double>( "diameter" );
  610. opt_string s = attribs.get_optional<string>( "shape" );
  611. if( s )
  612. {
  613. // (square | round | octagon | long | offset)
  614. if( !s->compare( "square" ) )
  615. shape = EPAD::SQUARE;
  616. else if( !s->compare( "round" ) )
  617. shape = EPAD::ROUND;
  618. else if( !s->compare( "octagon" ) )
  619. shape = EPAD::OCTAGON;
  620. else if( !s->compare( "long" ) )
  621. shape = EPAD::LONG;
  622. else if( !s->compare( "offset" ) )
  623. shape = EPAD::OFFSET;
  624. }
  625. rot = parseOptionalEROT( attribs );
  626. stop = parseOptionalBool( attribs, "stop" );
  627. thermals = parseOptionalBool( attribs, "thermals" );
  628. first = parseOptionalBool( attribs, "first" );
  629. }
  630. /// Eagle SMD pad
  631. struct ESMD
  632. {
  633. string name;
  634. double x;
  635. double y;
  636. double dx;
  637. double dy;
  638. int layer;
  639. opt_int roundness;
  640. opt_erot rot;
  641. opt_bool stop;
  642. opt_bool thermals;
  643. opt_bool cream;
  644. ESMD( CPTREE& aSMD );
  645. };
  646. ESMD::ESMD( CPTREE& aSMD )
  647. {
  648. CPTREE& attribs = aSMD.get_child( "<xmlattr>" );
  649. /*
  650. <!ATTLIST smd
  651. name %String; #REQUIRED
  652. x %Coord; #REQUIRED
  653. y %Coord; #REQUIRED
  654. dx %Dimension; #REQUIRED
  655. dy %Dimension; #REQUIRED
  656. layer %Layer; #REQUIRED
  657. roundness %Int; "0"
  658. rot %Rotation; "R0"
  659. stop %Bool; "yes"
  660. thermals %Bool; "yes"
  661. cream %Bool; "yes"
  662. >
  663. */
  664. // DTD #REQUIRED, throw exception if not found
  665. name = attribs.get<string>( "name" );
  666. x = attribs.get<double>( "x" );
  667. y = attribs.get<double>( "y" );
  668. dx = attribs.get<double>( "dx" );
  669. dy = attribs.get<double>( "dy" );
  670. layer = attribs.get<int>( "layer" );
  671. rot = parseOptionalEROT( attribs );
  672. roundness = attribs.get_optional<int>( "roundness" );
  673. thermals = parseOptionalBool( attribs, "thermals" );
  674. stop = parseOptionalBool( attribs, "stop" );
  675. thermals = parseOptionalBool( attribs, "thermals" );
  676. cream = parseOptionalBool( attribs, "cream" );
  677. }
  678. struct EVERTEX
  679. {
  680. double x;
  681. double y;
  682. EVERTEX( CPTREE& aVertex );
  683. };
  684. EVERTEX::EVERTEX( CPTREE& aVertex )
  685. {
  686. CPTREE& attribs = aVertex.get_child( "<xmlattr>" );
  687. /*
  688. <!ELEMENT vertex EMPTY>
  689. <!ATTLIST vertex
  690. x %Coord; #REQUIRED
  691. y %Coord; #REQUIRED
  692. curve %WireCurve; "0" -- the curvature from this vertex to the next one --
  693. >
  694. */
  695. x = attribs.get<double>( "x" );
  696. y = attribs.get<double>( "y" );
  697. }
  698. /// Eagle polygon, without vertices which are parsed as needed
  699. struct EPOLYGON
  700. {
  701. double width;
  702. int layer;
  703. opt_double spacing;
  704. // KiCad priority is opposite of Eagle rank, that is:
  705. // - Eagle Low rank drawn first
  706. // - KiCad high priority drawn first
  707. // So since Eagle has an upper limit we define this, used for the cases
  708. // where no rank is specified.
  709. static const int max_priority = 6;
  710. enum { // for pour
  711. SOLID,
  712. HATCH,
  713. CUTOUT,
  714. };
  715. int pour;
  716. opt_double isolate;
  717. opt_bool orphans;
  718. opt_bool thermals;
  719. opt_int rank;
  720. EPOLYGON( CPTREE& aPolygon );
  721. };
  722. EPOLYGON::EPOLYGON( CPTREE& aPolygon )
  723. {
  724. CPTREE& attribs = aPolygon.get_child( "<xmlattr>" );
  725. /*
  726. <!ATTLIST polygon
  727. width %Dimension; #REQUIRED
  728. layer %Layer; #REQUIRED
  729. spacing %Dimension; #IMPLIED
  730. pour %PolygonPour; "solid"
  731. isolate %Dimension; #IMPLIED -- only in <signal> or <package> context --
  732. orphans %Bool; "no" -- only in <signal> context --
  733. thermals %Bool; "yes" -- only in <signal> context --
  734. rank %Int; "0" -- 1..6 in <signal> context, 0 or 7 in <package> context --
  735. >
  736. */
  737. width = attribs.get<double>( "width" );
  738. layer = attribs.get<int>( "layer" );
  739. spacing = attribs.get_optional<double>( "spacing" );
  740. isolate = attribs.get_optional<double>( "isolate" );
  741. // default pour to solid fill
  742. pour = EPOLYGON::SOLID;
  743. opt_string s = attribs.get_optional<string>( "pour" );
  744. if( s )
  745. {
  746. // (solid | hatch | cutout)
  747. if( !s->compare( "hatch" ) )
  748. pour = EPOLYGON::HATCH;
  749. else if( !s->compare( "cutout" ) )
  750. pour = EPOLYGON::CUTOUT;
  751. }
  752. orphans = parseOptionalBool( attribs, "orphans" );
  753. thermals = parseOptionalBool( attribs, "thermals" );
  754. rank = attribs.get_optional<int>( "rank" );
  755. }
  756. /// Eagle hole element
  757. struct EHOLE
  758. {
  759. double x;
  760. double y;
  761. double drill;
  762. EHOLE( CPTREE& aHole );
  763. };
  764. EHOLE::EHOLE( CPTREE& aHole )
  765. {
  766. CPTREE& attribs = aHole.get_child( "<xmlattr>" );
  767. /*
  768. <!ELEMENT hole EMPTY>
  769. <!ATTLIST hole
  770. x %Coord; #REQUIRED
  771. y %Coord; #REQUIRED
  772. drill %Dimension; #REQUIRED
  773. >
  774. */
  775. // #REQUIRED:
  776. x = attribs.get<double>( "x" );
  777. y = attribs.get<double>( "y" );
  778. drill = attribs.get<double>( "drill" );
  779. }
  780. /// Eagle element element
  781. struct EELEMENT
  782. {
  783. string name;
  784. string library;
  785. string package;
  786. string value;
  787. double x;
  788. double y;
  789. opt_bool locked;
  790. opt_bool smashed;
  791. opt_erot rot;
  792. EELEMENT( CPTREE& aElement );
  793. };
  794. EELEMENT::EELEMENT( CPTREE& aElement )
  795. {
  796. CPTREE& attribs = aElement.get_child( "<xmlattr>" );
  797. /*
  798. <!ELEMENT element (attribute*, variant*)>
  799. <!ATTLIST element
  800. name %String; #REQUIRED
  801. library %String; #REQUIRED
  802. package %String; #REQUIRED
  803. value %String; #REQUIRED
  804. x %Coord; #REQUIRED
  805. y %Coord; #REQUIRED
  806. locked %Bool; "no"
  807. smashed %Bool; "no"
  808. rot %Rotation; "R0"
  809. >
  810. */
  811. // #REQUIRED
  812. name = attribs.get<string>( "name" );
  813. library = attribs.get<string>( "library" );
  814. value = attribs.get<string>( "value" );
  815. package = attribs.get<string>( "package" );
  816. ReplaceIllegalFileNameChars( &package );
  817. x = attribs.get<double>( "x" );
  818. y = attribs.get<double>( "y" );
  819. // optional
  820. locked = parseOptionalBool( attribs, "locked" );
  821. smashed = parseOptionalBool( attribs, "smashed" );
  822. rot = parseOptionalEROT( attribs );
  823. }
  824. struct ELAYER
  825. {
  826. int number;
  827. string name;
  828. int color;
  829. int fill;
  830. opt_bool visible;
  831. opt_bool active;
  832. ELAYER( CPTREE& aLayer );
  833. };
  834. ELAYER::ELAYER( CPTREE& aLayer )
  835. {
  836. CPTREE& attribs = aLayer.get_child( "<xmlattr>" );
  837. /*
  838. <!ELEMENT layer EMPTY>
  839. <!ATTLIST layer
  840. number %Layer; #REQUIRED
  841. name %String; #REQUIRED
  842. color %Int; #REQUIRED
  843. fill %Int; #REQUIRED
  844. visible %Bool; "yes"
  845. active %Bool; "yes"
  846. >
  847. */
  848. number = attribs.get<int>( "number" );
  849. name = attribs.get<string>( "name" );
  850. color = attribs.get<int>( "color" );
  851. fill = 1; // Temporary value.
  852. visible = parseOptionalBool( attribs, "visible" );
  853. active = parseOptionalBool( attribs, "active" );
  854. }
  855. /// Parse an eagle distance which is either mm, or mils if there is "mil" suffix.
  856. /// Return is in BIU.
  857. static double parseEagle( const string& aDistance )
  858. {
  859. double ret = strtod( aDistance.c_str(), NULL );
  860. if( aDistance.npos != aDistance.find( "mil" ) )
  861. ret = IU_PER_MILS * ret;
  862. else
  863. ret = IU_PER_MM * ret;
  864. return ret;
  865. }
  866. /// subset of eagle.drawing.board.designrules in the XML document
  867. struct ERULES
  868. {
  869. int psElongationLong; ///< percent over 100%. 0-> not elongated, 100->twice as wide as is tall
  870. ///< Goes into making a scaling factor for "long" pads.
  871. int psElongationOffset; ///< the offset of the hole within the "long" pad.
  872. double rvPadTop; ///< top pad size as percent of drill size
  873. // double rvPadBottom; ///< bottom pad size as percent of drill size
  874. double rlMinPadTop; ///< minimum copper annulus on through hole pads
  875. double rlMaxPadTop; ///< maximum copper annulus on through hole pads
  876. double rvViaOuter; ///< copper annulus is this percent of via hole
  877. double rlMinViaOuter; ///< minimum copper annulus on via
  878. double rlMaxViaOuter; ///< maximum copper annulus on via
  879. double mdWireWire; ///< wire to wire spacing I presume.
  880. ERULES() :
  881. psElongationLong ( 100 ),
  882. psElongationOffset ( 0 ),
  883. rvPadTop ( 0.25 ),
  884. // rvPadBottom ( 0.25 ),
  885. rlMinPadTop ( Mils2iu( 10 ) ),
  886. rlMaxPadTop ( Mils2iu( 20 ) ),
  887. rvViaOuter ( 0.25 ),
  888. rlMinViaOuter ( Mils2iu( 10 ) ),
  889. rlMaxViaOuter ( Mils2iu( 20 ) ),
  890. mdWireWire ( 0 )
  891. {}
  892. void parse( CPTREE& aRules );
  893. };
  894. void ERULES::parse( CPTREE& aRules )
  895. {
  896. for( CITER it = aRules.begin(); it != aRules.end(); ++it )
  897. {
  898. if( it->first != "param" )
  899. continue;
  900. CPTREE& attribs = it->second.get_child( "<xmlattr>" );
  901. const string& name = attribs.get<string>( "name" );
  902. if( name == "psElongationLong" )
  903. psElongationLong = attribs.get<int>( "value" );
  904. else if( name == "psElongationOffset" )
  905. psElongationOffset = attribs.get<int>( "value" );
  906. else if( name == "rvPadTop" )
  907. rvPadTop = attribs.get<double>( "value" );
  908. else if( name == "rlMinPadTop" )
  909. rlMinPadTop = parseEagle( attribs.get<string>( "value" ) );
  910. else if( name == "rlMaxPadTop" )
  911. rlMaxPadTop = parseEagle( attribs.get<string>( "value" ) );
  912. else if( name == "rvViaOuter" )
  913. rvViaOuter = attribs.get<double>( "value" );
  914. else if( name == "rlMinViaOuter" )
  915. rlMinViaOuter = parseEagle( attribs.get<string>( "value" ) );
  916. else if( name == "rlMaxViaOuter" )
  917. rlMaxViaOuter = parseEagle( attribs.get<string>( "value" ) );
  918. else if( name == "mdWireWire" )
  919. mdWireWire = parseEagle( attribs.get<string>( "value" ) );
  920. }
  921. }
  922. /// Assemble a two part key as a simple concatonation of aFirst and aSecond parts,
  923. /// using a separator.
  924. static inline string makeKey( const string& aFirst, const string& aSecond )
  925. {
  926. string key = aFirst + '\x02' + aSecond;
  927. return key;
  928. }
  929. /// Make a unique time stamp
  930. static inline unsigned long timeStamp( CPTREE& aTree )
  931. {
  932. // in this case from a unique tree memory location
  933. return (unsigned long)(void*) &aTree;
  934. }
  935. /// Convert an Eagle curve end to a KiCad center for S_ARC
  936. wxPoint kicad_arc_center( wxPoint start, wxPoint end, double angle )
  937. {
  938. // Eagle give us start and end.
  939. // S_ARC wants start to give the center, and end to give the start.
  940. double dx = end.x - start.x, dy = end.y - start.y;
  941. wxPoint mid = (start + end) / 2;
  942. double dlen = sqrt( dx*dx + dy*dy );
  943. double dist = dlen / ( 2 * tan( DEG2RAD( angle ) / 2 ) );
  944. wxPoint center(
  945. mid.x + dist * ( dy / dlen ),
  946. mid.y - dist * ( dx / dlen )
  947. );
  948. return center;
  949. }
  950. EAGLE_PLUGIN::EAGLE_PLUGIN() :
  951. m_rules( new ERULES() ),
  952. m_xpath( new XPATH() ),
  953. m_mod_time( wxDateTime::Now() )
  954. {
  955. init( NULL );
  956. clear_cu_map();
  957. }
  958. EAGLE_PLUGIN::~EAGLE_PLUGIN()
  959. {
  960. delete m_rules;
  961. delete m_xpath;
  962. }
  963. const wxString EAGLE_PLUGIN::PluginName() const
  964. {
  965. return wxT( "Eagle" );
  966. }
  967. const wxString EAGLE_PLUGIN::GetFileExtension() const
  968. {
  969. return wxT( "brd" );
  970. }
  971. int inline EAGLE_PLUGIN::kicad( double d ) const
  972. {
  973. return KiROUND( biu_per_mm * d );
  974. }
  975. wxSize inline EAGLE_PLUGIN::kicad_fontz( double d ) const
  976. {
  977. // texts seem to better match eagle when scaled down by 0.95
  978. int kz = kicad( d ) * 95 / 100;
  979. return wxSize( kz, kz );
  980. }
  981. BOARD* EAGLE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties )
  982. {
  983. LOCALE_IO toggle; // toggles on, then off, the C locale.
  984. PTREE doc;
  985. init( aProperties );
  986. m_board = aAppendToMe ? aAppendToMe : new BOARD();
  987. // Give the filename to the board if it's new
  988. if( !aAppendToMe )
  989. m_board->SetFileName( aFileName );
  990. // delete on exception, if I own m_board, according to aAppendToMe
  991. unique_ptr<BOARD> deleter( aAppendToMe ? NULL : m_board );
  992. try
  993. {
  994. // 8 bit "filename" should be encoded according to disk filename encoding,
  995. // (maybe this is current locale, maybe not, its a filesystem issue),
  996. // and is not necessarily utf8.
  997. string filename = (const char*) aFileName.char_str( wxConvFile );
  998. read_xml( filename, doc, xml_parser::no_comments );
  999. m_min_trace = INT_MAX;
  1000. m_min_via = INT_MAX;
  1001. m_min_via_hole = INT_MAX;
  1002. loadAllSections( doc );
  1003. BOARD_DESIGN_SETTINGS& designSettings = m_board->GetDesignSettings();
  1004. if( m_min_trace < designSettings.m_TrackMinWidth )
  1005. designSettings.m_TrackMinWidth = m_min_trace;
  1006. if( m_min_via < designSettings.m_ViasMinSize )
  1007. designSettings.m_ViasMinSize = m_min_via;
  1008. if( m_min_via_hole < designSettings.m_ViasMinDrill )
  1009. designSettings.m_ViasMinDrill = m_min_via_hole;
  1010. if( m_rules->mdWireWire )
  1011. {
  1012. NETCLASSPTR defaultNetclass = designSettings.GetDefault();
  1013. int clearance = KiROUND( m_rules->mdWireWire );
  1014. if( clearance < defaultNetclass->GetClearance() )
  1015. defaultNetclass->SetClearance( clearance );
  1016. }
  1017. // should be empty, else missing m_xpath->pop()
  1018. wxASSERT( m_xpath->Contents().size() == 0 );
  1019. }
  1020. catch( file_parser_error fpe )
  1021. {
  1022. // for xml_parser_error, what() has the line number in it,
  1023. // but no byte offset. That should be an adequate error message.
  1024. THROW_IO_ERROR( fpe.what() );
  1025. }
  1026. // Class ptree_error is a base class for xml_parser_error & file_parser_error,
  1027. // so one catch should be OK for all errors.
  1028. catch( ptree_error pte )
  1029. {
  1030. string errmsg = pte.what();
  1031. errmsg += " @\n";
  1032. errmsg += m_xpath->Contents();
  1033. THROW_IO_ERROR( errmsg );
  1034. }
  1035. // IO_ERROR exceptions are left uncaught, they pass upwards from here.
  1036. // Ensure the copper layers count is a multiple of 2
  1037. // Pcbnew does not like boards with odd layers count
  1038. // (these boards cannot exist. they actually have a even layers count)
  1039. int lyrcnt = m_board->GetCopperLayerCount();
  1040. if( (lyrcnt % 2) != 0 )
  1041. {
  1042. lyrcnt++;
  1043. m_board->SetCopperLayerCount( lyrcnt );
  1044. }
  1045. centerBoard();
  1046. deleter.release();
  1047. return m_board;
  1048. }
  1049. void EAGLE_PLUGIN::init( const PROPERTIES* aProperties )
  1050. {
  1051. m_hole_count = 0;
  1052. m_min_trace = 0;
  1053. m_min_via = 0;
  1054. m_min_via_hole = 0;
  1055. m_xpath->clear();
  1056. m_pads_to_nets.clear();
  1057. // m_templates.clear(); this is the FOOTPRINT cache too
  1058. m_board = NULL;
  1059. m_props = aProperties;
  1060. mm_per_biu = 1/IU_PER_MM;
  1061. biu_per_mm = IU_PER_MM;
  1062. delete m_rules;
  1063. m_rules = new ERULES();
  1064. }
  1065. void EAGLE_PLUGIN::clear_cu_map()
  1066. {
  1067. // All cu layers are invalid until we see them in the <layers> section while
  1068. // loading either a board or library. See loadLayerDefs().
  1069. for( unsigned i = 0; i < DIM(m_cu_map); ++i )
  1070. m_cu_map[i] = -1;
  1071. }
  1072. void EAGLE_PLUGIN::loadAllSections( CPTREE& aDoc )
  1073. {
  1074. CPTREE& drawing = aDoc.get_child( "eagle.drawing" );
  1075. CPTREE& board = drawing.get_child( "board" );
  1076. m_xpath->push( "eagle.drawing" );
  1077. {
  1078. m_xpath->push( "board" );
  1079. CPTREE& designrules = board.get_child( "designrules" );
  1080. loadDesignRules( designrules );
  1081. m_xpath->pop();
  1082. }
  1083. {
  1084. m_xpath->push( "layers" );
  1085. CPTREE& layers = drawing.get_child( "layers" );
  1086. loadLayerDefs( layers );
  1087. m_xpath->pop();
  1088. }
  1089. {
  1090. m_xpath->push( "board" );
  1091. CPTREE& plain = board.get_child( "plain" );
  1092. loadPlain( plain );
  1093. CPTREE& signals = board.get_child( "signals" );
  1094. loadSignals( signals );
  1095. CPTREE& libs = board.get_child( "libraries" );
  1096. loadLibraries( libs );
  1097. CPTREE& elems = board.get_child( "elements" );
  1098. loadElements( elems );
  1099. m_xpath->pop(); // "board"
  1100. }
  1101. m_xpath->pop(); // "eagle.drawing"
  1102. }
  1103. void EAGLE_PLUGIN::loadDesignRules( CPTREE& aDesignRules )
  1104. {
  1105. m_xpath->push( "designrules" );
  1106. m_rules->parse( aDesignRules );
  1107. m_xpath->pop(); // "designrules"
  1108. }
  1109. void EAGLE_PLUGIN::loadLayerDefs( CPTREE& aLayers )
  1110. {
  1111. typedef std::vector<ELAYER> ELAYERS;
  1112. typedef ELAYERS::const_iterator EITER;
  1113. ELAYERS cu; // copper layers
  1114. // find the subset of layers that are copper, and active
  1115. for( CITER layer = aLayers.begin(); layer != aLayers.end(); ++layer )
  1116. {
  1117. ELAYER elayer( layer->second );
  1118. if( elayer.number >= 1 && elayer.number <= 16 && ( !elayer.active || *elayer.active ) )
  1119. {
  1120. cu.push_back( elayer );
  1121. }
  1122. }
  1123. // establish cu layer map:
  1124. int ki_layer_count = 0;
  1125. for( EITER it = cu.begin(); it != cu.end(); ++it, ++ki_layer_count )
  1126. {
  1127. if( ki_layer_count == 0 )
  1128. m_cu_map[it->number] = F_Cu;
  1129. else if( ki_layer_count == int( cu.size()-1 ) )
  1130. m_cu_map[it->number] = B_Cu;
  1131. else
  1132. {
  1133. // some eagle boards do not have contiguous layer number sequences.
  1134. #if 0 // pre LAYER_ID & LSET:
  1135. m_cu_map[it->number] = cu.size() - 1 - ki_layer_count;
  1136. #else
  1137. m_cu_map[it->number] = ki_layer_count;
  1138. #endif
  1139. }
  1140. }
  1141. #if 0 && defined(DEBUG)
  1142. printf( "m_cu_map:\n" );
  1143. for( unsigned i=0; i<DIM(m_cu_map); ++i )
  1144. {
  1145. printf( "\t[%d]:%d\n", i, m_cu_map[i] );
  1146. }
  1147. #endif
  1148. // Set the layer names and cu count iff we're loading a board.
  1149. if( m_board )
  1150. {
  1151. m_board->SetCopperLayerCount( cu.size() );
  1152. for( EITER it = cu.begin(); it != cu.end(); ++it )
  1153. {
  1154. LAYER_ID layer = kicad_layer( it->number );
  1155. // these function provide their own protection against UNDEFINED_LAYER:
  1156. m_board->SetLayerName( layer, FROM_UTF8( it->name.c_str() ) );
  1157. m_board->SetLayerType( layer, LT_SIGNAL );
  1158. // could map the colors here
  1159. }
  1160. }
  1161. }
  1162. void EAGLE_PLUGIN::loadPlain( CPTREE& aGraphics )
  1163. {
  1164. m_xpath->push( "plain" );
  1165. // (polygon | wire | text | circle | rectangle | frame | hole)*
  1166. for( CITER gr = aGraphics.begin(); gr != aGraphics.end(); ++gr )
  1167. {
  1168. if( gr->first == "wire" )
  1169. {
  1170. m_xpath->push( "wire" );
  1171. EWIRE w( gr->second );
  1172. LAYER_ID layer = kicad_layer( w.layer );
  1173. wxPoint start( kicad_x( w.x1 ), kicad_y( w.y1 ) );
  1174. wxPoint end( kicad_x( w.x2 ), kicad_y( w.y2 ) );
  1175. if( layer != UNDEFINED_LAYER )
  1176. {
  1177. DRAWSEGMENT* dseg = new DRAWSEGMENT( m_board );
  1178. m_board->Add( dseg, ADD_APPEND );
  1179. if( !w.curve )
  1180. {
  1181. dseg->SetStart( start );
  1182. dseg->SetEnd( end );
  1183. }
  1184. else
  1185. {
  1186. wxPoint center = kicad_arc_center( start, end, *w.curve);
  1187. dseg->SetShape( S_ARC );
  1188. dseg->SetStart( center );
  1189. dseg->SetEnd( start );
  1190. dseg->SetAngle( *w.curve * -10.0 ); // KiCad rotates the other way
  1191. }
  1192. dseg->SetTimeStamp( timeStamp( gr->second ) );
  1193. dseg->SetLayer( layer );
  1194. dseg->SetWidth( Millimeter2iu( DEFAULT_PCB_EDGE_THICKNESS ) );
  1195. }
  1196. m_xpath->pop();
  1197. }
  1198. else if( gr->first == "text" )
  1199. {
  1200. #if defined(DEBUG)
  1201. if( gr->second.data() == "ATMEGA328" )
  1202. {
  1203. int breakhere = 1;
  1204. (void) breakhere;
  1205. }
  1206. #endif
  1207. m_xpath->push( "text" );
  1208. ETEXT t( gr->second );
  1209. LAYER_ID layer = kicad_layer( t.layer );
  1210. if( layer != UNDEFINED_LAYER )
  1211. {
  1212. TEXTE_PCB* pcbtxt = new TEXTE_PCB( m_board );
  1213. m_board->Add( pcbtxt, ADD_APPEND );
  1214. pcbtxt->SetLayer( layer );
  1215. pcbtxt->SetTimeStamp( timeStamp( gr->second ) );
  1216. pcbtxt->SetText( FROM_UTF8( t.text.c_str() ) );
  1217. pcbtxt->SetTextPosition( wxPoint( kicad_x( t.x ), kicad_y( t.y ) ) );
  1218. pcbtxt->SetSize( kicad_fontz( t.size ) );
  1219. double ratio = t.ratio ? *t.ratio : 8; // DTD says 8 is default
  1220. pcbtxt->SetThickness( kicad( t.size * ratio / 100 ) );
  1221. int align = t.align ? *t.align : ETEXT::BOTTOM_LEFT;
  1222. if( t.rot )
  1223. {
  1224. int sign = t.rot->mirror ? -1 : 1;
  1225. pcbtxt->SetMirrored( t.rot->mirror );
  1226. double degrees = t.rot->degrees;
  1227. if( degrees == 90 || t.rot->spin )
  1228. pcbtxt->SetOrientation( sign * t.rot->degrees * 10 );
  1229. else if( degrees == 180 )
  1230. align = ETEXT::TOP_RIGHT;
  1231. else if( degrees == 270 )
  1232. {
  1233. pcbtxt->SetOrientation( sign * 90 * 10 );
  1234. align = ETEXT::TOP_RIGHT;
  1235. }
  1236. }
  1237. switch( align )
  1238. {
  1239. case ETEXT::CENTER:
  1240. // this was the default in pcbtxt's constructor
  1241. break;
  1242. case ETEXT::CENTER_LEFT:
  1243. pcbtxt->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  1244. break;
  1245. case ETEXT::CENTER_RIGHT:
  1246. pcbtxt->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  1247. break;
  1248. case ETEXT::TOP_CENTER:
  1249. pcbtxt->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
  1250. break;
  1251. case ETEXT::TOP_LEFT:
  1252. pcbtxt->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  1253. pcbtxt->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
  1254. break;
  1255. case ETEXT::TOP_RIGHT:
  1256. pcbtxt->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  1257. pcbtxt->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
  1258. break;
  1259. case ETEXT::BOTTOM_CENTER:
  1260. pcbtxt->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  1261. break;
  1262. case ETEXT::BOTTOM_LEFT:
  1263. pcbtxt->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  1264. pcbtxt->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  1265. break;
  1266. case ETEXT::BOTTOM_RIGHT:
  1267. pcbtxt->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  1268. pcbtxt->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  1269. break;
  1270. }
  1271. }
  1272. m_xpath->pop();
  1273. }
  1274. else if( gr->first == "circle" )
  1275. {
  1276. m_xpath->push( "circle" );
  1277. ECIRCLE c( gr->second );
  1278. LAYER_ID layer = kicad_layer( c.layer );
  1279. if( layer != UNDEFINED_LAYER ) // unsupported layer
  1280. {
  1281. DRAWSEGMENT* dseg = new DRAWSEGMENT( m_board );
  1282. m_board->Add( dseg, ADD_APPEND );
  1283. dseg->SetShape( S_CIRCLE );
  1284. dseg->SetTimeStamp( timeStamp( gr->second ) );
  1285. dseg->SetLayer( layer );
  1286. dseg->SetStart( wxPoint( kicad_x( c.x ), kicad_y( c.y ) ) );
  1287. dseg->SetEnd( wxPoint( kicad_x( c.x + c.radius ), kicad_y( c.y ) ) );
  1288. dseg->SetWidth( kicad( c.width ) );
  1289. }
  1290. m_xpath->pop();
  1291. }
  1292. else if( gr->first == "rectangle" )
  1293. {
  1294. // This seems to be a simplified rectangular [copper] zone, cannot find any
  1295. // net related info on it from the DTD.
  1296. m_xpath->push( "rectangle" );
  1297. ERECT r( gr->second );
  1298. LAYER_ID layer = kicad_layer( r.layer );
  1299. if( IsCopperLayer( layer ) )
  1300. {
  1301. // use a "netcode = 0" type ZONE:
  1302. ZONE_CONTAINER* zone = new ZONE_CONTAINER( m_board );
  1303. m_board->Add( zone, ADD_APPEND );
  1304. zone->SetTimeStamp( timeStamp( gr->second ) );
  1305. zone->SetLayer( layer );
  1306. zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
  1307. CPolyLine::HATCH_STYLE outline_hatch = CPolyLine::DIAGONAL_EDGE;
  1308. zone->Outline()->Start( layer, kicad_x( r.x1 ), kicad_y( r.y1 ), outline_hatch );
  1309. zone->AppendCorner( wxPoint( kicad_x( r.x2 ), kicad_y( r.y1 ) ) );
  1310. zone->AppendCorner( wxPoint( kicad_x( r.x2 ), kicad_y( r.y2 ) ) );
  1311. zone->AppendCorner( wxPoint( kicad_x( r.x1 ), kicad_y( r.y2 ) ) );
  1312. zone->Outline()->CloseLastContour();
  1313. // this is not my fault:
  1314. zone->Outline()->SetHatch(
  1315. outline_hatch, Mils2iu( zone->Outline()->GetDefaultHatchPitchMils() ), true );
  1316. }
  1317. m_xpath->pop();
  1318. }
  1319. else if( gr->first == "hole" )
  1320. {
  1321. m_xpath->push( "hole" );
  1322. EHOLE e( gr->second );
  1323. // Fabricate a MODULE with a single PAD_ATTRIB_HOLE_NOT_PLATED pad.
  1324. // Use m_hole_count to gen up a unique name.
  1325. MODULE* module = new MODULE( m_board );
  1326. m_board->Add( module, ADD_APPEND );
  1327. char temp[40];
  1328. sprintf( temp, "@HOLE%d", m_hole_count++ );
  1329. module->SetReference( FROM_UTF8( temp ) );
  1330. module->Reference().SetVisible( false );
  1331. wxPoint pos( kicad_x( e.x ), kicad_y( e.y ) );
  1332. module->SetPosition( pos );
  1333. // Add a PAD_ATTRIB_HOLE_NOT_PLATED pad to this module.
  1334. D_PAD* pad = new D_PAD( module );
  1335. module->Pads().PushBack( pad );
  1336. pad->SetShape( PAD_SHAPE_CIRCLE );
  1337. pad->SetAttribute( PAD_ATTRIB_HOLE_NOT_PLATED );
  1338. /* pad's position is already centered on module at relative (0, 0)
  1339. wxPoint padpos( kicad_x( e.x ), kicad_y( e.y ) );
  1340. pad->SetPos0( padpos );
  1341. pad->SetPosition( padpos + module->GetPosition() );
  1342. */
  1343. wxSize sz( kicad( e.drill ), kicad( e.drill ) );
  1344. pad->SetDrillSize( sz );
  1345. pad->SetSize( sz );
  1346. pad->SetLayerSet( LSET::AllCuMask() );
  1347. m_xpath->pop();
  1348. }
  1349. else if( gr->first == "frame" )
  1350. {
  1351. // picture this
  1352. }
  1353. else if( gr->first == "polygon" )
  1354. {
  1355. // could be on a copper layer, could be on another layer.
  1356. // copper layer would be done using netCode=0 type of ZONE_CONTAINER.
  1357. }
  1358. else if( gr->first == "dimension" )
  1359. {
  1360. EDIMENSION d( gr->second );
  1361. DIMENSION* dimension = new DIMENSION( m_board );
  1362. m_board->Add( dimension, ADD_APPEND );
  1363. dimension->SetLayer( kicad_layer( d.layer ) );
  1364. // The origin and end are assumed to always be in this order from eagle
  1365. dimension->SetOrigin( wxPoint( kicad_x( d.x1 ), kicad_y( d.y1 ) ) );
  1366. dimension->SetEnd( wxPoint( kicad_x( d.x2 ), kicad_y( d.y2 ) ) );
  1367. dimension->Text().SetSize( m_board->GetDesignSettings().m_PcbTextSize );
  1368. int width = m_board->GetDesignSettings().m_PcbTextWidth;
  1369. int maxThickness = Clamp_Text_PenSize( width, dimension->Text().GetSize() );
  1370. if( width > maxThickness )
  1371. width = maxThickness;
  1372. dimension->Text().SetThickness( width );
  1373. dimension->SetWidth( width );
  1374. // check which axis the dimension runs in
  1375. // because the "height" of the dimension is perpendicular to that axis
  1376. // Note the check is just if two axes are close enough to each other
  1377. // Eagle appears to have some rounding errors
  1378. if( fabs( d.x1 - d.x2 ) < 0.05 )
  1379. dimension->SetHeight( kicad_x( d.x1 - d.x3 ) );
  1380. else
  1381. dimension->SetHeight( kicad_y( d.y3 - d.y1 ) );
  1382. dimension->AdjustDimensionDetails();
  1383. }
  1384. }
  1385. m_xpath->pop();
  1386. }
  1387. void EAGLE_PLUGIN::loadLibrary( CPTREE& aLib, const string* aLibName )
  1388. {
  1389. m_xpath->push( "packages" );
  1390. // library will have <xmlattr> node, skip that and get the single packages node
  1391. CPTREE& packages = aLib.get_child( "packages" );
  1392. // Create a MODULE for all the eagle packages, for use later via a copy constructor
  1393. // to instantiate needed MODULES in our BOARD. Save the MODULE templates in
  1394. // a MODULE_MAP using a single lookup key consisting of libname+pkgname.
  1395. for( CITER package = packages.begin(); package != packages.end(); ++package )
  1396. {
  1397. m_xpath->push( "package", "name" );
  1398. const string& pack_ref = package->second.get<string>( "<xmlattr>.name" );
  1399. string pack_name( pack_ref );
  1400. ReplaceIllegalFileNameChars( &pack_name );
  1401. #if 0 && defined(DEBUG)
  1402. if( pack_name == "TO220H" )
  1403. {
  1404. int breakhere = 1;
  1405. (void) breakhere;
  1406. }
  1407. #endif
  1408. m_xpath->Value( pack_name.c_str() );
  1409. string key = aLibName ? makeKey( *aLibName, pack_name ) : pack_name;
  1410. MODULE* m = makeModule( package->second, pack_name );
  1411. // add the templating MODULE to the MODULE template factory "m_templates"
  1412. std::pair<MODULE_ITER, bool> r = m_templates.insert( key, m );
  1413. if( !r.second
  1414. // && !( m_props && m_props->Value( "ignore_duplicates" ) )
  1415. )
  1416. {
  1417. wxString lib = aLibName ? FROM_UTF8( aLibName->c_str() ) : m_lib_path;
  1418. wxString pkg = FROM_UTF8( pack_name.c_str() );
  1419. wxString emsg = wxString::Format(
  1420. _( "<package> name: '%s' duplicated in eagle <library>: '%s'" ),
  1421. GetChars( pkg ),
  1422. GetChars( lib )
  1423. );
  1424. THROW_IO_ERROR( emsg );
  1425. }
  1426. m_xpath->pop();
  1427. }
  1428. m_xpath->pop(); // "packages"
  1429. }
  1430. void EAGLE_PLUGIN::loadLibraries( CPTREE& aLibs )
  1431. {
  1432. m_xpath->push( "libraries.library", "name" );
  1433. for( CITER library = aLibs.begin(); library != aLibs.end(); ++library )
  1434. {
  1435. const string& lib_name = library->second.get<string>( "<xmlattr>.name" );
  1436. m_xpath->Value( lib_name.c_str() );
  1437. loadLibrary( library->second, &lib_name );
  1438. }
  1439. m_xpath->pop();
  1440. }
  1441. void EAGLE_PLUGIN::loadElements( CPTREE& aElements )
  1442. {
  1443. m_xpath->push( "elements.element", "name" );
  1444. EATTR name;
  1445. EATTR value;
  1446. bool refanceNamePresetInPackageLayout;
  1447. bool valueNamePresetInPackageLayout;
  1448. for( CITER it = aElements.begin(); it != aElements.end(); ++it )
  1449. {
  1450. if( it->first != "element" )
  1451. continue;
  1452. EELEMENT e( it->second );
  1453. // use "NULL-ness" as an indication of presence of the attribute:
  1454. EATTR* nameAttr = 0;
  1455. EATTR* valueAttr = 0;
  1456. m_xpath->Value( e.name.c_str() );
  1457. string pkg_key = makeKey( e.library, e.package );
  1458. MODULE_CITER mi = m_templates.find( pkg_key );
  1459. if( mi == m_templates.end() )
  1460. {
  1461. wxString emsg = wxString::Format( _( "No '%s' package in library '%s'" ),
  1462. GetChars( FROM_UTF8( e.package.c_str() ) ),
  1463. GetChars( FROM_UTF8( e.library.c_str() ) ) );
  1464. THROW_IO_ERROR( emsg );
  1465. }
  1466. #if defined(DEBUG)
  1467. if( e.name == "ARM_C8" )
  1468. {
  1469. int breakhere = 1;
  1470. (void) breakhere;
  1471. }
  1472. #endif
  1473. // copy constructor to clone the template
  1474. MODULE* m = new MODULE( *mi->second );
  1475. m_board->Add( m, ADD_APPEND );
  1476. // update the nets within the pads of the clone
  1477. for( D_PAD* pad = m->Pads(); pad; pad = pad->Next() )
  1478. {
  1479. string pn_key = makeKey( e.name, TO_UTF8( pad->GetPadName() ) );
  1480. NET_MAP_CITER ni = m_pads_to_nets.find( pn_key );
  1481. if( ni != m_pads_to_nets.end() )
  1482. {
  1483. const ENET* enet = &ni->second;
  1484. pad->SetNetCode( enet->netcode );
  1485. }
  1486. }
  1487. refanceNamePresetInPackageLayout = true;
  1488. valueNamePresetInPackageLayout = true;
  1489. m->SetPosition( wxPoint( kicad_x( e.x ), kicad_y( e.y ) ) );
  1490. // Is >NAME field set in package layout ?
  1491. if( m->GetReference().size() == 0 )
  1492. {
  1493. m->Reference().SetVisible( false ); // No so no show
  1494. refanceNamePresetInPackageLayout = false;
  1495. }
  1496. // Is >VALUE field set in package layout
  1497. if( m->GetValue().size() == 0 )
  1498. {
  1499. m->Value().SetVisible( false ); // No so no show
  1500. valueNamePresetInPackageLayout = false;
  1501. }
  1502. m->SetReference( FROM_UTF8( e.name.c_str() ) );
  1503. m->SetValue( FROM_UTF8( e.value.c_str() ) );
  1504. if( !e.smashed )
  1505. { // Not smashed so show NAME & VALUE
  1506. if( valueNamePresetInPackageLayout )
  1507. m->Value().SetVisible( true ); // Only if place holder in package layout
  1508. if( refanceNamePresetInPackageLayout )
  1509. m->Reference().SetVisible( true ); // Only if place holder in package layout
  1510. }
  1511. else if( *e.smashed == true )
  1512. { // Smasted so set default to no show for NAME and VALUE
  1513. m->Value().SetVisible( false );
  1514. m->Reference().SetVisible( false );
  1515. // initalize these to default values incase the <attribute> elements are not present.
  1516. m_xpath->push( "attribute", "name" );
  1517. // VALUE and NAME can have something like our text "effects" overrides
  1518. // in SWEET and new schematic. Eagle calls these XML elements "attribute".
  1519. // There can be one for NAME and/or VALUE both. Features present in the
  1520. // EATTR override the ones established in the package only if they are
  1521. // present here (except for rot, which if not present means angle zero).
  1522. // So the logic is a bit different than in packageText() and in plain text.
  1523. for( CITER ait = it->second.begin(); ait != it->second.end(); ++ait )
  1524. {
  1525. if( ait->first != "attribute" )
  1526. continue;
  1527. EATTR a( ait->second );
  1528. if( a.name == "NAME" )
  1529. {
  1530. name = a;
  1531. nameAttr = &name;
  1532. // do we have a display attribute ?
  1533. if( a.display )
  1534. {
  1535. // Yes!
  1536. switch( *a.display )
  1537. {
  1538. case EATTR::VALUE :
  1539. nameAttr->name = e.name;
  1540. m->SetReference( e.name );
  1541. if( refanceNamePresetInPackageLayout )
  1542. m->Reference().SetVisible( true );
  1543. break;
  1544. case EATTR::NAME :
  1545. if( refanceNamePresetInPackageLayout )
  1546. {
  1547. m->SetReference( "NAME" );
  1548. m->Reference().SetVisible( true );
  1549. }
  1550. break;
  1551. case EATTR::BOTH :
  1552. if( refanceNamePresetInPackageLayout )
  1553. m->Reference().SetVisible( true );
  1554. nameAttr->name = nameAttr->name + " = " + e.name;
  1555. m->SetReference( "NAME = " + e.name );
  1556. break;
  1557. case EATTR::Off :
  1558. m->Reference().SetVisible( false );
  1559. break;
  1560. default:
  1561. nameAttr->name = e.name;
  1562. if( refanceNamePresetInPackageLayout )
  1563. m->Reference().SetVisible( true );
  1564. }
  1565. }
  1566. else
  1567. // No display, so default is visable, and show value of NAME
  1568. m->Reference().SetVisible( true );
  1569. }
  1570. else if( a.name == "VALUE" )
  1571. {
  1572. value = a;
  1573. valueAttr = &value;
  1574. if( a.display )
  1575. {
  1576. // Yes!
  1577. switch( *a.display )
  1578. {
  1579. case EATTR::VALUE :
  1580. valueAttr->value = e.value;
  1581. m->SetValue( e.value );
  1582. if( valueNamePresetInPackageLayout )
  1583. m->Value().SetVisible( true );
  1584. break;
  1585. case EATTR::NAME :
  1586. if( valueNamePresetInPackageLayout )
  1587. m->Value().SetVisible( true );
  1588. m->SetValue( "VALUE" );
  1589. break;
  1590. case EATTR::BOTH :
  1591. if( valueNamePresetInPackageLayout )
  1592. m->Value().SetVisible( true );
  1593. valueAttr->value = "VALUE = " + e.value;
  1594. m->SetValue( "VALUE = " + e.value );
  1595. break;
  1596. case EATTR::Off :
  1597. m->Value().SetVisible( false );
  1598. break;
  1599. default:
  1600. valueAttr->value = e.value;
  1601. if( valueNamePresetInPackageLayout )
  1602. m->Value().SetVisible( true );
  1603. }
  1604. }
  1605. else
  1606. // No display, so default is visible, and show value of NAME
  1607. m->Value().SetVisible( true );
  1608. }
  1609. }
  1610. m_xpath->pop(); // "attribute"
  1611. }
  1612. orientModuleAndText( m, e, nameAttr, valueAttr );
  1613. }
  1614. m_xpath->pop(); // "elements.element"
  1615. }
  1616. void EAGLE_PLUGIN::orientModuleAndText( MODULE* m, const EELEMENT& e,
  1617. const EATTR* nameAttr, const EATTR* valueAttr )
  1618. {
  1619. if( e.rot )
  1620. {
  1621. if( e.rot->mirror )
  1622. {
  1623. double orientation = e.rot->degrees + 180.0;
  1624. m->SetOrientation( orientation * 10 );
  1625. m->Flip( m->GetPosition() );
  1626. }
  1627. else
  1628. m->SetOrientation( e.rot->degrees * 10 );
  1629. }
  1630. orientModuleText( m, e, &m->Reference(), nameAttr );
  1631. orientModuleText( m, e, &m->Value(), valueAttr );
  1632. }
  1633. void EAGLE_PLUGIN::orientModuleText( MODULE* m, const EELEMENT& e,
  1634. TEXTE_MODULE* txt, const EATTR* aAttr )
  1635. {
  1636. // Smashed part ?
  1637. if( aAttr )
  1638. { // Yes
  1639. const EATTR& a = *aAttr;
  1640. if( a.value )
  1641. {
  1642. txt->SetText( FROM_UTF8( a.value->c_str() ) );
  1643. }
  1644. if( a.x && a.y ) // boost::optional
  1645. {
  1646. wxPoint pos( kicad_x( *a.x ), kicad_y( *a.y ) );
  1647. txt->SetTextPosition( pos );
  1648. }
  1649. // Even though size and ratio are both optional, I am not seeing
  1650. // a case where ratio is present but size is not.
  1651. double ratio = 8;
  1652. wxSize fontz = txt->GetSize();
  1653. if( a.size )
  1654. {
  1655. fontz = kicad_fontz( *a.size );
  1656. txt->SetSize( fontz );
  1657. if( a.ratio )
  1658. ratio = *a.ratio;
  1659. }
  1660. int lw = int( fontz.y * ratio / 100.0 );
  1661. txt->SetThickness( lw );
  1662. int align = ETEXT::BOTTOM_LEFT; // bottom-left is eagle default
  1663. // The "rot" in a EATTR seems to be assumed to be zero if it is not
  1664. // present, and this zero rotation becomes an override to the
  1665. // package's text field. If they did not want zero, they specify
  1666. // what they want explicitly.
  1667. double degrees = a.rot ? a.rot->degrees : 0;
  1668. double orient; // relative to parent
  1669. int sign = 1;
  1670. bool spin = false;
  1671. if( a.rot )
  1672. {
  1673. spin = a.rot->spin;
  1674. sign = a.rot->mirror ? -1 : 1;
  1675. txt->SetMirrored( a.rot->mirror );
  1676. }
  1677. if( degrees == 90 || degrees == 0 || spin )
  1678. {
  1679. orient = degrees - m->GetOrientation() / 10;
  1680. txt->SetOrientation( sign * orient * 10 );
  1681. }
  1682. else if( degrees == 180 )
  1683. {
  1684. orient = 0 - m->GetOrientation() / 10;
  1685. txt->SetOrientation( sign * orient * 10 );
  1686. align = ETEXT::TOP_RIGHT;
  1687. }
  1688. else if( degrees == 270 )
  1689. {
  1690. orient = 90 - m->GetOrientation() / 10;
  1691. align = ETEXT::TOP_RIGHT;
  1692. txt->SetOrientation( sign * orient * 10 );
  1693. }
  1694. else
  1695. {
  1696. orient = 90 - degrees - m->GetOrientation() / 10;
  1697. txt->SetOrientation( sign * orient * 10 );
  1698. }
  1699. switch( align )
  1700. {
  1701. case ETEXT::TOP_RIGHT:
  1702. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  1703. txt->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
  1704. break;
  1705. case ETEXT::BOTTOM_LEFT:
  1706. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  1707. txt->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  1708. break;
  1709. default:
  1710. ;
  1711. }
  1712. }
  1713. else // Part is not smash so use Lib default for NAME/VALUE // the text is per the original package, sans <attribute>
  1714. {
  1715. double degrees = ( txt->GetOrientation() + m->GetOrientation() ) / 10;
  1716. // @todo there are a few more cases than these to contend with:
  1717. if( (!txt->IsMirrored() && ( abs( degrees ) == 180 || abs( degrees ) == 270 ))
  1718. || ( txt->IsMirrored() && ( degrees == 360 ) ) )
  1719. {
  1720. // ETEXT::TOP_RIGHT:
  1721. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  1722. txt->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
  1723. }
  1724. }
  1725. }
  1726. MODULE* EAGLE_PLUGIN::makeModule( CPTREE& aPackage, const string& aPkgName ) const
  1727. {
  1728. std::unique_ptr<MODULE> m( new MODULE( m_board ) );
  1729. m->SetFPID( LIB_ID( aPkgName ) );
  1730. opt_string description = aPackage.get_optional<string>( "description" );
  1731. if( description )
  1732. m->SetDescription( FROM_UTF8( description->c_str() ) );
  1733. for( CITER it = aPackage.begin(); it != aPackage.end(); ++it )
  1734. {
  1735. CPTREE& t = it->second;
  1736. if( it->first == "wire" )
  1737. packageWire( m.get(), t );
  1738. else if( it->first == "pad" )
  1739. packagePad( m.get(), t );
  1740. else if( it->first == "text" )
  1741. packageText( m.get(), t );
  1742. else if( it->first == "rectangle" )
  1743. packageRectangle( m.get(), t );
  1744. else if( it->first == "polygon" )
  1745. packagePolygon( m.get(), t );
  1746. else if( it->first == "circle" )
  1747. packageCircle( m.get(), t );
  1748. else if( it->first == "hole" )
  1749. packageHole( m.get(), t );
  1750. else if( it->first == "smd" )
  1751. packageSMD( m.get(), t );
  1752. }
  1753. return m.release();
  1754. }
  1755. void EAGLE_PLUGIN::packageWire( MODULE* aModule, CPTREE& aTree ) const
  1756. {
  1757. EWIRE w( aTree );
  1758. LAYER_ID layer = kicad_layer( w.layer );
  1759. if( IsNonCopperLayer( layer ) ) // only valid non-copper wires, skip copper package wires
  1760. {
  1761. wxPoint start( kicad_x( w.x1 ), kicad_y( w.y1 ) );
  1762. wxPoint end( kicad_x( w.x2 ), kicad_y( w.y2 ) );
  1763. int width = kicad( w.width );
  1764. // FIXME: the cap attribute is ignored because kicad can't create lines
  1765. // with flat ends.
  1766. EDGE_MODULE* dwg;
  1767. if( !w.curve )
  1768. {
  1769. dwg = new EDGE_MODULE( aModule, S_SEGMENT );
  1770. dwg->SetStart0( start );
  1771. dwg->SetEnd0( end );
  1772. }
  1773. else
  1774. {
  1775. dwg = new EDGE_MODULE( aModule, S_ARC );
  1776. wxPoint center = kicad_arc_center( start, end, *w.curve);
  1777. dwg->SetStart0( center );
  1778. dwg->SetEnd0( start );
  1779. dwg->SetAngle( *w.curve * -10.0 ); // KiCad rotates the other way
  1780. }
  1781. dwg->SetLayer( layer );
  1782. dwg->SetWidth( width );
  1783. aModule->GraphicalItems().PushBack( dwg );
  1784. }
  1785. }
  1786. void EAGLE_PLUGIN::packagePad( MODULE* aModule, CPTREE& aTree ) const
  1787. {
  1788. // this is thru hole technology here, no SMDs
  1789. EPAD e( aTree );
  1790. D_PAD* pad = new D_PAD( aModule );
  1791. aModule->Pads().PushBack( pad );
  1792. pad->SetPadName( FROM_UTF8( e.name.c_str() ) );
  1793. // pad's "Position" is not relative to the module's,
  1794. // whereas Pos0 is relative to the module's but is the unrotated coordinate.
  1795. wxPoint padpos( kicad_x( e.x ), kicad_y( e.y ) );
  1796. pad->SetPos0( padpos );
  1797. RotatePoint( &padpos, aModule->GetOrientation() );
  1798. pad->SetPosition( padpos + aModule->GetPosition() );
  1799. pad->SetDrillSize( wxSize( kicad( e.drill ), kicad( e.drill ) ) );
  1800. pad->SetLayerSet( LSET::AllCuMask().set( B_Mask ).set( F_Mask ) );
  1801. if( e.shape )
  1802. {
  1803. switch( *e.shape )
  1804. {
  1805. case EPAD::ROUND:
  1806. wxASSERT( pad->GetShape()==PAD_SHAPE_CIRCLE ); // verify set in D_PAD constructor
  1807. break;
  1808. case EPAD::OCTAGON:
  1809. // no KiCad octagonal pad shape, use PAD_CIRCLE for now.
  1810. // pad->SetShape( PAD_OCTAGON );
  1811. wxASSERT( pad->GetShape()==PAD_SHAPE_CIRCLE ); // verify set in D_PAD constructor
  1812. break;
  1813. case EPAD::LONG:
  1814. pad->SetShape( PAD_SHAPE_OVAL );
  1815. break;
  1816. case EPAD::SQUARE:
  1817. pad->SetShape( PAD_SHAPE_RECT );
  1818. break;
  1819. case EPAD::OFFSET:
  1820. ; // don't know what to do here.
  1821. }
  1822. }
  1823. else
  1824. {
  1825. // if shape is not present, our default is circle and that matches their default "round"
  1826. }
  1827. if( e.diameter )
  1828. {
  1829. int diameter = kicad( *e.diameter );
  1830. pad->SetSize( wxSize( diameter, diameter ) );
  1831. }
  1832. else
  1833. {
  1834. double drillz = pad->GetDrillSize().x;
  1835. double annulus = drillz * m_rules->rvPadTop; // copper annulus, eagle "restring"
  1836. annulus = Clamp( m_rules->rlMinPadTop, annulus, m_rules->rlMaxPadTop );
  1837. int diameter = KiROUND( drillz + 2 * annulus );
  1838. pad->SetSize( wxSize( KiROUND( diameter ), KiROUND( diameter ) ) );
  1839. }
  1840. if( pad->GetShape() == PAD_SHAPE_OVAL )
  1841. {
  1842. // The Eagle "long" pad is wider than it is tall,
  1843. // m_elongation is percent elongation
  1844. wxSize sz = pad->GetSize();
  1845. sz.x = ( sz.x * ( 100 + m_rules->psElongationLong ) ) / 100;
  1846. pad->SetSize( sz );
  1847. }
  1848. if( e.rot )
  1849. {
  1850. pad->SetOrientation( e.rot->degrees * 10 );
  1851. }
  1852. // @todo: handle stop and thermal
  1853. }
  1854. void EAGLE_PLUGIN::packageText( MODULE* aModule, CPTREE& aTree ) const
  1855. {
  1856. ETEXT t( aTree );
  1857. LAYER_ID layer = kicad_layer( t.layer );
  1858. if( layer == UNDEFINED_LAYER )
  1859. {
  1860. layer = Cmts_User;
  1861. }
  1862. TEXTE_MODULE* txt;
  1863. if( t.text == ">NAME" || t.text == ">name" )
  1864. txt = &aModule->Reference();
  1865. else if( t.text == ">VALUE" || t.text == ">value" )
  1866. txt = &aModule->Value();
  1867. else
  1868. {
  1869. // FIXME: graphical text items are rotated for some reason.
  1870. txt = new TEXTE_MODULE( aModule );
  1871. aModule->GraphicalItems().PushBack( txt );
  1872. }
  1873. txt->SetTimeStamp( timeStamp( aTree ) );
  1874. txt->SetText( FROM_UTF8( t.text.c_str() ) );
  1875. wxPoint pos( kicad_x( t.x ), kicad_y( t.y ) );
  1876. txt->SetTextPosition( pos );
  1877. txt->SetPos0( pos - aModule->GetPosition() );
  1878. txt->SetLayer( layer );
  1879. txt->SetSize( kicad_fontz( t.size ) );
  1880. double ratio = t.ratio ? *t.ratio : 8; // DTD says 8 is default
  1881. txt->SetThickness( kicad( t.size * ratio / 100 ) );
  1882. int align = t.align ? *t.align : ETEXT::BOTTOM_LEFT; // bottom-left is eagle default
  1883. // An eagle package is never rotated, the DTD does not allow it.
  1884. // angle -= aModule->GetOrienation();
  1885. if( t.rot )
  1886. {
  1887. int sign = t.rot->mirror ? -1 : 1;
  1888. txt->SetMirrored( t.rot->mirror );
  1889. double degrees = t.rot->degrees;
  1890. if( degrees == 90 || t.rot->spin )
  1891. txt->SetOrientation( sign * degrees * 10 );
  1892. else if( degrees == 180 )
  1893. align = ETEXT::TOP_RIGHT;
  1894. else if( degrees == 270 )
  1895. {
  1896. align = ETEXT::TOP_RIGHT;
  1897. txt->SetOrientation( sign * 90 * 10 );
  1898. }
  1899. }
  1900. switch( align )
  1901. {
  1902. case ETEXT::CENTER:
  1903. // this was the default in pcbtxt's constructor
  1904. break;
  1905. case ETEXT::CENTER_LEFT:
  1906. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  1907. break;
  1908. case ETEXT::CENTER_RIGHT:
  1909. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  1910. break;
  1911. case ETEXT::TOP_CENTER:
  1912. txt->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
  1913. break;
  1914. case ETEXT::TOP_LEFT:
  1915. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  1916. txt->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
  1917. break;
  1918. case ETEXT::TOP_RIGHT:
  1919. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  1920. txt->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
  1921. break;
  1922. case ETEXT::BOTTOM_CENTER:
  1923. txt->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  1924. break;
  1925. case ETEXT::BOTTOM_LEFT:
  1926. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  1927. txt->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  1928. break;
  1929. case ETEXT::BOTTOM_RIGHT:
  1930. txt->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  1931. txt->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  1932. break;
  1933. }
  1934. }
  1935. void EAGLE_PLUGIN::packageRectangle( MODULE* aModule, CPTREE& aTree ) const
  1936. {
  1937. ERECT r( aTree );
  1938. LAYER_ID layer = kicad_layer( r.layer );
  1939. if( IsNonCopperLayer( layer ) ) // skip copper "package.rectangle"s
  1940. {
  1941. EDGE_MODULE* dwg = new EDGE_MODULE( aModule, S_POLYGON );
  1942. aModule->GraphicalItems().PushBack( dwg );
  1943. dwg->SetLayer( layer );
  1944. dwg->SetWidth( 0 );
  1945. dwg->SetTimeStamp( timeStamp( aTree ) );
  1946. std::vector<wxPoint> pts;
  1947. wxPoint start( wxPoint( kicad_x( r.x1 ), kicad_y( r.y1 ) ) );
  1948. wxPoint end( wxPoint( kicad_x( r.x1 ), kicad_y( r.y2 ) ) );
  1949. pts.push_back( start );
  1950. pts.push_back( wxPoint( kicad_x( r.x2 ), kicad_y( r.y1 ) ) );
  1951. pts.push_back( wxPoint( kicad_x( r.x2 ), kicad_y( r.y2 ) ) );
  1952. pts.push_back( end );
  1953. dwg->SetPolyPoints( pts );
  1954. dwg->SetStart0( start );
  1955. dwg->SetEnd0( end );
  1956. }
  1957. }
  1958. void EAGLE_PLUGIN::packagePolygon( MODULE* aModule, CPTREE& aTree ) const
  1959. {
  1960. EPOLYGON p( aTree );
  1961. LAYER_ID layer = kicad_layer( p.layer );
  1962. if( IsNonCopperLayer( layer ) ) // skip copper "package.rectangle"s
  1963. {
  1964. EDGE_MODULE* dwg = new EDGE_MODULE( aModule, S_POLYGON );
  1965. aModule->GraphicalItems().PushBack( dwg );
  1966. dwg->SetWidth( 0 ); // it's filled, no need for boundary width
  1967. /*
  1968. switch( layer )
  1969. {
  1970. case Eco1_User: layer = F_SilkS; break;
  1971. case Eco2_User: layer = B_SilkS; break;
  1972. // all MODULE templates (created from eagle packages) are on front layer
  1973. // until cloned.
  1974. case Cmts_User: layer = F_SilkS; break;
  1975. }
  1976. */
  1977. dwg->SetLayer( layer );
  1978. dwg->SetTimeStamp( timeStamp( aTree ) );
  1979. std::vector<wxPoint> pts;
  1980. pts.reserve( aTree.size() );
  1981. for( CITER vi = aTree.begin(); vi != aTree.end(); ++vi )
  1982. {
  1983. if( vi->first != "vertex" ) // skip <xmlattr> node
  1984. continue;
  1985. EVERTEX v( vi->second );
  1986. pts.push_back( wxPoint( kicad_x( v.x ), kicad_y( v.y ) ) );
  1987. }
  1988. dwg->SetPolyPoints( pts );
  1989. dwg->SetStart0( *pts.begin() );
  1990. dwg->SetEnd0( pts.back() );
  1991. }
  1992. }
  1993. void EAGLE_PLUGIN::packageCircle( MODULE* aModule, CPTREE& aTree ) const
  1994. {
  1995. ECIRCLE e( aTree );
  1996. LAYER_ID layer = kicad_layer( e.layer );
  1997. EDGE_MODULE* gr = new EDGE_MODULE( aModule, S_CIRCLE );
  1998. aModule->GraphicalItems().PushBack( gr );
  1999. gr->SetWidth( kicad( e.width ) );
  2000. switch( (int) layer )
  2001. {
  2002. case UNDEFINED_LAYER: layer = Cmts_User; break;
  2003. /*
  2004. case Eco1_User: layer = F_SilkS; break;
  2005. case Eco2_User: layer = B_SilkS; break;
  2006. */
  2007. default:
  2008. break;
  2009. }
  2010. gr->SetLayer( layer );
  2011. gr->SetTimeStamp( timeStamp( aTree ) );
  2012. gr->SetStart0( wxPoint( kicad_x( e.x ), kicad_y( e.y ) ) );
  2013. gr->SetEnd0( wxPoint( kicad_x( e.x + e.radius ), kicad_y( e.y ) ) );
  2014. }
  2015. void EAGLE_PLUGIN::packageHole( MODULE* aModule, CPTREE& aTree ) const
  2016. {
  2017. EHOLE e( aTree );
  2018. // we add a PAD_ATTRIB_HOLE_NOT_PLATED pad to this module.
  2019. D_PAD* pad = new D_PAD( aModule );
  2020. aModule->Pads().PushBack( pad );
  2021. pad->SetShape( PAD_SHAPE_CIRCLE );
  2022. pad->SetAttribute( PAD_ATTRIB_HOLE_NOT_PLATED );
  2023. // Mechanical purpose only:
  2024. // no offset, no net name, no pad name allowed
  2025. // pad->SetOffset( wxPoint( 0, 0 ) );
  2026. // pad->SetPadName( wxEmptyString );
  2027. wxPoint padpos( kicad_x( e.x ), kicad_y( e.y ) );
  2028. pad->SetPos0( padpos );
  2029. pad->SetPosition( padpos + aModule->GetPosition() );
  2030. wxSize sz( kicad( e.drill ), kicad( e.drill ) );
  2031. pad->SetDrillSize( sz );
  2032. pad->SetSize( sz );
  2033. pad->SetLayerSet( LSET::AllCuMask() /* | SOLDERMASK_LAYER_BACK | SOLDERMASK_LAYER_FRONT */ );
  2034. }
  2035. void EAGLE_PLUGIN::packageSMD( MODULE* aModule, CPTREE& aTree ) const
  2036. {
  2037. ESMD e( aTree );
  2038. LAYER_ID layer = kicad_layer( e.layer );
  2039. if( !IsCopperLayer( layer ) )
  2040. {
  2041. return;
  2042. }
  2043. D_PAD* pad = new D_PAD( aModule );
  2044. aModule->Pads().PushBack( pad );
  2045. pad->SetPadName( FROM_UTF8( e.name.c_str() ) );
  2046. pad->SetShape( PAD_SHAPE_RECT );
  2047. pad->SetAttribute( PAD_ATTRIB_SMD );
  2048. // pad's "Position" is not relative to the module's,
  2049. // whereas Pos0 is relative to the module's but is the unrotated coordinate.
  2050. wxPoint padpos( kicad_x( e.x ), kicad_y( e.y ) );
  2051. pad->SetPos0( padpos );
  2052. RotatePoint( &padpos, aModule->GetOrientation() );
  2053. pad->SetPosition( padpos + aModule->GetPosition() );
  2054. pad->SetSize( wxSize( kicad( e.dx ), kicad( e.dy ) ) );
  2055. pad->SetLayer( layer );
  2056. static const LSET front( 3, F_Cu, F_Paste, F_Mask );
  2057. static const LSET back( 3, B_Cu, B_Paste, B_Mask );
  2058. if( layer == F_Cu )
  2059. pad->SetLayerSet( front );
  2060. else if( layer == B_Cu )
  2061. pad->SetLayerSet( back );
  2062. // Optional according to DTD
  2063. if( e.roundness ) // set set shape to PAD_SHAPE_RECT above, in case roundness is not present
  2064. {
  2065. if( *e.roundness >= 75 ) // roundness goes from 0-100% as integer
  2066. {
  2067. if( e.dy == e.dx )
  2068. pad->SetShape( PAD_SHAPE_CIRCLE );
  2069. else
  2070. pad->SetShape( PAD_SHAPE_OVAL );
  2071. }
  2072. }
  2073. if( e.rot )
  2074. {
  2075. pad->SetOrientation( e.rot->degrees * 10 );
  2076. }
  2077. // don't know what stop, thermals, and cream should look like now.
  2078. }
  2079. /// non-owning container
  2080. typedef std::vector<ZONE_CONTAINER*> ZONES;
  2081. void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals )
  2082. {
  2083. ZONES zones; // per net
  2084. m_xpath->push( "signals.signal", "name" );
  2085. int netCode = 1;
  2086. for( CITER net = aSignals.begin(); net != aSignals.end(); ++net )
  2087. {
  2088. bool sawPad = false;
  2089. zones.clear();
  2090. const string& nname = net->second.get<string>( "<xmlattr>.name" );
  2091. wxString netName = FROM_UTF8( nname.c_str() );
  2092. m_board->Add( new NETINFO_ITEM( m_board, netName, netCode ) );
  2093. m_xpath->Value( nname.c_str() );
  2094. #if defined(DEBUG)
  2095. if( netName == wxT( "N$8" ) )
  2096. {
  2097. int breakhere = 1;
  2098. (void) breakhere;
  2099. }
  2100. #endif
  2101. // (contactref | polygon | wire | via)*
  2102. for( CITER it = net->second.begin(); it != net->second.end(); ++it )
  2103. {
  2104. if( it->first == "wire" )
  2105. {
  2106. m_xpath->push( "wire" );
  2107. EWIRE w( it->second );
  2108. LAYER_ID layer = kicad_layer( w.layer );
  2109. if( IsCopperLayer( layer ) )
  2110. {
  2111. TRACK* t = new TRACK( m_board );
  2112. t->SetTimeStamp( timeStamp( it->second ) );
  2113. t->SetPosition( wxPoint( kicad_x( w.x1 ), kicad_y( w.y1 ) ) );
  2114. t->SetEnd( wxPoint( kicad_x( w.x2 ), kicad_y( w.y2 ) ) );
  2115. int width = kicad( w.width );
  2116. if( width < m_min_trace )
  2117. m_min_trace = width;
  2118. t->SetWidth( width );
  2119. t->SetLayer( layer );
  2120. t->SetNetCode( netCode );
  2121. m_board->m_Track.Insert( t, NULL );
  2122. }
  2123. else
  2124. {
  2125. // put non copper wires where the sun don't shine.
  2126. }
  2127. m_xpath->pop();
  2128. }
  2129. else if( it->first == "via" )
  2130. {
  2131. m_xpath->push( "via" );
  2132. EVIA v( it->second );
  2133. LAYER_ID layer_front_most = kicad_layer( v.layer_front_most );
  2134. LAYER_ID layer_back_most = kicad_layer( v.layer_back_most );
  2135. if( IsCopperLayer( layer_front_most ) &&
  2136. IsCopperLayer( layer_back_most ) )
  2137. {
  2138. int kidiam;
  2139. int drillz = kicad( v.drill );
  2140. VIA* via = new VIA( m_board );
  2141. m_board->m_Track.Insert( via, NULL );
  2142. via->SetLayerPair( layer_front_most, layer_back_most );
  2143. if( v.diam )
  2144. {
  2145. kidiam = kicad( *v.diam );
  2146. via->SetWidth( kidiam );
  2147. }
  2148. else
  2149. {
  2150. double annulus = drillz * m_rules->rvViaOuter; // eagle "restring"
  2151. annulus = Clamp( m_rules->rlMinViaOuter, annulus, m_rules->rlMaxViaOuter );
  2152. kidiam = KiROUND( drillz + 2 * annulus );
  2153. via->SetWidth( kidiam );
  2154. }
  2155. via->SetDrill( drillz );
  2156. if( kidiam < m_min_via )
  2157. m_min_via = kidiam;
  2158. if( drillz < m_min_via_hole )
  2159. m_min_via_hole = drillz;
  2160. if( layer_front_most == F_Cu && layer_back_most == B_Cu )
  2161. via->SetViaType( VIA_THROUGH );
  2162. else if( layer_front_most == F_Cu || layer_back_most == B_Cu )
  2163. via->SetViaType( VIA_MICROVIA );
  2164. else
  2165. via->SetViaType( VIA_BLIND_BURIED );
  2166. via->SetTimeStamp( timeStamp( it->second ) );
  2167. wxPoint pos( kicad_x( v.x ), kicad_y( v.y ) );
  2168. via->SetPosition( pos );
  2169. via->SetEnd( pos );
  2170. via->SetNetCode( netCode );
  2171. }
  2172. m_xpath->pop();
  2173. }
  2174. else if( it->first == "contactref" )
  2175. {
  2176. m_xpath->push( "contactref" );
  2177. // <contactref element="RN1" pad="7"/>
  2178. CPTREE& attribs = it->second.get_child( "<xmlattr>" );
  2179. const string& reference = attribs.get<string>( "element" );
  2180. const string& pad = attribs.get<string>( "pad" );
  2181. string key = makeKey( reference, pad ) ;
  2182. // D(printf( "adding refname:'%s' pad:'%s' netcode:%d netname:'%s'\n", reference.c_str(), pad.c_str(), netCode, nname.c_str() );)
  2183. m_pads_to_nets[ key ] = ENET( netCode, nname );
  2184. m_xpath->pop();
  2185. sawPad = true;
  2186. }
  2187. else if( it->first == "polygon" )
  2188. {
  2189. m_xpath->push( "polygon" );
  2190. EPOLYGON p( it->second );
  2191. LAYER_ID layer = kicad_layer( p.layer );
  2192. if( IsCopperLayer( layer ) )
  2193. {
  2194. // use a "netcode = 0" type ZONE:
  2195. ZONE_CONTAINER* zone = new ZONE_CONTAINER( m_board );
  2196. m_board->Add( zone, ADD_APPEND );
  2197. zones.push_back( zone );
  2198. zone->SetTimeStamp( timeStamp( it->second ) );
  2199. zone->SetLayer( layer );
  2200. zone->SetNetCode( netCode );
  2201. bool first = true;
  2202. for( CITER vi = it->second.begin(); vi != it->second.end(); ++vi )
  2203. {
  2204. if( vi->first != "vertex" ) // skip <xmlattr> node
  2205. continue;
  2206. EVERTEX v( vi->second );
  2207. // the ZONE_CONTAINER API needs work, as you can see:
  2208. if( first )
  2209. {
  2210. zone->Outline()->Start( layer, kicad_x( v.x ), kicad_y( v.y ),
  2211. CPolyLine::NO_HATCH);
  2212. first = false;
  2213. }
  2214. else
  2215. zone->AppendCorner( wxPoint( kicad_x( v.x ), kicad_y( v.y ) ) );
  2216. }
  2217. zone->Outline()->CloseLastContour();
  2218. // If the pour is a cutout it needs to be set to a keepout
  2219. if( p.pour == EPOLYGON::CUTOUT )
  2220. {
  2221. zone->SetIsKeepout( true );
  2222. zone->SetDoNotAllowCopperPour( true );
  2223. zone->Outline()->SetHatchStyle( CPolyLine::NO_HATCH );
  2224. }
  2225. // if spacing is set the zone should be hatched
  2226. if( p.spacing )
  2227. zone->Outline()->SetHatch( CPolyLine::DIAGONAL_EDGE,
  2228. *p.spacing,
  2229. true );
  2230. // clearances, etc.
  2231. zone->SetArcSegmentCount( 32 ); // @todo: should be a constructor default?
  2232. zone->SetMinThickness( kicad( p.width ) );
  2233. // FIXME: KiCad zones have very rounded corners compared to eagle.
  2234. // This means that isolation amounts that work well in eagle
  2235. // tend to make copper intrude in soldermask free areas around pads.
  2236. if( p.isolate )
  2237. {
  2238. zone->SetZoneClearance( kicad( *p.isolate ) );
  2239. }
  2240. // missing == yes per DTD.
  2241. bool thermals = !p.thermals || *p.thermals;
  2242. zone->SetPadConnection( thermals ? PAD_ZONE_CONN_THERMAL : PAD_ZONE_CONN_FULL );
  2243. if( thermals )
  2244. {
  2245. // FIXME: eagle calculates dimensions for thermal spokes
  2246. // based on what the zone is connecting to.
  2247. // (i.e. width of spoke is half of the smaller side of an smd pad)
  2248. // This is a basic workaround
  2249. zone->SetThermalReliefGap( kicad( p.width + 0.05 ) );
  2250. zone->SetThermalReliefCopperBridge( kicad( p.width + 0.05 ) );
  2251. }
  2252. int rank = p.rank ? *p.rank : p.max_priority;
  2253. zone->SetPriority( rank );
  2254. }
  2255. m_xpath->pop(); // "polygon"
  2256. }
  2257. }
  2258. if( zones.size() && !sawPad )
  2259. {
  2260. // KiCad does not support an unconnected zone with its own non-zero netcode,
  2261. // but only when assigned netcode = 0 w/o a name...
  2262. for( ZONES::iterator it = zones.begin(); it != zones.end(); ++it )
  2263. (*it)->SetNetCode( NETINFO_LIST::UNCONNECTED );
  2264. // therefore omit this signal/net.
  2265. }
  2266. else
  2267. netCode++;
  2268. }
  2269. m_xpath->pop(); // "signals.signal"
  2270. }
  2271. LAYER_ID EAGLE_PLUGIN::kicad_layer( int aEagleLayer ) const
  2272. {
  2273. /* will assume this is a valid mapping for all eagle boards until I get paid more:
  2274. <layers>
  2275. <layer number="1" name="Top" color="4" fill="1" visible="yes" active="yes"/>
  2276. <layer number="2" name="Route2" color="1" fill="3" visible="no" active="no"/>
  2277. <layer number="3" name="Route3" color="4" fill="3" visible="no" active="no"/>
  2278. <layer number="4" name="Route4" color="1" fill="4" visible="no" active="no"/>
  2279. <layer number="5" name="Route5" color="4" fill="4" visible="no" active="no"/>
  2280. <layer number="6" name="Route6" color="1" fill="8" visible="no" active="no"/>
  2281. <layer number="7" name="Route7" color="4" fill="8" visible="no" active="no"/>
  2282. <layer number="8" name="Route8" color="1" fill="2" visible="no" active="no"/>
  2283. <layer number="9" name="Route9" color="4" fill="2" visible="no" active="no"/>
  2284. <layer number="10" name="Route10" color="1" fill="7" visible="no" active="no"/>
  2285. <layer number="11" name="Route11" color="4" fill="7" visible="no" active="no"/>
  2286. <layer number="12" name="Route12" color="1" fill="5" visible="no" active="no"/>
  2287. <layer number="13" name="Route13" color="4" fill="5" visible="no" active="no"/>
  2288. <layer number="14" name="Route14" color="1" fill="6" visible="no" active="no"/>
  2289. <layer number="15" name="Route15" color="4" fill="6" visible="no" active="no"/>
  2290. <layer number="16" name="Bottom" color="1" fill="1" visible="yes" active="yes"/>
  2291. <layer number="17" name="Pads" color="2" fill="1" visible="yes" active="yes"/>
  2292. <layer number="18" name="Vias" color="14" fill="1" visible="yes" active="yes"/>
  2293. <layer number="19" name="Unrouted" color="6" fill="1" visible="yes" active="yes"/>
  2294. <layer number="20" name="Dimension" color="15" fill="1" visible="yes" active="yes"/>
  2295. <layer number="21" name="tPlace" color="7" fill="1" visible="yes" active="yes"/>
  2296. <layer number="22" name="bPlace" color="7" fill="1" visible="yes" active="yes"/>
  2297. <layer number="23" name="tOrigins" color="15" fill="1" visible="yes" active="yes"/>
  2298. <layer number="24" name="bOrigins" color="15" fill="1" visible="yes" active="yes"/>
  2299. <layer number="25" name="tNames" color="7" fill="1" visible="yes" active="yes"/>
  2300. <layer number="26" name="bNames" color="7" fill="1" visible="yes" active="yes"/>
  2301. <layer number="27" name="tValues" color="7" fill="1" visible="no" active="yes"/>
  2302. <layer number="28" name="bValues" color="7" fill="1" visible="no" active="yes"/>
  2303. <layer number="29" name="tStop" color="2" fill="3" visible="no" active="yes"/>
  2304. <layer number="30" name="bStop" color="5" fill="6" visible="no" active="yes"/>
  2305. <layer number="31" name="tCream" color="7" fill="4" visible="no" active="yes"/>
  2306. <layer number="32" name="bCream" color="7" fill="5" visible="no" active="yes"/>
  2307. <layer number="33" name="tFinish" color="6" fill="3" visible="no" active="yes"/>
  2308. <layer number="34" name="bFinish" color="6" fill="6" visible="no" active="yes"/>
  2309. <layer number="35" name="tGlue" color="7" fill="4" visible="no" active="yes"/>
  2310. <layer number="36" name="bGlue" color="7" fill="5" visible="no" active="yes"/>
  2311. <layer number="37" name="tTest" color="7" fill="1" visible="no" active="yes"/>
  2312. <layer number="38" name="bTest" color="7" fill="1" visible="no" active="yes"/>
  2313. <layer number="39" name="tKeepout" color="4" fill="11" visible="no" active="yes"/>
  2314. <layer number="40" name="bKeepout" color="1" fill="11" visible="no" active="yes"/>
  2315. <layer number="41" name="tRestrict" color="4" fill="10" visible="no" active="yes"/>
  2316. <layer number="42" name="bRestrict" color="1" fill="10" visible="no" active="yes"/>
  2317. <layer number="43" name="vRestrict" color="2" fill="10" visible="no" active="yes"/>
  2318. <layer number="44" name="Drills" color="7" fill="1" visible="no" active="yes"/>
  2319. <layer number="45" name="Holes" color="7" fill="1" visible="no" active="yes"/>
  2320. <layer number="46" name="Milling" color="3" fill="1" visible="no" active="yes"/>
  2321. <layer number="47" name="Measures" color="7" fill="1" visible="no" active="yes"/>
  2322. <layer number="48" name="Document" color="7" fill="1" visible="no" active="yes"/>
  2323. <layer number="49" name="ReferenceLC" color="13" fill="1" visible="yes" active="yes"/>
  2324. <layer number="50" name="ReferenceLS" color="12" fill="1" visible="yes" active="yes"/>
  2325. <layer number="51" name="tDocu" color="7" fill="1" visible="yes" active="yes"/>
  2326. <layer number="52" name="bDocu" color="7" fill="1" visible="yes" active="yes"/>
  2327. * These layers are used only in eagle schematic.
  2328. * They should not be found in board files.
  2329. * They are listed for info only.
  2330. <layer number="91" name="Nets" color="2" fill="1" visible="no" active="no"/>
  2331. <layer number="92" name="Busses" color="1" fill="1" visible="no" active="no"/>
  2332. <layer number="93" name="Pins" color="2" fill="1" visible="no" active="no"/>
  2333. <layer number="94" name="Symbols" color="4" fill="1" visible="no" active="no"/>
  2334. <layer number="95" name="Names" color="7" fill="1" visible="no" active="no"/>
  2335. <layer number="96" name="Values" color="7" fill="1" visible="no" active="no"/>
  2336. <layer number="97" name="Info" color="7" fill="1" visible="no" active="no"/>
  2337. <layer number="98" name="Guide" color="6" fill="1" visible="no" active="no"/>
  2338. * These layers are user layers
  2339. <layer number="160" name="???" color="7" fill="1" visible="yes" active="yes"/>
  2340. <layer number="161" name="???" color="7" fill="1" visible="yes" active="yes"/>
  2341. </layers>
  2342. */
  2343. int kiLayer;
  2344. // eagle copper layer:
  2345. if( aEagleLayer >= 1 && aEagleLayer < int( DIM( m_cu_map ) ) )
  2346. {
  2347. kiLayer = m_cu_map[aEagleLayer];
  2348. }
  2349. else
  2350. {
  2351. // translate non-copper eagle layer to pcbnew layer
  2352. switch( aEagleLayer )
  2353. {
  2354. case 20: kiLayer = Edge_Cuts; break; // eagle says "Dimension" layer, but it's for board perimeter
  2355. case 21: kiLayer = F_SilkS; break;
  2356. case 22: kiLayer = B_SilkS; break;
  2357. case 25: kiLayer = F_SilkS; break;
  2358. case 26: kiLayer = B_SilkS; break;
  2359. case 27: kiLayer = F_SilkS; break;
  2360. case 28: kiLayer = B_SilkS; break;
  2361. case 29: kiLayer = F_Mask; break;
  2362. case 30: kiLayer = B_Mask; break;
  2363. case 31: kiLayer = F_Paste; break;
  2364. case 32: kiLayer = B_Paste; break;
  2365. case 33: kiLayer = F_Mask; break;
  2366. case 34: kiLayer = B_Mask; break;
  2367. case 35: kiLayer = F_Adhes; break;
  2368. case 36: kiLayer = B_Adhes; break;
  2369. case 48: kiLayer = Cmts_User; break;
  2370. case 49: kiLayer = Cmts_User; break;
  2371. case 50: kiLayer = Cmts_User; break;
  2372. // Packages show the future chip pins on SMD parts using layer 51.
  2373. // This is an area slightly smaller than the PAD/SMD copper area.
  2374. // Carry those visual aids into the MODULE on the fabrication layer,
  2375. // not silkscreen. This is perhaps not perfect, but there is not a lot
  2376. // of other suitable paired layers
  2377. case 51: kiLayer = F_Fab; break;
  2378. case 52: kiLayer = B_Fab; break;
  2379. // thes layers are defined as user layers. put them on ECO layers
  2380. case 160: kiLayer = Eco1_User; break;
  2381. case 161: kiLayer = Eco2_User; break;
  2382. default:
  2383. // some layers do not map to KiCad
  2384. // DBG( printf( "unsupported eagle layer: %d\n", aEagleLayer );)
  2385. kiLayer = UNDEFINED_LAYER; break;
  2386. }
  2387. }
  2388. return LAYER_ID( kiLayer );
  2389. }
  2390. void EAGLE_PLUGIN::centerBoard()
  2391. {
  2392. if( m_props )
  2393. {
  2394. UTF8 page_width;
  2395. UTF8 page_height;
  2396. if( m_props->Value( "page_width", &page_width ) &&
  2397. m_props->Value( "page_height", &page_height ) )
  2398. {
  2399. EDA_RECT bbbox = m_board->ComputeBoundingBox( true );
  2400. int w = atoi( page_width.c_str() );
  2401. int h = atoi( page_height.c_str() );
  2402. int desired_x = ( w - bbbox.GetWidth() ) / 2;
  2403. int desired_y = ( h - bbbox.GetHeight() ) / 2;
  2404. DBG(printf( "bbox.width:%d bbox.height:%d w:%d h:%d desired_x:%d desired_y:%d\n",
  2405. bbbox.GetWidth(), bbbox.GetHeight(), w, h, desired_x, desired_y );)
  2406. m_board->Move( wxPoint( desired_x - bbbox.GetX(), desired_y - bbbox.GetY() ) );
  2407. }
  2408. }
  2409. }
  2410. wxDateTime EAGLE_PLUGIN::getModificationTime( const wxString& aPath )
  2411. {
  2412. wxFileName fn( aPath );
  2413. // Do not call wxFileName::GetModificationTime() on a non-existent file, because
  2414. // if it fails, wx's implementation calls the crap wxLogSysError() which
  2415. // eventually infects our UI with an unwanted popup window, so don't let it fail.
  2416. if( !fn.IsFileReadable() )
  2417. {
  2418. wxString msg = wxString::Format(
  2419. _( "File '%s' is not readable." ),
  2420. GetChars( aPath ) );
  2421. THROW_IO_ERROR( msg );
  2422. }
  2423. /*
  2424. // update the writable flag while we have a wxFileName, in a network this
  2425. // is possibly quite dynamic anyway.
  2426. m_writable = fn.IsFileWritable();
  2427. */
  2428. wxDateTime modTime = fn.GetModificationTime();
  2429. if( !modTime.IsValid() )
  2430. modTime.Now();
  2431. return modTime;
  2432. }
  2433. void EAGLE_PLUGIN::cacheLib( const wxString& aLibPath )
  2434. {
  2435. try
  2436. {
  2437. wxDateTime modtime = getModificationTime( aLibPath );
  2438. // Fixes assertions in wxWidgets debug builds for the wxDateTime object. Refresh the
  2439. // cache if either of the wxDateTime objects are invalid or the last file modification
  2440. // time differs from the current file modification time.
  2441. bool load = !m_mod_time.IsValid() || !modtime.IsValid() ||
  2442. m_mod_time != modtime;
  2443. if( aLibPath != m_lib_path || load )
  2444. {
  2445. PTREE doc;
  2446. LOCALE_IO toggle; // toggles on, then off, the C locale.
  2447. m_templates.clear();
  2448. // Set this before completion of loading, since we rely on it for
  2449. // text of an exception. Delay setting m_mod_time until after successful load
  2450. // however.
  2451. m_lib_path = aLibPath;
  2452. // 8 bit "filename" should be encoded according to disk filename encoding,
  2453. // (maybe this is current locale, maybe not, its a filesystem issue),
  2454. // and is not necessarily utf8.
  2455. string filename = (const char*) aLibPath.char_str( wxConvFile );
  2456. read_xml( filename, doc, xml_parser::no_comments );
  2457. // clear the cu map and then rebuild it.
  2458. clear_cu_map();
  2459. m_xpath->push( "eagle.drawing.layers" );
  2460. CPTREE& layers = doc.get_child( "eagle.drawing.layers" );
  2461. loadLayerDefs( layers );
  2462. m_xpath->pop();
  2463. m_xpath->push( "eagle.drawing.library" );
  2464. CPTREE& library = doc.get_child( "eagle.drawing.library" );
  2465. loadLibrary( library, NULL );
  2466. m_xpath->pop();
  2467. m_mod_time = modtime;
  2468. }
  2469. }
  2470. catch( file_parser_error fpe )
  2471. {
  2472. // for xml_parser_error, what() has the line number in it,
  2473. // but no byte offset. That should be an adequate error message.
  2474. THROW_IO_ERROR( fpe.what() );
  2475. }
  2476. // Class ptree_error is a base class for xml_parser_error & file_parser_error,
  2477. // so one catch should be OK for all errors.
  2478. catch( ptree_error pte )
  2479. {
  2480. string errmsg = pte.what();
  2481. errmsg += " @\n";
  2482. errmsg += m_xpath->Contents();
  2483. THROW_IO_ERROR( errmsg );
  2484. }
  2485. }
  2486. wxArrayString EAGLE_PLUGIN::FootprintEnumerate( const wxString& aLibraryPath, const PROPERTIES* aProperties )
  2487. {
  2488. init( aProperties );
  2489. cacheLib( aLibraryPath );
  2490. wxArrayString ret;
  2491. for( MODULE_CITER it = m_templates.begin(); it != m_templates.end(); ++it )
  2492. ret.Add( FROM_UTF8( it->first.c_str() ) );
  2493. return ret;
  2494. }
  2495. MODULE* EAGLE_PLUGIN::FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
  2496. const PROPERTIES* aProperties )
  2497. {
  2498. init( aProperties );
  2499. cacheLib( aLibraryPath );
  2500. string key = TO_UTF8( aFootprintName );
  2501. MODULE_CITER mi = m_templates.find( key );
  2502. if( mi == m_templates.end() )
  2503. return NULL;
  2504. // copy constructor to clone the template
  2505. MODULE* ret = new MODULE( *mi->second );
  2506. return ret;
  2507. }
  2508. void EAGLE_PLUGIN::FootprintLibOptions( PROPERTIES* aListToAppendTo ) const
  2509. {
  2510. PLUGIN::FootprintLibOptions( aListToAppendTo );
  2511. /*
  2512. (*aListToAppendTo)["ignore_duplicates"] = UTF8( _(
  2513. "Ignore duplicately named footprints within the same Eagle library. "
  2514. "Only the first similarly named footprint will be loaded."
  2515. ));
  2516. */
  2517. }
  2518. /*
  2519. void EAGLE_PLUGIN::Save( const wxString& aFileName, BOARD* aBoard, const PROPERTIES* aProperties )
  2520. {
  2521. // Eagle lovers apply here.
  2522. }
  2523. void EAGLE_PLUGIN::FootprintSave( const wxString& aLibraryPath, const MODULE* aFootprint, const PROPERTIES* aProperties )
  2524. {
  2525. }
  2526. void EAGLE_PLUGIN::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName )
  2527. {
  2528. }
  2529. void EAGLE_PLUGIN::FootprintLibCreate( const wxString& aLibraryPath, const PROPERTIES* aProperties )
  2530. {
  2531. }
  2532. bool EAGLE_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties )
  2533. {
  2534. }
  2535. bool EAGLE_PLUGIN::IsFootprintLibWritable( const wxString& aLibraryPath )
  2536. {
  2537. return true;
  2538. }
  2539. */