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.

2853 lines
85 KiB

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