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.

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