KiCad PCB EDA Suite
eagle_plugin.cpp
Go to the documentation of this file.
1 
2 /*
3  * This program source code file is part of KiCad, a free EDA CAD application.
4  *
5  * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6  * Copyright (C) 2012-2016 KiCad Developers, see AUTHORS.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 
27 /*
28 
29 Pcbnew PLUGIN for Eagle 6.x XML *.brd and footprint format.
30 
31 XML parsing and converting:
32 Getting line numbers and byte offsets from the source XML file is not
33 possible using currently available XML libraries within KiCad project:
34 wxXmlDocument and boost::property_tree.
35 
36 property_tree will give line numbers but no byte offsets, and only during
37 document loading. This means that if we have a problem after the document is
38 successfully loaded, there is no way to correlate back to line number and byte
39 offset of the problem. So a different approach is taken, one which relies on the
40 XML elements themselves using an XPATH type of reporting mechanism. The path to
41 the problem is reported in the error messages. This means keeping track of that
42 path as we traverse the XML document for the sole purpose of accurate error
43 reporting.
44 
45 User can load the source XML file into firefox or other xml browser and follow
46 our error message.
47 
48 Load() TODO's
49 
50 *) verify zone fill clearances are correct
51 
52 */
53 
54 #include <errno.h>
55 
56 #include <wx/string.h>
57 #include <boost/property_tree/ptree.hpp>
58 #include <boost/property_tree/xml_parser.hpp>
59 
60 #include <eagle_plugin.h>
61 
62 #include <common.h>
63 #include <macros.h>
64 #include <fctsys.h>
65 #include <trigo.h>
66 #include <macros.h>
67 #include <kicad_string.h>
68 #include <properties.h>
69 #include <wx/filename.h>
70 
71 #include <class_board.h>
72 #include <class_module.h>
73 #include <class_track.h>
74 #include <class_edge_mod.h>
75 #include <class_zone.h>
76 #include <class_pcb_text.h>
77 #include <class_dimension.h>
78 
79 using namespace boost::property_tree;
80 using namespace std;
81 
83 typedef PTREE::const_assoc_iterator CA_ITER;
84 typedef PTREE::const_iterator CITER;
85 typedef std::pair<CA_ITER, CA_ITER> CA_ITER_RANGE;
86 
87 typedef MODULE_MAP::iterator MODULE_ITER;
88 typedef MODULE_MAP::const_iterator MODULE_CITER;
89 
94 
95 
97 struct TRIPLET
98 {
99  const char* element;
100  const char* attribute;
101  const char* value;
102 
103  TRIPLET( const char* aElement, const char* aAttribute = "", const char* aValue = "" ) :
104  element( aElement ),
105  attribute( aAttribute ),
106  value( aValue )
107  {}
108 };
109 
110 
124 class XPATH
125 {
126  std::vector<TRIPLET> p;
127 
128 public:
129  void push( const char* aPathSegment, const char* aAttribute="" )
130  {
131  p.push_back( TRIPLET( aPathSegment, aAttribute ) );
132  }
133 
134  void clear() { p.clear(); }
135 
136  void pop() { p.pop_back(); }
137 
139  void Value( const char* aValue )
140  {
141  p.back().value = aValue;
142  }
143 
145  void Attribute( const char* aAttribute )
146  {
147  p.back().attribute = aAttribute;
148  }
149 
151  string Contents()
152  {
153  typedef std::vector<TRIPLET>::const_iterator CITER_TRIPLET;
154 
155  string ret;
156 
157  for( CITER_TRIPLET it = p.begin(); it != p.end(); ++it )
158  {
159  if( it != p.begin() )
160  ret += '.';
161 
162  ret += it->element;
163 
164  if( it->attribute[0] && it->value[0] )
165  {
166  ret += '[';
167  ret += it->attribute;
168  ret += '=';
169  ret += it->value;
170  ret += ']';
171  }
172  }
173 
174  return ret;
175  }
176 };
177 
178 
184 static opt_bool parseOptionalBool( CPTREE& attribs, const char* aName )
185 {
186  opt_bool ret;
187  opt_string stemp = attribs.get_optional<string>( aName );
188 
189  if( stemp )
190  ret = !stemp->compare( "yes" );
191 
192  return ret;
193 }
194 
195 
196 // All of the 'E'STRUCTS below merely hold Eagle XML information verbatim, in binary.
197 // For maintenance and troubleshooting purposes, it was thought that we'd need to
198 // separate the conversion process into distinct steps. There is no intent to have KiCad
199 // forms of information in these 'E'STRUCTS. They are only binary forms
200 // of the Eagle information in the corresponding Eagle XML nodes.
201 
202 
204 struct EROT
205 {
206  bool mirror;
207  bool spin;
208  double degrees;
209 
210  EROT() :
211  mirror( false ),
212  spin( false ),
213  degrees( 0 )
214  {}
215 
216  EROT( double aDegrees ) :
217  mirror( false ),
218  spin( false ),
219  degrees( aDegrees )
220  {}
221 };
222 
224 
227 static EROT erot( const string& aRot )
228 {
229  EROT rot;
230 
231  rot.spin = aRot.find( 'S' ) != aRot.npos;
232  rot.mirror = aRot.find( 'M' ) != aRot.npos;
233  rot.degrees = strtod( aRot.c_str()
234  + 1 // skip leading 'R'
235  + int( rot.spin ) // skip optional leading 'S'
236  + int( rot.mirror ), // skip optional leading 'M'
237  NULL );
238  return rot;
239 }
240 
243 {
244  opt_erot ret;
245  opt_string stemp = attribs.get_optional<string>( "rot" );
246  if( stemp )
247  ret = erot( *stemp );
248  return ret;
249 }
250 
252 struct EWIRE
253 {
254  double x1;
255  double y1;
256  double x2;
257  double y2;
258  double width;
260 
261  // for style: (continuous | longdash | shortdash | dashdot)
262  enum {
267  };
270 
271  // for cap: (flat | round)
272  enum {
275  };
277 
278  EWIRE( CPTREE& aWire );
279 };
280 
288 {
289  CPTREE& attribs = aWire.get_child( "<xmlattr>" );
290 
291  /*
292  <!ELEMENT wire EMPTY>
293  <!ATTLIST wire
294  x1 %Coord; #REQUIRED
295  y1 %Coord; #REQUIRED
296  x2 %Coord; #REQUIRED
297  y2 %Coord; #REQUIRED
298  width %Dimension; #REQUIRED
299  layer %Layer; #REQUIRED
300  extent %Extent; #IMPLIED -- only applicable for airwires --
301  style %WireStyle; "continuous"
302  curve %WireCurve; "0"
303  cap %WireCap; "round" -- only applicable if 'curve' is not zero --
304  >
305  */
306 
307  x1 = attribs.get<double>( "x1" );
308  y1 = attribs.get<double>( "y1" );
309  x2 = attribs.get<double>( "x2" );
310  y2 = attribs.get<double>( "y2" );
311  width = attribs.get<double>( "width" );
312  layer = attribs.get<int>( "layer" );
313 
314  curve = attribs.get_optional<double>( "curve" );
315 
316  opt_string s = attribs.get_optional<string>( "style" );
317  if( s )
318  {
319  if( !s->compare( "continuous" ) )
320  style = EWIRE::CONTINUOUS;
321  else if( !s->compare( "longdash" ) )
322  style = EWIRE::LONGDASH;
323  else if( !s->compare( "shortdash" ) )
324  style = EWIRE::SHORTDASH;
325  else if( !s->compare( "dashdot" ) )
326  style = EWIRE::DASHDOT;
327  }
328 
329  s = attribs.get_optional<string>( "cap" );
330  if( s )
331  {
332  if( !s->compare( "round" ) )
333  cap = EWIRE::ROUND;
334  else if( !s->compare( "flat" ) )
335  cap = EWIRE::FLAT;
336  }
337  // ignoring extent
338 }
339 
340 
342 struct EVIA
343 {
344  double x;
345  double y;
348  double drill;
351  EVIA( CPTREE& aVia );
352 };
353 
355 {
356  CPTREE& attribs = aVia.get_child( "<xmlattr>" );
357 
358  /*
359  <!ELEMENT via EMPTY>
360  <!ATTLIST via
361  x %Coord; #REQUIRED
362  y %Coord; #REQUIRED
363  extent %Extent; #REQUIRED
364  drill %Dimension; #REQUIRED
365  diameter %Dimension; "0"
366  shape %ViaShape; "round"
367  alwaysstop %Bool; "no"
368  >
369  */
370 
371  x = attribs.get<double>( "x" );
372  y = attribs.get<double>( "y" );
373 
374  string ext = attribs.get<string>( "extent" );
375 
376  sscanf( ext.c_str(), "%d-%d", &layer_front_most, &layer_back_most );
377 
378  drill = attribs.get<double>( "drill" );
379  diam = attribs.get_optional<double>( "diameter" );
380  shape = attribs.get_optional<string>( "shape" );
381 }
382 
383 
385 struct ECIRCLE
386 {
387  double x;
388  double y;
389  double radius;
390  double width;
392 
393  ECIRCLE( CPTREE& aCircle );
394 };
395 
397 {
398  CPTREE& attribs = aCircle.get_child( "<xmlattr>" );
399 
400  /*
401  <!ELEMENT circle EMPTY>
402  <!ATTLIST circle
403  x %Coord; #REQUIRED
404  y %Coord; #REQUIRED
405  radius %Coord; #REQUIRED
406  width %Dimension; #REQUIRED
407  layer %Layer; #REQUIRED
408  >
409  */
410 
411  x = attribs.get<double>( "x" );
412  y = attribs.get<double>( "y" );
413  radius = attribs.get<double>( "radius" );
414  width = attribs.get<double>( "width" );
415  layer = attribs.get<int>( "layer" );
416 }
417 
418 
420 struct ERECT
421 {
422  double x1;
423  double y1;
424  double x2;
425  double y2;
426  int layer;
428 
429  ERECT( CPTREE& aRect );
430 };
431 
433 {
434  CPTREE& attribs = aRect.get_child( "<xmlattr>" );
435 
436  /*
437  <!ELEMENT rectangle EMPTY>
438  <!ATTLIST rectangle
439  x1 %Coord; #REQUIRED
440  y1 %Coord; #REQUIRED
441  x2 %Coord; #REQUIRED
442  y2 %Coord; #REQUIRED
443  layer %Layer; #REQUIRED
444  rot %Rotation; "R0"
445  >
446  */
447 
448  x1 = attribs.get<double>( "x1" );
449  y1 = attribs.get<double>( "y1" );
450  x2 = attribs.get<double>( "x2" );
451  y2 = attribs.get<double>( "y2" );
452  layer = attribs.get<int>( "layer" );
453  rot = parseOptionalEROT( attribs );
454 }
455 
456 
458 struct EATTR
459 {
460  string name;
468 
469  enum { // for 'display'
474  };
476 
477  EATTR( CPTREE& aTree );
478  EATTR() {}
479 };
480 
487 EATTR::EATTR( CPTREE& aAttribute )
488 {
489  CPTREE& attribs = aAttribute.get_child( "<xmlattr>" );
490 
491  /*
492  <!ELEMENT attribute EMPTY>
493  <!ATTLIST attribute
494  name %String; #REQUIRED
495  value %String; #IMPLIED
496  x %Coord; #IMPLIED
497  y %Coord; #IMPLIED
498  size %Dimension; #IMPLIED
499  layer %Layer; #IMPLIED
500  font %TextFont; #IMPLIED
501  ratio %Int; #IMPLIED
502  rot %Rotation; "R0"
503  display %AttributeDisplay; "value" -- only in <element> or <instance> context --
504  constant %Bool; "no" -- only in <device> context --
505  >
506  */
507 
508  name = attribs.get<string>( "name" ); // #REQUIRED
509  value = attribs.get_optional<string>( "value" );
510 
511  x = attribs.get_optional<double>( "x" );
512  y = attribs.get_optional<double>( "y" );
513  size = attribs.get_optional<double>( "size" );
514 
515  // KiCad cannot currently put a TEXTE_MODULE on a different layer than the MODULE
516  // Eagle can it seems.
517  layer = attribs.get_optional<int>( "layer" );
518 
519  ratio = attribs.get_optional<double>( "ratio" );
520  rot = parseOptionalEROT( attribs );
521 
522  opt_string stemp = attribs.get_optional<string>( "display" );
523  if( stemp )
524  {
525  // (off | value | name | both)
526  if( !stemp->compare( "off" ) )
527  display = EATTR::Off;
528  else if( !stemp->compare( "value" ) )
529  display = EATTR::VALUE;
530  else if( !stemp->compare( "name" ) )
531  display = EATTR::NAME;
532  else if( !stemp->compare( "both" ) )
533  display = EATTR::BOTH;
534  }
535 }
536 
539 {
540  double x1;
541  double y1;
542  double x2;
543  double y2;
544  double x3;
545  double y3;
546  int layer;
547 
549 
550  EDIMENSION( CPTREE& aDimension );
551 };
552 
554 {
555  CPTREE& attribs = aDimension.get_child( "<xmlattr>" );
556 
557  /*
558  <!ELEMENT dimension EMPTY>
559  <!ATTLIST dimension
560  x1 %Coord; #REQUIRED
561  y1 %Coord; #REQUIRED
562  x2 %Coord; #REQUIRED
563  y2 %Coord; #REQUIRED
564  x3 %Coord; #REQUIRED
565  y3 %Coord; #REQUIRED
566  layer %Layer; #REQUIRED
567  dtype %DimensionType; "parallel"
568  >
569  */
570 
571  x1 = attribs.get<double>( "x1" );
572  y1 = attribs.get<double>( "y1" );
573  x2 = attribs.get<double>( "x2" );
574  y2 = attribs.get<double>( "y2" );
575  x3 = attribs.get<double>( "x3" );
576  y3 = attribs.get<double>( "y3" );
577  layer = attribs.get<int>( "layer" );
578 
579  opt_string dimType = attribs.get_optional<string>( "dtype" );
580 
581  if(!dimType)
582  {
583  // default type is parallel
584  }
585 }
586 
588 struct ETEXT
589 {
590  string text;
591  double x;
592  double y;
593  double size;
594  int layer;
598 
599  enum { // for align
605 
606  // opposites are -1 x above, used by code tricks in here
607  CENTER_RIGHT = -CENTER_LEFT,
608  BOTTOM_CENTER = -TOP_CENTER,
609  BOTTOM_LEFT = -TOP_RIGHT,
610  BOTTOM_RIGHT = -TOP_LEFT,
611  };
612 
614 
615  ETEXT( CPTREE& aText );
616 };
617 
619 {
620  CPTREE& attribs = aText.get_child( "<xmlattr>" );
621 
622  /*
623  <!ELEMENT text (#PCDATA)>
624  <!ATTLIST text
625  x %Coord; #REQUIRED
626  y %Coord; #REQUIRED
627  size %Dimension; #REQUIRED
628  layer %Layer; #REQUIRED
629  font %TextFont; "proportional"
630  ratio %Int; "8"
631  rot %Rotation; "R0"
632  align %Align; "bottom-left"
633  >
634  */
635 
636  text = aText.data();
637  x = attribs.get<double>( "x" );
638  y = attribs.get<double>( "y" );
639  size = attribs.get<double>( "size" );
640  layer = attribs.get<int>( "layer" );
641 
642  font = attribs.get_optional<string>( "font" );
643  ratio = attribs.get_optional<double>( "ratio" );
644  rot = parseOptionalEROT( attribs );
645 
646  opt_string stemp = attribs.get_optional<string>( "align" );
647  if( stemp )
648  {
649  // (bottom-left | bottom-center | bottom-right | center-left |
650  // center | center-right | top-left | top-center | top-right)
651  if( !stemp->compare( "center" ) )
652  align = ETEXT::CENTER;
653  else if( !stemp->compare( "center-right" ) )
654  align = ETEXT::CENTER_RIGHT;
655  else if( !stemp->compare( "top-left" ) )
656  align = ETEXT::TOP_LEFT;
657  else if( !stemp->compare( "top-center" ) )
658  align = ETEXT::TOP_CENTER;
659  else if( !stemp->compare( "top-right" ) )
660  align = ETEXT::TOP_RIGHT;
661  else if( !stemp->compare( "bottom-left" ) )
662  align = ETEXT::BOTTOM_LEFT;
663  else if( !stemp->compare( "bottom-center" ) )
664  align = ETEXT::BOTTOM_CENTER;
665  else if( !stemp->compare( "bottom-right" ) )
666  align = ETEXT::BOTTOM_RIGHT;
667  else if( !stemp->compare( "center-left" ) )
668  align = ETEXT::CENTER_LEFT;
669  }
670 }
671 
672 
674 struct EPAD
675 {
676  string name;
677  double x;
678  double y;
679  double drill;
681 
682  // for shape: (square | round | octagon | long | offset)
683  enum {
689  };
695 
696  EPAD( CPTREE& aPad );
697 };
698 
700 {
701  CPTREE& attribs = aPad.get_child( "<xmlattr>" );
702 
703  /*
704  <!ELEMENT pad EMPTY>
705  <!ATTLIST pad
706  name %String; #REQUIRED
707  x %Coord; #REQUIRED
708  y %Coord; #REQUIRED
709  drill %Dimension; #REQUIRED
710  diameter %Dimension; "0"
711  shape %PadShape; "round"
712  rot %Rotation; "R0"
713  stop %Bool; "yes"
714  thermals %Bool; "yes"
715  first %Bool; "no"
716  >
717  */
718 
719  // #REQUIRED says DTD, throw exception if not found
720  name = attribs.get<string>( "name" );
721  x = attribs.get<double>( "x" );
722  y = attribs.get<double>( "y" );
723  drill = attribs.get<double>( "drill" );
724 
725  diameter = attribs.get_optional<double>( "diameter" );
726 
727  opt_string s = attribs.get_optional<string>( "shape" );
728  if( s )
729  {
730  // (square | round | octagon | long | offset)
731  if( !s->compare( "square" ) )
732  shape = EPAD::SQUARE;
733  else if( !s->compare( "round" ) )
734  shape = EPAD::ROUND;
735  else if( !s->compare( "octagon" ) )
736  shape = EPAD::OCTAGON;
737  else if( !s->compare( "long" ) )
738  shape = EPAD::LONG;
739  else if( !s->compare( "offset" ) )
740  shape = EPAD::OFFSET;
741  }
742 
743  rot = parseOptionalEROT( attribs );
744  stop = parseOptionalBool( attribs, "stop" );
745  thermals = parseOptionalBool( attribs, "thermals" );
746  first = parseOptionalBool( attribs, "first" );
747 }
748 
749 
751 struct ESMD
752 {
753  string name;
754  double x;
755  double y;
756  double dx;
757  double dy;
758  int layer;
764 
765  ESMD( CPTREE& aSMD );
766 };
767 
769 {
770  CPTREE& attribs = aSMD.get_child( "<xmlattr>" );
771 
772  /*
773  <!ATTLIST smd
774  name %String; #REQUIRED
775  x %Coord; #REQUIRED
776  y %Coord; #REQUIRED
777  dx %Dimension; #REQUIRED
778  dy %Dimension; #REQUIRED
779  layer %Layer; #REQUIRED
780  roundness %Int; "0"
781  rot %Rotation; "R0"
782  stop %Bool; "yes"
783  thermals %Bool; "yes"
784  cream %Bool; "yes"
785  >
786  */
787 
788  // DTD #REQUIRED, throw exception if not found
789  name = attribs.get<string>( "name" );
790  x = attribs.get<double>( "x" );
791  y = attribs.get<double>( "y" );
792  dx = attribs.get<double>( "dx" );
793  dy = attribs.get<double>( "dy" );
794  layer = attribs.get<int>( "layer" );
795  rot = parseOptionalEROT( attribs );
796 
797  roundness = attribs.get_optional<int>( "roundness" );
798  thermals = parseOptionalBool( attribs, "thermals" );
799  stop = parseOptionalBool( attribs, "stop" );
800  thermals = parseOptionalBool( attribs, "thermals" );
801  cream = parseOptionalBool( attribs, "cream" );
802 }
803 
804 
805 struct EVERTEX
806 {
807  double x;
808  double y;
809 
810  EVERTEX( CPTREE& aVertex );
811 };
812 
814 {
815  CPTREE& attribs = aVertex.get_child( "<xmlattr>" );
816 
817  /*
818  <!ELEMENT vertex EMPTY>
819  <!ATTLIST vertex
820  x %Coord; #REQUIRED
821  y %Coord; #REQUIRED
822  curve %WireCurve; "0" -- the curvature from this vertex to the next one --
823  >
824  */
825 
826  x = attribs.get<double>( "x" );
827  y = attribs.get<double>( "y" );
828 }
829 
830 
832 struct EPOLYGON
833 {
834  double width;
835  int layer;
837 
838  // KiCad priority is opposite of Eagle rank, that is:
839  // - Eagle Low rank drawn first
840  // - KiCad high priority drawn first
841  // So since Eagle has an upper limit we define this, used for the cases
842  // where no rank is specified.
843  static const int max_priority = 6;
844 
845  enum { // for pour
849  };
850  int pour;
855 
856  EPOLYGON( CPTREE& aPolygon );
857 };
858 
860 {
861  CPTREE& attribs = aPolygon.get_child( "<xmlattr>" );
862 
863  /*
864  <!ATTLIST polygon
865  width %Dimension; #REQUIRED
866  layer %Layer; #REQUIRED
867  spacing %Dimension; #IMPLIED
868  pour %PolygonPour; "solid"
869  isolate %Dimension; #IMPLIED -- only in <signal> or <package> context --
870  orphans %Bool; "no" -- only in <signal> context --
871  thermals %Bool; "yes" -- only in <signal> context --
872  rank %Int; "0" -- 1..6 in <signal> context, 0 or 7 in <package> context --
873  >
874  */
875 
876  width = attribs.get<double>( "width" );
877  layer = attribs.get<int>( "layer" );
878  spacing = attribs.get_optional<double>( "spacing" );
879  isolate = attribs.get_optional<double>( "isolate" );
880  // default pour to solid fill
881  pour = EPOLYGON::SOLID;
882  opt_string s = attribs.get_optional<string>( "pour" );
883 
884  if( s )
885  {
886  // (solid | hatch | cutout)
887  if( !s->compare( "hatch" ) )
888  pour = EPOLYGON::HATCH;
889  else if( !s->compare( "cutout" ) )
890  pour = EPOLYGON::CUTOUT;
891  }
892 
893  orphans = parseOptionalBool( attribs, "orphans" );
894  thermals = parseOptionalBool( attribs, "thermals" );
895  rank = attribs.get_optional<int>( "rank" );
896 }
897 
899 struct EHOLE
900 {
901  double x;
902  double y;
903  double drill;
904 
905  EHOLE( CPTREE& aHole );
906 };
907 
909 {
910  CPTREE& attribs = aHole.get_child( "<xmlattr>" );
911 
912  /*
913  <!ELEMENT hole EMPTY>
914  <!ATTLIST hole
915  x %Coord; #REQUIRED
916  y %Coord; #REQUIRED
917  drill %Dimension; #REQUIRED
918  >
919  */
920 
921  // #REQUIRED:
922  x = attribs.get<double>( "x" );
923  y = attribs.get<double>( "y" );
924  drill = attribs.get<double>( "drill" );
925 }
926 
927 
929 struct EELEMENT
930 {
931  string name;
932  string library;
933  string package;
934  string value;
935  double x;
936  double y;
940 
941  EELEMENT( CPTREE& aElement );
942 };
943 
945 {
946  CPTREE& attribs = aElement.get_child( "<xmlattr>" );
947 
948  /*
949  <!ELEMENT element (attribute*, variant*)>
950  <!ATTLIST element
951  name %String; #REQUIRED
952  library %String; #REQUIRED
953  package %String; #REQUIRED
954  value %String; #REQUIRED
955  x %Coord; #REQUIRED
956  y %Coord; #REQUIRED
957  locked %Bool; "no"
958  smashed %Bool; "no"
959  rot %Rotation; "R0"
960  >
961  */
962 
963  // #REQUIRED
964  name = attribs.get<string>( "name" );
965  library = attribs.get<string>( "library" );
966  value = attribs.get<string>( "value" );
967 
968  package = attribs.get<string>( "package" );
969  ReplaceIllegalFileNameChars( &package );
970 
971  x = attribs.get<double>( "x" );
972  y = attribs.get<double>( "y" );
973 
974  // optional
975  locked = parseOptionalBool( attribs, "locked" );
976  smashed = parseOptionalBool( attribs, "smashed" );
977  rot = parseOptionalEROT( attribs );
978 }
979 
980 
981 struct ELAYER
982 {
983  int number;
984  string name;
985  int color;
986  int fill;
989 
990  ELAYER( CPTREE& aLayer );
991 };
992 
994 {
995  CPTREE& attribs = aLayer.get_child( "<xmlattr>" );
996 
997  /*
998  <!ELEMENT layer EMPTY>
999  <!ATTLIST layer
1000  number %Layer; #REQUIRED
1001  name %String; #REQUIRED
1002  color %Int; #REQUIRED
1003  fill %Int; #REQUIRED
1004  visible %Bool; "yes"
1005  active %Bool; "yes"
1006  >
1007  */
1008 
1009  number = attribs.get<int>( "number" );
1010  name = attribs.get<string>( "name" );
1011  color = attribs.get<int>( "color" );
1012  fill = 1; // Temporary value.
1013  visible = parseOptionalBool( attribs, "visible" );
1014  active = parseOptionalBool( attribs, "active" );
1015 }
1016 
1017 
1020 static double parseEagle( const string& aDistance )
1021 {
1022  double ret = strtod( aDistance.c_str(), NULL );
1023  if( aDistance.npos != aDistance.find( "mil" ) )
1024  ret = IU_PER_MILS * ret;
1025  else
1026  ret = IU_PER_MM * ret;
1027 
1028  return ret;
1029 }
1030 
1031 
1033 struct ERULES
1034 {
1036 
1039 
1040  double rvPadTop;
1041  // double rvPadBottom; ///< bottom pad size as percent of drill size
1042 
1043  double rlMinPadTop;
1044  double rlMaxPadTop;
1045 
1046  double rvViaOuter;
1047  double rlMinViaOuter;
1048  double rlMaxViaOuter;
1049  double mdWireWire;
1050 
1051 
1053  psElongationLong ( 100 ),
1054  psElongationOffset ( 0 ),
1055  rvPadTop ( 0.25 ),
1056  // rvPadBottom ( 0.25 ),
1057  rlMinPadTop ( Mils2iu( 10 ) ),
1058  rlMaxPadTop ( Mils2iu( 20 ) ),
1059 
1060  rvViaOuter ( 0.25 ),
1061  rlMinViaOuter ( Mils2iu( 10 ) ),
1062  rlMaxViaOuter ( Mils2iu( 20 ) ),
1063  mdWireWire ( 0 )
1064  {}
1065 
1066  void parse( CPTREE& aRules );
1067 };
1068 
1069 void ERULES::parse( CPTREE& aRules )
1070 {
1071  for( CITER it = aRules.begin(); it != aRules.end(); ++it )
1072  {
1073  if( it->first != "param" )
1074  continue;
1075 
1076  CPTREE& attribs = it->second.get_child( "<xmlattr>" );
1077 
1078  const string& name = attribs.get<string>( "name" );
1079 
1080  if( name == "psElongationLong" )
1081  psElongationLong = attribs.get<int>( "value" );
1082  else if( name == "psElongationOffset" )
1083  psElongationOffset = attribs.get<int>( "value" );
1084  else if( name == "rvPadTop" )
1085  rvPadTop = attribs.get<double>( "value" );
1086  else if( name == "rlMinPadTop" )
1087  rlMinPadTop = parseEagle( attribs.get<string>( "value" ) );
1088  else if( name == "rlMaxPadTop" )
1089  rlMaxPadTop = parseEagle( attribs.get<string>( "value" ) );
1090  else if( name == "rvViaOuter" )
1091  rvViaOuter = attribs.get<double>( "value" );
1092  else if( name == "rlMinViaOuter" )
1093  rlMinViaOuter = parseEagle( attribs.get<string>( "value" ) );
1094  else if( name == "rlMaxViaOuter" )
1095  rlMaxViaOuter = parseEagle( attribs.get<string>( "value" ) );
1096  else if( name == "mdWireWire" )
1097  mdWireWire = parseEagle( attribs.get<string>( "value" ) );
1098  }
1099 }
1100 
1101 
1104 static inline string makeKey( const string& aFirst, const string& aSecond )
1105 {
1106  string key = aFirst + '\x02' + aSecond;
1107  return key;
1108 }
1109 
1110 
1112 static inline unsigned long timeStamp( CPTREE& aTree )
1113 {
1114  // in this case from a unique tree memory location
1115  return (unsigned long)(void*) &aTree;
1116 }
1117 
1118 
1121 {
1122  // Eagle give us start and end.
1123  // S_ARC wants start to give the center, and end to give the start.
1124  double dx = end.x - start.x, dy = end.y - start.y;
1125  wxPoint mid = (start + end) / 2;
1126 
1127  double dlen = sqrt( dx*dx + dy*dy );
1128  double dist = dlen / ( 2 * tan( DEG2RAD( angle ) / 2 ) );
1129 
1130  wxPoint center(
1131  mid.x + dist * ( dy / dlen ),
1132  mid.y - dist * ( dx / dlen )
1133  );
1134 
1135  return center;
1136 }
1137 
1138 
1140  m_rules( new ERULES() ),
1141  m_xpath( new XPATH() ),
1142  m_mod_time( wxDateTime::Now() )
1143 {
1144  init( NULL );
1145 
1146  clear_cu_map();
1147 }
1148 
1149 
1151 {
1152  delete m_rules;
1153  delete m_xpath;
1154 }
1155 
1156 
1157 const wxString EAGLE_PLUGIN::PluginName() const
1158 {
1159  return wxT( "Eagle" );
1160 }
1161 
1162 
1163 const wxString EAGLE_PLUGIN::GetFileExtension() const
1164 {
1165  return wxT( "brd" );
1166 }
1167 
1168 
1169 int inline EAGLE_PLUGIN::kicad( double d ) const
1170 {
1171  return KiROUND( biu_per_mm * d );
1172 }
1173 
1174 
1175 wxSize inline EAGLE_PLUGIN::kicad_fontz( double d ) const
1176 {
1177  // texts seem to better match eagle when scaled down by 0.95
1178  int kz = kicad( d ) * 95 / 100;
1179  return wxSize( kz, kz );
1180 }
1181 
1182 
1183 BOARD* EAGLE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties )
1184 {
1185  LOCALE_IO toggle; // toggles on, then off, the C locale.
1186  PTREE doc;
1187 
1188  init( aProperties );
1189 
1190  m_board = aAppendToMe ? aAppendToMe : new BOARD();
1191 
1192  // Give the filename to the board if it's new
1193  if( !aAppendToMe )
1194  m_board->SetFileName( aFileName );
1195 
1196  // delete on exception, if I own m_board, according to aAppendToMe
1197  unique_ptr<BOARD> deleter( aAppendToMe ? NULL : m_board );
1198 
1199  try
1200  {
1201  // 8 bit "filename" should be encoded according to disk filename encoding,
1202  // (maybe this is current locale, maybe not, its a filesystem issue),
1203  // and is not necessarily utf8.
1204  string filename = (const char*) aFileName.char_str( wxConvFile );
1205 
1206  read_xml( filename, doc, xml_parser::no_comments );
1207 
1208  m_min_trace = INT_MAX;
1209  m_min_via = INT_MAX;
1210  m_min_via_hole = INT_MAX;
1211 
1212  loadAllSections( doc );
1213 
1214  BOARD_DESIGN_SETTINGS& designSettings = m_board->GetDesignSettings();
1215 
1216  if( m_min_trace < designSettings.m_TrackMinWidth )
1217  designSettings.m_TrackMinWidth = m_min_trace;
1218 
1219  if( m_min_via < designSettings.m_ViasMinSize )
1220  designSettings.m_ViasMinSize = m_min_via;
1221 
1222  if( m_min_via_hole < designSettings.m_ViasMinDrill )
1223  designSettings.m_ViasMinDrill = m_min_via_hole;
1224 
1225  if( m_rules->mdWireWire )
1226  {
1227  NETCLASSPTR defaultNetclass = designSettings.GetDefault();
1228  int clearance = KiROUND( m_rules->mdWireWire );
1229 
1230  if( clearance < defaultNetclass->GetClearance() )
1231  defaultNetclass->SetClearance( clearance );
1232  }
1233 
1234  // should be empty, else missing m_xpath->pop()
1235  wxASSERT( m_xpath->Contents().size() == 0 );
1236  }
1237 
1238  catch( file_parser_error fpe )
1239  {
1240  // for xml_parser_error, what() has the line number in it,
1241  // but no byte offset. That should be an adequate error message.
1242  THROW_IO_ERROR( fpe.what() );
1243  }
1244 
1245  // Class ptree_error is a base class for xml_parser_error & file_parser_error,
1246  // so one catch should be OK for all errors.
1247  catch( ptree_error pte )
1248  {
1249  string errmsg = pte.what();
1250 
1251  errmsg += " @\n";
1252  errmsg += m_xpath->Contents();
1253 
1254  THROW_IO_ERROR( errmsg );
1255  }
1256 
1257  // IO_ERROR exceptions are left uncaught, they pass upwards from here.
1258 
1259  // Ensure the copper layers count is a multiple of 2
1260  // Pcbnew does not like boards with odd layers count
1261  // (these boards cannot exist. they actually have a even layers count)
1262  int lyrcnt = m_board->GetCopperLayerCount();
1263 
1264  if( (lyrcnt % 2) != 0 )
1265  {
1266  lyrcnt++;
1267  m_board->SetCopperLayerCount( lyrcnt );
1268  }
1269 
1270  centerBoard();
1271 
1272  deleter.release();
1273  return m_board;
1274 }
1275 
1276 
1277 void EAGLE_PLUGIN::init( const PROPERTIES* aProperties )
1278 {
1279  m_hole_count = 0;
1280  m_min_trace = 0;
1281  m_min_via = 0;
1282  m_min_via_hole = 0;
1283  m_xpath->clear();
1284  m_pads_to_nets.clear();
1285 
1286  // m_templates.clear(); this is the FOOTPRINT cache too
1287 
1288  m_board = NULL;
1289  m_props = aProperties;
1290 
1291  mm_per_biu = 1/IU_PER_MM;
1292  biu_per_mm = IU_PER_MM;
1293 
1294  delete m_rules;
1295  m_rules = new ERULES();
1296 }
1297 
1298 
1300 {
1301  // All cu layers are invalid until we see them in the <layers> section while
1302  // loading either a board or library. See loadLayerDefs().
1303  for( unsigned i = 0; i < DIM(m_cu_map); ++i )
1304  m_cu_map[i] = -1;
1305 }
1306 
1307 
1309 {
1310  CPTREE& drawing = aDoc.get_child( "eagle.drawing" );
1311  CPTREE& board = drawing.get_child( "board" );
1312 
1313  m_xpath->push( "eagle.drawing" );
1314 
1315  {
1316  m_xpath->push( "board" );
1317 
1318  CPTREE& designrules = board.get_child( "designrules" );
1319  loadDesignRules( designrules );
1320 
1321  m_xpath->pop();
1322  }
1323 
1324  {
1325  m_xpath->push( "layers" );
1326 
1327  CPTREE& layers = drawing.get_child( "layers" );
1328  loadLayerDefs( layers );
1329 
1330  m_xpath->pop();
1331  }
1332 
1333  {
1334  m_xpath->push( "board" );
1335 
1336  CPTREE& plain = board.get_child( "plain" );
1337  loadPlain( plain );
1338 
1339  CPTREE& signals = board.get_child( "signals" );
1340  loadSignals( signals );
1341 
1342  CPTREE& libs = board.get_child( "libraries" );
1343  loadLibraries( libs );
1344 
1345  CPTREE& elems = board.get_child( "elements" );
1346  loadElements( elems );
1347 
1348  m_xpath->pop(); // "board"
1349  }
1350 
1351  m_xpath->pop(); // "eagle.drawing"
1352 }
1353 
1354 
1356 {
1357  m_xpath->push( "designrules" );
1358  m_rules->parse( aDesignRules );
1359  m_xpath->pop(); // "designrules"
1360 }
1361 
1362 
1364 {
1365  typedef std::vector<ELAYER> ELAYERS;
1366  typedef ELAYERS::const_iterator EITER;
1367 
1368  ELAYERS cu; // copper layers
1369 
1370  // find the subset of layers that are copper, and active
1371  for( CITER layer = aLayers.begin(); layer != aLayers.end(); ++layer )
1372  {
1373  ELAYER elayer( layer->second );
1374 
1375  if( elayer.number >= 1 && elayer.number <= 16 && ( !elayer.active || *elayer.active ) )
1376  {
1377  cu.push_back( elayer );
1378  }
1379  }
1380 
1381  // establish cu layer map:
1382  int ki_layer_count = 0;
1383 
1384  for( EITER it = cu.begin(); it != cu.end(); ++it, ++ki_layer_count )
1385  {
1386  if( ki_layer_count == 0 )
1387  m_cu_map[it->number] = F_Cu;
1388  else if( ki_layer_count == int( cu.size()-1 ) )
1389  m_cu_map[it->number] = B_Cu;
1390  else
1391  {
1392  // some eagle boards do not have contiguous layer number sequences.
1393 
1394 #if 0 // pre LAYER_ID & LSET:
1395  m_cu_map[it->number] = cu.size() - 1 - ki_layer_count;
1396 #else
1397  m_cu_map[it->number] = ki_layer_count;
1398 #endif
1399  }
1400  }
1401 
1402 #if 0 && defined(DEBUG)
1403  printf( "m_cu_map:\n" );
1404  for( unsigned i=0; i<DIM(m_cu_map); ++i )
1405  {
1406  printf( "\t[%d]:%d\n", i, m_cu_map[i] );
1407  }
1408 #endif
1409 
1410  // Set the layer names and cu count iff we're loading a board.
1411  if( m_board )
1412  {
1413  m_board->SetCopperLayerCount( cu.size() );
1414 
1415  for( EITER it = cu.begin(); it != cu.end(); ++it )
1416  {
1417  LAYER_ID layer = kicad_layer( it->number );
1418 
1419  // these function provide their own protection against UNDEFINED_LAYER:
1420  m_board->SetLayerName( layer, FROM_UTF8( it->name.c_str() ) );
1421  m_board->SetLayerType( layer, LT_SIGNAL );
1422 
1423  // could map the colors here
1424  }
1425  }
1426 }
1427 
1428 
1430 {
1431  m_xpath->push( "plain" );
1432 
1433  // (polygon | wire | text | circle | rectangle | frame | hole)*
1434  for( CITER gr = aGraphics.begin(); gr != aGraphics.end(); ++gr )
1435  {
1436  if( gr->first == "wire" )
1437  {
1438  m_xpath->push( "wire" );
1439 
1440  EWIRE w( gr->second );
1441  LAYER_ID layer = kicad_layer( w.layer );
1442 
1443  wxPoint start( kicad_x( w.x1 ), kicad_y( w.y1 ) );
1444  wxPoint end( kicad_x( w.x2 ), kicad_y( w.y2 ) );
1445 
1446  if( layer != UNDEFINED_LAYER )
1447  {
1448  DRAWSEGMENT* dseg = new DRAWSEGMENT( m_board );
1449  m_board->Add( dseg, ADD_APPEND );
1450 
1451  if( !w.curve )
1452  {
1453  dseg->SetStart( start );
1454  dseg->SetEnd( end );
1455  }
1456  else
1457  {
1458  wxPoint center = kicad_arc_center( start, end, *w.curve);
1459 
1460  dseg->SetShape( S_ARC );
1461  dseg->SetStart( center );
1462  dseg->SetEnd( start );
1463  dseg->SetAngle( *w.curve * -10.0 ); // KiCad rotates the other way
1464  }
1465 
1466  dseg->SetTimeStamp( timeStamp( gr->second ) );
1467  dseg->SetLayer( layer );
1468  dseg->SetWidth( Millimeter2iu( DEFAULT_PCB_EDGE_THICKNESS ) );
1469  }
1470  m_xpath->pop();
1471  }
1472  else if( gr->first == "text" )
1473  {
1474  m_xpath->push( "text" );
1475 
1476  ETEXT t( gr->second );
1477  LAYER_ID layer = kicad_layer( t.layer );
1478 
1479  if( layer != UNDEFINED_LAYER )
1480  {
1481  TEXTE_PCB* pcbtxt = new TEXTE_PCB( m_board );
1482  m_board->Add( pcbtxt, ADD_APPEND );
1483 
1484  pcbtxt->SetLayer( layer );
1485  pcbtxt->SetTimeStamp( timeStamp( gr->second ) );
1486  pcbtxt->SetText( FROM_UTF8( t.text.c_str() ) );
1487  pcbtxt->SetTextPos( wxPoint( kicad_x( t.x ), kicad_y( t.y ) ) );
1488 
1489  pcbtxt->SetTextSize( kicad_fontz( t.size ) );
1490 
1491  double ratio = t.ratio ? *t.ratio : 8; // DTD says 8 is default
1492 
1493  pcbtxt->SetThickness( kicad( t.size * ratio / 100 ) );
1494 
1495  int align = t.align ? *t.align : ETEXT::BOTTOM_LEFT;
1496 
1497  if( t.rot )
1498  {
1499  int sign = t.rot->mirror ? -1 : 1;
1500  pcbtxt->SetMirrored( t.rot->mirror );
1501 
1502  double degrees = t.rot->degrees;
1503 
1504  if( degrees == 90 || t.rot->spin )
1505  pcbtxt->SetTextAngle( sign * t.rot->degrees * 10 );
1506  else if( degrees == 180 )
1507  align = ETEXT::TOP_RIGHT;
1508  else if( degrees == 270 )
1509  {
1510  pcbtxt->SetTextAngle( sign * 90 * 10 );
1511  align = ETEXT::TOP_RIGHT;
1512  }
1513  }
1514 
1515  switch( align )
1516  {
1517  case ETEXT::CENTER:
1518  // this was the default in pcbtxt's constructor
1519  break;
1520 
1521  case ETEXT::CENTER_LEFT:
1523  break;
1524 
1525  case ETEXT::CENTER_RIGHT:
1527  break;
1528 
1529  case ETEXT::TOP_CENTER:
1531  break;
1532 
1533  case ETEXT::TOP_LEFT:
1536  break;
1537 
1538  case ETEXT::TOP_RIGHT:
1541  break;
1542 
1543  case ETEXT::BOTTOM_CENTER:
1545  break;
1546 
1547  case ETEXT::BOTTOM_LEFT:
1550  break;
1551 
1552  case ETEXT::BOTTOM_RIGHT:
1555  break;
1556  }
1557  }
1558  m_xpath->pop();
1559  }
1560  else if( gr->first == "circle" )
1561  {
1562  m_xpath->push( "circle" );
1563 
1564  ECIRCLE c( gr->second );
1565  LAYER_ID layer = kicad_layer( c.layer );
1566 
1567  if( layer != UNDEFINED_LAYER ) // unsupported layer
1568  {
1569  DRAWSEGMENT* dseg = new DRAWSEGMENT( m_board );
1570  m_board->Add( dseg, ADD_APPEND );
1571 
1572  dseg->SetShape( S_CIRCLE );
1573  dseg->SetTimeStamp( timeStamp( gr->second ) );
1574  dseg->SetLayer( layer );
1575  dseg->SetStart( wxPoint( kicad_x( c.x ), kicad_y( c.y ) ) );
1576  dseg->SetEnd( wxPoint( kicad_x( c.x + c.radius ), kicad_y( c.y ) ) );
1577  dseg->SetWidth( kicad( c.width ) );
1578  }
1579  m_xpath->pop();
1580  }
1581  else if( gr->first == "rectangle" )
1582  {
1583  // This seems to be a simplified rectangular [copper] zone, cannot find any
1584  // net related info on it from the DTD.
1585  m_xpath->push( "rectangle" );
1586 
1587  ERECT r( gr->second );
1588  LAYER_ID layer = kicad_layer( r.layer );
1589 
1590  if( IsCopperLayer( layer ) )
1591  {
1592  // use a "netcode = 0" type ZONE:
1593  ZONE_CONTAINER* zone = new ZONE_CONTAINER( m_board );
1594  m_board->Add( zone, ADD_APPEND );
1595 
1596  zone->SetTimeStamp( timeStamp( gr->second ) );
1597  zone->SetLayer( layer );
1599 
1601 
1602  zone->AppendCorner( wxPoint( kicad_x( r.x1 ), kicad_y( r.y1 ) ) );
1603  zone->AppendCorner( wxPoint( kicad_x( r.x2 ), kicad_y( r.y1 ) ) );
1604  zone->AppendCorner( wxPoint( kicad_x( r.x2 ), kicad_y( r.y2 ) ) );
1605  zone->AppendCorner( wxPoint( kicad_x( r.x1 ), kicad_y( r.y2 ) ) );
1606 
1607  // this is not my fault:
1608  zone->SetHatch( outline_hatch, Mils2iu( zone->GetDefaultHatchPitchMils() ), true );
1609  }
1610 
1611  m_xpath->pop();
1612  }
1613  else if( gr->first == "hole" )
1614  {
1615  m_xpath->push( "hole" );
1616  EHOLE e( gr->second );
1617 
1618  // Fabricate a MODULE with a single PAD_ATTRIB_HOLE_NOT_PLATED pad.
1619  // Use m_hole_count to gen up a unique name.
1620 
1621  MODULE* module = new MODULE( m_board );
1622  m_board->Add( module, ADD_APPEND );
1623 
1624  char temp[40];
1625  sprintf( temp, "@HOLE%d", m_hole_count++ );
1626  module->SetReference( FROM_UTF8( temp ) );
1627  module->Reference().SetVisible( false );
1628 
1629  wxPoint pos( kicad_x( e.x ), kicad_y( e.y ) );
1630 
1631  module->SetPosition( pos );
1632 
1633  // Add a PAD_ATTRIB_HOLE_NOT_PLATED pad to this module.
1634  D_PAD* pad = new D_PAD( module );
1635  module->Pads().PushBack( pad );
1636 
1637  pad->SetShape( PAD_SHAPE_CIRCLE );
1639 
1640  /* pad's position is already centered on module at relative (0, 0)
1641  wxPoint padpos( kicad_x( e.x ), kicad_y( e.y ) );
1642 
1643  pad->SetPos0( padpos );
1644  pad->SetPosition( padpos + module->GetPosition() );
1645  */
1646 
1647  wxSize sz( kicad( e.drill ), kicad( e.drill ) );
1648 
1649  pad->SetDrillSize( sz );
1650  pad->SetSize( sz );
1651 
1652  pad->SetLayerSet( LSET::AllCuMask() );
1653  m_xpath->pop();
1654  }
1655  else if( gr->first == "frame" )
1656  {
1657  // picture this
1658  }
1659  else if( gr->first == "polygon" )
1660  {
1661  // could be on a copper layer, could be on another layer.
1662  // copper layer would be done using netCode=0 type of ZONE_CONTAINER.
1663  }
1664  else if( gr->first == "dimension" )
1665  {
1666  EDIMENSION d( gr->second );
1667 
1668  DIMENSION* dimension = new DIMENSION( m_board );
1669  m_board->Add( dimension, ADD_APPEND );
1670 
1671  dimension->SetLayer( kicad_layer( d.layer ) );
1672  // The origin and end are assumed to always be in this order from eagle
1673  dimension->SetOrigin( wxPoint( kicad_x( d.x1 ), kicad_y( d.y1 ) ) );
1674  dimension->SetEnd( wxPoint( kicad_x( d.x2 ), kicad_y( d.y2 ) ) );
1676 
1677  int width = m_board->GetDesignSettings().m_PcbTextWidth;
1678  int maxThickness = Clamp_Text_PenSize( width, dimension->Text().GetTextSize() );
1679 
1680  if( width > maxThickness )
1681  width = maxThickness;
1682 
1683  dimension->Text().SetThickness( width );
1684  dimension->SetWidth( width );
1685 
1686  // check which axis the dimension runs in
1687  // because the "height" of the dimension is perpendicular to that axis
1688  // Note the check is just if two axes are close enough to each other
1689  // Eagle appears to have some rounding errors
1690  if( fabs( d.x1 - d.x2 ) < 0.05 )
1691  dimension->SetHeight( kicad_x( d.x1 - d.x3 ) );
1692  else
1693  dimension->SetHeight( kicad_y( d.y3 - d.y1 ) );
1694 
1695  dimension->AdjustDimensionDetails();
1696  }
1697  }
1698  m_xpath->pop();
1699 }
1700 
1701 
1702 void EAGLE_PLUGIN::loadLibrary( CPTREE& aLib, const string* aLibName )
1703 {
1704  m_xpath->push( "packages" );
1705 
1706  // library will have <xmlattr> node, skip that and get the single packages node
1707  CPTREE& packages = aLib.get_child( "packages" );
1708 
1709  // Create a MODULE for all the eagle packages, for use later via a copy constructor
1710  // to instantiate needed MODULES in our BOARD. Save the MODULE templates in
1711  // a MODULE_MAP using a single lookup key consisting of libname+pkgname.
1712 
1713  for( CITER package = packages.begin(); package != packages.end(); ++package )
1714  {
1715  m_xpath->push( "package", "name" );
1716 
1717  const string& pack_ref = package->second.get<string>( "<xmlattr>.name" );
1718 
1719  string pack_name( pack_ref );
1720 
1721  ReplaceIllegalFileNameChars( &pack_name );
1722 
1723  m_xpath->Value( pack_name.c_str() );
1724 
1725  string key = aLibName ? makeKey( *aLibName, pack_name ) : pack_name;
1726 
1727  MODULE* m = makeModule( package->second, pack_name );
1728 
1729  // add the templating MODULE to the MODULE template factory "m_templates"
1730  std::pair<MODULE_ITER, bool> r = m_templates.insert( key, m );
1731 
1732  if( !r.second
1733  // && !( m_props && m_props->Value( "ignore_duplicates" ) )
1734  )
1735  {
1736  wxString lib = aLibName ? FROM_UTF8( aLibName->c_str() ) : m_lib_path;
1737  wxString pkg = FROM_UTF8( pack_name.c_str() );
1738 
1739  wxString emsg = wxString::Format(
1740  _( "<package> name: '%s' duplicated in eagle <library>: '%s'" ),
1741  GetChars( pkg ),
1742  GetChars( lib )
1743  );
1744  THROW_IO_ERROR( emsg );
1745  }
1746 
1747  m_xpath->pop();
1748  }
1749 
1750  m_xpath->pop(); // "packages"
1751 }
1752 
1753 
1755 {
1756  m_xpath->push( "libraries.library", "name" );
1757 
1758  for( CITER library = aLibs.begin(); library != aLibs.end(); ++library )
1759  {
1760  const string& lib_name = library->second.get<string>( "<xmlattr>.name" );
1761 
1762  m_xpath->Value( lib_name.c_str() );
1763 
1764  loadLibrary( library->second, &lib_name );
1765  }
1766 
1767  m_xpath->pop();
1768 }
1769 
1770 
1772 {
1773  m_xpath->push( "elements.element", "name" );
1774 
1775  EATTR name;
1776  EATTR value;
1777  bool refanceNamePresetInPackageLayout;
1778  bool valueNamePresetInPackageLayout;
1779 
1780 
1781 
1782  for( CITER it = aElements.begin(); it != aElements.end(); ++it )
1783  {
1784  if( it->first != "element" )
1785  continue;
1786 
1787  EELEMENT e( it->second );
1788 
1789  // use "NULL-ness" as an indication of presence of the attribute:
1790  EATTR* nameAttr = 0;
1791  EATTR* valueAttr = 0;
1792 
1793  m_xpath->Value( e.name.c_str() );
1794 
1795  string pkg_key = makeKey( e.library, e.package );
1796 
1797  MODULE_CITER mi = m_templates.find( pkg_key );
1798 
1799  if( mi == m_templates.end() )
1800  {
1801  wxString emsg = wxString::Format( _( "No '%s' package in library '%s'" ),
1802  GetChars( FROM_UTF8( e.package.c_str() ) ),
1803  GetChars( FROM_UTF8( e.library.c_str() ) ) );
1804  THROW_IO_ERROR( emsg );
1805  }
1806 
1807  // copy constructor to clone the template
1808  MODULE* m = new MODULE( *mi->second );
1809  m_board->Add( m, ADD_APPEND );
1810 
1811  // update the nets within the pads of the clone
1812  for( D_PAD* pad = m->Pads(); pad; pad = pad->Next() )
1813  {
1814  string pn_key = makeKey( e.name, TO_UTF8( pad->GetPadName() ) );
1815 
1816  NET_MAP_CITER ni = m_pads_to_nets.find( pn_key );
1817  if( ni != m_pads_to_nets.end() )
1818  {
1819  const ENET* enet = &ni->second;
1820  pad->SetNetCode( enet->netcode );
1821  }
1822  }
1823 
1824  refanceNamePresetInPackageLayout = true;
1825  valueNamePresetInPackageLayout = true;
1826  m->SetPosition( wxPoint( kicad_x( e.x ), kicad_y( e.y ) ) );
1827  // Is >NAME field set in package layout ?
1828  if( m->GetReference().size() == 0 )
1829  {
1830  m->Reference().SetVisible( false ); // No so no show
1831  refanceNamePresetInPackageLayout = false;
1832  }
1833  // Is >VALUE field set in package layout
1834  if( m->GetValue().size() == 0 )
1835  {
1836  m->Value().SetVisible( false ); // No so no show
1837  valueNamePresetInPackageLayout = false;
1838  }
1839  m->SetReference( FROM_UTF8( e.name.c_str() ) );
1840  m->SetValue( FROM_UTF8( e.value.c_str() ) );
1841 
1842  if( !e.smashed )
1843  { // Not smashed so show NAME & VALUE
1844  if( valueNamePresetInPackageLayout )
1845  m->Value().SetVisible( true ); // Only if place holder in package layout
1846  if( refanceNamePresetInPackageLayout )
1847  m->Reference().SetVisible( true ); // Only if place holder in package layout
1848  }
1849  else if( *e.smashed == true )
1850  { // Smasted so set default to no show for NAME and VALUE
1851  m->Value().SetVisible( false );
1852  m->Reference().SetVisible( false );
1853 
1854  // initalize these to default values incase the <attribute> elements are not present.
1855  m_xpath->push( "attribute", "name" );
1856 
1857  // VALUE and NAME can have something like our text "effects" overrides
1858  // in SWEET and new schematic. Eagle calls these XML elements "attribute".
1859  // There can be one for NAME and/or VALUE both. Features present in the
1860  // EATTR override the ones established in the package only if they are
1861  // present here (except for rot, which if not present means angle zero).
1862  // So the logic is a bit different than in packageText() and in plain text.
1863  for( CITER ait = it->second.begin(); ait != it->second.end(); ++ait )
1864  {
1865 
1866  if( ait->first != "attribute" )
1867  continue;
1868 
1869  EATTR a( ait->second );
1870 
1871  if( a.name == "NAME" )
1872  {
1873  name = a;
1874  nameAttr = &name;
1875 
1876  // do we have a display attribute ?
1877  if( a.display )
1878  {
1879  // Yes!
1880  switch( *a.display )
1881  {
1882  case EATTR::VALUE :
1883  nameAttr->name = e.name;
1884  m->SetReference( e.name );
1885  if( refanceNamePresetInPackageLayout )
1886  m->Reference().SetVisible( true );
1887  break;
1888 
1889  case EATTR::NAME :
1890  if( refanceNamePresetInPackageLayout )
1891  {
1892  m->SetReference( "NAME" );
1893  m->Reference().SetVisible( true );
1894  }
1895  break;
1896 
1897  case EATTR::BOTH :
1898  if( refanceNamePresetInPackageLayout )
1899  m->Reference().SetVisible( true );
1900  nameAttr->name = nameAttr->name + " = " + e.name;
1901  m->SetReference( "NAME = " + e.name );
1902  break;
1903 
1904  case EATTR::Off :
1905  m->Reference().SetVisible( false );
1906  break;
1907 
1908  default:
1909  nameAttr->name = e.name;
1910  if( refanceNamePresetInPackageLayout )
1911  m->Reference().SetVisible( true );
1912  }
1913  }
1914  else
1915  // No display, so default is visable, and show value of NAME
1916  m->Reference().SetVisible( true );
1917  }
1918  else if( a.name == "VALUE" )
1919  {
1920  value = a;
1921  valueAttr = &value;
1922 
1923  if( a.display )
1924  {
1925  // Yes!
1926  switch( *a.display )
1927  {
1928  case EATTR::VALUE :
1929  valueAttr->value = e.value;
1930  m->SetValue( e.value );
1931  if( valueNamePresetInPackageLayout )
1932  m->Value().SetVisible( true );
1933  break;
1934 
1935  case EATTR::NAME :
1936  if( valueNamePresetInPackageLayout )
1937  m->Value().SetVisible( true );
1938  m->SetValue( "VALUE" );
1939  break;
1940 
1941  case EATTR::BOTH :
1942  if( valueNamePresetInPackageLayout )
1943  m->Value().SetVisible( true );
1944  valueAttr->value = "VALUE = " + e.value;
1945  m->SetValue( "VALUE = " + e.value );
1946  break;
1947 
1948  case EATTR::Off :
1949  m->Value().SetVisible( false );
1950  break;
1951 
1952  default:
1953  valueAttr->value = e.value;
1954  if( valueNamePresetInPackageLayout )
1955  m->Value().SetVisible( true );
1956  }
1957  }
1958  else
1959  // No display, so default is visible, and show value of NAME
1960  m->Value().SetVisible( true );
1961 
1962  }
1963  }
1964 
1965  m_xpath->pop(); // "attribute"
1966  }
1967 
1968  orientModuleAndText( m, e, nameAttr, valueAttr );
1969  }
1970 
1971  m_xpath->pop(); // "elements.element"
1972 }
1973 
1974 
1976  const EATTR* nameAttr, const EATTR* valueAttr )
1977 {
1978  if( e.rot )
1979  {
1980  if( e.rot->mirror )
1981  {
1982  double orientation = e.rot->degrees + 180.0;
1983  m->SetOrientation( orientation * 10 );
1984  m->Flip( m->GetPosition() );
1985  }
1986  else
1987  m->SetOrientation( e.rot->degrees * 10 );
1988  }
1989 
1990  orientModuleText( m, e, &m->Reference(), nameAttr );
1991  orientModuleText( m, e, &m->Value(), valueAttr );
1992 }
1993 
1994 
1996  TEXTE_MODULE* txt, const EATTR* aAttr )
1997 {
1998  // Smashed part ?
1999  if( aAttr )
2000  { // Yes
2001  const EATTR& a = *aAttr;
2002 
2003  if( a.value )
2004  {
2005  txt->SetText( FROM_UTF8( a.value->c_str() ) );
2006  }
2007 
2008  if( a.x && a.y ) // boost::optional
2009  {
2010  wxPoint pos( kicad_x( *a.x ), kicad_y( *a.y ) );
2011  txt->SetTextPos( pos );
2012  }
2013 
2014  // Even though size and ratio are both optional, I am not seeing
2015  // a case where ratio is present but size is not.
2016  double ratio = 8;
2017  wxSize fontz = txt->GetTextSize();
2018 
2019  if( a.size )
2020  {
2021  fontz = kicad_fontz( *a.size );
2022  txt->SetTextSize( fontz );
2023 
2024  if( a.ratio )
2025  ratio = *a.ratio;
2026  }
2027 
2028  int lw = int( fontz.y * ratio / 100.0 );
2029  txt->SetThickness( lw );
2030 
2031  int align = ETEXT::BOTTOM_LEFT; // bottom-left is eagle default
2032 
2033  // The "rot" in a EATTR seems to be assumed to be zero if it is not
2034  // present, and this zero rotation becomes an override to the
2035  // package's text field. If they did not want zero, they specify
2036  // what they want explicitly.
2037  double degrees = a.rot ? a.rot->degrees : 0;
2038  double orient; // relative to parent
2039 
2040  int sign = 1;
2041  bool spin = false;
2042 
2043  if( a.rot )
2044  {
2045  spin = a.rot->spin;
2046  sign = a.rot->mirror ? -1 : 1;
2047  txt->SetMirrored( a.rot->mirror );
2048  }
2049 
2050  if( degrees == 90 || degrees == 0 || spin )
2051  {
2052  orient = degrees - m->GetOrientation() / 10;
2053  txt->SetTextAngle( sign * orient * 10 );
2054  }
2055  else if( degrees == 180 )
2056  {
2057  orient = 0 - m->GetOrientation() / 10;
2058  txt->SetTextAngle( sign * orient * 10 );
2059  align = ETEXT::TOP_RIGHT;
2060  }
2061  else if( degrees == 270 )
2062  {
2063  orient = 90 - m->GetOrientation() / 10;
2064  align = ETEXT::TOP_RIGHT;
2065  txt->SetTextAngle( sign * orient * 10 );
2066  }
2067  else
2068  {
2069  orient = 90 - degrees - m->GetOrientation() / 10;
2070  txt->SetTextAngle( sign * orient * 10 );
2071  }
2072 
2073  switch( align )
2074  {
2075  case ETEXT::TOP_RIGHT:
2078  break;
2079 
2080  case ETEXT::BOTTOM_LEFT:
2083  break;
2084 
2085  default:
2086  ;
2087  }
2088  }
2089  else // Part is not smash so use Lib default for NAME/VALUE // the text is per the original package, sans <attribute>
2090  {
2091  double degrees = ( txt->GetTextAngle() + m->GetOrientation() ) / 10;
2092 
2093  // @todo there are a few more cases than these to contend with:
2094  if( (!txt->IsMirrored() && ( abs( degrees ) == 180 || abs( degrees ) == 270 ))
2095  || ( txt->IsMirrored() && ( degrees == 360 ) ) )
2096  {
2097  // ETEXT::TOP_RIGHT:
2100  }
2101  }
2102 }
2103 
2104 MODULE* EAGLE_PLUGIN::makeModule( CPTREE& aPackage, const string& aPkgName ) const
2105 {
2106  std::unique_ptr<MODULE> m( new MODULE( m_board ) );
2107 
2108  m->SetFPID( LIB_ID( aPkgName ) );
2109 
2110  opt_string description = aPackage.get_optional<string>( "description" );
2111  if( description )
2112  m->SetDescription( FROM_UTF8( description->c_str() ) );
2113 
2114  for( CITER it = aPackage.begin(); it != aPackage.end(); ++it )
2115  {
2116  CPTREE& t = it->second;
2117 
2118  if( it->first == "wire" )
2119  packageWire( m.get(), t );
2120 
2121  else if( it->first == "pad" )
2122  packagePad( m.get(), t );
2123 
2124  else if( it->first == "text" )
2125  packageText( m.get(), t );
2126 
2127  else if( it->first == "rectangle" )
2128  packageRectangle( m.get(), t );
2129 
2130  else if( it->first == "polygon" )
2131  packagePolygon( m.get(), t );
2132 
2133  else if( it->first == "circle" )
2134  packageCircle( m.get(), t );
2135 
2136  else if( it->first == "hole" )
2137  packageHole( m.get(), t );
2138 
2139  else if( it->first == "smd" )
2140  packageSMD( m.get(), t );
2141  }
2142 
2143  return m.release();
2144 }
2145 
2146 
2147 void EAGLE_PLUGIN::packageWire( MODULE* aModule, CPTREE& aTree ) const
2148 {
2149  EWIRE w( aTree );
2150  LAYER_ID layer = kicad_layer( w.layer );
2151 
2152  if( IsNonCopperLayer( layer ) ) // only valid non-copper wires, skip copper package wires
2153  {
2154  wxPoint start( kicad_x( w.x1 ), kicad_y( w.y1 ) );
2155  wxPoint end( kicad_x( w.x2 ), kicad_y( w.y2 ) );
2156  int width = kicad( w.width );
2157 
2158  // FIXME: the cap attribute is ignored because kicad can't create lines
2159  // with flat ends.
2160  EDGE_MODULE* dwg;
2161  if( !w.curve )
2162  {
2163  dwg = new EDGE_MODULE( aModule, S_SEGMENT );
2164 
2165  dwg->SetStart0( start );
2166  dwg->SetEnd0( end );
2167  }
2168  else
2169  {
2170  dwg = new EDGE_MODULE( aModule, S_ARC );
2171  wxPoint center = kicad_arc_center( start, end, *w.curve);
2172 
2173  dwg->SetStart0( center );
2174  dwg->SetEnd0( start );
2175  dwg->SetAngle( *w.curve * -10.0 ); // KiCad rotates the other way
2176  }
2177 
2178  dwg->SetLayer( layer );
2179  dwg->SetWidth( width );
2180 
2181  aModule->GraphicalItems().PushBack( dwg );
2182  }
2183 }
2184 
2185 
2186 void EAGLE_PLUGIN::packagePad( MODULE* aModule, CPTREE& aTree ) const
2187 {
2188  // this is thru hole technology here, no SMDs
2189  EPAD e( aTree );
2190 
2191  D_PAD* pad = new D_PAD( aModule );
2192  aModule->Pads().PushBack( pad );
2193 
2194  pad->SetPadName( FROM_UTF8( e.name.c_str() ) );
2195 
2196  // pad's "Position" is not relative to the module's,
2197  // whereas Pos0 is relative to the module's but is the unrotated coordinate.
2198 
2199  wxPoint padpos( kicad_x( e.x ), kicad_y( e.y ) );
2200 
2201  pad->SetPos0( padpos );
2202 
2203  RotatePoint( &padpos, aModule->GetOrientation() );
2204 
2205  pad->SetPosition( padpos + aModule->GetPosition() );
2206 
2207  pad->SetDrillSize( wxSize( kicad( e.drill ), kicad( e.drill ) ) );
2208 
2209  pad->SetLayerSet( LSET::AllCuMask().set( B_Mask ).set( F_Mask ) );
2210 
2211  if( e.shape )
2212  {
2213  switch( *e.shape )
2214  {
2215  case EPAD::ROUND:
2216  wxASSERT( pad->GetShape()==PAD_SHAPE_CIRCLE ); // verify set in D_PAD constructor
2217  break;
2218 
2219  case EPAD::OCTAGON:
2220  // no KiCad octagonal pad shape, use PAD_CIRCLE for now.
2221  // pad->SetShape( PAD_OCTAGON );
2222  wxASSERT( pad->GetShape()==PAD_SHAPE_CIRCLE ); // verify set in D_PAD constructor
2223  break;
2224 
2225  case EPAD::LONG:
2226  pad->SetShape( PAD_SHAPE_OVAL );
2227  break;
2228 
2229  case EPAD::SQUARE:
2230  pad->SetShape( PAD_SHAPE_RECT );
2231  break;
2232 
2233  case EPAD::OFFSET:
2234  ; // don't know what to do here.
2235  }
2236  }
2237  else
2238  {
2239  // if shape is not present, our default is circle and that matches their default "round"
2240  }
2241 
2242  if( e.diameter )
2243  {
2244  int diameter = kicad( *e.diameter );
2245  pad->SetSize( wxSize( diameter, diameter ) );
2246  }
2247  else
2248  {
2249  double drillz = pad->GetDrillSize().x;
2250  double annulus = drillz * m_rules->rvPadTop; // copper annulus, eagle "restring"
2251  annulus = Clamp( m_rules->rlMinPadTop, annulus, m_rules->rlMaxPadTop );
2252  int diameter = KiROUND( drillz + 2 * annulus );
2253  pad->SetSize( wxSize( KiROUND( diameter ), KiROUND( diameter ) ) );
2254  }
2255 
2256  if( pad->GetShape() == PAD_SHAPE_OVAL )
2257  {
2258  // The Eagle "long" pad is wider than it is tall,
2259  // m_elongation is percent elongation
2260  wxSize sz = pad->GetSize();
2261  sz.x = ( sz.x * ( 100 + m_rules->psElongationLong ) ) / 100;
2262  pad->SetSize( sz );
2263  }
2264 
2265  if( e.rot )
2266  {
2267  pad->SetOrientation( e.rot->degrees * 10 );
2268  }
2269 
2270  // @todo: handle stop and thermal
2271 }
2272 
2273 
2274 void EAGLE_PLUGIN::packageText( MODULE* aModule, CPTREE& aTree ) const
2275 {
2276  ETEXT t( aTree );
2277  LAYER_ID layer = kicad_layer( t.layer );
2278 
2279  if( layer == UNDEFINED_LAYER )
2280  {
2281  layer = Cmts_User;
2282  }
2283 
2284  TEXTE_MODULE* txt;
2285 
2286  if( t.text == ">NAME" || t.text == ">name" )
2287  txt = &aModule->Reference();
2288  else if( t.text == ">VALUE" || t.text == ">value" )
2289  txt = &aModule->Value();
2290  else
2291  {
2292  // FIXME: graphical text items are rotated for some reason.
2293  txt = new TEXTE_MODULE( aModule );
2294  aModule->GraphicalItems().PushBack( txt );
2295  }
2296 
2297  txt->SetTimeStamp( timeStamp( aTree ) );
2298  txt->SetText( FROM_UTF8( t.text.c_str() ) );
2299 
2300  wxPoint pos( kicad_x( t.x ), kicad_y( t.y ) );
2301 
2302  txt->SetTextPos( pos );
2303  txt->SetPos0( pos - aModule->GetPosition() );
2304 
2305  txt->SetLayer( layer );
2306  txt->SetTextSize( kicad_fontz( t.size ) );
2307 
2308  double ratio = t.ratio ? *t.ratio : 8; // DTD says 8 is default
2309 
2310  txt->SetThickness( kicad( t.size * ratio / 100 ) );
2311 
2312  int align = t.align ? *t.align : ETEXT::BOTTOM_LEFT; // bottom-left is eagle default
2313 
2314  // An eagle package is never rotated, the DTD does not allow it.
2315  // angle -= aModule->GetOrienation();
2316 
2317  if( t.rot )
2318  {
2319  int sign = t.rot->mirror ? -1 : 1;
2320  txt->SetMirrored( t.rot->mirror );
2321 
2322  double degrees = t.rot->degrees;
2323 
2324  if( degrees == 90 || t.rot->spin )
2325  txt->SetTextAngle( sign * degrees * 10 );
2326  else if( degrees == 180 )
2327  align = ETEXT::TOP_RIGHT;
2328  else if( degrees == 270 )
2329  {
2330  align = ETEXT::TOP_RIGHT;
2331  txt->SetTextAngle( sign * 90 * 10 );
2332  }
2333  }
2334 
2335  switch( align )
2336  {
2337  case ETEXT::CENTER:
2338  // this was the default in pcbtxt's constructor
2339  break;
2340 
2341  case ETEXT::CENTER_LEFT:
2343  break;
2344 
2345  case ETEXT::CENTER_RIGHT:
2347  break;
2348 
2349  case ETEXT::TOP_CENTER:
2351  break;
2352 
2353  case ETEXT::TOP_LEFT:
2356  break;
2357 
2358  case ETEXT::TOP_RIGHT:
2361  break;
2362 
2363  case ETEXT::BOTTOM_CENTER:
2365  break;
2366 
2367  case ETEXT::BOTTOM_LEFT:
2370  break;
2371 
2372  case ETEXT::BOTTOM_RIGHT:
2375  break;
2376  }
2377 }
2378 
2379 
2380 void EAGLE_PLUGIN::packageRectangle( MODULE* aModule, CPTREE& aTree ) const
2381 {
2382  ERECT r( aTree );
2383  LAYER_ID layer = kicad_layer( r.layer );
2384 
2385  if( IsNonCopperLayer( layer ) ) // skip copper "package.rectangle"s
2386  {
2387  EDGE_MODULE* dwg = new EDGE_MODULE( aModule, S_POLYGON );
2388  aModule->GraphicalItems().PushBack( dwg );
2389 
2390  dwg->SetLayer( layer );
2391  dwg->SetWidth( 0 );
2392 
2393  dwg->SetTimeStamp( timeStamp( aTree ) );
2394 
2395  std::vector<wxPoint> pts;
2396 
2397  wxPoint start( wxPoint( kicad_x( r.x1 ), kicad_y( r.y1 ) ) );
2398  wxPoint end( wxPoint( kicad_x( r.x1 ), kicad_y( r.y2 ) ) );
2399 
2400  pts.push_back( start );
2401  pts.push_back( wxPoint( kicad_x( r.x2 ), kicad_y( r.y1 ) ) );
2402  pts.push_back( wxPoint( kicad_x( r.x2 ), kicad_y( r.y2 ) ) );
2403  pts.push_back( end );
2404 
2405  dwg->SetPolyPoints( pts );
2406 
2407  dwg->SetStart0( start );
2408  dwg->SetEnd0( end );
2409  }
2410 }
2411 
2412 
2413 void EAGLE_PLUGIN::packagePolygon( MODULE* aModule, CPTREE& aTree ) const
2414 {
2415  EPOLYGON p( aTree );
2416  LAYER_ID layer = kicad_layer( p.layer );
2417 
2418  if( IsNonCopperLayer( layer ) ) // skip copper "package.rectangle"s
2419  {
2420  EDGE_MODULE* dwg = new EDGE_MODULE( aModule, S_POLYGON );
2421  aModule->GraphicalItems().PushBack( dwg );
2422 
2423  dwg->SetWidth( 0 ); // it's filled, no need for boundary width
2424 
2425  /*
2426  switch( layer )
2427  {
2428  case Eco1_User: layer = F_SilkS; break;
2429  case Eco2_User: layer = B_SilkS; break;
2430 
2431  // all MODULE templates (created from eagle packages) are on front layer
2432  // until cloned.
2433  case Cmts_User: layer = F_SilkS; break;
2434  }
2435  */
2436 
2437  dwg->SetLayer( layer );
2438 
2439  dwg->SetTimeStamp( timeStamp( aTree ) );
2440 
2441  std::vector<wxPoint> pts;
2442  pts.reserve( aTree.size() );
2443 
2444  for( CITER vi = aTree.begin(); vi != aTree.end(); ++vi )
2445  {
2446  if( vi->first != "vertex" ) // skip <xmlattr> node
2447  continue;
2448 
2449  EVERTEX v( vi->second );
2450 
2451  pts.push_back( wxPoint( kicad_x( v.x ), kicad_y( v.y ) ) );
2452  }
2453 
2454  dwg->SetPolyPoints( pts );
2455 
2456  dwg->SetStart0( *pts.begin() );
2457  dwg->SetEnd0( pts.back() );
2458  }
2459 }
2460 
2461 
2462 void EAGLE_PLUGIN::packageCircle( MODULE* aModule, CPTREE& aTree ) const
2463 {
2464  ECIRCLE e( aTree );
2465  LAYER_ID layer = kicad_layer( e.layer );
2466  EDGE_MODULE* gr = new EDGE_MODULE( aModule, S_CIRCLE );
2467 
2468  aModule->GraphicalItems().PushBack( gr );
2469 
2470  gr->SetWidth( kicad( e.width ) );
2471 
2472  switch( (int) layer )
2473  {
2474  case UNDEFINED_LAYER: layer = Cmts_User; break;
2475  /*
2476  case Eco1_User: layer = F_SilkS; break;
2477  case Eco2_User: layer = B_SilkS; break;
2478  */
2479  default:
2480  break;
2481  }
2482 
2483  gr->SetLayer( layer );
2484  gr->SetTimeStamp( timeStamp( aTree ) );
2485 
2486  gr->SetStart0( wxPoint( kicad_x( e.x ), kicad_y( e.y ) ) );
2487  gr->SetEnd0( wxPoint( kicad_x( e.x + e.radius ), kicad_y( e.y ) ) );
2488 }
2489 
2490 
2491 void EAGLE_PLUGIN::packageHole( MODULE* aModule, CPTREE& aTree ) const
2492 {
2493  EHOLE e( aTree );
2494 
2495  // we add a PAD_ATTRIB_HOLE_NOT_PLATED pad to this module.
2496  D_PAD* pad = new D_PAD( aModule );
2497  aModule->Pads().PushBack( pad );
2498 
2499  pad->SetShape( PAD_SHAPE_CIRCLE );
2501 
2502  // Mechanical purpose only:
2503  // no offset, no net name, no pad name allowed
2504  // pad->SetOffset( wxPoint( 0, 0 ) );
2505  // pad->SetPadName( wxEmptyString );
2506 
2507  wxPoint padpos( kicad_x( e.x ), kicad_y( e.y ) );
2508 
2509  pad->SetPos0( padpos );
2510  pad->SetPosition( padpos + aModule->GetPosition() );
2511 
2512  wxSize sz( kicad( e.drill ), kicad( e.drill ) );
2513 
2514  pad->SetDrillSize( sz );
2515  pad->SetSize( sz );
2516 
2517  pad->SetLayerSet( LSET::AllCuMask() /* | SOLDERMASK_LAYER_BACK | SOLDERMASK_LAYER_FRONT */ );
2518 }
2519 
2520 
2521 void EAGLE_PLUGIN::packageSMD( MODULE* aModule, CPTREE& aTree ) const
2522 {
2523  ESMD e( aTree );
2524  LAYER_ID layer = kicad_layer( e.layer );
2525 
2526  if( !IsCopperLayer( layer ) )
2527  {
2528  return;
2529  }
2530 
2531  D_PAD* pad = new D_PAD( aModule );
2532  aModule->Pads().PushBack( pad );
2533 
2534  pad->SetPadName( FROM_UTF8( e.name.c_str() ) );
2535  pad->SetShape( PAD_SHAPE_RECT );
2536  pad->SetAttribute( PAD_ATTRIB_SMD );
2537 
2538  // pad's "Position" is not relative to the module's,
2539  // whereas Pos0 is relative to the module's but is the unrotated coordinate.
2540 
2541  wxPoint padpos( kicad_x( e.x ), kicad_y( e.y ) );
2542 
2543  pad->SetPos0( padpos );
2544 
2545  RotatePoint( &padpos, aModule->GetOrientation() );
2546 
2547  pad->SetPosition( padpos + aModule->GetPosition() );
2548 
2549  pad->SetSize( wxSize( kicad( e.dx ), kicad( e.dy ) ) );
2550 
2551  pad->SetLayer( layer );
2552 
2553  static const LSET front( 3, F_Cu, F_Paste, F_Mask );
2554  static const LSET back( 3, B_Cu, B_Paste, B_Mask );
2555 
2556  if( layer == F_Cu )
2557  pad->SetLayerSet( front );
2558  else if( layer == B_Cu )
2559  pad->SetLayerSet( back );
2560 
2561  // Optional according to DTD
2562  if( e.roundness ) // set set shape to PAD_SHAPE_RECT above, in case roundness is not present
2563  {
2564  if( *e.roundness >= 75 ) // roundness goes from 0-100% as integer
2565  {
2566  if( e.dy == e.dx )
2567  pad->SetShape( PAD_SHAPE_CIRCLE );
2568  else
2569  pad->SetShape( PAD_SHAPE_OVAL );
2570  }
2571  }
2572 
2573  if( e.rot )
2574  {
2575  pad->SetOrientation( e.rot->degrees * 10 );
2576  }
2577 
2578  // don't know what stop, thermals, and cream should look like now.
2579 }
2580 
2582 typedef std::vector<ZONE_CONTAINER*> ZONES;
2583 
2584 
2586 {
2587  ZONES zones; // per net
2588 
2589  m_xpath->push( "signals.signal", "name" );
2590 
2591  int netCode = 1;
2592 
2593  for( CITER net = aSignals.begin(); net != aSignals.end(); ++net )
2594  {
2595  bool sawPad = false;
2596 
2597  zones.clear();
2598 
2599  const string& nname = net->second.get<string>( "<xmlattr>.name" );
2600  wxString netName = FROM_UTF8( nname.c_str() );
2601  m_board->Add( new NETINFO_ITEM( m_board, netName, netCode ) );
2602 
2603  m_xpath->Value( nname.c_str() );
2604 
2605  // (contactref | polygon | wire | via)*
2606  for( CITER it = net->second.begin(); it != net->second.end(); ++it )
2607  {
2608  if( it->first == "wire" )
2609  {
2610  m_xpath->push( "wire" );
2611  EWIRE w( it->second );
2612  LAYER_ID layer = kicad_layer( w.layer );
2613 
2614  if( IsCopperLayer( layer ) )
2615  {
2616  TRACK* t = new TRACK( m_board );
2617 
2618  t->SetTimeStamp( timeStamp( it->second ) );
2619 
2620  t->SetPosition( wxPoint( kicad_x( w.x1 ), kicad_y( w.y1 ) ) );
2621  t->SetEnd( wxPoint( kicad_x( w.x2 ), kicad_y( w.y2 ) ) );
2622 
2623  int width = kicad( w.width );
2624  if( width < m_min_trace )
2625  m_min_trace = width;
2626 
2627  t->SetWidth( width );
2628  t->SetLayer( layer );
2629  t->SetNetCode( netCode );
2630 
2631  m_board->m_Track.Insert( t, NULL );
2632  }
2633  else
2634  {
2635  // put non copper wires where the sun don't shine.
2636  }
2637 
2638  m_xpath->pop();
2639  }
2640 
2641  else if( it->first == "via" )
2642  {
2643  m_xpath->push( "via" );
2644  EVIA v( it->second );
2645 
2646  LAYER_ID layer_front_most = kicad_layer( v.layer_front_most );
2647  LAYER_ID layer_back_most = kicad_layer( v.layer_back_most );
2648 
2649  if( IsCopperLayer( layer_front_most ) &&
2650  IsCopperLayer( layer_back_most ) )
2651  {
2652  int kidiam;
2653  int drillz = kicad( v.drill );
2654  VIA* via = new VIA( m_board );
2655  m_board->m_Track.Insert( via, NULL );
2656 
2657  via->SetLayerPair( layer_front_most, layer_back_most );
2658 
2659  if( v.diam )
2660  {
2661  kidiam = kicad( *v.diam );
2662  via->SetWidth( kidiam );
2663  }
2664  else
2665  {
2666  double annulus = drillz * m_rules->rvViaOuter; // eagle "restring"
2667  annulus = Clamp( m_rules->rlMinViaOuter, annulus, m_rules->rlMaxViaOuter );
2668  kidiam = KiROUND( drillz + 2 * annulus );
2669  via->SetWidth( kidiam );
2670  }
2671 
2672  via->SetDrill( drillz );
2673 
2674  if( kidiam < m_min_via )
2675  m_min_via = kidiam;
2676 
2677  if( drillz < m_min_via_hole )
2678  m_min_via_hole = drillz;
2679 
2680  if( layer_front_most == F_Cu && layer_back_most == B_Cu )
2681  via->SetViaType( VIA_THROUGH );
2682  else if( layer_front_most == F_Cu || layer_back_most == B_Cu )
2683  via->SetViaType( VIA_MICROVIA );
2684  else
2685  via->SetViaType( VIA_BLIND_BURIED );
2686 
2687  via->SetTimeStamp( timeStamp( it->second ) );
2688 
2689  wxPoint pos( kicad_x( v.x ), kicad_y( v.y ) );
2690 
2691  via->SetPosition( pos );
2692  via->SetEnd( pos );
2693 
2694  via->SetNetCode( netCode );
2695  }
2696  m_xpath->pop();
2697  }
2698 
2699  else if( it->first == "contactref" )
2700  {
2701  m_xpath->push( "contactref" );
2702  // <contactref element="RN1" pad="7"/>
2703  CPTREE& attribs = it->second.get_child( "<xmlattr>" );
2704 
2705  const string& reference = attribs.get<string>( "element" );
2706  const string& pad = attribs.get<string>( "pad" );
2707 
2708  string key = makeKey( reference, pad ) ;
2709 
2710  // D(printf( "adding refname:'%s' pad:'%s' netcode:%d netname:'%s'\n", reference.c_str(), pad.c_str(), netCode, nname.c_str() );)
2711 
2712  m_pads_to_nets[ key ] = ENET( netCode, nname );
2713 
2714  m_xpath->pop();
2715 
2716  sawPad = true;
2717  }
2718 
2719  else if( it->first == "polygon" )
2720  {
2721  m_xpath->push( "polygon" );
2722 
2723  EPOLYGON p( it->second );
2724  LAYER_ID layer = kicad_layer( p.layer );
2725 
2726  if( IsCopperLayer( layer ) )
2727  {
2728  // use a "netcode = 0" type ZONE:
2729  ZONE_CONTAINER* zone = new ZONE_CONTAINER( m_board );
2730  m_board->Add( zone, ADD_APPEND );
2731  zones.push_back( zone );
2732 
2733  zone->SetTimeStamp( timeStamp( it->second ) );
2734  zone->SetLayer( layer );
2735  zone->SetNetCode( netCode );
2736 
2737  for( CITER vi = it->second.begin(); vi != it->second.end(); ++vi )
2738  {
2739  if( vi->first != "vertex" ) // skip <xmlattr> node
2740  continue;
2741 
2742  EVERTEX v( vi->second );
2743 
2744  // Append the corner
2745  zone->AppendCorner( wxPoint( kicad_x( v.x ), kicad_y( v.y ) ) );
2746  }
2747 
2748  // If the pour is a cutout it needs to be set to a keepout
2749  if( p.pour == EPOLYGON::CUTOUT )
2750  {
2751  zone->SetIsKeepout( true );
2752  zone->SetDoNotAllowCopperPour( true );
2754  }
2755 
2756  // if spacing is set the zone should be hatched
2757  if( p.spacing )
2758  zone->SetHatch( ZONE_CONTAINER::DIAGONAL_EDGE, *p.spacing, true );
2759 
2760  // clearances, etc.
2761  zone->SetArcSegmentCount( 32 ); // @todo: should be a constructor default?
2762  zone->SetMinThickness( kicad( p.width ) );
2763 
2764  // FIXME: KiCad zones have very rounded corners compared to eagle.
2765  // This means that isolation amounts that work well in eagle
2766  // tend to make copper intrude in soldermask free areas around pads.
2767  if( p.isolate )
2768  {
2769  zone->SetZoneClearance( kicad( *p.isolate ) );
2770  }
2771 
2772  // missing == yes per DTD.
2773  bool thermals = !p.thermals || *p.thermals;
2775  if( thermals )
2776  {
2777  // FIXME: eagle calculates dimensions for thermal spokes
2778  // based on what the zone is connecting to.
2779  // (i.e. width of spoke is half of the smaller side of an smd pad)
2780  // This is a basic workaround
2781  zone->SetThermalReliefGap( kicad( p.width + 0.05 ) );
2782  zone->SetThermalReliefCopperBridge( kicad( p.width + 0.05 ) );
2783  }
2784 
2785  int rank = p.rank ? *p.rank : p.max_priority;
2786  zone->SetPriority( rank );
2787  }
2788 
2789  m_xpath->pop(); // "polygon"
2790  }
2791  }
2792 
2793  if( zones.size() && !sawPad )
2794  {
2795  // KiCad does not support an unconnected zone with its own non-zero netcode,
2796  // but only when assigned netcode = 0 w/o a name...
2797  for( ZONES::iterator it = zones.begin(); it != zones.end(); ++it )
2798  (*it)->SetNetCode( NETINFO_LIST::UNCONNECTED );
2799 
2800  // therefore omit this signal/net.
2801  }
2802  else
2803  netCode++;
2804  }
2805 
2806  m_xpath->pop(); // "signals.signal"
2807 }
2808 
2809 
2810 LAYER_ID EAGLE_PLUGIN::kicad_layer( int aEagleLayer ) const
2811 {
2812  /* will assume this is a valid mapping for all eagle boards until I get paid more:
2813 
2814  <layers>
2815  <layer number="1" name="Top" color="4" fill="1" visible="yes" active="yes"/>
2816  <layer number="2" name="Route2" color="1" fill="3" visible="no" active="no"/>
2817  <layer number="3" name="Route3" color="4" fill="3" visible="no" active="no"/>
2818  <layer number="4" name="Route4" color="1" fill="4" visible="no" active="no"/>
2819  <layer number="5" name="Route5" color="4" fill="4" visible="no" active="no"/>
2820  <layer number="6" name="Route6" color="1" fill="8" visible="no" active="no"/>
2821  <layer number="7" name="Route7" color="4" fill="8" visible="no" active="no"/>
2822  <layer number="8" name="Route8" color="1" fill="2" visible="no" active="no"/>
2823  <layer number="9" name="Route9" color="4" fill="2" visible="no" active="no"/>
2824  <layer number="10" name="Route10" color="1" fill="7" visible="no" active="no"/>
2825  <layer number="11" name="Route11" color="4" fill="7" visible="no" active="no"/>
2826  <layer number="12" name="Route12" color="1" fill="5" visible="no" active="no"/>
2827  <layer number="13" name="Route13" color="4" fill="5" visible="no" active="no"/>
2828  <layer number="14" name="Route14" color="1" fill="6" visible="no" active="no"/>
2829  <layer number="15" name="Route15" color="4" fill="6" visible="no" active="no"/>
2830  <layer number="16" name="Bottom" color="1" fill="1" visible="yes" active="yes"/>
2831  <layer number="17" name="Pads" color="2" fill="1" visible="yes" active="yes"/>
2832  <layer number="18" name="Vias" color="14" fill="1" visible="yes" active="yes"/>
2833  <layer number="19" name="Unrouted" color="6" fill="1" visible="yes" active="yes"/>
2834  <layer number="20" name="Dimension" color="15" fill="1" visible="yes" active="yes"/>
2835  <layer number="21" name="tPlace" color="7" fill="1" visible="yes" active="yes"/>
2836  <layer number="22" name="bPlace" color="7" fill="1" visible="yes" active="yes"/>
2837  <layer number="23" name="tOrigins" color="15" fill="1" visible="yes" active="yes"/>
2838  <layer number="24" name="bOrigins" color="15" fill="1" visible="yes" active="yes"/>
2839  <layer number="25" name="tNames" color="7" fill="1" visible="yes" active="yes"/>
2840  <layer number="26" name="bNames" color="7" fill="1" visible="yes" active="yes"/>
2841  <layer number="27" name="tValues" color="7" fill="1" visible="no" active="yes"/>
2842  <layer number="28" name="bValues" color="7" fill="1" visible="no" active="yes"/>
2843  <layer number="29" name="tStop" color="2" fill="3" visible="no" active="yes"/>
2844  <layer number="30" name="bStop" color="5" fill="6" visible="no" active="yes"/>
2845  <layer number="31" name="tCream" color="7" fill="4" visible="no" active="yes"/>
2846  <layer number="32" name="bCream" color="7" fill="5" visible="no" active="yes"/>
2847  <layer number="33" name="tFinish" color="6" fill="3" visible="no" active="yes"/>
2848  <layer number="34" name="bFinish" color="6" fill="6" visible="no" active="yes"/>
2849  <layer number="35" name="tGlue" color="7" fill="4" visible="no" active="yes"/>
2850  <layer number="36" name="bGlue" color="7" fill="5" visible="no" active="yes"/>
2851  <layer number="37" name="tTest" color="7" fill="1" visible="no" active="yes"/>
2852  <layer number="38" name="bTest" color="7" fill="1" visible="no" active="yes"/>
2853  <layer number="39" name="tKeepout" color="4" fill="11" visible="no" active="yes"/>
2854  <layer number="40" name="bKeepout" color="1" fill="11" visible="no" active="yes"/>
2855  <layer number="41" name="tRestrict" color="4" fill="10" visible="no" active="yes"/>
2856  <layer number="42" name="bRestrict" color="1" fill="10" visible="no" active="yes"/>
2857  <layer number="43" name="vRestrict" color="2" fill="10" visible="no" active="yes"/>
2858  <layer number="44" name="Drills" color="7" fill="1" visible="no" active="yes"/>
2859  <layer number="45" name="Holes" color="7" fill="1" visible="no" active="yes"/>
2860  <layer number="46" name="Milling" color="3" fill="1" visible="no" active="yes"/>
2861  <layer number="47" name="Measures" color="7" fill="1" visible="no" active="yes"/>
2862  <layer number="48" name="Document" color="7" fill="1" visible="no" active="yes"/>
2863  <layer number="49" name="ReferenceLC" color="13" fill="1" visible="yes" active="yes"/>
2864  <layer number="50" name="ReferenceLS" color="12" fill="1" visible="yes" active="yes"/>
2865  <layer number="51" name="tDocu" color="7" fill="1" visible="yes" active="yes"/>
2866  <layer number="52" name="bDocu" color="7" fill="1" visible="yes" active="yes"/>
2867 
2868  * These layers are used only in eagle schematic.
2869  * They should not be found in board files.
2870  * They are listed for info only.
2871  <layer number="91" name="Nets" color="2" fill="1" visible="no" active="no"/>
2872  <layer number="92" name="Busses" color="1" fill="1" visible="no" active="no"/>
2873  <layer number="93" name="Pins" color="2" fill="1" visible="no" active="no"/>
2874  <layer number="94" name="Symbols" color="4" fill="1" visible="no" active="no"/>
2875  <layer number="95" name="Names" color="7" fill="1" visible="no" active="no"/>
2876  <layer number="96" name="Values" color="7" fill="1" visible="no" active="no"/>
2877  <layer number="97" name="Info" color="7" fill="1" visible="no" active="no"/>
2878  <layer number="98" name="Guide" color="6" fill="1" visible="no" active="no"/>
2879 
2880  * These layers are user layers
2881  <layer number="160" name="???" color="7" fill="1" visible="yes" active="yes"/>
2882  <layer number="161" name="???" color="7" fill="1" visible="yes" active="yes"/>
2883 
2884  </layers>
2885 
2886  */
2887 
2888  int kiLayer;
2889 
2890  // eagle copper layer:
2891  if( aEagleLayer >= 1 && aEagleLayer < int( DIM( m_cu_map ) ) )
2892  {
2893  kiLayer = m_cu_map[aEagleLayer];
2894  }
2895 
2896  else
2897  {
2898  // translate non-copper eagle layer to pcbnew layer
2899  switch( aEagleLayer )
2900  {
2901  case 20: kiLayer = Edge_Cuts; break; // eagle says "Dimension" layer, but it's for board perimeter
2902  case 21: kiLayer = F_SilkS; break;
2903  case 22: kiLayer = B_SilkS; break;
2904  case 25: kiLayer = F_SilkS; break;
2905  case 26: kiLayer = B_SilkS; break;
2906  case 27: kiLayer = F_SilkS; break;
2907  case 28: kiLayer = B_SilkS; break;
2908  case 29: kiLayer = F_Mask; break;
2909  case 30: kiLayer = B_Mask; break;
2910  case 31: kiLayer = F_Paste; break;
2911  case 32: kiLayer = B_Paste; break;
2912  case 33: kiLayer = F_Mask; break;
2913  case 34: kiLayer = B_Mask; break;
2914  case 35: kiLayer = F_Adhes; break;
2915  case 36: kiLayer = B_Adhes; break;
2916  case 48: kiLayer = Cmts_User; break;
2917  case 49: kiLayer = Cmts_User; break;
2918  case 50: kiLayer = Cmts_User; break;
2919 
2920  // Packages show the future chip pins on SMD parts using layer 51.
2921  // This is an area slightly smaller than the PAD/SMD copper area.
2922  // Carry those visual aids into the MODULE on the fabrication layer,
2923  // not silkscreen. This is perhaps not perfect, but there is not a lot
2924  // of other suitable paired layers
2925  case 51: kiLayer = F_Fab; break;
2926  case 52: kiLayer = B_Fab; break;
2927 
2928  // thes layers are defined as user layers. put them on ECO layers
2929  case 160: kiLayer = Eco1_User; break;
2930  case 161: kiLayer = Eco2_User; break;
2931  default:
2932  // some layers do not map to KiCad
2933  // DBG( printf( "unsupported eagle layer: %d\n", aEagleLayer );)
2934  kiLayer = UNDEFINED_LAYER; break;
2935  }
2936  }
2937 
2938  return LAYER_ID( kiLayer );
2939 }
2940 
2941 
2943 {
2944  if( m_props )
2945  {
2946  UTF8 page_width;
2947  UTF8 page_height;
2948 
2949  if( m_props->Value( "page_width", &page_width ) &&
2950  m_props->Value( "page_height", &page_height ) )
2951  {
2953 
2954  int w = atoi( page_width.c_str() );
2955  int h = atoi( page_height.c_str() );
2956 
2957  int desired_x = ( w - bbbox.GetWidth() ) / 2;
2958  int desired_y = ( h - bbbox.GetHeight() ) / 2;
2959 
2960  DBG(printf( "bbox.width:%d bbox.height:%d w:%d h:%d desired_x:%d desired_y:%d\n",
2961  bbbox.GetWidth(), bbbox.GetHeight(), w, h, desired_x, desired_y );)
2962 
2963  m_board->Move( wxPoint( desired_x - bbbox.GetX(), desired_y - bbbox.GetY() ) );
2964  }
2965  }
2966 }
2967 
2968 
2969 wxDateTime EAGLE_PLUGIN::getModificationTime( const wxString& aPath )
2970 {
2971  wxFileName fn( aPath );
2972 
2973  // Do not call wxFileName::GetModificationTime() on a non-existent file, because
2974  // if it fails, wx's implementation calls the crap wxLogSysError() which
2975  // eventually infects our UI with an unwanted popup window, so don't let it fail.
2976  if( !fn.IsFileReadable() )
2977  {
2978  wxString msg = wxString::Format(
2979  _( "File '%s' is not readable." ),
2980  GetChars( aPath ) );
2981 
2982  THROW_IO_ERROR( msg );
2983  }
2984 
2985  /*
2986  // update the writable flag while we have a wxFileName, in a network this
2987  // is possibly quite dynamic anyway.
2988  m_writable = fn.IsFileWritable();
2989  */
2990 
2991  wxDateTime modTime = fn.GetModificationTime();
2992 
2993  if( !modTime.IsValid() )
2994  modTime.Now();
2995 
2996  return modTime;
2997 }
2998 
2999 
3000 void EAGLE_PLUGIN::cacheLib( const wxString& aLibPath )
3001 {
3002  try
3003  {
3004  wxDateTime modtime = getModificationTime( aLibPath );
3005 
3006  // Fixes assertions in wxWidgets debug builds for the wxDateTime object. Refresh the
3007  // cache if either of the wxDateTime objects are invalid or the last file modification
3008  // time differs from the current file modification time.
3009  bool load = !m_mod_time.IsValid() || !modtime.IsValid() ||
3010  m_mod_time != modtime;
3011 
3012  if( aLibPath != m_lib_path || load )
3013  {
3014  PTREE doc;
3015  LOCALE_IO toggle; // toggles on, then off, the C locale.
3016 
3017  m_templates.clear();
3018 
3019  // Set this before completion of loading, since we rely on it for
3020  // text of an exception. Delay setting m_mod_time until after successful load
3021  // however.
3022  m_lib_path = aLibPath;
3023 
3024  // 8 bit "filename" should be encoded according to disk filename encoding,
3025  // (maybe this is current locale, maybe not, its a filesystem issue),
3026  // and is not necessarily utf8.
3027  string filename = (const char*) aLibPath.char_str( wxConvFile );
3028 
3029  read_xml( filename, doc, xml_parser::no_comments );
3030 
3031  // clear the cu map and then rebuild it.
3032  clear_cu_map();
3033 
3034  m_xpath->push( "eagle.drawing.layers" );
3035  CPTREE& layers = doc.get_child( "eagle.drawing.layers" );
3036  loadLayerDefs( layers );
3037  m_xpath->pop();
3038 
3039  m_xpath->push( "eagle.drawing.library" );
3040  CPTREE& library = doc.get_child( "eagle.drawing.library" );
3041  loadLibrary( library, NULL );
3042  m_xpath->pop();
3043 
3044  m_mod_time = modtime;
3045  }
3046  }
3047  catch( file_parser_error fpe )
3048  {
3049  // for xml_parser_error, what() has the line number in it,
3050  // but no byte offset. That should be an adequate error message.
3051  THROW_IO_ERROR( fpe.what() );
3052  }
3053 
3054  // Class ptree_error is a base class for xml_parser_error & file_parser_error,
3055  // so one catch should be OK for all errors.
3056  catch( ptree_error pte )
3057  {
3058  string errmsg = pte.what();
3059 
3060  errmsg += " @\n";
3061  errmsg += m_xpath->Contents();
3062 
3063  THROW_IO_ERROR( errmsg );
3064  }
3065 }
3066 
3067 
3068 wxArrayString EAGLE_PLUGIN::FootprintEnumerate( const wxString& aLibraryPath, const PROPERTIES* aProperties )
3069 {
3070  init( aProperties );
3071 
3072  cacheLib( aLibraryPath );
3073 
3074  wxArrayString ret;
3075 
3076  for( MODULE_CITER it = m_templates.begin(); it != m_templates.end(); ++it )
3077  ret.Add( FROM_UTF8( it->first.c_str() ) );
3078 
3079  return ret;
3080 }
3081 
3082 
3083 MODULE* EAGLE_PLUGIN::FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
3084  const PROPERTIES* aProperties )
3085 {
3086  init( aProperties );
3087 
3088  cacheLib( aLibraryPath );
3089 
3090  string key = TO_UTF8( aFootprintName );
3091 
3092  MODULE_CITER mi = m_templates.find( key );
3093 
3094  if( mi == m_templates.end() )
3095  return NULL;
3096 
3097  // copy constructor to clone the template
3098  MODULE* ret = new MODULE( *mi->second );
3099 
3100  return ret;
3101 }
3102 
3103 
3104 void EAGLE_PLUGIN::FootprintLibOptions( PROPERTIES* aListToAppendTo ) const
3105 {
3106  PLUGIN::FootprintLibOptions( aListToAppendTo );
3107 
3108  /*
3109  (*aListToAppendTo)["ignore_duplicates"] = UTF8( _(
3110  "Ignore duplicately named footprints within the same Eagle library. "
3111  "Only the first similarly named footprint will be loaded."
3112  ));
3113  */
3114 }
3115 
3116 
3117 /*
3118 void EAGLE_PLUGIN::Save( const wxString& aFileName, BOARD* aBoard, const PROPERTIES* aProperties )
3119 {
3120  // Eagle lovers apply here.
3121 }
3122 
3123 
3124 void EAGLE_PLUGIN::FootprintSave( const wxString& aLibraryPath, const MODULE* aFootprint, const PROPERTIES* aProperties )
3125 {
3126 }
3127 
3128 
3129 void EAGLE_PLUGIN::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName )
3130 {
3131 }
3132 
3133 
3134 void EAGLE_PLUGIN::FootprintLibCreate( const wxString& aLibraryPath, const PROPERTIES* aProperties )
3135 {
3136 }
3137 
3138 
3139 bool EAGLE_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties )
3140 {
3141 }
3142 
3143 
3144 bool EAGLE_PLUGIN::IsFootprintLibWritable( const wxString& aLibraryPath )
3145 {
3146  return true;
3147 }
3148 
3149 */
void SetMirrored(bool isMirrored)
Definition: eda_text.h:178
void packageCircle(MODULE *aModule, CPTREE &aTree) const
opt_double diameter
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Function AllCuMask returns a mask holding the requested number of Cu LAYER_IDs.
Definition: lset.cpp:638
Eagle rotation.
Class UTF8 is an 8 bit std::string that is assuredly encoded in UTF8, and supplies special conversion...
Definition: utf8.h:53
#define DIM(x)
of elements in an array
Definition: macros.h:98
MODULE_MAP::iterator MODULE_ITER
void SetEnd0(const wxPoint &aPoint)
double width
boost::optional< double > opt_double
ESMD(CPTREE &aSMD)
string package
double rlMaxViaOuter
maximum copper annulus on via
Class ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:78
bool mirror
opt_double curve
range is -359.9..359.9
MODULE * makeModule(CPTREE &aPackage, const std::string &aPkgName) const
Function makeModule creates a MODULE from an Eagle package.
double radius
void SetTextAngle(double aAngle)
double size
bool SetLayerType(LAYER_ID aLayer, LAYER_T aLayerType)
Function SetLayerType changes the type of the layer given by aLayer.
TEXTE_MODULE & Reference()
Definition: class_module.h:455
opt_double isolate
void SetShape(STROKE_T aShape)
opt_bool stop
NETCLASSPTR GetDefault() const
Function GetDefault.
opt_int rank
const T & Clamp(const T &lower, const T &value, const T &upper)
Function Clamp limits value within the range lower <= value <= upper.
Definition: macros.h:127
ERECT(CPTREE &aRect)
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes...
Definition: macros.h:53
void centerBoard()
move the BOARD into the center of the page
BOARD * m_board
which BOARD is being worked on, no ownership here
Definition: eagle_plugin.h:137
TEXTE_PCB class definition.
string name
double y
void SetViaType(VIATYPE_T aViaType)
Definition: class_track.h:443
static int KiROUND(double v)
KiROUND rounds a floating point number to an int using "round halfway cases away from zero"...
Definition: common.h:107
EELEMENT(CPTREE &aElement)
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:63
Class LOCALE_IO is a class that can be instantiated within a scope in which you are expecting excepti...
Definition: common.h:166
void FootprintLibOptions(PROPERTIES *aProperties) const override
Function FootprintLibOptions appends supported PLUGIN options to aListToAppenTo along with internatio...
void packagePolygon(MODULE *aModule, CPTREE &aTree) const
string name
void SetPosition(const wxPoint &aPoint) override
Definition: class_track.h:416
void SetEnd(const wxPoint &aEnd)
Definition: class_track.h:116
void clear()
static double parseEagle(const string &aDistance)
Parse an eagle distance which is either mm, or mils if there is "mil" suffix.
void loadAllSections(CPTREE &aDocument)
ERULES * m_rules
Eagle design rules.
Definition: eagle_plugin.h:123
opt_int cap
double y
void packageText(MODULE *aModule, CPTREE &aTree) const
int m_PcbTextWidth
current Pcb (not module) Text width
static string makeKey(const string &aFirst, const string &aSecond)
Assemble a two part key as a simple concatonation of aFirst and aSecond parts, using a separator...
void Flip(const wxPoint &aCentre) override
Function Flip Flip this object, i.e.
Class BOARD to handle a board.
const wxPoint & GetPosition() const override
Definition: class_module.h:143
const PTREE CPTREE
Definition: eagle_plugin.h:63
double x
void push(const char *aPathSegment, const char *aAttribute="")
bool Value(const char *aName, UTF8 *aFetchedValue=NULL) const
Function Value fetches a property by aName and returns true if that property was found, else false.
Definition: properties.cpp:24
Eagle element element.
static opt_erot parseOptionalEROT(CPTREE &attribs)
Eagle "rot" fields are optional, handle that by returning opt_erot.
polygon (not yet used for tracks, but could be in microwave apps)
Class XPATH keeps track of what we are working on within a PTREE.
void parse(CPTREE &aRules)
virtual void SetLayer(LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
static const int max_priority
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:59
double rlMaxPadTop
maximum copper annulus on through hole pads
void SetTextPos(const wxPoint &aPoint)
Definition: eda_text.h:223
static const int dist[10][10]
Definition: dist.cpp:57
void SetVisible(bool aVisible)
Definition: eda_text.h:175
opt_double ratio
opt_bool visible
void Attribute(const char *aAttribute)
modify the last path node's attribute
int GetHeight() const
double y
void SetCopperLayerCount(int aCount)
ELAYER(CPTREE &aLayer)
opt_erot rot
opt_bool thermals
double x1
bool ReplaceIllegalFileNameChars(std::string *aName, int aReplaceChar)
Function ReplaceIllegalFileNameChars checks aName for illegal file name characters.
Definition: string.cpp:483
opt_bool smashed
void SetPosition(const wxPoint &aPos) override
Definition: class_pad.h:169
Classes to handle copper zones.
BOARD * Load(const wxString &aFileName, BOARD *aAppendToMe, const PROPERTIES *aProperties=NULL) override
Function Load loads information from some input file format that this PLUGIN implementation knows abo...
const wxString & GetValue() const
Function GetValue.
Definition: class_module.h:439
wxArrayString FootprintEnumerate(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Function FootprintEnumerate returns a list of footprint names contained within the library at aLibrar...
usual segment : line with rounded ends
void SetArcSegmentCount(int aArcSegCount)
Definition: class_zone.h:197
const char * element
NET_MAP::const_iterator NET_MAP_CITER
Definition: eagle_plugin.h:60
void SetHatch(int aHatchStyle, int aHatchPitch, bool aRebuildHatch)
Function SetHatch sets all hatch parameters for the zone.
Definition: class_zone.cpp:881
void init(const PROPERTIES *aProperties)
initialize PLUGIN like a constructor would, and futz with fresh BOARD if needed.
opt_erot rot
void SetDrillSize(const wxSize &aSize)
Definition: class_pad.h:187
double degrees
opt_double size
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:214
boost::optional< int > opt_int
Eagle SMD pad.
wxSize kicad_fontz(double d) const
create a font size (fontz) from an eagle font size scalar
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
opt_double spacing
void loadLibrary(CPTREE &aLib, const std::string *aLibName)
Function loadLibrary loads the Eagle "library" XML element, which can occur either under a "libraries...
double y2
const wxSize & GetDrillSize() const
Definition: class_pad.h:188
Class LIB_ID.
Definition: lib_id.h:56
int m_min_via
smallest via we find on Load(), in BIU.
Definition: eagle_plugin.h:140
double rvViaOuter
copper annulus is this percent of via hole
Class PROPERTIES is a name/value tuple with unique names and optional values.
Definition: properties.h:34
#define cu(a)
Definition: auxiliary.h:88
Eagle hole element.
Eagle text element.
PAD_SHAPE_T GetShape() const
Function GetShape.
Definition: class_pad.h:166
#define abs(a)
Definition: auxiliary.h:84
opt_bool thermals
double x2
DLIST< BOARD_ITEM > & GraphicalItems()
Definition: class_module.h:136
opt_erot rot
XPATH * m_xpath
keeps track of what we are working on within XML document during a Load().
Definition: eagle_plugin.h:124
void SetTimeStamp(time_t aNewTimeStamp)
Definition: base_struct.h:203
double GetTextAngle() const
Definition: eda_text.h:164
Functions relatives to tracks, vias and segments used to fill zones.
#define DEFAULT_PCB_EDGE_THICKNESS
int m_cu_map[17]
map eagle to kicad, cu layers only.
Definition: eagle_plugin.h:121
bool IsNonCopperLayer(LAYER_NUM aLayerId)
Function IsNonCopperLayer tests whether a layer is a non copper layer.
int kicad_y(double y) const
Definition: eagle_plugin.h:156
This file contains miscellaneous commonly used macros and functions.
void SetWidth(int aWidth)
Definition: class_track.h:113
double dx
EHOLE(CPTREE &aHole)
void PushBack(T *aNewElement)
Function PushBack puts aNewElement at the end of the list sequence.
Definition: dlist.h:250
int layer_back_most
< extent
segment (element) of our XPATH into the Eagle XML document tree in PTREE form.
const EDA_RECT GetBoardEdgesBoundingBox() const
Function GetBoardEdgesBoundingBox Returns the board bounding box calculated using exclusively the boa...
Definition: class_board.h:839
void SetPriority(unsigned aPriority)
Function SetPriority.
Definition: class_zone.h:113
boost::optional< EROT > opt_erot
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes...
Definition: macros.h:47
DIMENSION class definition.
static opt_bool parseOptionalBool(CPTREE &attribs, const char *aName)
Function parseOptionalBool returns an opt_bool and sets it true or false according to the presence an...
EVIA(CPTREE &aVia)
void SetLayer(LAYER_ID aLayer) override
Function SetLayer sets the layer this item is on.
void loadDesignRules(CPTREE &aDesignRules)
opt_string dimensionType
EAGLE_PLUGIN::BIU BIU
opt_bool stop
int m_min_via_hole
smallest via diameter hole we find on Load(), in BIU.
Definition: eagle_plugin.h:141
void SetLayerPair(LAYER_ID aTopLayer, LAYER_ID aBottomLayer)
Function SetLayerPair For a via m_Layer contains the top layer, the other layer is in m_BottomLayer...
string text
void SetOrigin(const wxPoint &aOrigin)
Function SetOrigin Sets a new origin of the crossbar line.
Class LSET is a set of LAYER_IDs.
double y
void cacheLib(const wxString &aLibraryPath)
This PLUGIN only caches one footprint library, this determines which one.
const PROPERTIES * m_props
passed via Save() or Load(), no ownership, may be NULL.
Definition: eagle_plugin.h:136
void packagePad(MODULE *aModule, CPTREE &aTree) const
opt_int style
LAYER_NUM layer
ECIRCLE(CPTREE &aCircle)
double x1
Eagle thru hol pad.
opt_bool thermals
double GetOrientation() const
Definition: class_module.h:147
static EROT erot(const string &aRot)
parse an Eagle XML "rot" field.
TEXTE_MODULE & Value()
read/write accessors:
Definition: class_module.h:454
void SetPos0(const wxPoint &aPos)
Definition: class_pad.h:175
wxSize m_PcbTextSize
current Pcb (not module) Text size
int m_TrackMinWidth
track min value for width ((min copper size value
void SetEnd(const wxPoint &aEnd)
Function SetEnd Sets a new end of the crossbar line.
void AppendCorner(wxPoint position, bool aAllowDuplication=false)
Function AppendCorner.
Definition: class_zone.h:546
int Clamp_Text_PenSize(int aPenSize, int aSize, bool aBold)
Function Clamp_Text_PenSize As a rule, pen width should not be >1/4em, otherwise the character will b...
Definition: drawtxt.cpp:67
string name
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:194
Arcs (with rounded ends)
int m_ViasMinSize
vias (not micro vias) min diameter
Eagle circle.
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_INSERT) override
>
opt_double diam
double y1
wxString m_lib_path
Definition: eagle_plugin.h:146
std::vector< TRIPLET > p
int m_ViasMinDrill
vias (not micro vias) min drill diameter
D_PAD * Next() const
Definition: class_pad.h:106
int psElongationOffset
the offset of the hole within the "long" pad.
const wxSize & GetSize() const
Definition: class_pad.h:182
EWIRE(CPTREE &aWire)
Constructor EWIRE converts a "wire"'s xml attributes ( <wire> ) to binary without additional conv...
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:530
void SetSize(const wxSize &aSize)
Definition: class_pad.h:181
double x
bool SetNetCode(int aNetCode, bool aNoAssert=false)
Function SetNetCode sets net using a net code.
void packageRectangle(MODULE *aModule, CPTREE &aTree) const
subset of eagle.drawing.board.designrules in the XML document
EDIMENSION(CPTREE &aDimension)
void SetReference(const wxString &aReference)
Function SetReference.
Definition: class_module.h:421
void packageSMD(MODULE *aModule, CPTREE &aTree) const
opt_string value
int kicad_x(double x) const
Definition: eagle_plugin.h:157
#define THROW_IO_ERROR(x)
Definition: utf8.cpp:60
void loadSignals(CPTREE &aSignals)
HATCH_STYLE
Zone hatch styles.
Definition: class_zone.h:85
void SetFileName(const wxString &aFileName)
Definition: class_board.h:235
double y1
void SetPosition(const wxPoint &aPos) override
void SetZoneClearance(int aZoneClearance)
Definition: class_zone.h:204
std::pair< CA_ITER, CA_ITER > CA_ITER_RANGE
int layer
static wxDateTime getModificationTime(const wxString &aPath)
get a file's or dir's modification time.
double mdWireWire
wire to wire spacing I presume.
std::vector< ZONE_CONTAINER * > ZONES
non-owning container
double x
double width
int m_min_trace
smallest trace we find on Load(), in BIU.
Definition: eagle_plugin.h:139
string value
double dy
bool SetLayerName(LAYER_ID aLayer, const wxString &aLayerName)
Function SetLayerName changes the name of the layer given by aLayer.
wxPoint kicad_arc_center(wxPoint start, wxPoint end, double angle)
Convert an Eagle curve end to a KiCad center for S_ARC.
opt_int roundness
string name
double mm_per_biu
how many mm in each BIU
Definition: eagle_plugin.h:143
int m_hole_count
generates unique module names from eagle "hole"s.
Definition: eagle_plugin.h:127
LAYER_NUM layer
Eagle XML rectangle in binary.
opt_erot rot
void SetAttribute(PAD_ATTR_T aAttribute)
Definition: class_pad.cpp:297
opt_int align
void SetPos0(const wxPoint &aPos)
int psElongationLong
percent over 100%.
void AdjustDimensionDetails(bool aDoNotChangeText=false)
Function AdjustDimensionDetails Calculate coordinates of segments used to draw the dimension...
void SetStart(const wxPoint &aStart)
int LAYER_NUM
Type LAYER_NUM can be replaced with int and removed.
void SetThermalReliefCopperBridge(int aThermalReliefCopperBridge)
Definition: class_zone.h:191
void packageHole(MODULE *aModule, CPTREE &aTree) const
void SetPolyPoints(const std::vector< wxPoint > &aPoints)
opt_double x
EPOLYGON(CPTREE &aPolygon)
string name
void orientModuleAndText(MODULE *m, const EELEMENT &e, const EATTR *nameAttr, const EATTR *valueAttr)
PTREE::const_iterator CITER
string Contents()
return the contents of the XPATH as a single string
void Move(const wxPoint &aMoveVector) override
Function Move move this object.
void SetDoNotAllowCopperPour(bool aEnable)
Definition: class_zone.h:650
Eagle "attribute" XML element, no foolin'.
void loadLibraries(CPTREE &aLibs)
opt_string shape
opt_int layer
Eagle via.
EPAD(CPTREE &aPad)
double width
void SetLayerSet(LSET aLayerMask)
Definition: class_pad.h:234
Class NETINFO_ITEM handles the data for a net.
void packageWire(MODULE *aModule, CPTREE &aTree) const
MODULE_MAP::const_iterator MODULE_CITER
ETEXT(CPTREE &aText)
string library
opt_erot rot
boost::property_tree::ptree PTREE
Definition: eagle_plugin.h:62
int netcode
Definition: eagle_plugin.h:46
double x2
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
double drill
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
double DEG2RAD(double deg)
Definition: trigo.h:191
LAYER_ID kicad_layer(int aLayer) const
Convert an Eagle layer to a KiCad layer.
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:166
TRIPLET(const char *aElement, const char *aAttribute="", const char *aValue="")
void loadPlain(CPTREE &aPlain)
double x
const wxString & GetReference() const
Function GetReference.
Definition: class_module.h:411
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:193
LAYER_ID
Enum LAYER_ID is the set of PCB layers.
bool IsMirrored() const
Definition: eda_text.h:179
void SetOrientation(double newangle)
void SetPosition(const wxPoint &aPos) override
Definition: class_track.h:110
void SetHeight(int aHeight)
Function SetHeight Sets the length of feature lines.
MODULE_MAP m_templates
is part of a MODULE factory that operates using copy construction.
Definition: eagle_plugin.h:131
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
TEXTE_PCB & Text()
wxDateTime m_mod_time
Definition: eagle_plugin.h:147
Class EDA_RECT handles the component boundary box.
PTREE::const_assoc_iterator CA_ITER
void SetDrill(int aDrill)
Function SetDrill sets the drill value for vias.
Definition: class_track.h:450
void SetStart0(const wxPoint &aPoint)
double drill
< inclusive
void SetValue(const wxString &aValue)
Function SetValue.
Definition: class_module.h:448
opt_double ratio
int GetX() const
void SetHatchStyle(HATCH_STYLE aStyle)
Definition: class_zone.h:559
NET_MAP m_pads_to_nets
net list
Definition: eagle_plugin.h:129
The common library.
int GetWidth() const
void SetShape(PAD_SHAPE_T aShape)
Definition: class_pad.h:167
opt_bool first
void SetPadName(const wxString &name)
Set the pad name (sometimes called pad number, although it can be an array ref like AA12 the pad name...
Definition: class_pad.cpp:404
int GetY() const
void SetEnd(const wxPoint &aEnd)
Eagle wire.
void SetOrientation(double aAngle)
Function SetOrientation sets the rotation angle of the pad.
Definition: class_pad.cpp:306
opt_bool orphans
void SetAngle(double aAngle)
Function SetAngle sets the angle for arcs, and normalizes it within the range 0 - 360 degrees...
bool IsCopperLayer(LAYER_NUM aLayerId)
Function IsCopperLayer tests whether a layer is a copper layer.
double x
double y
double x
opt_int shape
static int GetDefaultHatchPitchMils()
Function GetDefaultHatchPitchMils.
Definition: class_zone.h:670
opt_erot rot
#define DBG(x)
Definition: fctsys.h:33
Eagle dimension element.
double rvPadTop
top pad size as percent of drill size
boost::optional< string > opt_string
DLIST< D_PAD > & Pads()
Definition: class_module.h:133
void SetTextAngle(double aAngle)
DLIST< TRACK > m_Track
Definition: class_board.h:244
bool spin
double biu_per_mm
how many bius in a mm
Definition: eagle_plugin.h:144
Module description (excepted pads)
const wxSize & GetTextSize() const
Definition: eda_text.h:215
double drill
EROT(double aDegrees)
Eagle polygon, without vertices which are parsed as needed.
opt_int display
void pop()
void SetIsKeepout(bool aEnable)
Definition: class_zone.h:649
void SetPadConnection(ZoneConnection aPadConnection)
Definition: class_zone.h:207
opt_string font
boost::optional< bool > opt_bool
void SetWidth(int aWidth)
EDGE_MODULE class definition.
const char * value
const wxString PluginName() const override
Function PluginName returns a brief hard coded name for this PLUGIN.
const char * attribute
void SetMinThickness(int aMinThickness)
Definition: class_zone.h:210
void loadElements(CPTREE &aElements)
opt_double y
double rlMinPadTop
minimum copper annulus on through hole pads
double rlMinViaOuter
minimum copper annulus on via
virtual void FootprintLibOptions(PROPERTIES *aListToAppendTo) const
Function FootprintLibOptions appends supported PLUGIN options to aListToAppenTo along with internatio...
Definition: plugin.cpp:122
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
static unsigned long timeStamp(CPTREE &aTree)
Make a unique time stamp.
Use thermal relief for pads.
Definition: zones.h:58
void SetThermalReliefGap(int aThermalReliefGap)
Definition: class_zone.h:188
MODULE * FootprintLoad(const wxString &aLibraryPath, const wxString &aFootprintName, const PROPERTIES *aProperties=NULL) override
Function FootprintLoad loads a footprint having aFootprintName from the aLibraryPath containing a lib...
Class DIMENSION.
opt_bool active
double x
double y
double y2
void Insert(T *aNewElement, T *aElementAfterMe)
Function Insert puts aNewElement just in front of aElementAfterMe in the list sequence.
Definition: dlist.h:200
void SetThickness(int aNewThickness)
Function SetThickness sets pen width.
Definition: eda_text.h:148
const wxString GetFileExtension() const override
Function GetFileExtension returns the file extension for the PLUGIN.
void loadLayerDefs(CPTREE &aLayers)
EVERTEX(CPTREE &aVertex)
pads are covered by copper
Definition: zones.h:59
void Value(const char *aValue)
modify the last path node's value
Class BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.
int layer_front_most
int sign(T val)
Definition: math_util.h:44
virtual void SetText(const wxString &aText)
Definition: eda_text.h:141
double y
opt_bool cream
opt_bool locked
void orientModuleText(MODULE *m, const EELEMENT &e, TEXTE_MODULE *txt, const EATTR *a)
void SetWidth(int aWidth)
int kicad(double d) const
Convert an Eagle distance to a KiCad distance.