KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_io_eagle.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25
26/*
27
28Pcbnew PLUGIN for Eagle 6.x XML *.brd and footprint format.
29
30XML parsing and converting:
31Getting line numbers and byte offsets from the source XML file is not
32possible using currently available XML libraries within KiCad project:
33wxXmlDocument and boost::property_tree.
34
35property_tree will give line numbers but no byte offsets, and only during
36document loading. This means that if we have a problem after the document is
37successfully loaded, there is no way to correlate back to line number and byte
38offset of the problem. So a different approach is taken, one which relies on the
39XML elements themselves using an XPATH type of reporting mechanism. The path to
40the problem is reported in the error messages. This means keeping track of that
41path as we traverse the XML document for the sole purpose of accurate error
42reporting.
43
44User can load the source XML file into firefox or other xml browser and follow
45our error message.
46
47Load() TODO's
48
49*) verify zone fill clearances are correct
50
51*/
52
53#include <cerrno>
54
55#include <wx/string.h>
56#include <wx/xml/xml.h>
57#include <wx/filename.h>
58#include <wx/log.h>
59#include <wx/wfstream.h>
60#include <wx/txtstrm.h>
61#include <wx/window.h>
62
64#include <font/fontconfig.h>
66#include <string_utils.h>
67#include <trigo.h>
68#include <progress_reporter.h>
69#include <project.h>
70#include <board.h>
72#include <footprint.h>
73#include <pad.h>
74#include <pcb_track.h>
75#include <pcb_shape.h>
76#include <zone.h>
77#include <padstack.h>
78#include <pcb_text.h>
79#include <pcb_dimension.h>
80#include <reporter.h>
81
82#include <pcb_io/pcb_io.h>
84
85using namespace std;
86
87
90static int parseEagle( const wxString& aDistance )
91{
92 ECOORD::EAGLE_UNIT unit = ( aDistance.npos != aDistance.find( "mil" ) )
95
96 ECOORD coord( aDistance, unit );
97
98 return coord.ToPcbUnits();
99}
100
101
102// In Eagle one can specify DRC rules where min value > max value,
103// in such case the max value has the priority
104template<typename T>
105static T eagleClamp( T aMin, T aValue, T aMax )
106{
107 T ret = std::max( aMin, aValue );
108 return std::min( aMax, ret );
109}
110
111
114static wxString makeKey( const wxString& aFirst, const wxString& aSecond )
115{
116 wxString key = aFirst + '\x02' + aSecond;
117 return key;
118}
119
120
121void PCB_IO_EAGLE::setKeepoutSettingsToZone( ZONE* aZone, int aLayer ) const
122{
123 if( aLayer == EAGLE_LAYER::TRESTRICT || aLayer == EAGLE_LAYER::BRESTRICT )
124 {
125 aZone->SetIsRuleArea( true );
126 aZone->SetDoNotAllowVias( true );
127 aZone->SetDoNotAllowTracks( true );
128 aZone->SetDoNotAllowZoneFills( true );
129 aZone->SetDoNotAllowPads( true );
130 aZone->SetDoNotAllowFootprints( false );
131
132 if( aLayer == EAGLE_LAYER::TRESTRICT ) // front layer keepout
133 aZone->SetLayer( F_Cu );
134 else // bottom layer keepout
135 aZone->SetLayer( B_Cu );
136 }
137 else if( aLayer == EAGLE_LAYER::VRESTRICT )
138 {
139 aZone->SetIsRuleArea( true );
140 aZone->SetDoNotAllowVias( true );
141 aZone->SetDoNotAllowTracks( false );
142 aZone->SetDoNotAllowZoneFills( false );
143 aZone->SetDoNotAllowPads( false );
144 aZone->SetDoNotAllowFootprints( false );
145
146 aZone->SetLayerSet( LSET::AllCuMask() );
147 }
148 else // copper pour cutout
149 {
150 aZone->SetIsRuleArea( true );
151 aZone->SetDoNotAllowVias( false );
152 aZone->SetDoNotAllowTracks( false );
153 aZone->SetDoNotAllowZoneFills( true );
154 aZone->SetDoNotAllowPads( false );
155 aZone->SetDoNotAllowFootprints( false );
156
157 aZone->SetLayerSet( { kicad_layer( aLayer ) } );
158 }
159}
160
161
162void ERULES::parse( wxXmlNode* aRules, std::function<void()> aCheckpoint )
163{
164 wxXmlNode* child = aRules->GetChildren();
165
166 while( child )
167 {
168 aCheckpoint();
169
170 if( child->GetName() == wxT( "param" ) )
171 {
172 const wxString& name = child->GetAttribute( wxT( "name" ) );
173 const wxString& value = child->GetAttribute( wxT( "value" ) );
174
175 if( name == wxT( "psElongationLong" ) )
176 psElongationLong = wxAtoi( value );
177 else if( name == wxT( "psElongationOffset" ) )
178 psElongationOffset = wxAtoi( value );
179 else if( name == wxT( "mvStopFrame" ) )
180 value.ToCDouble( &mvStopFrame );
181 else if( name == wxT( "mvCreamFrame" ) )
182 value.ToCDouble( &mvCreamFrame );
183 else if( name == wxT( "mlMinStopFrame" ) )
184 mlMinStopFrame = parseEagle( value );
185 else if( name == wxT( "mlMaxStopFrame" ) )
186 mlMaxStopFrame = parseEagle( value );
187 else if( name == wxT( "mlMinCreamFrame" ) )
188 mlMinCreamFrame = parseEagle( value );
189 else if( name == wxT( "mlMaxCreamFrame" ) )
190 mlMaxCreamFrame = parseEagle( value );
191 else if( name == wxT( "srRoundness" ) )
192 value.ToCDouble( &srRoundness );
193 else if( name == wxT( "srMinRoundness" ) )
194 srMinRoundness = parseEagle( value );
195 else if( name == wxT( "srMaxRoundness" ) )
196 srMaxRoundness = parseEagle( value );
197 else if( name == wxT( "psTop" ) )
198 psTop = wxAtoi( value );
199 else if( name == wxT( "psBottom" ) )
200 psBottom = wxAtoi( value );
201 else if( name == wxT( "psFirst" ) )
202 psFirst = wxAtoi( value );
203 else if( name == wxT( "rvPadTop" ) )
204 value.ToCDouble( &rvPadTop );
205 else if( name == wxT( "rlMinPadTop" ) )
206 rlMinPadTop = parseEagle( value );
207 else if( name == wxT( "rlMaxPadTop" ) )
208 rlMaxPadTop = parseEagle( value );
209 else if( name == wxT( "rvViaOuter" ) )
210 value.ToCDouble( &rvViaOuter );
211 else if( name == wxT( "rlMinViaOuter" ) )
212 rlMinViaOuter = parseEagle( value );
213 else if( name == wxT( "rlMaxViaOuter" ) )
214 rlMaxViaOuter = parseEagle( value );
215 else if( name == wxT( "mdWireWire" ) )
216 mdWireWire = parseEagle( value );
217 }
218
219 child = child->GetNext();
220 }
221}
222
223
225 PCB_IO( wxS( "Eagle" ) ),
226 m_rules( new ERULES() ),
227 m_xpath( new XPATH() ),
228 m_progressReporter( nullptr ),
229 m_doneCount( 0 ),
230 m_lastProgressCount( 0 ),
231 m_totalCount( 0 ),
232 m_timestamp( wxDateTime::Now().GetValue().GetValue() )
233{
234 using namespace std::placeholders;
235
236 init( nullptr );
237 clear_cu_map();
239}
240
241
243{
245 delete m_rules;
246 delete m_xpath;
247}
248
249
250bool PCB_IO_EAGLE::CanReadBoard( const wxString& aFileName ) const
251{
252 if( !PCB_IO::CanReadBoard( aFileName ) )
253 return false;
254
255 return checkHeader( aFileName );
256}
257
258
259bool PCB_IO_EAGLE::CanReadLibrary( const wxString& aFileName ) const
260{
261 if( !PCB_IO::CanReadLibrary( aFileName ) )
262 return false;
263
264 return checkHeader( aFileName );
265}
266
267
268bool PCB_IO_EAGLE::CanReadFootprint( const wxString& aFileName ) const
269{
270 return CanReadLibrary( aFileName );
271}
272
273
274bool PCB_IO_EAGLE::checkHeader(const wxString& aFileName) const
275{
276 wxFileInputStream input( aFileName );
277
278 if( !input.IsOk() )
279 return false;
280
281 wxTextInputStream text( input );
282
283 for( int i = 0; i < 8; i++ )
284 {
285 if( input.Eof() )
286 return false;
287
288 if( text.ReadLine().Contains( wxS( "<eagle" ) ) )
289 return true;
290 }
291
292 return false;
293}
294
295
297{
298 const unsigned PROGRESS_DELTA = 50;
299
301 {
302 if( ++m_doneCount > m_lastProgressCount + PROGRESS_DELTA )
303 {
304 m_progressReporter->SetCurrentProgress( ( (double) m_doneCount ) / std::max( 1U, m_totalCount ) );
305
307 THROW_IO_ERROR( _( "File import canceled by user." ) );
308
310 }
311 }
312}
313
314
315VECTOR2I inline PCB_IO_EAGLE::kicad_fontsize( const ECOORD& d, int aTextThickness ) const
316{
317 // Eagle includes stroke thickness in the text size, KiCAD does not
318 int kz = d.ToPcbUnits();
319 return VECTOR2I( kz - aTextThickness, kz - aTextThickness );
320}
321
322
323BOARD* PCB_IO_EAGLE::LoadBoard( const wxString& aFileName, BOARD* aAppendToMe,
324 const std::map<std::string, UTF8>* aProperties, PROJECT* aProject )
325{
326 wxXmlNode* doc;
327
329
330 init( aProperties );
331
332 m_board = aAppendToMe ? aAppendToMe : new BOARD();
333
334 // Give the filename to the board if it's new
335 if( !aAppendToMe )
336 m_board->SetFileName( aFileName );
337
338 // delete on exception, if I own m_board, according to aAppendToMe
339 unique_ptr<BOARD> deleter( aAppendToMe ? nullptr : m_board );
340
341 try
342 {
344 {
345 m_progressReporter->Report( wxString::Format( _( "Loading %s..." ), aFileName ) );
346
348 THROW_IO_ERROR( _( "File import canceled by user." ) );
349 }
350
351 wxFileName fn = aFileName;
352
353 // Load the document
354 wxFFileInputStream stream( fn.GetFullPath() );
355 wxXmlDocument xmlDocument;
356
357 if( !stream.IsOk() || !xmlDocument.Load( stream ) )
358 {
359 THROW_IO_ERROR( wxString::Format( _( "Unable to read file '%s'" ),
360 fn.GetFullPath() ) );
361 }
362
363 doc = xmlDocument.GetRoot();
364
365 m_min_trace = INT_MAX;
366 m_min_hole = INT_MAX;
367 m_min_via = INT_MAX;
368 m_min_annulus = INT_MAX;
369
370 loadAllSections( doc );
371
373
374 if( m_min_trace < bds.m_TrackMinWidth )
376
377 if( m_min_via < bds.m_ViasMinSize )
379
380 if( m_min_hole < bds.m_MinThroughDrill )
382
385
386 if( m_rules->mdWireWire )
388
389 NETCLASS defaults( wxT( "dummy" ) );
390
391 auto finishNetclass =
392 [&]( const std::shared_ptr<NETCLASS>& netclass )
393 {
394 // If Eagle has a clearance matrix then we'll build custom rules from that.
395 // Netclasses should just be the board minimum clearance.
396 netclass->SetClearance( KiROUND( bds.m_MinClearance ) );
397
398 if( netclass->GetTrackWidth() == INT_MAX )
399 netclass->SetTrackWidth( defaults.GetTrackWidth() );
400
401 if( netclass->GetViaDiameter() == INT_MAX )
402 netclass->SetViaDiameter( defaults.GetViaDiameter() );
403
404 if( netclass->GetViaDrill() == INT_MAX )
405 netclass->SetViaDrill( defaults.GetViaDrill() );
406 };
407
408 std::shared_ptr<NET_SETTINGS>& netSettings = bds.m_NetSettings;
409
410 finishNetclass( netSettings->GetDefaultNetclass() );
411
412 for( const auto& [name, netclass] : netSettings->GetNetclasses() )
413 finishNetclass( netclass );
414
417
418 fn.SetExt( wxT( "kicad_dru" ) );
419 wxFile rulesFile( fn.GetFullPath(), wxFile::write );
420 rulesFile.Write( m_customRules );
421
422 // should be empty, else missing m_xpath->pop()
423 wxASSERT( m_xpath->Contents().size() == 0 );
424 }
425 catch( const XML_PARSER_ERROR &exc )
426 {
427 wxString errmsg = exc.what();
428
429 errmsg += wxT( "\n@ " );
430 errmsg += m_xpath->Contents();
431
432 THROW_IO_ERROR( errmsg );
433 }
434
435 // IO_ERROR exceptions are left uncaught, they pass upwards from here.
436
438
439 LSET enabledLayers = m_board->GetDesignSettings().GetEnabledLayers();
440
441 for( const auto& [eagleLayerName, layer] : m_layer_map )
442 enabledLayers.set( layer );
443
444 m_board->GetDesignSettings().SetEnabledLayers( enabledLayers );
445
446 centerBoard();
447
448 deleter.release();
449 return m_board;
450}
451
452
454{
455 std::vector<FOOTPRINT*> retval;
456
457 for( const auto& [ name, footprint ] : m_templates )
458 retval.push_back( static_cast<FOOTPRINT*>( footprint->Clone() ) );
459
460 return retval;
461}
462
463
464void PCB_IO_EAGLE::init( const std::map<std::string, UTF8>* aProperties )
465{
466 m_hole_count = 0;
467 m_min_trace = 0;
468 m_min_hole = 0;
469 m_min_via = 0;
470 m_min_annulus = 0;
471 m_xpath->clear();
472 m_pads_to_nets.clear();
473
474 m_board = nullptr;
475 m_props = aProperties;
476
477
478 delete m_rules;
479 m_rules = new ERULES();
480}
481
482
484{
485 // All cu layers are invalid until we see them in the <layers> section while
486 // loading either a board or library. See loadLayerDefs().
487 for( unsigned i = 0; i < arrayDim(m_cu_map); ++i )
488 m_cu_map[i] = -1;
489}
490
491
492void PCB_IO_EAGLE::loadAllSections( wxXmlNode* aDoc )
493{
494 wxXmlNode* drawing = MapChildren( aDoc )["drawing"];
495 NODE_MAP drawingChildren = MapChildren( drawing );
496
497 wxXmlNode* board = drawingChildren["board"];
498 NODE_MAP boardChildren = MapChildren( board );
499
500 auto count_children =
501 [this]( wxXmlNode* aNode )
502 {
503 if( aNode )
504 {
505 wxXmlNode* child = aNode->GetChildren();
506
507 while( child )
508 {
509 m_totalCount++;
510 child = child->GetNext();
511 }
512 }
513 };
514
515 wxXmlNode* designrules = boardChildren["designrules"];
516 wxXmlNode* layers = drawingChildren["layers"];
517 wxXmlNode* plain = boardChildren["plain"];
518 wxXmlNode* classes = boardChildren["classes"];
519 wxXmlNode* signals = boardChildren["signals"];
520 wxXmlNode* libs = boardChildren["libraries"];
521 wxXmlNode* elems = boardChildren["elements"];
522
524 {
525 m_totalCount = 0;
526 m_doneCount = 0;
527
528 count_children( designrules );
529 count_children( layers );
530 count_children( plain );
531 count_children( signals );
532 count_children( elems );
533
534 while( libs )
535 {
536 count_children( MapChildren( libs )["packages"] );
537 libs = libs->GetNext();
538 }
539
540 // Rewind
541 libs = boardChildren["libraries"];
542 }
543
544 m_xpath->push( "eagle.drawing" );
545
546 {
547 m_xpath->push( "board" );
548
549 loadDesignRules( designrules );
550
551 m_xpath->pop();
552 }
553
554 {
555 m_xpath->push( "layers" );
556
557 loadLayerDefs( layers );
559
560 m_xpath->pop();
561 }
562
563 {
564 m_xpath->push( "board" );
565
566 loadPlain( plain );
567 loadClasses( classes );
568 loadSignals( signals );
569 loadLibraries( libs );
570 loadElements( elems );
571
572 m_xpath->pop();
573 }
574
575 m_xpath->pop(); // "eagle.drawing"
576}
577
578
579void PCB_IO_EAGLE::loadDesignRules( wxXmlNode* aDesignRules )
580{
581 if( aDesignRules )
582 {
583 m_xpath->push( "designrules" );
584 m_rules->parse( aDesignRules,
585 [this]()
586 {
587 checkpoint();
588 } );
589 m_xpath->pop(); // "designrules"
590 }
591}
592
593
594void PCB_IO_EAGLE::loadLayerDefs( wxXmlNode* aLayers )
595{
596 if( !aLayers )
597 return;
598
599 ELAYERS cu; // copper layers
600
601 // Get the first layer and iterate
602 wxXmlNode* layerNode = aLayers->GetChildren();
603
604 m_eagleLayers.clear();
605 m_eagleLayersIds.clear();
606
607 while( layerNode )
608 {
609 ELAYER elayer( layerNode );
610 m_eagleLayers.insert( std::make_pair( elayer.number, elayer ) );
611 m_eagleLayersIds.insert( std::make_pair( elayer.name, elayer.number ) );
612
613 // find the subset of layers that are copper and active
614 if( elayer.number >= 1 && elayer.number <= 16 && ( !elayer.active || *elayer.active ) )
615 cu.push_back( elayer );
616
617 layerNode = layerNode->GetNext();
618 }
619
620 // establish cu layer map:
621 int ki_layer_count = 0;
622
623 for( EITER it = cu.begin(); it != cu.end(); ++it, ++ki_layer_count )
624 {
625 if( ki_layer_count == 0 )
626 {
627 m_cu_map[it->number] = F_Cu;
628 }
629 else if( ki_layer_count == int( cu.size()-1 ) )
630 {
631 m_cu_map[it->number] = B_Cu;
632 }
633 else
634 {
635 // some eagle boards do not have contiguous layer number sequences.
636 m_cu_map[it->number] = BoardLayerFromLegacyId( ki_layer_count );
637 }
638 }
639
640 // Set the layer names and cu count if we're loading a board.
641 if( m_board )
642 {
643 m_board->SetCopperLayerCount( cu.size() );
644
645 for( EITER it = cu.begin(); it != cu.end(); ++it )
646 {
647 PCB_LAYER_ID layer = kicad_layer( it->number );
648
649 // these function provide their own protection against non enabled layers:
650 if( layer >= 0 && layer < PCB_LAYER_ID_COUNT ) // layer should be valid
651 {
652 m_board->SetLayerName( layer, it->name );
653 m_board->SetLayerType( layer, LT_SIGNAL );
654 }
655
656 // could map the colors here
657 }
658 }
659}
660
661
662#define DIMENSION_PRECISION DIM_PRECISION::X_XX // 0.01 mm
663
664
665void PCB_IO_EAGLE::loadPlain( wxXmlNode* aGraphics )
666{
667 if( !aGraphics )
668 return;
669
670 m_xpath->push( "plain" );
671
672 // Get the first graphic and iterate
673 wxXmlNode* gr = aGraphics->GetChildren();
674
675 // (polygon | wire | text | circle | rectangle | frame | hole)*
676 while( gr )
677 {
678 checkpoint();
679
680 wxString grName = gr->GetName();
681
682 if( grName == wxT( "wire" ) )
683 {
684 m_xpath->push( "wire" );
685
686 EWIRE w( gr );
687 PCB_LAYER_ID layer = kicad_layer( w.layer );
688
689 VECTOR2I start( kicad_x( w.x1 ), kicad_y( w.y1 ) );
690 VECTOR2I end( kicad_x( w.x2 ), kicad_y( w.y2 ) );
691
692 if( layer != UNDEFINED_LAYER )
693 {
694 PCB_SHAPE* shape = new PCB_SHAPE( m_board );
695 int width = w.width.ToPcbUnits();
696
697 // KiCad cannot handle zero or negative line widths
698 if( width <= 0 )
699 width = m_board->GetDesignSettings().GetLineThickness( layer );
700
701 m_board->Add( shape, ADD_MODE::APPEND );
702
703 if( !w.curve )
704 {
705 shape->SetShape( SHAPE_T::SEGMENT );
706 shape->SetStart( start );
707 shape->SetEnd( end );
708 }
709 else
710 {
711 VECTOR2I center = ConvertArcCenter( start, end, *w.curve );
712
713 shape->SetShape( SHAPE_T::ARC );
714 shape->SetCenter( center );
715 shape->SetStart( start );
716 shape->SetArcAngleAndEnd( -EDA_ANGLE( *w.curve, DEGREES_T ), true ); // KiCad rotates the other way
717 }
718
719 shape->SetLayer( layer );
720 shape->SetStroke( STROKE_PARAMS( width, LINE_STYLE::SOLID ) );
721 }
722
723 m_xpath->pop();
724 }
725 else if( grName == wxT( "text" ) )
726 {
727 m_xpath->push( "text" );
728
729 ETEXT t( gr );
730 PCB_LAYER_ID layer = kicad_layer( t.layer );
731
732 if( layer != UNDEFINED_LAYER )
733 {
734 PCB_TEXT* pcbtxt = new PCB_TEXT( m_board );
735 m_board->Add( pcbtxt, ADD_MODE::APPEND );
736
737 pcbtxt->SetLayer( layer );
738 wxString kicadText = interpretText( t.text );
739 pcbtxt->SetText( kicadText );
740
741 double ratio = t.ratio ? *t.ratio : 8; // DTD says 8 is default
742 int textThickness = KiROUND( t.size.ToPcbUnits() * ratio / 100.0 );
743 pcbtxt->SetTextThickness( textThickness );
744 pcbtxt->SetTextSize( kicad_fontsize( t.size, textThickness ) );
745 pcbtxt->SetKeepUpright( false );
746
747 // Eagle's anchor is independent of text justification; KiCad's is not.
748 VECTOR2I eagleAnchor( kicad_x( t.x ), kicad_y( t.y ) );
749 int align = t.align ? *t.align : ETEXT::BOTTOM_LEFT;
750 BOX2I textbox = pcbtxt->GetBoundingBox();
751 VECTOR2I offset( 0, 0 );
752 double degrees = 0;
753 int signX = 0;
754 int signY = 0;
755
756 if( t.rot )
757 {
758 degrees = t.rot->degrees;
759
760 if( t.rot->mirror && !t.rot->spin )
761 degrees *= -1;
762
763 if( t.rot->mirror )
764 pcbtxt->SetMirrored( t.rot->mirror );
765
766 if( degrees > 90 && degrees <= 270 )
767 {
768 if( degrees == 270 && t.rot->mirror )
769 degrees = 270; // an odd special-case
770 else
771 degrees -= 180;
772
773 signX = t.rot->mirror ? 1 : -1;
774 signY = 1;
775 }
776
777 pcbtxt->SetTextAngle( EDA_ANGLE( degrees, DEGREES_T ) );
778 }
779
780 switch( align )
781 {
785 offset.y = signY * (int) textbox.GetHeight();
786 break;
787
789 case ETEXT::TOP_LEFT:
790 case ETEXT::TOP_RIGHT:
791 offset.y = -signY * (int) textbox.GetHeight();
792 break;
793
794 default:
795 break;
796 }
797
798 switch( align )
799 {
800 case ETEXT::TOP_LEFT:
803 offset.x = signX * (int) textbox.GetWidth();
804 break;
805
806 case ETEXT::TOP_RIGHT:
809 offset.x = -signX * (int) textbox.GetWidth();
810 break;
811
812 default:
813 break;
814 }
815
816 RotatePoint( offset, EDA_ANGLE( degrees, DEGREES_T ) );
817 pcbtxt->SetTextPos( eagleAnchor + offset );
818
819 switch( align )
820 {
821 case ETEXT::CENTER:
824 break;
825
829 break;
830
834 break;
835
839 break;
840
841 case ETEXT::TOP_LEFT:
844 break;
845
846 case ETEXT::TOP_RIGHT:
849 break;
850
854 break;
855
859 break;
860
864 break;
865 }
866
867 // Refine justification and rotation for mirrored texts
868 if( pcbtxt->IsMirrored() && degrees < -90 && degrees >= -270 )
869 {
870 pcbtxt->SetTextAngle( EDA_ANGLE( 180+degrees, DEGREES_T ) );
871
872 if( pcbtxt->GetHorizJustify() == GR_TEXT_H_ALIGN_LEFT )
874 else if( pcbtxt->GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
876
877 if( pcbtxt->GetVertJustify() == GR_TEXT_V_ALIGN_BOTTOM )
879 else if( pcbtxt->GetVertJustify() == GR_TEXT_V_ALIGN_TOP )
881 }
882 }
883
884 m_xpath->pop();
885 }
886 else if( grName == wxT( "circle" ) )
887 {
888 m_xpath->push( "circle" );
889
890 ECIRCLE c( gr );
891
892 int width = c.width.ToPcbUnits();
893 int radius = c.radius.ToPcbUnits();
894
897 {
898 ZONE* zone = new ZONE( m_board );
899 m_board->Add( zone, ADD_MODE::APPEND );
900
902
903 // approximate circle as polygon
904 VECTOR2I center( kicad_x( c.x ), kicad_y( c.y ) );
905 int outlineRadius = radius + ( width / 2 );
906 int segsInCircle = GetArcToSegmentCount( outlineRadius, ARC_HIGH_DEF, FULL_CIRCLE );
907 EDA_ANGLE delta = ANGLE_360 / segsInCircle;
908
909 for( EDA_ANGLE angle = ANGLE_0; angle < ANGLE_360; angle += delta )
910 {
911 VECTOR2I rotatedPoint( outlineRadius, 0 );
912 RotatePoint( rotatedPoint, angle );
913 zone->AppendCorner( center + rotatedPoint, -1 );
914 }
915
916 if( width > 0 )
917 {
918 zone->NewHole();
919 int innerRadius = radius - ( width / 2 );
920 segsInCircle = GetArcToSegmentCount( innerRadius, ARC_HIGH_DEF, FULL_CIRCLE );
921 delta = ANGLE_360 / segsInCircle;
922
923 for( EDA_ANGLE angle = ANGLE_0; angle < ANGLE_360; angle += delta )
924 {
925 VECTOR2I rotatedPoint( innerRadius, 0 );
926 RotatePoint( rotatedPoint, angle );
927 zone->AppendCorner( center + rotatedPoint, 0 );
928 }
929 }
930
931 zone->SetBorderDisplayStyle( ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE,
933 }
934 else
935 {
936 PCB_LAYER_ID layer = kicad_layer( c.layer );
937
938 if( layer != UNDEFINED_LAYER ) // unsupported layer
939 {
940 PCB_SHAPE* shape = new PCB_SHAPE( m_board, SHAPE_T::CIRCLE );
941 m_board->Add( shape, ADD_MODE::APPEND );
942 shape->SetFilled( false );
943 shape->SetLayer( layer );
944 shape->SetStart( VECTOR2I( kicad_x( c.x ), kicad_y( c.y ) ) );
945 shape->SetEnd( VECTOR2I( kicad_x( c.x ) + radius, kicad_y( c.y ) ) );
946 shape->SetStroke( STROKE_PARAMS( width, LINE_STYLE::SOLID ) );
947 }
948 }
949
950 m_xpath->pop();
951 }
952 else if( grName == wxT( "rectangle" ) )
953 {
954 // This seems to be a simplified rectangular [copper] zone, cannot find any
955 // net related info on it from the DTD.
956 m_xpath->push( "rectangle" );
957
958 ERECT r( gr );
959 PCB_LAYER_ID layer = kicad_layer( r.layer );
960
961 if( layer != UNDEFINED_LAYER )
962 {
963 ZONE* zone = new ZONE( m_board );
964
965 m_board->Add( zone, ADD_MODE::APPEND );
966
967 zone->SetLayer( layer );
969
970 ZONE_BORDER_DISPLAY_STYLE outline_hatch = ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE;
971
972 const int outlineIdx = -1; // this is the id of the copper zone main outline
973 zone->AppendCorner( VECTOR2I( kicad_x( r.x1 ), kicad_y( r.y1 ) ), outlineIdx );
974 zone->AppendCorner( VECTOR2I( kicad_x( r.x2 ), kicad_y( r.y1 ) ), outlineIdx );
975 zone->AppendCorner( VECTOR2I( kicad_x( r.x2 ), kicad_y( r.y2 ) ), outlineIdx );
976 zone->AppendCorner( VECTOR2I( kicad_x( r.x1 ), kicad_y( r.y2 ) ), outlineIdx );
977
978 if( r.rot )
979 {
980 VECTOR2I center( ( kicad_x( r.x1 ) + kicad_x( r.x2 ) ) / 2,
981 ( kicad_y( r.y1 ) + kicad_y( r.y2 ) ) / 2 );
982 zone->Rotate( center, EDA_ANGLE( r.rot->degrees, DEGREES_T ) );
983 }
984
985 // this is not my fault:
986 zone->SetBorderDisplayStyle( outline_hatch, ZONE::GetDefaultHatchPitch(), true );
987 }
988
989 m_xpath->pop();
990 }
991 else if( grName == wxT( "hole" ) )
992 {
993 m_xpath->push( "hole" );
994
995 // Fabricate a FOOTPRINT with a single PAD_ATTRIB::NPTH pad.
996 // Use m_hole_count to gen up a unique reference designator.
997
998 FOOTPRINT* footprint = new FOOTPRINT( m_board );
999 m_board->Add( footprint, ADD_MODE::APPEND );
1000 int hole_count = m_hole_count++;
1001 footprint->SetReference( wxString::Format( wxT( "UNK_HOLE_%d" ), hole_count ) );
1002 footprint->Reference().SetVisible( false );
1003 // Mandatory: gives a dummy but valid LIB_ID
1004 LIB_ID fpid( wxEmptyString, wxString::Format( wxT( "dummyfp%d" ), hole_count ) );
1005 footprint->SetFPID( fpid );
1006
1007 packageHole( footprint, gr, true );
1008
1009 m_xpath->pop();
1010 }
1011 else if( grName == wxT( "frame" ) )
1012 {
1013 // picture this
1014 }
1015 else if( grName == wxT( "polygon" ) )
1016 {
1017 m_xpath->push( "polygon" );
1018 loadPolygon( gr );
1019 m_xpath->pop(); // "polygon"
1020 }
1021 else if( grName == wxT( "dimension" ) )
1022 {
1023 const BOARD_DESIGN_SETTINGS& designSettings = m_board->GetDesignSettings();
1024
1025 EDIMENSION d( gr );
1026 PCB_LAYER_ID layer = kicad_layer( d.layer );
1027 VECTOR2I pt1( kicad_x( d.x1 ), kicad_y( d.y1 ) );
1028 VECTOR2I pt2( kicad_x( d.x2 ), kicad_y( d.y2 ) );
1029 VECTOR2I pt3( kicad_x( d.x3 ), kicad_y( d.y3 ) );
1030 VECTOR2I textSize = designSettings.GetTextSize( layer );
1031 int textThickness = designSettings.GetLineThickness( layer );
1032
1033 if( d.textsize )
1034 {
1035 double ratio = 8; // DTD says 8 is default
1036 textThickness = KiROUND( d.textsize->ToPcbUnits() * ratio / 100.0 );
1037 textSize = kicad_fontsize( *d.textsize, textThickness );
1038 }
1039
1040 if( layer != UNDEFINED_LAYER )
1041 {
1042 if( d.dimensionType == wxT( "angle" ) )
1043 {
1044 // Kicad doesn't (at present) support angle dimensions
1045 }
1046 else if( d.dimensionType == wxT( "radius" ) )
1047 {
1048 PCB_DIM_RADIAL* dimension = new PCB_DIM_RADIAL( m_board );
1049 m_board->Add( dimension, ADD_MODE::APPEND );
1050
1051 dimension->SetLayer( layer );
1052 dimension->SetPrecision( DIMENSION_PRECISION );
1053
1054 dimension->SetStart( pt1 );
1055 dimension->SetEnd( pt2 );
1056 dimension->SetTextPos( pt3 );
1057 dimension->SetTextSize( textSize );
1058 dimension->SetTextThickness( textThickness );
1059 dimension->SetLineThickness( designSettings.GetLineThickness( layer ) );
1060 dimension->SetUnits( EDA_UNITS::MM );
1061 }
1062 else if( d.dimensionType == wxT( "leader" ) )
1063 {
1064 PCB_DIM_LEADER* leader = new PCB_DIM_LEADER( m_board );
1065 m_board->Add( leader, ADD_MODE::APPEND );
1066
1067 leader->SetLayer( layer );
1069
1070 leader->SetStart( pt1 );
1071 leader->SetEnd( pt2 );
1072 leader->SetTextPos( pt3 );
1073 leader->SetTextSize( textSize );
1074 leader->SetTextThickness( textThickness );
1075 leader->SetOverrideText( wxEmptyString );
1076 leader->SetLineThickness( designSettings.GetLineThickness( layer ) );
1077 }
1078 else // horizontal, vertical, <default>, diameter
1079 {
1081 m_board->Add( dimension, ADD_MODE::APPEND );
1082
1083 if( d.dimensionType )
1084 {
1085 // Eagle dimension graphic arms may have different lengths, but they look
1086 // incorrect in KiCad (the graphic is tilted). Make them even length in
1087 // such case.
1088 if( *d.dimensionType == wxT( "horizontal" ) )
1089 {
1090 int newY = ( pt1.y + pt2.y ) / 2;
1091 pt1.y = newY;
1092 pt2.y = newY;
1093 }
1094 else if( *d.dimensionType == wxT( "vertical" ) )
1095 {
1096 int newX = ( pt1.x + pt2.x ) / 2;
1097 pt1.x = newX;
1098 pt2.x = newX;
1099 }
1100 }
1101
1102 dimension->SetLayer( layer );
1103 dimension->SetPrecision( DIMENSION_PRECISION );
1104
1105 // The origin and end are assumed to always be in this order from eagle
1106 dimension->SetStart( pt1 );
1107 dimension->SetEnd( pt2 );
1108 dimension->SetTextSize( textSize );
1109 dimension->SetTextThickness( textThickness );
1110 dimension->SetLineThickness( designSettings.GetLineThickness( layer ) );
1111 dimension->SetUnits( EDA_UNITS::MM );
1112
1113 // check which axis the dimension runs in
1114 // because the "height" of the dimension is perpendicular to that axis
1115 // Note the check is just if two axes are close enough to each other
1116 // Eagle appears to have some rounding errors
1117 if( abs( pt1.x - pt2.x ) < 50000 ) // 50000 nm = 0.05 mm
1118 {
1119 int offset = pt3.x - pt1.x;
1120
1121 if( pt1.y > pt2.y )
1122 dimension->SetHeight( offset );
1123 else
1124 dimension->SetHeight( -offset );
1125 }
1126 else if( abs( pt1.y - pt2.y ) < 50000 )
1127 {
1128 int offset = pt3.y - pt1.y;
1129
1130 if( pt1.x > pt2.x )
1131 dimension->SetHeight( -offset );
1132 else
1133 dimension->SetHeight( offset );
1134 }
1135 else
1136 {
1137 int offset = KiROUND( pt3.Distance( pt1 ) );
1138
1139 if( pt1.y > pt2.y )
1140 dimension->SetHeight( offset );
1141 else
1142 dimension->SetHeight( -offset );
1143 }
1144 }
1145 }
1146 }
1147
1148 // Get next graphic
1149 gr = gr->GetNext();
1150 }
1151
1152 m_xpath->pop();
1153}
1154
1155
1156void PCB_IO_EAGLE::loadLibrary( wxXmlNode* aLib, const wxString* aLibName )
1157{
1158 if( !aLib )
1159 return;
1160
1161 wxString urn = aLib->GetAttribute( "urn" );
1162
1163 wxString urnOrdinal;
1164
1165 if( !urn.IsEmpty() )
1166 urnOrdinal = urn.AfterLast( ':' );
1167
1168 // library will have <xmlattr> node, skip that and get the single packages node
1169 wxXmlNode* packages = MapChildren( aLib )["packages"];
1170
1171 if( !packages )
1172 return;
1173
1174 m_xpath->push( "packages" );
1175
1176 // Create a FOOTPRINT for all the eagle packages, for use later via a copy constructor
1177 // to instantiate needed footprints in our BOARD. Save the FOOTPRINT templates in
1178 // a FOOTPRINT_MAP using a single lookup key consisting of libname+pkgname.
1179
1180 // Get the first package and iterate
1181 wxXmlNode* package = packages->GetChildren();
1182
1183 while( package )
1184 {
1185 checkpoint();
1186
1187 m_xpath->push( "package", "name" );
1188
1189 wxString pack_ref = package->GetAttribute( "name" );
1190
1191 if( !urnOrdinal.IsEmpty() )
1192 pack_ref += wxS( "_" ) + urnOrdinal;
1193
1194 ReplaceIllegalFileNameChars( pack_ref, '_' );
1195
1196 m_xpath->Value( pack_ref.ToUTF8() );
1197
1198 wxString key = aLibName ? makeKey( *aLibName, pack_ref ) : pack_ref;
1199
1200 FOOTPRINT* footprint = makeFootprint( package, pack_ref );
1201
1202 // add the templating FOOTPRINT to the FOOTPRINT template factory "m_templates"
1203 auto r = m_templates.insert( { key, footprint } );
1204
1205 if( !r.second /* && !( m_props && m_props->Value( "ignore_duplicates" ) ) */ )
1206 {
1207 wxString lib = aLibName ? *aLibName : m_lib_path;
1208 const wxString& pkg = pack_ref;
1209
1210 wxString emsg = wxString::Format( _( "<package> '%s' duplicated in <library> '%s'" ),
1211 pkg,
1212 lib );
1213 THROW_IO_ERROR( emsg );
1214 }
1215
1216 m_xpath->pop();
1217
1218 package = package->GetNext();
1219 }
1220
1221 m_xpath->pop(); // "packages"
1222}
1223
1224
1225void PCB_IO_EAGLE::loadLibraries( wxXmlNode* aLibs )
1226{
1227 if( !aLibs )
1228 return;
1229
1230 m_xpath->push( "libraries.library", "name" );
1231
1232 // Get the first library and iterate
1233 wxXmlNode* library = aLibs->GetChildren();
1234
1235 while( library )
1236 {
1237 const wxString& lib_name = library->GetAttribute( "name" );
1238
1239 m_xpath->Value( lib_name.c_str() );
1240 loadLibrary( library, &lib_name );
1241 library = library->GetNext();
1242 }
1243
1244 m_xpath->pop();
1245}
1246
1247
1248void PCB_IO_EAGLE::loadElements( wxXmlNode* aElements )
1249{
1250 if( !aElements )
1251 return;
1252
1253 m_xpath->push( "elements.element", "name" );
1254
1255 EATTR name;
1256 EATTR value;
1257 bool refanceNamePresetInPackageLayout;
1258 bool valueNamePresetInPackageLayout;
1259
1260 // Get the first element and iterate
1261 wxXmlNode* element = aElements->GetChildren();
1262
1263 while( element )
1264 {
1265 checkpoint();
1266
1267 if( element->GetName() != wxT( "element" ) )
1268 {
1269 // Get next item
1270 element = element->GetNext();
1271 continue;
1272 }
1273
1274 EELEMENT e( element );
1275
1276 // use "NULL-ness" as an indication of presence of the attribute:
1277 EATTR* nameAttr = nullptr;
1278 EATTR* valueAttr = nullptr;
1279
1280 m_xpath->Value( e.name.c_str() );
1281
1282 wxString packageName = e.package;
1283
1284 if( e.library_urn )
1285 packageName = e.package + wxS( "_" ) + e.library_urn->assetId;
1286
1287 wxString pkg_key = makeKey( e.library, packageName );
1288 auto it = m_templates.find( pkg_key );
1289
1290 if( it == m_templates.end() )
1291 {
1292 wxString emsg = wxString::Format( _( "No '%s' package in library '%s'." ),
1293 packageName, e.library );
1294 THROW_IO_ERROR( emsg );
1295 }
1296
1297 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( it->second->Duplicate( IGNORE_PARENT_GROUP ) );
1298
1299 m_board->Add( footprint, ADD_MODE::APPEND );
1300
1301 // update the nets within the pads of the clone
1302 for( PAD* pad : footprint->Pads() )
1303 {
1304 wxString pn_key = makeKey( e.name, pad->GetNumber() );
1305
1306 NET_MAP_CITER ni = m_pads_to_nets.find( pn_key );
1307 if( ni != m_pads_to_nets.end() )
1308 {
1309 const ENET* enet = &ni->second;
1310 pad->SetNetCode( enet->netcode );
1311 }
1312 }
1313
1314 refanceNamePresetInPackageLayout = true;
1315 valueNamePresetInPackageLayout = true;
1316 footprint->SetPosition( VECTOR2I( kicad_x( e.x ), kicad_y( e.y ) ) );
1317
1318 // Is >NAME field set in package layout ?
1319 if( footprint->GetReference().size() == 0 )
1320 {
1321 footprint->Reference().SetVisible( false ); // No so no show
1322 refanceNamePresetInPackageLayout = false;
1323 }
1324
1325 // Is >VALUE field set in package layout
1326 if( footprint->GetValue().size() == 0 )
1327 {
1328 footprint->Value().SetVisible( false ); // No so no show
1329 valueNamePresetInPackageLayout = false;
1330 }
1331
1332 wxString reference = e.name;
1333
1334 // EAGLE allows references to be single digits. This breaks KiCad
1335 // netlisting, which requires parts to have non-digit + digit
1336 // annotation. If the reference begins with a number, we prepend
1337 // 'UNK' (unknown) for the symbol designator.
1338 if( reference.find_first_not_of( "0123456789" ) != 0 )
1339 reference.Prepend( "UNK" );
1340
1341 // EAGLE allows designator to start with # but that is used in KiCad
1342 // for symbols which do not have a footprint
1343 if( reference.find_first_not_of( "#" ) != 0 )
1344 reference.Prepend( "UNK" );
1345
1346 // reference must end with a number but EAGLE does not enforce this
1347 if( reference.find_last_not_of( "0123456789" ) == (reference.Length()-1) )
1348 reference.Append( "0" );
1349
1350 footprint->SetReference( reference );
1351 footprint->SetValue( e.value );
1352
1353 if( !e.smashed )
1354 {
1355 // Not smashed so show NAME & VALUE
1356 if( valueNamePresetInPackageLayout )
1357 footprint->Value().SetVisible( true ); // Only if place holder in package layout
1358
1359 if( refanceNamePresetInPackageLayout )
1360 footprint->Reference().SetVisible( true ); // Only if place holder in package layout
1361 }
1362 else if( *e.smashed == true )
1363 {
1364 // Smashed so set default to no show for NAME and VALUE
1365 footprint->Value().SetVisible( false );
1366 footprint->Reference().SetVisible( false );
1367
1368 // initialize these to default values in case the <attribute> elements are not present.
1369 m_xpath->push( "attribute", "name" );
1370
1371 // VALUE and NAME can have something like our text "effects" overrides
1372 // in SWEET and new schematic. Eagle calls these XML elements "attribute".
1373 // There can be one for NAME and/or VALUE both. Features present in the
1374 // EATTR override the ones established in the package only if they are
1375 // present here (except for rot, which if not present means angle zero).
1376 // So the logic is a bit different than in packageText() and in plain text.
1377
1378 // Get the first attribute and iterate
1379 wxXmlNode* attribute = element->GetChildren();
1380
1381 while( attribute )
1382 {
1383 if( attribute->GetName() != wxT( "attribute" ) )
1384 {
1385 attribute = attribute->GetNext();
1386 continue;
1387 }
1388
1389 EATTR a( attribute );
1390
1391 if( a.name == wxT( "NAME" ) )
1392 {
1393 name = a;
1394 nameAttr = &name;
1395
1396 // do we have a display attribute ?
1397 if( a.display )
1398 {
1399 // Yes!
1400 switch( *a.display )
1401 {
1402 case EATTR::VALUE :
1403 {
1404 nameAttr->name = reference;
1405
1406 if( refanceNamePresetInPackageLayout )
1407 footprint->Reference().SetVisible( true );
1408
1409 break;
1410 }
1411
1412 case EATTR::NAME :
1413 if( refanceNamePresetInPackageLayout )
1414 {
1415 footprint->SetReference( "NAME" );
1416 footprint->Reference().SetVisible( true );
1417 }
1418
1419 break;
1420
1421 case EATTR::BOTH :
1422 if( refanceNamePresetInPackageLayout )
1423 footprint->Reference().SetVisible( true );
1424
1425 nameAttr->name = nameAttr->name + wxT( " = " ) + e.name;
1426 footprint->SetReference( wxT( "NAME = " ) + e.name );
1427 break;
1428
1429 case EATTR::Off :
1430 footprint->Reference().SetVisible( false );
1431 break;
1432
1433 default:
1434 nameAttr->name = e.name;
1435
1436 if( refanceNamePresetInPackageLayout )
1437 footprint->Reference().SetVisible( true );
1438 }
1439 }
1440 else
1441 {
1442 // No display, so default is visible, and show value of NAME
1443 footprint->Reference().SetVisible( true );
1444 }
1445 }
1446 else if( a.name == wxT( "VALUE" ) )
1447 {
1448 value = a;
1449 valueAttr = &value;
1450
1451 if( a.display )
1452 {
1453 // Yes!
1454 switch( *a.display )
1455 {
1456 case EATTR::VALUE :
1457 valueAttr->value = opt_wxString( e.value );
1458 footprint->SetValue( e.value );
1459
1460 if( valueNamePresetInPackageLayout )
1461 footprint->Value().SetVisible( true );
1462
1463 break;
1464
1465 case EATTR::NAME :
1466 if( valueNamePresetInPackageLayout )
1467 footprint->Value().SetVisible( true );
1468
1469 footprint->SetValue( wxT( "VALUE" ) );
1470 break;
1471
1472 case EATTR::BOTH :
1473 if( valueNamePresetInPackageLayout )
1474 footprint->Value().SetVisible( true );
1475
1476 valueAttr->value = opt_wxString( wxT( "VALUE = " ) + e.value );
1477 footprint->SetValue( wxT( "VALUE = " ) + e.value );
1478 break;
1479
1480 case EATTR::Off :
1481 footprint->Value().SetVisible( false );
1482 break;
1483
1484 default:
1485 valueAttr->value = opt_wxString( e.value );
1486
1487 if( valueNamePresetInPackageLayout )
1488 footprint->Value().SetVisible( true );
1489 }
1490 }
1491 else
1492 {
1493 // No display, so default is visible, and show value of NAME
1494 footprint->Value().SetVisible( true );
1495 }
1496
1497 }
1498
1499 attribute = attribute->GetNext();
1500 }
1501
1502 m_xpath->pop(); // "attribute"
1503 }
1504
1505 orientFootprintAndText( footprint, e, nameAttr, valueAttr );
1506
1507 // Get next element
1508 element = element->GetNext();
1509 }
1510
1511 m_xpath->pop(); // "elements.element"
1512}
1513
1514
1515ZONE* PCB_IO_EAGLE::loadPolygon( wxXmlNode* aPolyNode )
1516{
1517 EPOLYGON p( aPolyNode );
1518 PCB_LAYER_ID layer = kicad_layer( p.layer );
1519 bool keepout = ( p.layer == EAGLE_LAYER::TRESTRICT
1521 || p.layer == EAGLE_LAYER::VRESTRICT );
1522
1523 if( layer == UNDEFINED_LAYER )
1524 {
1525 wxLogMessage( wxString::Format( _( "Ignoring a polygon since Eagle layer '%s' (%d) was not mapped" ),
1526 eagle_layer_name( p.layer ),
1527 p.layer ) );
1528 return nullptr;
1529 }
1530
1531 // use a "netcode = 0" type ZONE:
1532 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( m_board );
1533
1534 if( !keepout )
1535 zone->SetLayer( layer );
1536 else
1537 setKeepoutSettingsToZone( zone.get(), p.layer );
1538
1539 // Get the first vertex and iterate
1540 wxXmlNode* vertex = aPolyNode->GetChildren();
1541 std::vector<EVERTEX> vertices;
1542
1543 // Create a circular vector of vertices
1544 // The "curve" parameter indicates a curve from the current
1545 // to the next vertex, so we keep the first at the end as well
1546 // to allow the curve to link back
1547 while( vertex )
1548 {
1549 if( vertex->GetName() == wxT( "vertex" ) )
1550 vertices.emplace_back( vertex );
1551
1552 vertex = vertex->GetNext();
1553 }
1554
1555 // According to Eagle's doc, by default, the orphans (islands in KiCad parlance)
1556 // are always removed
1557 if( !p.orphans || !p.orphans.Get() )
1558 zone->SetIslandRemovalMode( ISLAND_REMOVAL_MODE::ALWAYS );
1559 else
1560 zone->SetIslandRemovalMode( ISLAND_REMOVAL_MODE::NEVER );
1561
1562 vertices.push_back( vertices[0] );
1563
1564 SHAPE_POLY_SET polygon;
1565 polygon.NewOutline();
1566
1567 for( size_t i = 0; i < vertices.size() - 1; i++ )
1568 {
1569 EVERTEX v1 = vertices[i];
1570
1571 // Append the corner
1572 polygon.Append( kicad_x( v1.x ), kicad_y( v1.y ) );
1573
1574 if( v1.curve )
1575 {
1576 EVERTEX v2 = vertices[i + 1];
1577 VECTOR2I center = ConvertArcCenter( VECTOR2I( kicad_x( v1.x ), kicad_y( v1.y ) ),
1578 VECTOR2I( kicad_x( v2.x ), kicad_y( v2.y ) ), *v1.curve );
1579 double angle = DEG2RAD( *v1.curve );
1580 double end_angle = atan2( kicad_y( v2.y ) - center.y, kicad_x( v2.x ) - center.x );
1581 double radius = sqrt( pow( center.x - kicad_x( v1.x ), 2 ) + pow( center.y - kicad_y( v1.y ), 2 ) );
1582
1583 int segCount = GetArcToSegmentCount( KiROUND( radius ), ARC_HIGH_DEF,
1584 EDA_ANGLE( *v1.curve, DEGREES_T ) );
1585 double delta_angle = angle / segCount;
1586
1587 for( double a = end_angle + angle; fabs( a - end_angle ) > fabs( delta_angle ); a -= delta_angle )
1588 {
1589 polygon.Append( KiROUND( radius * cos( a ) ) + center.x,
1590 KiROUND( radius * sin( a ) ) + center.y );
1591 }
1592 }
1593 }
1594
1595 // Eagle traces the zone such that half of the pen width is outside the polygon.
1596 // We trace the zone such that the copper is completely inside.
1597 if( p.width.ToPcbUnits() > 0 )
1598 polygon.Inflate( p.width.ToPcbUnits() / 2, CORNER_STRATEGY::ALLOW_ACUTE_CORNERS, ARC_HIGH_DEF, true );
1599
1600 if( polygon.OutlineCount() != 1 )
1601 {
1602 wxLogMessage( wxString::Format( _( "Skipping a polygon on layer '%s' (%d): outline count is not 1" ),
1603 eagle_layer_name( p.layer ),
1604 p.layer ) );
1605
1606 return nullptr;
1607 }
1608
1609 zone->AddPolygon( polygon.COutline( 0 ) );
1610
1611 // If the pour is a cutout it needs to be set to a keepout
1612 if( p.pour == EPOLYGON::ECUTOUT )
1613 {
1614 zone->SetIsRuleArea( true );
1615 zone->SetDoNotAllowVias( false );
1616 zone->SetDoNotAllowTracks( false );
1617 zone->SetDoNotAllowPads( false );
1618 zone->SetDoNotAllowFootprints( false );
1619 zone->SetDoNotAllowZoneFills( true );
1620 zone->SetHatchStyle( ZONE_BORDER_DISPLAY_STYLE::NO_HATCH );
1621 }
1622 else if( p.pour == EPOLYGON::EHATCH )
1623 {
1624 int spacing = p.spacing ? p.spacing->ToPcbUnits() : 50 * pcbIUScale.IU_PER_MILS;
1625
1626 zone->SetFillMode( ZONE_FILL_MODE::HATCH_PATTERN );
1627 zone->SetHatchThickness( p.width.ToPcbUnits() );
1628 zone->SetHatchGap( spacing - p.width.ToPcbUnits() );
1629 zone->SetHatchOrientation( ANGLE_0 );
1630 }
1631
1632 // We divide the thickness by half because we are tracing _inside_ the zone outline
1633 // This means the radius of curvature will be twice the size for an equivalent EAGLE zone
1634 zone->SetMinThickness( std::max<int>( ZONE_THICKNESS_MIN_VALUE_MM * pcbIUScale.IU_PER_MM,
1635 p.width.ToPcbUnits() / 2 ) );
1636
1637 if( p.isolate )
1638 zone->SetLocalClearance( p.isolate->ToPcbUnits() );
1639 else
1640 zone->SetLocalClearance( 1 ); // @todo: set minimum clearance value based on board settings
1641
1642 // missing == yes per DTD.
1643 bool thermals = !p.thermals || *p.thermals;
1644 zone->SetPadConnection( thermals ? ZONE_CONNECTION::THERMAL : ZONE_CONNECTION::FULL );
1645
1646 if( thermals )
1647 {
1648 // FIXME: eagle calculates dimensions for thermal spokes
1649 // based on what the zone is connecting to.
1650 // (i.e. width of spoke is half of the smaller side of an smd pad)
1651 // This is a basic workaround
1652 zone->SetThermalReliefGap( p.width.ToPcbUnits() + 50000 ); // 50000nm == 0.05mm
1653 zone->SetThermalReliefSpokeWidth( p.width.ToPcbUnits() + 50000 );
1654 }
1655
1656 int rank = p.rank ? (p.max_priority - *p.rank) : p.max_priority;
1657 zone->SetAssignedPriority( rank );
1658
1659 ZONE* zonePtr = zone.release();
1660 m_board->Add( zonePtr, ADD_MODE::APPEND );
1661
1662 return zonePtr;
1663}
1664
1665
1667 const EATTR* aNameAttr, const EATTR* aValueAttr )
1668{
1669 if( e.rot )
1670 {
1671 if( e.rot->mirror )
1672 {
1673 aFootprint->SetOrientation( EDA_ANGLE( e.rot->degrees + 180.0, DEGREES_T ) );
1674 aFootprint->Flip( aFootprint->GetPosition(), FLIP_DIRECTION::TOP_BOTTOM );
1675 }
1676 else
1677 {
1678 aFootprint->SetOrientation( EDA_ANGLE( e.rot->degrees, DEGREES_T ) );
1679 }
1680 }
1681
1682 orientFPText( aFootprint, e, &aFootprint->Reference(), aNameAttr );
1683 orientFPText( aFootprint, e, &aFootprint->Value(), aValueAttr );
1684}
1685
1686
1687void PCB_IO_EAGLE::orientFPText( FOOTPRINT* aFootprint, const EELEMENT& e, PCB_TEXT* aFPText,
1688 const EATTR* aAttr )
1689{
1690 // Smashed part ?
1691 if( aAttr )
1692 {
1693 // Yes
1694 const EATTR& a = *aAttr;
1695
1696 if( a.value )
1697 aFPText->SetText( *a.value );
1698
1699 if( a.x && a.y ) // std::optional
1700 {
1701 VECTOR2I pos( kicad_x( *a.x ), kicad_y( *a.y ) );
1702 aFPText->SetTextPos( pos );
1703 }
1704
1705 // Even though size and ratio are both optional, I am not seeing
1706 // a case where ratio is present but size is not.
1707 double ratio = 8;
1708
1709 if( a.ratio )
1710 ratio = *a.ratio;
1711
1712 VECTOR2I fontz = aFPText->GetTextSize();
1713 int textThickness = KiROUND( fontz.y * ratio / 100.0 );
1714
1715 aFPText->SetTextThickness( textThickness );
1716
1717 if( a.size )
1718 {
1719 fontz = kicad_fontsize( *a.size, textThickness );
1720 aFPText->SetTextSize( fontz );
1721 }
1722
1723 int align = ETEXT::BOTTOM_LEFT; // bottom-left is eagle default
1724
1725 if( a.align )
1726 align = *a.align;
1727
1728 // The "rot" in a EATTR seems to be assumed to be zero if it is not
1729 // present, and this zero rotation becomes an override to the
1730 // package's text field. If they did not want zero, they specify
1731 // what they want explicitly.
1732 double degrees = a.rot ? a.rot->degrees : 0.0;
1733 int sign = 1;
1734 bool spin = false;
1735
1736 if( a.rot )
1737 {
1738 spin = a.rot->spin;
1739 sign = a.rot->mirror ? -1 : 1;
1740 aFPText->SetMirrored( a.rot->mirror );
1741 }
1742
1743 if( degrees == 90 || degrees == 0 || spin )
1744 {
1745 degrees *= sign;
1746 }
1747 else if( degrees == 180 )
1748 {
1749 degrees = 0;
1750 align = -align;
1751 }
1752 else if( degrees == 270 )
1753 {
1754 align = -align;
1755 degrees = sign * 90;
1756 }
1757 else
1758 {
1759 degrees = 90 - (sign * degrees);
1760 }
1761
1762 aFPText->SetTextAngle( EDA_ANGLE( degrees, DEGREES_T ) );
1763
1764 switch( align )
1765 {
1766 case ETEXT::TOP_RIGHT:
1769 break;
1770
1771 case ETEXT::BOTTOM_LEFT:
1774 break;
1775
1776 case ETEXT::TOP_LEFT:
1779 break;
1780
1784 break;
1785
1786 case ETEXT::TOP_CENTER:
1789 break;
1790
1794 break;
1795
1796 case ETEXT::CENTER:
1799 break;
1800
1801 case ETEXT::CENTER_LEFT:
1804 break;
1805
1809 break;
1810
1811 default:
1812 ;
1813 }
1814
1815 // Refine justification and rotation for mirrored texts
1816 if( aFPText->IsMirrored() && degrees < -90 && degrees >= -270 )
1817 {
1818 aFPText->SetTextAngle( EDA_ANGLE( 180+degrees, DEGREES_T ) );
1819
1820 if( aFPText->GetHorizJustify() == GR_TEXT_H_ALIGN_LEFT )
1822 else if( aFPText->GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
1824
1825 if( aFPText->GetVertJustify() == GR_TEXT_V_ALIGN_BOTTOM )
1827 else if( aFPText->GetVertJustify() == GR_TEXT_V_ALIGN_TOP )
1829 }
1830 }
1831 else
1832 {
1833 // Part is not smash so use Lib default for NAME/VALUE
1834 // the text is per the original package, sans <attribute>.
1835 double degrees = aFPText->GetTextAngle().AsDegrees()
1836 + aFootprint->GetOrientation().AsDegrees();
1837
1838 // bottom-left is eagle default
1841
1842 if( !aFPText->IsMirrored() && abs( degrees ) <= -180 )
1843 {
1846 }
1847 }
1848}
1849
1850
1851FOOTPRINT* PCB_IO_EAGLE::makeFootprint( wxXmlNode* aPackage, const wxString& aPkgName )
1852{
1853 std::unique_ptr<FOOTPRINT> m = std::make_unique<FOOTPRINT>( m_board );
1854
1855 LIB_ID fpID;
1856 fpID.Parse( aPkgName, true );
1857 m->SetFPID( fpID );
1858
1859 // Get the first package item and iterate
1860 wxXmlNode* packageItem = aPackage->GetChildren();
1861
1862 // layer 27 is default layer for tValues
1863 // set default layer for created footprint
1864 PCB_LAYER_ID layer = kicad_layer( 27 );
1865 m.get()->Value().SetLayer( layer );
1866
1867 while( packageItem )
1868 {
1869 const wxString& itemName = packageItem->GetName();
1870
1871 if( itemName == wxT( "description" ) )
1872 {
1873 wxString descr = convertDescription( UnescapeHTML( packageItem->GetNodeContent() ) );
1874 m->SetLibDescription( descr );
1875 }
1876 else if( itemName == wxT( "wire" ) )
1877 packageWire( m.get(), packageItem );
1878 else if( itemName == wxT( "pad" ) )
1879 packagePad( m.get(), packageItem );
1880 else if( itemName == wxT( "text" ) )
1881 packageText( m.get(), packageItem );
1882 else if( itemName == wxT( "rectangle" ) )
1883 packageRectangle( m.get(), packageItem );
1884 else if( itemName == wxT( "polygon" ) )
1885 packagePolygon( m.get(), packageItem );
1886 else if( itemName == wxT( "circle" ) )
1887 packageCircle( m.get(), packageItem );
1888 else if( itemName == wxT( "hole" ) )
1889 packageHole( m.get(), packageItem, false );
1890 else if( itemName == wxT( "smd" ) )
1891 packageSMD( m.get(), packageItem );
1892
1893 packageItem = packageItem->GetNext();
1894 }
1895
1896 return m.release();
1897}
1898
1899
1900void PCB_IO_EAGLE::packageWire( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const
1901{
1902 EWIRE w( aTree );
1903 PCB_LAYER_ID layer = kicad_layer( w.layer );
1904 VECTOR2I start( kicad_x( w.x1 ), kicad_y( w.y1 ) );
1905 VECTOR2I end( kicad_x( w.x2 ), kicad_y( w.y2 ) );
1906 int width = w.width.ToPcbUnits();
1907
1908 if( layer == UNDEFINED_LAYER )
1909 {
1910 wxLogMessage( wxString::Format( _( "Ignoring a wire since Eagle layer '%s' (%d) was not mapped" ),
1911 eagle_layer_name( w.layer ),
1912 w.layer ) );
1913 return;
1914 }
1915
1916 // KiCad cannot handle zero or negative line widths which apparently have meaning in Eagle.
1917 if( width <= 0 )
1918 {
1919 BOARD* board = aFootprint->GetBoard();
1920
1921 if( board )
1922 {
1923 width = board->GetDesignSettings().GetLineThickness( layer );
1924 }
1925 else
1926 {
1927 // When loading footprint libraries, there is no board so use the default KiCad
1928 // line widths.
1929 switch( layer )
1930 {
1931 case Edge_Cuts: width = pcbIUScale.mmToIU( DEFAULT_EDGE_WIDTH ); break;
1932
1933 case F_SilkS:
1934 case B_SilkS: width = pcbIUScale.mmToIU( DEFAULT_SILK_LINE_WIDTH ); break;
1935
1936 case F_CrtYd:
1937 case B_CrtYd: width = pcbIUScale.mmToIU( DEFAULT_COURTYARD_WIDTH ); break;
1938
1939 default: width = pcbIUScale.mmToIU( DEFAULT_LINE_WIDTH ); break;
1940 }
1941 }
1942 }
1943
1944 // FIXME: the cap attribute is ignored because KiCad can't create lines with flat ends.
1945 PCB_SHAPE* dwg;
1946
1947 if( !w.curve )
1948 {
1949 dwg = new PCB_SHAPE( aFootprint, SHAPE_T::SEGMENT );
1950
1951 dwg->SetStart( start );
1952 dwg->SetEnd( end );
1953 }
1954 else
1955 {
1956 dwg = new PCB_SHAPE( aFootprint, SHAPE_T::ARC );
1957 VECTOR2I center = ConvertArcCenter( start, end, *w.curve );
1958
1959 dwg->SetCenter( center );
1960 dwg->SetStart( start );
1961 dwg->SetArcAngleAndEnd( -EDA_ANGLE( *w.curve, DEGREES_T ), true ); // KiCad rotates the other way
1962 }
1963
1964 dwg->SetLayer( layer );
1965 dwg->SetStroke( STROKE_PARAMS( width, LINE_STYLE::SOLID ) );
1966 dwg->Rotate( { 0, 0 }, aFootprint->GetOrientation() );
1967 dwg->Move( aFootprint->GetPosition() );
1968
1969 aFootprint->Add( dwg );
1970}
1971
1972
1973void PCB_IO_EAGLE::packagePad( FOOTPRINT* aFootprint, wxXmlNode* aTree )
1974{
1975 // this is thru hole technology here, no SMDs
1976 EPAD e( aTree );
1977 int shape = EPAD::UNDEF;
1978 int eagleDrillz = e.drill ? e.drill->ToPcbUnits() : 0;
1979
1980 std::unique_ptr<PAD> pad = std::make_unique<PAD>( aFootprint );
1981 transferPad( e, pad.get() );
1982
1983 if( e.first && *e.first && m_rules->psFirst != EPAD::UNDEF )
1984 shape = m_rules->psFirst;
1985 else if( aFootprint->GetLayer() == F_Cu && m_rules->psTop != EPAD::UNDEF )
1986 shape = m_rules->psTop;
1987 else if( aFootprint->GetLayer() == B_Cu && m_rules->psBottom != EPAD::UNDEF )
1988 shape = m_rules->psBottom;
1989
1990 pad->SetDrillSize( VECTOR2I( eagleDrillz, eagleDrillz ) );
1991 pad->SetLayerSet( LSET::AllCuMask() );
1992
1993 if( eagleDrillz < m_min_hole )
1994 m_min_hole = eagleDrillz;
1995
1996 // Solder mask
1997 if( !e.stop || *e.stop == true ) // enabled by default
1998 pad->SetLayerSet( pad->GetLayerSet().set( B_Mask ).set( F_Mask ) );
1999
2000 if( shape == EPAD::ROUND || shape == EPAD::SQUARE || shape == EPAD::OCTAGON )
2001 e.shape = shape;
2002
2003 if( e.shape )
2004 {
2005 switch( *e.shape )
2006 {
2007 case EPAD::ROUND:
2008 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::CIRCLE );
2009 break;
2010
2011 case EPAD::OCTAGON:
2012 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::CHAMFERED_RECT );
2013 pad->SetChamferPositions( PADSTACK::ALL_LAYERS, RECT_CHAMFER_ALL );
2014 pad->SetChamferRectRatio( PADSTACK::ALL_LAYERS, 1 - M_SQRT1_2 ); // Regular polygon
2015 break;
2016
2017 case EPAD::LONG:
2018 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::OVAL );
2019 break;
2020
2021 case EPAD::SQUARE:
2022 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::RECTANGLE );
2023 break;
2024
2025 case EPAD::OFFSET:
2026 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::OVAL );
2027 break;
2028 }
2029 }
2030 else
2031 {
2032 // if shape is not present, our default is circle and that matches their default "round"
2033 }
2034
2035 if( e.diameter && e.diameter->value > 0 )
2036 {
2037 int diameter = e.diameter->ToPcbUnits();
2038 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( diameter, diameter ) );
2039 }
2040 else
2041 {
2042 double drillz = pad->GetDrillSize().x;
2043 double annulus = drillz * m_rules->rvPadTop; // copper annulus, eagle "restring"
2044 annulus = eagleClamp( m_rules->rlMinPadTop, annulus, m_rules->rlMaxPadTop );
2045 int diameter = KiROUND( drillz + 2 * annulus );
2046 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( KiROUND( diameter ), KiROUND( diameter ) ) );
2047 }
2048
2049 if( pad->GetShape( PADSTACK::ALL_LAYERS ) == PAD_SHAPE::OVAL )
2050 {
2051 // The Eagle "long" pad is wider than it is tall; m_elongation is percent elongation
2052 VECTOR2I sz = pad->GetSize( PADSTACK::ALL_LAYERS );
2053 sz.x = ( sz.x * ( 100 + m_rules->psElongationLong ) ) / 100;
2054 pad->SetSize( PADSTACK::ALL_LAYERS, sz );
2055
2056 if( e.shape && *e.shape == EPAD::OFFSET )
2057 {
2058 int offset = KiROUND( ( sz.x - sz.y ) / 2.0 );
2059 pad->SetOffset( PADSTACK::ALL_LAYERS, VECTOR2I( offset, 0 ) );
2060 }
2061 }
2062
2063 if( e.rot )
2064 pad->SetOrientation( EDA_ANGLE( e.rot->degrees, DEGREES_T ) );
2065
2066 // Eagle spokes are always '+'
2067 pad->SetThermalSpokeAngle( ANGLE_0 );
2068
2069 if( pad->GetSizeX() > 0 && pad->GetSizeY() > 0 && pad->HasHole() )
2070 {
2071 aFootprint->Add( pad.release() );
2072 }
2073 else
2074 {
2075 wxFileName fileName( m_lib_path );
2076
2077 if( m_board)
2078 wxLogError( _( "Invalid zero-sized pad ignored in\nfile: %s" ), m_board->GetFileName() );
2079 else
2080 wxLogError( _( "Invalid zero-sized pad ignored in\nfile: %s" ), fileName.GetFullName() );
2081 }
2082}
2083
2084
2085void PCB_IO_EAGLE::packageText( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const
2086{
2087 ETEXT t( aTree );
2088 PCB_LAYER_ID layer = kicad_layer( t.layer );
2089
2090 if( layer == UNDEFINED_LAYER )
2091 {
2092 wxLogMessage( wxString::Format( _( "Ignoring a text since Eagle layer '%s' (%d) was not mapped" ),
2093 eagle_layer_name( t.layer ),
2094 t.layer ) );
2095 return;
2096 }
2097
2098 PCB_TEXT* textItem;
2099
2100 if( t.text.Upper() == wxT( ">NAME" ) && aFootprint->GetReference().IsEmpty() )
2101 {
2102 textItem = &aFootprint->Reference();
2103
2104 textItem->SetText( wxT( "REF**" ) );
2105 }
2106 else if( t.text.Upper() == wxT( ">VALUE" ) && aFootprint->GetValue().IsEmpty() )
2107 {
2108 textItem = &aFootprint->Value();
2109
2110 textItem->SetText( aFootprint->GetFPID().GetLibItemName() );
2111 }
2112 else
2113 {
2114 textItem = new PCB_TEXT( aFootprint );
2115 aFootprint->Add( textItem );
2116
2117 textItem->SetText( interpretText( t.text ) );
2118 }
2119
2120 VECTOR2I pos( kicad_x( t.x ), kicad_y( t.y ) );
2121
2122 textItem->SetPosition( pos );
2123 textItem->SetLayer( layer );
2124
2125 double ratio = t.ratio ? *t.ratio : 8; // DTD says 8 is default
2126 int textThickness = KiROUND( t.size.ToPcbUnits() * ratio / 100.0 );
2127
2128 textItem->SetTextThickness( textThickness );
2129 textItem->SetTextSize( kicad_fontsize( t.size, textThickness ) );
2130 textItem->SetKeepUpright( false );
2131
2132 int align = t.align ? *t.align : ETEXT::BOTTOM_LEFT; // bottom-left is eagle default
2133
2134 // An eagle package is never rotated, the DTD does not allow it.
2135 // angle -= aFootprint->GetOrienation();
2136
2137 if( t.rot )
2138 {
2139 int sign = t.rot->mirror ? -1 : 1;
2140 textItem->SetMirrored( t.rot->mirror );
2141
2142 double degrees = t.rot->degrees;
2143 textItem->SetTextAngle( EDA_ANGLE( sign * degrees, DEGREES_T ) );
2144 }
2145
2146 switch( align )
2147 {
2148 case ETEXT::CENTER:
2151 break;
2152
2153 case ETEXT::CENTER_LEFT:
2156 break;
2157
2161 break;
2162
2163 case ETEXT::TOP_CENTER:
2166 break;
2167
2168 case ETEXT::TOP_LEFT:
2171 break;
2172
2173 case ETEXT::TOP_RIGHT:
2176 break;
2177
2181 break;
2182
2183 case ETEXT::BOTTOM_LEFT:
2186 break;
2187
2191 break;
2192 }
2193}
2194
2195
2196void PCB_IO_EAGLE::packageRectangle( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const
2197{
2198 ERECT r( aTree );
2199
2202 {
2203 ZONE* zone = new ZONE( aFootprint );
2204 aFootprint->Add( zone, ADD_MODE::APPEND );
2205
2206 setKeepoutSettingsToZone( zone, r.layer );
2207
2208 const int outlineIdx = -1; // this is the id of the copper zone main outline
2209 zone->AppendCorner( VECTOR2I( kicad_x( r.x1 ), kicad_y( r.y1 ) ), outlineIdx );
2210 zone->AppendCorner( VECTOR2I( kicad_x( r.x2 ), kicad_y( r.y1 ) ), outlineIdx );
2211 zone->AppendCorner( VECTOR2I( kicad_x( r.x2 ), kicad_y( r.y2 ) ), outlineIdx );
2212 zone->AppendCorner( VECTOR2I( kicad_x( r.x1 ), kicad_y( r.y2 ) ), outlineIdx );
2213
2214 if( r.rot )
2215 {
2216 VECTOR2I center( ( kicad_x( r.x1 ) + kicad_x( r.x2 ) ) / 2,
2217 ( kicad_y( r.y1 ) + kicad_y( r.y2 ) ) / 2 );
2218 zone->Rotate( center, EDA_ANGLE( r.rot->degrees, DEGREES_T ) );
2219 }
2220
2221 zone->SetBorderDisplayStyle( ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE,
2223 }
2224 else
2225 {
2226 PCB_LAYER_ID layer = kicad_layer( r.layer );
2227
2228 if( layer == UNDEFINED_LAYER )
2229 {
2230 wxLogMessage( wxString::Format( _( "Ignoring a rectangle since Eagle layer '%s' (%d) was not mapped" ),
2231 eagle_layer_name( r.layer ),
2232 r.layer ) );
2233 return;
2234 }
2235
2236 PCB_SHAPE* dwg = new PCB_SHAPE( aFootprint, SHAPE_T::POLY );
2237
2238 aFootprint->Add( dwg );
2239
2240 dwg->SetLayer( layer );
2241 dwg->SetStroke( STROKE_PARAMS( 0 ) );
2242 dwg->SetFilled( true );
2243
2244 std::vector<VECTOR2I> pts;
2245
2246 VECTOR2I start( VECTOR2I( kicad_x( r.x1 ), kicad_y( r.y1 ) ) );
2247 VECTOR2I end( VECTOR2I( kicad_x( r.x1 ), kicad_y( r.y2 ) ) );
2248
2249 pts.push_back( start );
2250 pts.emplace_back( kicad_x( r.x2 ), kicad_y( r.y1 ) );
2251 pts.emplace_back( kicad_x( r.x2 ), kicad_y( r.y2 ) );
2252 pts.push_back( end );
2253
2254 dwg->SetPolyPoints( pts );
2255
2256 if( r.rot )
2257 dwg->Rotate( dwg->GetCenter(), EDA_ANGLE( r.rot->degrees, DEGREES_T ) );
2258
2259 dwg->Rotate( { 0, 0 }, aFootprint->GetOrientation() );
2260 dwg->Move( aFootprint->GetPosition() );
2261 }
2262}
2263
2264
2265void PCB_IO_EAGLE::packagePolygon( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const
2266{
2267 EPOLYGON p( aTree );
2268
2269 std::vector<VECTOR2I> pts;
2270
2271 // Get the first vertex and iterate
2272 wxXmlNode* vertex = aTree->GetChildren();
2273 std::vector<EVERTEX> vertices;
2274
2275 // Create a circular vector of vertices
2276 // The "curve" parameter indicates a curve from the current
2277 // to the next vertex, so we keep the first at the end as well
2278 // to allow the curve to link back
2279 while( vertex )
2280 {
2281 if( vertex->GetName() == wxT( "vertex" ) )
2282 vertices.emplace_back( vertex );
2283
2284 vertex = vertex->GetNext();
2285 }
2286
2287 vertices.push_back( vertices[0] );
2288
2289 for( size_t i = 0; i < vertices.size() - 1; i++ )
2290 {
2291 EVERTEX v1 = vertices[i];
2292
2293 // Append the corner
2294 pts.emplace_back( kicad_x( v1.x ), kicad_y( v1.y ) );
2295
2296 if( v1.curve )
2297 {
2298 EVERTEX v2 = vertices[i + 1];
2299 VECTOR2I center = ConvertArcCenter( VECTOR2I( kicad_x( v1.x ), kicad_y( v1.y ) ),
2300 VECTOR2I( kicad_x( v2.x ), kicad_y( v2.y ) ),
2301 *v1.curve );
2302 double angle = DEG2RAD( *v1.curve );
2303 double end_angle = atan2( kicad_y( v2.y ) - center.y, kicad_x( v2.x ) - center.x );
2304 double radius = sqrt( pow( center.x - kicad_x( v1.x ), 2 ) + pow( center.y - kicad_y( v1.y ), 2 ) );
2305
2306 // Don't allow a zero-radius curve
2307 if( KiROUND( radius ) == 0 )
2308 radius = 1.0;
2309
2310 int segCount = GetArcToSegmentCount( KiROUND( radius ), ARC_HIGH_DEF,
2311 EDA_ANGLE( *v1.curve, DEGREES_T ) );
2312 double delta = angle / segCount;
2313
2314 for( double a = end_angle + angle; fabs( a - end_angle ) > fabs( delta ); a -= delta )
2315 {
2316 pts.push_back( VECTOR2I( KiROUND( radius * cos( a ) ),
2317 KiROUND( radius * sin( a ) ) ) + center );
2318 }
2319 }
2320 }
2321
2322 PCB_LAYER_ID layer = kicad_layer( p.layer );
2323
2324 if( ( p.pour == EPOLYGON::ECUTOUT && layer != UNDEFINED_LAYER )
2328 {
2329 ZONE* zone = new ZONE( aFootprint );
2330 aFootprint->Add( zone, ADD_MODE::APPEND );
2331
2332 setKeepoutSettingsToZone( zone, p.layer );
2333
2334 SHAPE_LINE_CHAIN outline( pts );
2335 outline.SetClosed( true );
2336 zone->Outline()->AddOutline( outline );
2337
2338 zone->SetBorderDisplayStyle( ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE,
2340 }
2341 else
2342 {
2343 if( layer == UNDEFINED_LAYER )
2344 {
2345 wxLogMessage( wxString::Format( _( "Ignoring a polygon since Eagle layer '%s' (%d) was not mapped" ),
2346 eagle_layer_name( p.layer ),
2347 p.layer ) );
2348 return;
2349 }
2350
2351 PCB_SHAPE* dwg = new PCB_SHAPE( aFootprint, SHAPE_T::POLY );
2352
2353 aFootprint->Add( dwg );
2354
2355 dwg->SetStroke( STROKE_PARAMS( 0 ) );
2356 dwg->SetFilled( true );
2357 dwg->SetLayer( layer );
2358
2359 dwg->SetPolyPoints( pts );
2360 dwg->Rotate( { 0, 0 }, aFootprint->GetOrientation() );
2361 dwg->Move( aFootprint->GetPosition() );
2362 dwg->GetPolyShape().Inflate( p.width.ToPcbUnits() / 2, CORNER_STRATEGY::ALLOW_ACUTE_CORNERS,
2363 ARC_HIGH_DEF );
2364 }
2365}
2366
2367
2368void PCB_IO_EAGLE::packageCircle( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const
2369{
2370 ECIRCLE e( aTree );
2371
2372 int width = e.width.ToPcbUnits();
2373 int radius = e.radius.ToPcbUnits();
2374
2378 {
2379 ZONE* zone = new ZONE( aFootprint );
2380 aFootprint->Add( zone, ADD_MODE::APPEND );
2381
2382 setKeepoutSettingsToZone( zone, e.layer );
2383
2384 // approximate circle as polygon
2385 VECTOR2I center( kicad_x( e.x ), kicad_y( e.y ) );
2386 int outlineRadius = radius + ( width / 2 );
2387 int segsInCircle = GetArcToSegmentCount( outlineRadius, ARC_HIGH_DEF, FULL_CIRCLE );
2388 EDA_ANGLE delta = ANGLE_360 / segsInCircle;
2389
2390 for( EDA_ANGLE angle = ANGLE_0; angle < ANGLE_360; angle += delta )
2391 {
2392 VECTOR2I rotatedPoint( outlineRadius, 0 );
2393 RotatePoint( rotatedPoint, angle );
2394 zone->AppendCorner( center + rotatedPoint, -1 );
2395 }
2396
2397 if( width > 0 )
2398 {
2399 zone->NewHole();
2400 int innerRadius = radius - ( width / 2 );
2401 segsInCircle = GetArcToSegmentCount( innerRadius, ARC_HIGH_DEF, FULL_CIRCLE );
2402 delta = ANGLE_360 / segsInCircle;
2403
2404 for( EDA_ANGLE angle = ANGLE_0; angle < ANGLE_360; angle += delta )
2405 {
2406 VECTOR2I rotatedPoint( innerRadius, 0 );
2407 RotatePoint( rotatedPoint, angle );
2408 zone->AppendCorner( center + rotatedPoint, 0 );
2409 }
2410 }
2411
2412 zone->SetBorderDisplayStyle( ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE,
2414 }
2415 else
2416 {
2417 PCB_LAYER_ID layer = kicad_layer( e.layer );
2418
2419 if( layer == UNDEFINED_LAYER )
2420 {
2421 wxLogMessage( wxString::Format( _( "Ignoring a circle since Eagle layer '%s' (%d) was not mapped" ),
2422 eagle_layer_name( e.layer ),
2423 e.layer ) );
2424 return;
2425 }
2426
2427 PCB_SHAPE* gr = new PCB_SHAPE( aFootprint, SHAPE_T::CIRCLE );
2428
2429 // width == 0 means filled circle
2430 if( width <= 0 )
2431 {
2432 width = radius;
2433 radius = radius / 2;
2434 gr->SetFilled( true );
2435 }
2436
2437 aFootprint->Add( gr );
2438 gr->SetStroke( STROKE_PARAMS( width, LINE_STYLE::SOLID ) );
2439
2440 switch( (int) layer )
2441 {
2442 case UNDEFINED_LAYER:
2443 layer = Cmts_User;
2444 break;
2445 default:
2446 break;
2447 }
2448
2449 gr->SetLayer( layer );
2450 gr->SetStart( VECTOR2I( kicad_x( e.x ), kicad_y( e.y ) ) );
2451 gr->SetEnd( VECTOR2I( kicad_x( e.x ) + radius, kicad_y( e.y ) ) );
2452 gr->Rotate( { 0, 0 }, aFootprint->GetOrientation() );
2453 gr->Move( aFootprint->GetPosition() );
2454 }
2455}
2456
2457
2458void PCB_IO_EAGLE::packageHole( FOOTPRINT* aFootprint, wxXmlNode* aTree, bool aCenter ) const
2459{
2460 EHOLE e( aTree );
2461
2462 if( e.drill.value == 0 )
2463 return;
2464
2465 // we add a PAD_ATTRIB::NPTH pad to this footprint.
2466 PAD* pad = new PAD( aFootprint );
2467 aFootprint->Add( pad );
2468
2469 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::CIRCLE );
2470 pad->SetAttribute( PAD_ATTRIB::NPTH );
2471
2472 // Mechanical purpose only:
2473 // no offset, no net name, no pad name allowed
2474 // pad->SetOffset( VECTOR2I( 0, 0 ) );
2475 // pad->SetNumber( wxEmptyString );
2476
2477 VECTOR2I padpos( kicad_x( e.x ), kicad_y( e.y ) );
2478
2479 if( aCenter )
2480 {
2481 aFootprint->SetPosition( padpos );
2482 pad->SetPosition( padpos );
2483 }
2484 else
2485 {
2486 pad->SetPosition( padpos + aFootprint->GetPosition() );
2487 }
2488
2489 VECTOR2I sz( e.drill.ToPcbUnits(), e.drill.ToPcbUnits() );
2490
2491 pad->SetDrillSize( sz );
2492 pad->SetSize( PADSTACK::ALL_LAYERS, sz );
2493
2494 pad->SetLayerSet( LSET( LSET::AllCuMask() ).set( B_Mask ).set( F_Mask ) );
2495}
2496
2497
2498void PCB_IO_EAGLE::packageSMD( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const
2499{
2500 ESMD e( aTree );
2501 PCB_LAYER_ID layer = kicad_layer( e.layer );
2502
2503 if( !IsCopperLayer( layer ) || e.dx.value == 0 || e.dy.value == 0 )
2504 return;
2505
2506 PAD* pad = new PAD( aFootprint );
2507 aFootprint->Add( pad );
2508 transferPad( e, pad );
2509
2510 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::RECTANGLE );
2511 pad->SetAttribute( PAD_ATTRIB::SMD );
2512
2513 VECTOR2I padSize( e.dx.ToPcbUnits(), e.dy.ToPcbUnits() );
2514 pad->SetSize( PADSTACK::ALL_LAYERS, padSize );
2515 pad->SetLayer( layer );
2516
2517 const LSET front( { F_Cu, F_Paste, F_Mask } );
2518 const LSET back( { B_Cu, B_Paste, B_Mask } );
2519
2520 if( layer == F_Cu )
2521 pad->SetLayerSet( front );
2522 else if( layer == B_Cu )
2523 pad->SetLayerSet( back );
2524
2525 int minPadSize = std::min( padSize.x, padSize.y );
2526
2527 // Rounded rectangle pads
2528 int roundRadius = eagleClamp( m_rules->srMinRoundness * 2,
2529 (int) ( minPadSize * m_rules->srRoundness ),
2530 m_rules->srMaxRoundness * 2 );
2531
2532 if( e.roundness || roundRadius > 0 )
2533 {
2534 double roundRatio = (double) roundRadius / minPadSize / 2.0;
2535
2536 // Eagle uses a different definition of roundness, hence division by 200
2537 if( e.roundness )
2538 roundRatio = std::fmax( *e.roundness / 200.0, roundRatio );
2539
2540 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::ROUNDRECT );
2541 pad->SetRoundRectRadiusRatio( PADSTACK::ALL_LAYERS, roundRatio );
2542 }
2543
2544 if( e.rot )
2545 pad->SetOrientation( EDA_ANGLE( e.rot->degrees, DEGREES_T ) );
2546
2547 // Eagle spokes are always '+'
2548 pad->SetThermalSpokeAngle( ANGLE_0 );
2549
2550 pad->SetLocalSolderPasteMargin( -eagleClamp( m_rules->mlMinCreamFrame,
2551 (int) ( m_rules->mvCreamFrame * minPadSize ),
2552 m_rules->mlMaxCreamFrame ) );
2553
2554 // Solder mask
2555 if( e.stop && *e.stop == false ) // enabled by default
2556 {
2557 if( layer == F_Cu )
2558 pad->SetLayerSet( pad->GetLayerSet().set( F_Mask, false ) );
2559 else if( layer == B_Cu )
2560 pad->SetLayerSet( pad->GetLayerSet().set( B_Mask, false ) );
2561 }
2562
2563 // Solder paste (only for SMD pads)
2564 if( e.cream && *e.cream == false ) // enabled by default
2565 {
2566 if( layer == F_Cu )
2567 pad->SetLayerSet( pad->GetLayerSet().set( F_Paste, false ) );
2568 else if( layer == B_Cu )
2569 pad->SetLayerSet( pad->GetLayerSet().set( B_Paste, false ) );
2570 }
2571}
2572
2573
2574void PCB_IO_EAGLE::transferPad( const EPAD_COMMON& aEaglePad, PAD* aPad ) const
2575{
2576 aPad->SetNumber( aEaglePad.name );
2577
2578 VECTOR2I padPos( kicad_x( aEaglePad.x ), kicad_y( aEaglePad.y ) );
2579
2580 // Solder mask
2581 const VECTOR2I& padSize( aPad->GetSize( PADSTACK::ALL_LAYERS ) );
2582
2583 aPad->SetLocalSolderMaskMargin( eagleClamp( m_rules->mlMinStopFrame,
2584 (int) ( m_rules->mvStopFrame * std::min( padSize.x, padSize.y ) ),
2585 m_rules->mlMaxStopFrame ) );
2586
2587 // Solid connection to copper zones
2588 if( aEaglePad.thermals && !*aEaglePad.thermals )
2589 aPad->SetLocalZoneConnection( ZONE_CONNECTION::FULL );
2590
2591 FOOTPRINT* footprint = aPad->GetParentFootprint();
2592 wxCHECK( footprint, /* void */ );
2593 RotatePoint( padPos, footprint->GetOrientation() );
2594 aPad->SetPosition( padPos + footprint->GetPosition() );
2595}
2596
2597
2599{
2600 for( const auto& [ name, footprint ] : m_templates )
2601 {
2602 footprint->SetParent( nullptr );
2603 delete footprint;
2604 }
2605
2606 m_templates.clear();
2607}
2608
2609
2610void PCB_IO_EAGLE::loadClasses( wxXmlNode* aClasses )
2611{
2612 // Eagle board DTD defines the "classes" element as 0 or 1.
2613 if( !aClasses )
2614 return;
2615
2616 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
2617
2618 m_xpath->push( "classes.class", "number" );
2619
2620 std::vector<ECLASS> eClasses;
2621 wxXmlNode* classNode = aClasses->GetChildren();
2622
2623 while( classNode )
2624 {
2625 checkpoint();
2626
2627 ECLASS eClass( classNode );
2628 std::shared_ptr<NETCLASS> netclass;
2629
2630 if( eClass.name.CmpNoCase( wxT( "default" ) ) == 0 )
2631 {
2632 netclass = bds.m_NetSettings->GetDefaultNetclass();
2633 }
2634 else
2635 {
2636 netclass.reset( new NETCLASS( eClass.name ) );
2637 bds.m_NetSettings->SetNetclass( eClass.name, netclass );
2638 }
2639
2640 netclass->SetTrackWidth( INT_MAX );
2641 netclass->SetViaDiameter( INT_MAX );
2642 netclass->SetViaDrill( INT_MAX );
2643
2644 eClasses.emplace_back( eClass );
2645 m_classMap[ eClass.number ] = netclass;
2646
2647 // Get next class
2648 classNode = classNode->GetNext();
2649 }
2650
2651 m_customRules = wxT( "(version 1)" );
2652
2653 for( ECLASS& eClass : eClasses )
2654 {
2655 for( const auto& [className, pt] : eClass.clearanceMap )
2656 {
2657 if( m_classMap[className] != nullptr )
2658 {
2659 wxString rule;
2660 rule.Printf( wxT( "(rule \"class %s:%s\"\n"
2661 " (condition \"A.NetClass == '%s' && B.NetClass == '%s'\")\n"
2662 " (constraint clearance (min %smm)))\n" ),
2663 eClass.number,
2664 className,
2665 eClass.name,
2666 m_classMap[className]->GetName(),
2667 EDA_UNIT_UTILS::UI::StringFromValue( pcbIUScale, EDA_UNITS::MM, pt.ToPcbUnits() ) );
2668
2669 m_customRules += wxT( "\n" ) + rule;
2670 }
2671 }
2672 }
2673
2674 m_xpath->pop(); // "classes.class"
2675}
2676
2677
2678void PCB_IO_EAGLE::loadSignals( wxXmlNode* aSignals )
2679{
2680 // Eagle board DTD defines the "signals" element as 0 or 1.
2681 if( !aSignals )
2682 return;
2683
2684 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
2685
2686 ZONES zones; // per net
2687 int netCode = 1;
2688
2689 m_xpath->push( "signals.signal", "name" );
2690
2691 // Get the first signal and iterate
2692 wxXmlNode* net = aSignals->GetChildren();
2693
2694 while( net )
2695 {
2696 checkpoint();
2697
2698 bool sawPad = false;
2699
2700 zones.clear();
2701
2702 const wxString& netName = escapeName( net->GetAttribute( "name" ) );
2703 NETINFO_ITEM* netInfo = new NETINFO_ITEM( m_board, netName, netCode );
2704 std::shared_ptr<NETCLASS> netclass;
2705
2706 if( net->HasAttribute( "class" ) )
2707 {
2708 auto netclassIt = m_classMap.find( net->GetAttribute( "class" ) );
2709
2710 if( netclassIt != m_classMap.end() )
2711 {
2712 bds.m_NetSettings->SetNetclassPatternAssignment( netName, netclassIt->second->GetName() );
2713 netInfo->SetNetClass( netclassIt->second );
2714 netclass = netclassIt->second;
2715 }
2716 }
2717
2718 m_board->Add( netInfo );
2719
2720 m_xpath->Value( netName.c_str() );
2721
2722 // Get the first net item and iterate
2723 wxXmlNode* netItem = net->GetChildren();
2724
2725 // (contactref | polygon | wire | via)*
2726 while( netItem )
2727 {
2728 const wxString& itemName = netItem->GetName();
2729
2730 if( itemName == wxT( "wire" ) )
2731 {
2732 m_xpath->push( "wire" );
2733
2734 EWIRE w( netItem );
2735 PCB_LAYER_ID layer = kicad_layer( w.layer );
2736
2737 if( IsCopperLayer( layer ) )
2738 {
2739 VECTOR2I start( kicad_x( w.x1 ), kicad_y( w.y1 ) );
2740 VECTOR2I end( kicad_x( w.x2 ), kicad_y( w.y2 ) );
2741
2742 int width = w.width.ToPcbUnits();
2743
2744 if( width < m_min_trace )
2745 m_min_trace = width;
2746
2747 if( netclass && width < netclass->GetTrackWidth() )
2748 netclass->SetTrackWidth( width );
2749
2750 if( w.curve )
2751 {
2752 VECTOR2I center = ConvertArcCenter( start, end, *w.curve );
2753 double radius = sqrt( pow( center.x - kicad_x( w.x1 ), 2 ) +
2754 pow( center.y - kicad_y( w.y1 ), 2 ) );
2755 VECTOR2I mid = CalcArcMid( start, end, center, true );
2756 VECTOR2I otherMid = CalcArcMid( start, end, center, false );
2757
2758 double radiusA = ( mid - center ).EuclideanNorm();
2759 double radiusB = ( otherMid - center ).EuclideanNorm();
2760
2761 if( abs( radiusA - radius ) > abs( radiusB - radius ) )
2762 std::swap( mid, otherMid );
2763
2764 PCB_ARC* arc = new PCB_ARC( m_board );
2765
2766 arc->SetPosition( start );
2767 arc->SetMid( mid );
2768 arc->SetEnd( end );
2769 arc->SetWidth( width );
2770 arc->SetLayer( layer );
2771 arc->SetNetCode( netCode );
2772
2773 m_board->Add( arc );
2774 }
2775 else
2776 {
2777 PCB_TRACK* track = new PCB_TRACK( m_board );
2778
2779 track->SetPosition( start );
2780 track->SetEnd( VECTOR2I( kicad_x( w.x2 ), kicad_y( w.y2 ) ) );
2781 track->SetWidth( width );
2782 track->SetLayer( layer );
2783 track->SetNetCode( netCode );
2784
2785 m_board->Add( track );
2786 }
2787 }
2788 else
2789 {
2790 // put non copper wires where the sun don't shine.
2791 }
2792
2793 m_xpath->pop();
2794 }
2795 else if( itemName == wxT( "via" ) )
2796 {
2797 m_xpath->push( "via" );
2798 EVIA v( netItem );
2799
2801 std::swap( v.layer_front_most, v.layer_back_most );
2802
2803 PCB_LAYER_ID layer_front_most = kicad_layer( v.layer_front_most );
2804 PCB_LAYER_ID layer_back_most = kicad_layer( v.layer_back_most );
2805
2806 if( IsCopperLayer( layer_front_most ) && IsCopperLayer( layer_back_most )
2807 && layer_front_most != layer_back_most )
2808 {
2809 int kidiam;
2810 int drillz = v.drill.ToPcbUnits();
2811 PCB_VIA* via = new PCB_VIA( m_board );
2812 m_board->Add( via );
2813
2814 if( v.diam )
2815 {
2816 kidiam = v.diam->ToPcbUnits();
2817 via->SetWidth( PADSTACK::ALL_LAYERS, kidiam );
2818 }
2819 else
2820 {
2821 double annulus = drillz * m_rules->rvViaOuter; // eagle "restring"
2822 annulus = eagleClamp( m_rules->rlMinViaOuter, annulus, m_rules->rlMaxViaOuter );
2823 kidiam = KiROUND( drillz + 2 * annulus );
2824 via->SetWidth( PADSTACK::ALL_LAYERS, kidiam );
2825 }
2826
2827 via->SetDrill( drillz );
2828
2829 // make sure the via diameter respects the restring rules
2830
2831 int via_width = via->GetWidth( PADSTACK::ALL_LAYERS );
2832
2833 if( !v.diam || via_width <= via->GetDrill() )
2834 {
2835 double annular_width = ( via_width - via->GetDrill() ) / 2.0;
2836 double clamped_annular_width = eagleClamp( m_rules->rlMinViaOuter,
2837 annular_width,
2838 m_rules->rlMaxViaOuter );
2839 via->SetWidth( PADSTACK::ALL_LAYERS, drillz + 2 * clamped_annular_width );
2840 }
2841
2842 if( kidiam < m_min_via )
2843 m_min_via = kidiam;
2844
2845 if( netclass && kidiam < netclass->GetViaDiameter() )
2846 netclass->SetViaDiameter( kidiam );
2847
2848 if( drillz < m_min_hole )
2849 m_min_hole = drillz;
2850
2851 if( netclass && drillz < netclass->GetViaDrill() )
2852 netclass->SetViaDrill( drillz );
2853
2854 if( ( kidiam - drillz ) / 2 < m_min_annulus )
2855 m_min_annulus = ( kidiam - drillz ) / 2;
2856
2857 if( layer_front_most == F_Cu && layer_back_most == B_Cu )
2858 {
2859 via->SetViaType( VIATYPE::THROUGH );
2860 }
2864 else if( v.layer_back_most - v.layer_front_most == 1 )
2865 {
2866 via->SetViaType( VIATYPE::MICROVIA );
2867 }
2868 else
2869 {
2870 via->SetViaType( VIATYPE::BLIND_BURIED );
2871 }
2872
2873 VECTOR2I pos( kicad_x( v.x ), kicad_y( v.y ) );
2874
2875 via->SetLayerPair( layer_front_most, layer_back_most );
2876 via->SetPosition( pos );
2877 via->SetEnd( pos );
2878
2879 via->SetNetCode( netCode );
2880 }
2881
2882 m_xpath->pop();
2883 }
2884
2885 else if( itemName == wxT( "contactref" ) )
2886 {
2887 m_xpath->push( "contactref" );
2888 // <contactref element="RN1" pad="7"/>
2889
2890 const wxString& reference = netItem->GetAttribute( "element" );
2891 const wxString& pad = netItem->GetAttribute( "pad" );
2892 wxString key = makeKey( reference, pad ) ;
2893
2894 m_pads_to_nets[ key ] = ENET( netCode, netName );
2895
2896 m_xpath->pop();
2897
2898 sawPad = true;
2899 }
2900
2901 else if( itemName == wxT( "polygon" ) )
2902 {
2903 m_xpath->push( "polygon" );
2904 auto* zone = loadPolygon( netItem );
2905
2906 if( zone )
2907 {
2908 zones.push_back( zone );
2909
2910 if( !zone->GetIsRuleArea() )
2911 zone->SetNetCode( netCode );
2912 }
2913
2914 m_xpath->pop(); // "polygon"
2915 }
2916
2917 netItem = netItem->GetNext();
2918 }
2919
2920 if( zones.size() && !sawPad )
2921 {
2922 // KiCad does not support an unconnected zone with its own non-zero netcode,
2923 // but only when assigned netcode = 0 w/o a name...
2924 for( ZONE* zone : zones )
2925 zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
2926
2927 // therefore omit this signal/net.
2928 }
2929 else
2930 {
2931 netCode++;
2932 }
2933
2934 // Get next signal
2935 net = net->GetNext();
2936 }
2937
2938 m_xpath->pop(); // "signals.signal"
2939}
2940
2941
2942std::map<wxString, PCB_LAYER_ID> PCB_IO_EAGLE::DefaultLayerMappingCallback(
2943 const std::vector<INPUT_LAYER_DESC>& aInputLayerDescriptionVector )
2944{
2945 std::map<wxString, PCB_LAYER_ID> layer_map;
2946
2947 for ( const INPUT_LAYER_DESC& layer : aInputLayerDescriptionVector )
2948 {
2949 PCB_LAYER_ID layerId = std::get<0>( defaultKicadLayer( eagle_layer_id( layer.Name ) ) );
2950 layer_map.emplace( layer.Name, layerId );
2951 }
2952
2953 return layer_map;
2954}
2955
2956
2957void PCB_IO_EAGLE::mapEagleLayersToKicad( bool aIsLibraryCache )
2958{
2959 std::vector<INPUT_LAYER_DESC> inputDescs;
2960
2961 for ( const std::pair<const int, ELAYER>& layerPair : m_eagleLayers )
2962 {
2963 const ELAYER& eLayer = layerPair.second;
2964
2965 INPUT_LAYER_DESC layerDesc;
2966 std::tie( layerDesc.AutoMapLayer, layerDesc.PermittedLayers, layerDesc.Required ) =
2967 defaultKicadLayer( eLayer.number, aIsLibraryCache );
2968
2969 if( layerDesc.AutoMapLayer == UNDEFINED_LAYER )
2970 continue; // Ignore unused copper layers
2971
2972 layerDesc.Name = eLayer.name;
2973
2974 inputDescs.push_back( layerDesc );
2975 }
2976
2977 if( m_progressReporter && dynamic_cast<wxWindow*>( m_progressReporter ) )
2978 dynamic_cast<wxWindow*>( m_progressReporter )->Hide();
2979
2980 m_layer_map = m_layer_mapping_handler( inputDescs );
2981
2982 if( m_progressReporter && dynamic_cast<wxWindow*>( m_progressReporter ))
2983 dynamic_cast<wxWindow*>( m_progressReporter )->Show();
2984}
2985
2986
2988{
2989 auto result = m_layer_map.find( eagle_layer_name( aEagleLayer ) );
2990 return result == m_layer_map.end() ? UNDEFINED_LAYER : result->second;
2991}
2992
2993
2994std::tuple<PCB_LAYER_ID, LSET, bool> PCB_IO_EAGLE::defaultKicadLayer( int aEagleLayer,
2995 bool aIsLibraryCache ) const
2996{
2997 // eagle copper layer:
2998 if( aEagleLayer >= 1 && aEagleLayer < int( arrayDim( m_cu_map ) ) )
2999 {
3000 LSET copperLayers;
3001
3002 for( int copperLayer : m_cu_map )
3003 {
3004 if( copperLayer >= 0 )
3005 copperLayers[copperLayer] = true;
3006 }
3007
3008 return { PCB_LAYER_ID( m_cu_map[aEagleLayer] ), copperLayers, true };
3009 }
3010
3011 int kiLayer = UNSELECTED_LAYER;
3012 bool required = false;
3013 LSET permittedLayers;
3014
3015 permittedLayers.set();
3016
3017 // translate non-copper eagle layer to pcbnew layer
3018 switch( aEagleLayer )
3019 {
3020 // Eagle says "Dimension" layer, but it's for board perimeter
3022 kiLayer = Edge_Cuts;
3023 required = true;
3024 permittedLayers = LSET( { Edge_Cuts } );
3025 break;
3026
3028 kiLayer = F_SilkS;
3029 break;
3031 kiLayer = B_SilkS;
3032 break;
3034 kiLayer = F_SilkS;
3035 break;
3037 kiLayer = B_SilkS;
3038 break;
3040 kiLayer = F_Fab;
3041 break;
3043 kiLayer = B_Fab;
3044 break;
3045 case EAGLE_LAYER::TSTOP:
3046 kiLayer = F_Mask;
3047 break;
3048 case EAGLE_LAYER::BSTOP:
3049 kiLayer = B_Mask;
3050 break;
3052 kiLayer = F_Paste;
3053 break;
3055 kiLayer = B_Paste;
3056 break;
3058 kiLayer = F_Mask;
3059 break;
3061 kiLayer = B_Mask;
3062 break;
3063 case EAGLE_LAYER::TGLUE:
3064 kiLayer = F_Adhes;
3065 break;
3066 case EAGLE_LAYER::BGLUE:
3067 kiLayer = B_Adhes;
3068 break;
3070 kiLayer = Cmts_User;
3071 break;
3073 kiLayer = Cmts_User;
3074 break;
3076 kiLayer = Cmts_User;
3077 break;
3078
3079 // Packages show the future chip pins on SMD parts using layer 51.
3080 // This is an area slightly smaller than the PAD/SMD copper area.
3081 // Carry those visual aids into the FOOTPRINT on the fabrication layer,
3082 // not silkscreen. This is perhaps not perfect, but there is not a lot
3083 // of other suitable paired layers
3084 case EAGLE_LAYER::TDOCU:
3085 kiLayer = F_Fab;
3086 break;
3087 case EAGLE_LAYER::BDOCU:
3088 kiLayer = B_Fab;
3089 break;
3090
3091 // these layers are defined as user layers. put them on ECO layers
3093 kiLayer = Eco1_User;
3094 break;
3096 kiLayer = Eco2_User;
3097 break;
3098
3099 // these will also appear in the ratsnest, so there's no need for a warning
3101 kiLayer = Dwgs_User;
3102 break;
3103
3105 kiLayer = F_CrtYd;
3106 break;
3108 kiLayer = B_CrtYd;
3109 break;
3110
3112 case EAGLE_LAYER::TTEST:
3113 case EAGLE_LAYER::BTEST:
3114 case EAGLE_LAYER::HOLES:
3115 default:
3116 if( aIsLibraryCache )
3117 kiLayer = UNDEFINED_LAYER;
3118 else
3119 kiLayer = UNSELECTED_LAYER;
3120
3121 break;
3122 }
3123
3124 return { PCB_LAYER_ID( kiLayer ), permittedLayers, required };
3125}
3126
3127
3128const wxString& PCB_IO_EAGLE::eagle_layer_name( int aLayer ) const
3129{
3130 static const wxString unknown( "unknown" );
3131 auto it = m_eagleLayers.find( aLayer );
3132 return it == m_eagleLayers.end() ? unknown : it->second.name;
3133}
3134
3135
3136int PCB_IO_EAGLE::eagle_layer_id( const wxString& aLayerName ) const
3137{
3138 static const int unknown = -1;
3139 auto it = m_eagleLayersIds.find( aLayerName );
3140 return it == m_eagleLayersIds.end() ? unknown : it->second;
3141}
3142
3143
3145{
3146 if( m_props )
3147 {
3148 UTF8 page_width;
3149 UTF8 page_height;
3150
3151 if( auto it = m_props->find( "page_width" ); it != m_props->end() )
3152 page_width = it->second;
3153
3154 if( auto it = m_props->find( "page_height" ); it != m_props->end() )
3155 page_height = it->second;
3156
3157 if( !page_width.empty() && !page_height.empty() )
3158 {
3159 BOX2I bbbox = m_board->GetBoardEdgesBoundingBox();
3160
3161 int w = atoi( page_width.c_str() );
3162 int h = atoi( page_height.c_str() );
3163
3164 int desired_x = ( w - bbbox.GetWidth() ) / 2;
3165 int desired_y = ( h - bbbox.GetHeight() ) / 2;
3166
3167 m_board->Move( VECTOR2I( desired_x - bbbox.GetX(), desired_y - bbbox.GetY() ) );
3168 }
3169 }
3170}
3171
3172
3173long long PCB_IO_EAGLE::GetLibraryTimestamp( const wxString& aPath ) const
3174{
3175 // File hasn't been loaded yet.
3176 if( aPath.IsEmpty() )
3177 return wxDateTime::Now().GetValue().GetValue();
3178
3179 wxFileName fn( aPath );
3180
3181 if( fn.IsFileReadable() && fn.GetModificationTime().IsValid() )
3182 return fn.GetModificationTime().GetValue().GetValue();
3183 else
3184 return 0;
3185}
3186
3187
3188void PCB_IO_EAGLE::cacheLib( const wxString& aLibPath )
3189{
3191
3192 try
3193 {
3194 long long timestamp = GetLibraryTimestamp( aLibPath );
3195
3196 if( aLibPath != m_lib_path || m_timestamp != timestamp )
3197 {
3198 wxXmlNode* doc;
3199
3200 deleteTemplates();
3201
3202 // Set this before completion of loading, since we rely on it for
3203 // text of an exception. Delay setting m_mod_time until after successful load
3204 // however.
3205 m_lib_path = aLibPath;
3206
3207 // 8 bit "filename" should be encoded according to disk filename encoding,
3208 // (maybe this is current locale, maybe not, its a filesystem issue),
3209 // and is not necessarily utf8.
3210 string filename = (const char*) aLibPath.char_str( wxConvFile );
3211
3212 // Load the document
3213 wxFileName fn( filename );
3214 wxFFileInputStream stream( fn.GetFullPath() );
3215 wxXmlDocument xmlDocument;
3216
3217 if( !stream.IsOk() || !xmlDocument.Load( stream ) )
3218 THROW_IO_ERROR( wxString::Format( _( "Unable to read file '%s'." ), fn.GetFullPath() ) );
3219
3220 doc = xmlDocument.GetRoot();
3221
3222 wxXmlNode* drawing = MapChildren( doc )["drawing"];
3223 NODE_MAP drawingChildren = MapChildren( drawing );
3224
3225 // clear the cu map and then rebuild it.
3226 clear_cu_map();
3227
3228 m_xpath->push( "eagle.drawing.layers" );
3229 wxXmlNode* layers = drawingChildren["layers"];
3230 loadLayerDefs( layers );
3231 mapEagleLayersToKicad( true );
3232 m_xpath->pop();
3233
3234 m_xpath->push( "eagle.drawing.library" );
3235 wxXmlNode* library = drawingChildren["library"];
3236
3237 loadLibrary( library, nullptr );
3238 m_xpath->pop();
3239
3240 m_timestamp = timestamp;
3241 }
3242 }
3243 catch(...)
3244 {
3245 }
3246 // TODO: Handle exceptions
3247 // catch( file_parser_error fpe )
3248 // {
3249 // // for xml_parser_error, what() has the line number in it,
3250 // // but no byte offset. That should be an adequate error message.
3251 // THROW_IO_ERROR( fpe.what() );
3252 // }
3253 //
3254 // // Class ptree_error is a base class for xml_parser_error & file_parser_error,
3255 // // so one catch should be OK for all errors.
3256 // catch( ptree_error pte )
3257 // {
3258 // string errmsg = pte.what();
3259 //
3260 // errmsg += " @\n";
3261 // errmsg += m_xpath->Contents();
3262 //
3263 // THROW_IO_ERROR( errmsg );
3264 // }
3265}
3266
3267
3268void PCB_IO_EAGLE::FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibraryPath,
3269 bool aBestEfforts, const std::map<std::string, UTF8>* aProperties )
3270{
3271 wxString errorMsg;
3272
3273 init( aProperties );
3274
3275 try
3276 {
3277 cacheLib( aLibraryPath );
3278 }
3279 catch( const IO_ERROR& ioe )
3280 {
3281 errorMsg = ioe.What();
3282 }
3283
3284 // Some of the files may have been parsed correctly so we want to add the valid files to
3285 // the library.
3286
3287 for( const auto& [ name, footprint ] : m_templates )
3288 aFootprintNames.Add( name );
3289
3290 if( !errorMsg.IsEmpty() && !aBestEfforts )
3291 THROW_IO_ERROR( errorMsg );
3292}
3293
3294
3295FOOTPRINT* PCB_IO_EAGLE::FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
3296 bool aKeepUUID, const std::map<std::string, UTF8>* aProperties )
3297{
3298 init( aProperties );
3299 cacheLib( aLibraryPath );
3300 auto it = m_templates.find( aFootprintName );
3301
3302 if( it == m_templates.end() )
3303 return nullptr;
3304
3305 // Return a copy of the template
3306 FOOTPRINT* copy = (FOOTPRINT*) it->second->Duplicate( IGNORE_PARENT_GROUP );
3307 copy->SetParent( nullptr );
3308 return copy;
3309}
3310
3311
3313{
3314 int minLayerCount = 2;
3315
3316 std::map<wxString, PCB_LAYER_ID>::const_iterator it;
3317
3318 for( it = m_layer_map.begin(); it != m_layer_map.end(); ++it )
3319 {
3320 PCB_LAYER_ID layerId = it->second;
3321
3322 if( !IsCopperLayer( layerId ) || layerId == F_Cu || layerId == B_Cu )
3323 continue;
3324
3325 int ordinal = CopperLayerToOrdinal( layerId );
3326
3327 if( ( ordinal + 2 ) > minLayerCount )
3328 minLayerCount = ordinal + 2;
3329 }
3330
3331 // Ensure the copper layers count is a multiple of 2
3332 // Pcbnew does not like boards with odd layers count
3333 // (these boards cannot exist. they actually have a even layers count)
3334 if( ( minLayerCount % 2 ) != 0 )
3335 minLayerCount++;
3336
3337 return minLayerCount;
3338}
const char * name
Definition: DXF_plotter.cpp:62
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
Definition: arraydim.h:31
constexpr int ARC_HIGH_DEF
Definition: base_units.h:129
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:112
@ LT_SIGNAL
Definition: board.h:182
#define DEFAULT_SILK_LINE_WIDTH
#define DEFAULT_EDGE_WIDTH
#define DEFAULT_LINE_WIDTH
#define DEFAULT_COURTYARD_WIDTH
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
BASE_SET & set(size_t pos)
Definition: base_set.h:116
bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
Container for design settings for a BOARD object.
void SetEnabledLayers(const LSET &aMask)
Change the bit-mask of enabled layers to aMask.
std::shared_ptr< NET_SETTINGS > m_NetSettings
const LSET & GetEnabledLayers() const
Return a bit-mask of all the layers that are enabled.
VECTOR2I GetTextSize(PCB_LAYER_ID aLayer) const
Return the default text size from the layer class for the given layer.
int GetLineThickness(PCB_LAYER_ID aLayer) const
Return the default graphic segment thickness from the layer class for the given layer.
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:280
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:79
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:97
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:317
bool m_LegacyDesignSettingsLoaded
True if the legacy board design settings were loaded from a file.
Definition: board.h:404
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: board.cpp:1147
void SetFileName(const wxString &aFileName)
Definition: board.h:352
bool SetLayerName(PCB_LAYER_ID aLayer, const wxString &aLayerName)
Changes the name of the layer given by aLayer.
Definition: board.cpp:698
bool m_LegacyNetclassesLoaded
True if netclasses were loaded from the file.
Definition: board.h:408
void SetCopperLayerCount(int aCount)
Definition: board.cpp:865
bool SetLayerType(PCB_LAYER_ID aLayer, LAYER_T aLayerType)
Change the type of the layer given by aLayer.
Definition: board.cpp:749
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:1024
constexpr coord_type GetY() const
Definition: box2.h:208
constexpr size_type GetWidth() const
Definition: box2.h:214
constexpr coord_type GetX() const
Definition: box2.h:207
constexpr size_type GetHeight() const
Definition: box2.h:215
double AsDegrees() const
Definition: eda_angle.h:116
void SetCenter(const VECTOR2I &aCenter)
Definition: eda_shape.cpp:956
SHAPE_POLY_SET & GetPolyShape()
Definition: eda_shape.h:337
virtual void SetFilled(bool aFlag)
Definition: eda_shape.h:136
void SetStart(const VECTOR2I &aStart)
Definition: eda_shape.h:177
void SetShape(SHAPE_T aShape)
Definition: eda_shape.h:167
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:219
void SetArcAngleAndEnd(const EDA_ANGLE &aAngle, bool aCheckNegativeAngle=false)
Set the end point from the angle center and start.
Definition: eda_shape.cpp:1108
void SetPolyPoints(const std::vector< VECTOR2I > &aPoints)
Definition: eda_shape.cpp:1780
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:144
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition: eda_text.cpp:533
void SetTextPos(const VECTOR2I &aPoint)
Definition: eda_text.cpp:578
void SetMirrored(bool isMirrored)
Definition: eda_text.cpp:393
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition: eda_text.cpp:417
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition: eda_text.h:197
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:386
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.cpp:284
bool IsMirrored() const
Definition: eda_text.h:187
void SetKeepUpright(bool aKeepUpright)
Definition: eda_text.cpp:425
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition: eda_text.h:200
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:270
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition: eda_text.cpp:299
VECTOR2I GetTextSize() const
Definition: eda_text.h:258
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition: eda_text.cpp:409
void SetPosition(const VECTOR2I &aPos) override
Definition: footprint.cpp:2513
void SetFPID(const LIB_ID &aFPID)
Definition: footprint.h:252
EDA_ANGLE GetOrientation() const
Definition: footprint.h:230
void SetOrientation(const EDA_ANGLE &aNewAngle)
Definition: footprint.cpp:2595
PCB_FIELD & Value()
read/write accessors:
Definition: footprint.h:663
std::deque< PAD * > & Pads()
Definition: footprint.h:209
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: footprint.h:239
const LIB_ID & GetFPID() const
Definition: footprint.h:251
void SetReference(const wxString &aReference)
Definition: footprint.h:633
void SetValue(const wxString &aValue)
Definition: footprint.h:654
PCB_FIELD & Reference()
Definition: footprint.h:664
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: footprint.cpp:1080
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
Definition: footprint.cpp:2454
const wxString & GetValue() const
Definition: footprint.h:649
const wxString & GetReference() const
Definition: footprint.h:627
VECTOR2I GetPosition() const override
Definition: footprint.h:227
virtual bool CanReadLibrary(const wxString &aFileName) const
Checks if this IO object can read the specified library file/directory.
Definition: io_base.cpp:71
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:77
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
virtual void RegisterCallback(LAYER_MAPPING_HANDLER aLayerMappingHandler)
Register a different handler to be called when mapping of input layers to KiCad layers occurs.
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:52
const UTF8 & GetLibItemName() const
Definition: lib_id.h:102
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:37
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition: lset.cpp:591
A collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:45
int GetViaDiameter() const
Definition: netclass.h:133
int GetViaDrill() const
Definition: netclass.h:141
int GetTrackWidth() const
Definition: netclass.h:125
Handle the data for a net.
Definition: netinfo.h:56
void SetNetClass(const std::shared_ptr< NETCLASS > &aNetClass)
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition: netinfo.h:381
T & Get()
Return a reference to the value of the attribute assuming it is available.
Definition: eagle_parser.h:305
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition: padstack.h:145
Definition: pad.h:54
void SetNumber(const wxString &aNumber)
Set the pad number (note that it can be alphanumeric, such as the array reference "AA12").
Definition: pad.h:135
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition: pad.h:462
void SetLocalZoneConnection(ZONE_CONNECTION aType)
Definition: pad.h:485
void SetPosition(const VECTOR2I &aPos) override
Definition: pad.h:202
const VECTOR2I & GetSize(PCB_LAYER_ID aLayer) const
Definition: pad.h:264
void SetPosition(const VECTOR2I &aPos) override
Definition: pcb_track.h:347
void SetMid(const VECTOR2I &aMid)
Definition: pcb_track.h:344
void SetUnits(EDA_UNITS aUnits)
void SetLineThickness(int aWidth)
virtual void SetEnd(const VECTOR2I &aPoint)
void SetPrecision(DIM_PRECISION aPrecision)
virtual void SetStart(const VECTOR2I &aPoint)
void SetOverrideText(const wxString &aValue)
For better understanding of the points that make a dimension:
void SetHeight(int aHeight)
Set the distance from the feature points to the crossbar line.
A leader is a dimension-like object pointing to a specific point.
A radial dimension indicates either the radius or diameter of an arc or circle.
std::vector< ELAYER > ELAYERS
Definition: pcb_io_eagle.h:323
void packageSMD(FOOTPRINT *aFootprint, wxXmlNode *aTree) const
Handles common pad properties.
void loadPlain(wxXmlNode *aPlain)
int m_min_trace
smallest trace we find on Load(), in BIU.
Definition: pcb_io_eagle.h:355
std::map< wxString, PCB_LAYER_ID > m_layer_map
Map of Eagle layers to KiCad layers.
Definition: pcb_io_eagle.h:329
void orientFPText(FOOTPRINT *aFootprint, const EELEMENT &e, PCB_TEXT *aFPText, const EATTR *aAttr)
VECTOR2I kicad_fontsize(const ECOORD &d, int aTextThickness) const
create a font size (fontz) from an eagle font size scalar and KiCad font thickness
std::map< wxString, PCB_LAYER_ID > DefaultLayerMappingCallback(const std::vector< INPUT_LAYER_DESC > &aInputLayerDescriptionVector)
Return the automapped layers.
bool checkHeader(const wxString &aFileName) const
void loadElements(wxXmlNode *aElements)
FOOTPRINT * makeFootprint(wxXmlNode *aPackage, const wxString &aPkgName)
Create a FOOTPRINT from an Eagle package.
int m_min_hole
smallest diameter hole we find on Load(), in BIU.
Definition: pcb_io_eagle.h:356
std::vector< FOOTPRINT * > GetImportedCachedLibraryFootprints() override
Return a container with the cached library footprints generated in the last call to Load.
XPATH * m_xpath
keeps track of what we are working on within XML document during a Load().
Definition: pcb_io_eagle.h:337
unsigned m_totalCount
for progress reporting
Definition: pcb_io_eagle.h:353
void cacheLib(const wxString &aLibraryPath)
This PLUGIN only caches one footprint library, this determines which one.
int m_hole_count
generates unique footprint names from eagle "hole"s.
Definition: pcb_io_eagle.h:340
std::map< wxString, FOOTPRINT * > m_templates
is part of a FOOTPRINT factory that operates using copy construction.
Definition: pcb_io_eagle.h:344
std::map< wxString, int > m_eagleLayersIds
Eagle layer ids stored by layer name.
Definition: pcb_io_eagle.h:328
void mapEagleLayersToKicad(bool aIsLibraryCache=false)
Generate mapping between Eagle and KiCad layers.
std::tuple< PCB_LAYER_ID, LSET, bool > defaultKicadLayer(int aEagleLayer, bool aIsLibraryCache=false) const
Get the default KiCad layer corresponding to an Eagle layer of the board, a set of sensible layer map...
BOARD * LoadBoard(const wxString &aFileName, BOARD *aAppendToMe, const std::map< std::string, UTF8 > *aProperties=nullptr, PROJECT *aProject=nullptr) override
Load information from some input file format that this PCB_IO implementation knows about into either ...
void loadLibraries(wxXmlNode *aLibs)
void init(const std::map< std::string, UTF8 > *aProperties)
initialize PLUGIN like a constructor would, and futz with fresh BOARD if needed.
FOOTPRINT * FootprintLoad(const wxString &aLibraryPath, const wxString &aFootprintName, bool aKeepUUID=false, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Load a footprint having aFootprintName from the aLibraryPath containing a library format that this PC...
int eagle_layer_id(const wxString &aLayerName) const
Get Eagle layer number by its name.
void loadAllSections(wxXmlNode *aDocument)
bool CanReadFootprint(const wxString &aFileName) const override
Checks if this PCB_IO can read a footprint from specified file or directory.
void packageWire(FOOTPRINT *aFootprint, wxXmlNode *aTree) const
bool CanReadBoard(const wxString &aFileName) const override
Checks if this PCB_IO can read the specified board file.
const wxString & eagle_layer_name(int aLayer) const
Get Eagle layer name by its number.
ELAYERS::const_iterator EITER
Definition: pcb_io_eagle.h:324
void packageRectangle(FOOTPRINT *aFootprint, wxXmlNode *aTree) const
int kicad_y(const ECOORD &y) const
Convert an Eagle distance to a KiCad distance.
Definition: pcb_io_eagle.h:197
void loadClasses(wxXmlNode *aClasses)
std::map< int, ELAYER > m_eagleLayers
Eagle layer data stored by layer number.
Definition: pcb_io_eagle.h:327
wxString m_customRules
Definition: pcb_io_eagle.h:334
NET_MAP m_pads_to_nets
net list
Definition: pcb_io_eagle.h:342
void packageText(FOOTPRINT *aFootprint, wxXmlNode *aTree) const
int getMinimumCopperLayerCount() const
Determines the minimum copper layer stackup count that includes all mapped layers.
void packageHole(FOOTPRINT *aFootprint, wxXmlNode *aTree, bool aCenter) const
void packagePolygon(FOOTPRINT *aFootprint, wxXmlNode *aTree) const
void centerBoard()
move the BOARD into the center of the page
unsigned m_lastProgressCount
Definition: pcb_io_eagle.h:352
int m_cu_map[17]
map eagle to KiCad, cu layers only.
Definition: pcb_io_eagle.h:326
ZONE * loadPolygon(wxXmlNode *aPolyNode)
Load a copper or keepout polygon and adds it to the board.
int m_min_via
smallest via we find on Load(), in BIU.
Definition: pcb_io_eagle.h:357
bool CanReadLibrary(const wxString &aFileName) const override
Checks if this IO object can read the specified library file/directory.
void clear_cu_map()
void packageCircle(FOOTPRINT *aFootprint, wxXmlNode *aTree) const
void loadLibrary(wxXmlNode *aLib, const wxString *aLibName)
Load the Eagle "library" XML element, which can occur either under a "libraries" element (if a *....
void packagePad(FOOTPRINT *aFootprint, wxXmlNode *aTree)
void loadSignals(wxXmlNode *aSignals)
ERULES * m_rules
Eagle design rules.
Definition: pcb_io_eagle.h:336
PCB_LAYER_ID kicad_layer(int aLayer) const
Convert an Eagle layer to a KiCad layer.
void orientFootprintAndText(FOOTPRINT *aFootprint, const EELEMENT &e, const EATTR *aNameAttr, const EATTR *aValueAttr)
long long GetLibraryTimestamp(const wxString &aLibraryPath) const override
Generate a timestamp representing all the files in the library (including the library directory).
int m_min_annulus
smallest via annulus we find on Load(), in BIU.
Definition: pcb_io_eagle.h:358
void loadLayerDefs(wxXmlNode *aLayers)
void FootprintEnumerate(wxArrayString &aFootprintNames, const wxString &aLibraryPath, bool aBestEfforts, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Return a list of footprint names contained within the library at aLibraryPath.
void setKeepoutSettingsToZone(ZONE *aZone, int aLayer) const
void transferPad(const EPAD_COMMON &aEaglePad, PAD *aPad) const
Deletes the footprint templates list.
void deleteTemplates()
int kicad_x(const ECOORD &x) const
Definition: pcb_io_eagle.h:198
void loadDesignRules(wxXmlNode *aDesignRules)
PROGRESS_REPORTER * m_progressReporter
optional; may be nullptr
Definition: pcb_io_eagle.h:350
unsigned m_doneCount
Definition: pcb_io_eagle.h:351
A base class that BOARD loading and saving plugins should derive from.
Definition: pcb_io.h:71
BOARD * m_board
The board BOARD being worked on, no ownership here.
Definition: pcb_io.h:324
virtual bool CanReadBoard(const wxString &aFileName) const
Checks if this PCB_IO can read the specified board file.
Definition: pcb_io.cpp:42
const std::map< std::string, UTF8 > * m_props
Properties passed via Save() or Load(), no ownership, may be NULL.
Definition: pcb_io.h:327
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_shape.h:81
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
Definition: pcb_shape.cpp:564
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition: pcb_shape.cpp:176
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: pcb_shape.cpp:471
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: pcb_shape.h:92
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: pcb_text.cpp:346
virtual void SetPosition(const VECTOR2I &aPos) override
Definition: pcb_text.h:89
void SetEnd(const VECTOR2I &aEnd)
Definition: pcb_track.h:148
void SetPosition(const VECTOR2I &aPos) override
Definition: pcb_track.h:141
virtual void SetWidth(int aWidth)
Definition: pcb_track.h:145
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void Report(const wxString &aMessage)=0
Display aMessage in the progress bar dialog.
virtual void SetCurrentProgress(double aProgress)=0
Set the progress value to aProgress (0..1).
Container for project specific data.
Definition: project.h:65
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
Represent a set of closed polygons.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
int NewOutline()
Creates a new empty polygon in the set and returns its index.
int OutlineCount() const
Return the number of outlines in the set.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
Simple container to manage line stroke parameters.
Definition: stroke_params.h:94
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
Definition: utf8.h:72
bool empty() const
Definition: utf8.h:110
const char * c_str() const
Definition: utf8.h:109
double Distance(const VECTOR2< extended_type > &aVector) const
Compute the distance between two vectors.
Definition: vector2d.h:561
T y
Definition: vector3.h:64
T x
Definition: vector3.h:63
static REPORTER & GetInstance()
Definition: reporter.cpp:202
Keep track of what we are working on within a PTREE.
Definition: eagle_parser.h:124
void pop()
Definition: eagle_parser.h:135
void clear()
Definition: eagle_parser.h:133
void push(const char *aPathSegment, const char *aAttribute="")
Definition: eagle_parser.h:128
wxString Contents()
Return the contents of the XPATH as a single string.
Definition: eagle_parser.h:150
Handle a list of polygons defining a copper zone.
Definition: zone.h:74
void SetDoNotAllowPads(bool aEnable)
Definition: zone.h:728
void SetBorderDisplayStyle(ZONE_BORDER_DISPLAY_STYLE aBorderHatchStyle, int aBorderHatchPitch, bool aRebuilBorderdHatch)
Set all hatch parameters for the zone.
Definition: zone.cpp:1225
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition: zone.cpp:505
SHAPE_POLY_SET * Outline()
Definition: zone.h:335
void NewHole()
Create a new hole on the zone; i.e., a new contour on the zone's outline.
Definition: zone.h:573
void SetIsRuleArea(bool aEnable)
Definition: zone.h:705
void SetDoNotAllowTracks(bool aEnable)
Definition: zone.h:727
void Rotate(const VECTOR2I &aCentre, const EDA_ANGLE &aAngle) override
Rotate the outlines.
Definition: zone.cpp:1031
void SetLayerSet(const LSET &aLayerSet) override
Definition: zone.cpp:511
void SetDoNotAllowVias(bool aEnable)
Definition: zone.h:726
void SetDoNotAllowFootprints(bool aEnable)
Definition: zone.h:729
bool AppendCorner(VECTOR2I aPosition, int aHoleIdx, bool aAllowDuplication=false)
Add a new corner to the zone outline (to the main outline or a hole)
Definition: zone.cpp:1134
void SetDoNotAllowZoneFills(bool aEnable)
Definition: zone.h:725
static int GetDefaultHatchPitch()
Definition: zone.cpp:1281
static void SetReporter(REPORTER *aReporter)
Set the reporter to use for reporting font substitution warnings.
Definition: fontconfig.cpp:64
NODE_MAP MapChildren(wxXmlNode *aCurrentNode)
Provide an easy access to the children of an XML node via their names.
wxString escapeName(const wxString &aNetName)
Translates Eagle special characters to their counterparts in KiCad.
wxString interpretText(const wxString &aText)
Interprets special characters in Eagle text and converts them to KiCAD notation.
VECTOR2I ConvertArcCenter(const VECTOR2I &aStart, const VECTOR2I &aEnd, double aAngle)
Convert an Eagle curve end to a KiCad center for S_ARC.
wxString convertDescription(wxString aDescr)
Converts Eagle's HTML description into KiCad description format.
OPTIONAL_XML_ATTRIBUTE< wxString > opt_wxString
Definition: eagle_parser.h:391
std::unordered_map< wxString, wxXmlNode * > NODE_MAP
Definition: eagle_parser.h:54
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:411
@ DEGREES_T
Definition: eda_angle.h:31
static constexpr EDA_ANGLE FULL_CIRCLE
Definition: eda_angle.h:409
static constexpr EDA_ANGLE ANGLE_360
Definition: eda_angle.h:417
#define IGNORE_PARENT_GROUP
Definition: eda_item.h:55
a few functions useful in geometry calculations.
int GetArcToSegmentCount(int aRadius, int aErrorMax, const EDA_ANGLE &aArcAngle)
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:39
PCB_LAYER_ID BoardLayerFromLegacyId(int aLegacyId)
Retrieve a layer ID from an integer converted from a legacy (pre-V9) enum value.
Definition: layer_id.cpp:216
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition: layer_ids.h:665
size_t CopperLayerToOrdinal(PCB_LAYER_ID aLayer)
Converts KiCad copper layer enum to an ordinal between the front and back layers.
Definition: layer_ids.h:894
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ F_CrtYd
Definition: layer_ids.h:116
@ B_Adhes
Definition: layer_ids.h:103
@ Edge_Cuts
Definition: layer_ids.h:112
@ Dwgs_User
Definition: layer_ids.h:107
@ F_Paste
Definition: layer_ids.h:104
@ Cmts_User
Definition: layer_ids.h:108
@ F_Adhes
Definition: layer_ids.h:102
@ B_Mask
Definition: layer_ids.h:98
@ B_Cu
Definition: layer_ids.h:65
@ Eco1_User
Definition: layer_ids.h:109
@ F_Mask
Definition: layer_ids.h:97
@ B_Paste
Definition: layer_ids.h:105
@ UNSELECTED_LAYER
Definition: layer_ids.h:62
@ F_Fab
Definition: layer_ids.h:119
@ F_SilkS
Definition: layer_ids.h:100
@ B_CrtYd
Definition: layer_ids.h:115
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ Eco2_User
Definition: layer_ids.h:110
@ B_SilkS
Definition: layer_ids.h:101
@ PCB_LAYER_ID_COUNT
Definition: layer_ids.h:171
@ F_Cu
Definition: layer_ids.h:64
@ B_Fab
Definition: layer_ids.h:118
KICOMMON_API wxString StringFromValue(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, double aValue, bool aAddUnitsText=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Return the string from aValue according to aUnits (inch, mm ...) for display.
Definition: eda_units.cpp:310
STL namespace.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:400
static wxString makeKey(const wxString &aFirst, const wxString &aSecond)
Assemble a two part key as a simple concatenation of aFirst and aSecond parts, using a separator.
#define DIMENSION_PRECISION
static int parseEagle(const wxString &aDistance)
Parse an eagle distance which is either mm, or mils if there is "mil" suffix.
static T eagleClamp(T aMin, T aValue, T aMax)
std::vector< ZONE * > ZONES
Definition: pcb_io_eagle.h:47
NET_MAP::const_iterator NET_MAP_CITER
Definition: pcb_io_eagle.h:49
bool ReplaceIllegalFileNameChars(std::string *aName, int aReplaceChar)
Checks aName for illegal file name characters.
wxString UnescapeHTML(const wxString &aString)
Return a new wxString unescaped from HTML format.
Parse an Eagle "attribute" XML element.
Definition: eagle_parser.h:834
opt_double ratio
Definition: eagle_parser.h:862
opt_wxString value
Definition: eagle_parser.h:856
opt_ecoord size
Definition: eagle_parser.h:859
opt_ecoord y
Definition: eagle_parser.h:858
wxString name
Definition: eagle_parser.h:855
opt_erot rot
Definition: eagle_parser.h:863
opt_int align
Definition: eagle_parser.h:874
opt_int display
Definition: eagle_parser.h:873
opt_ecoord x
Definition: eagle_parser.h:857
Eagle circle.
Definition: eagle_parser.h:760
ECOORD x
Definition: eagle_parser.h:772
ECOORD radius
Definition: eagle_parser.h:774
ECOORD y
Definition: eagle_parser.h:773
ECOORD width
Definition: eagle_parser.h:775
wxString number
wxString name
@ EU_MM
millimeters
Definition: eagle_parser.h:486
@ EU_MIL
mils/thous
Definition: eagle_parser.h:488
long long int value
Value expressed in nanometers.
Definition: eagle_parser.h:492
int ToPcbUnits() const
Definition: eagle_parser.h:530
const double IU_PER_MM
Definition: base_units.h:76
const double IU_PER_MILS
Definition: base_units.h:77
constexpr int mmToIU(double mm) const
Definition: base_units.h:92
Eagle dimension element.
Definition: eagle_parser.h:885
opt_wxString dimensionType
Definition: eagle_parser.h:917
opt_ecoord textsize
Definition: eagle_parser.h:915
Eagle element element.
opt_erot rot
wxString name
wxString library
wxString package
ECOORD y
opt_bool smashed
ECOORD x
wxString value
opt_eurn library_urn
Eagle hole element.
ECOORD y
ECOORD drill
ECOORD x
wxString name
opt_bool active
int number
Eagle net.
Definition: eagle_parser.h:554
int netcode
Definition: eagle_parser.h:563
Structure holding common properties for through-hole and SMD pads.
opt_bool thermals
opt_bool stop
wxString name
opt_erot rot
Eagle thru hole pad.
opt_ecoord diameter
opt_bool first
opt_ecoord drill
opt_int shape
Eagle polygon, without vertices which are parsed as needed.
opt_bool orphans
opt_int rank
opt_bool thermals
opt_ecoord spacing
static const int max_priority
ECOORD width
opt_ecoord isolate
Eagle XML rectangle in binary.
Definition: eagle_parser.h:786
ECOORD x2
Definition: eagle_parser.h:801
ECOORD y1
Definition: eagle_parser.h:800
opt_erot rot
Definition: eagle_parser.h:804
int layer
Definition: eagle_parser.h:803
ECOORD y2
Definition: eagle_parser.h:802
ECOORD x1
Definition: eagle_parser.h:799
double degrees
Definition: eagle_parser.h:585
bool spin
Definition: eagle_parser.h:584
bool mirror
Definition: eagle_parser.h:583
subset of eagle.drawing.board.designrules in the XML document
Definition: pcb_io_eagle.h:54
int psBottom
Shape of the bottom pads.
Definition: pcb_io_eagle.h:104
int psElongationLong
Definition: pcb_io_eagle.h:89
double mvStopFrame
solderpaste mask, expressed as percentage of the smaller pad/via dimension
Definition: pcb_io_eagle.h:94
double srRoundness
corner rounding ratio for SMD pads (percentage)
Definition: pcb_io_eagle.h:107
double rlMinViaOuter
minimum copper annulus on via
Definition: pcb_io_eagle.h:122
int mlMaxCreamFrame
solder paste mask, maximum size (Eagle mils, here nanometers)
Definition: pcb_io_eagle.h:101
int mlMinCreamFrame
solder paste mask, minimum size (Eagle mils, here nanometers)
Definition: pcb_io_eagle.h:100
int psTop
Shape of the top pads.
Definition: pcb_io_eagle.h:103
double rlMaxViaOuter
maximum copper annulus on via
Definition: pcb_io_eagle.h:123
void parse(wxXmlNode *aRules, std::function< void()> aCheckpoint)
percent over 100%.
double mdWireWire
wire to wire spacing I presume.
Definition: pcb_io_eagle.h:124
double rvPadTop
top pad size as percent of drill size
Definition: pcb_io_eagle.h:115
int srMaxRoundness
Definition: pcb_io_eagle.h:113
double rvViaOuter
copper annulus is this percent of via hole
Definition: pcb_io_eagle.h:121
double rlMinPadTop
minimum copper annulus on through hole pads
Definition: pcb_io_eagle.h:118
double mvCreamFrame
Definition: pcb_io_eagle.h:97
int psElongationOffset
the offset of the hole within the "long" pad.
Definition: pcb_io_eagle.h:91
int mlMinStopFrame
solder mask, minimum size (Eagle mils, here nanometers)
Definition: pcb_io_eagle.h:98
int srMinRoundness
corner rounding radius, maximum size (Eagle mils, here nanometers)
Definition: pcb_io_eagle.h:110
int mlMaxStopFrame
solder mask, maximum size (Eagle mils, here nanometers)
Definition: pcb_io_eagle.h:99
double rlMaxPadTop
maximum copper annulus on through hole pads
Definition: pcb_io_eagle.h:119
int psFirst
Shape of the first pads.
Definition: pcb_io_eagle.h:105
Eagle SMD pad.
opt_int roundness
ECOORD dx
int layer
opt_bool cream
ECOORD dy
Eagle text element.
Definition: eagle_parser.h:935
opt_double ratio
Definition: eagle_parser.h:957
wxString text
Definition: eagle_parser.h:951
ECOORD y
Definition: eagle_parser.h:953
ECOORD size
Definition: eagle_parser.h:954
opt_erot rot
Definition: eagle_parser.h:958
opt_int align
Definition: eagle_parser.h:974
ECOORD x
Definition: eagle_parser.h:952
@ BOTTOM_CENTER
Definition: eagle_parser.h:969
@ BOTTOM_RIGHT
Definition: eagle_parser.h:971
@ TOP_CENTER
Definition: eagle_parser.h:963
@ TOP_LEFT
Definition: eagle_parser.h:964
@ TOP_RIGHT
Definition: eagle_parser.h:965
@ CENTER_RIGHT
Definition: eagle_parser.h:968
@ CENTER_LEFT
Definition: eagle_parser.h:962
@ BOTTOM_LEFT
Definition: eagle_parser.h:970
int layer
Definition: eagle_parser.h:955
wxString assetId
The unique asset identifier for the asset type.
Definition: eagle_parser.h:452
Eagle vertex.
Definition: eagle_parser.h:603
Eagle via.
Definition: eagle_parser.h:729
opt_ecoord diam
Definition: eagle_parser.h:748
ECOORD drill
< inclusive
Definition: eagle_parser.h:747
ECOORD y
Definition: eagle_parser.h:744
int layer_front_most
Definition: eagle_parser.h:745
int layer_back_most
< extent
Definition: eagle_parser.h:746
ECOORD x
Definition: eagle_parser.h:743
Eagle wire.
Definition: eagle_parser.h:623
ECOORD width
Definition: eagle_parser.h:646
int layer
Definition: eagle_parser.h:647
ECOORD x2
Definition: eagle_parser.h:644
ECOORD y2
Definition: eagle_parser.h:645
ECOORD x1
Definition: eagle_parser.h:642
ECOORD y1
Definition: eagle_parser.h:643
opt_double curve
range is -359.9..359.9
Definition: eagle_parser.h:657
Describes an imported layer and how it could be mapped to KiCad Layers.
PCB_LAYER_ID AutoMapLayer
Best guess as to what the equivalent KiCad layer might be.
bool Required
Should we require the layer to be assigned?
LSET PermittedLayers
KiCad layers that the imported layer can be mapped onto.
wxString Name
Imported layer name as displayed in original application.
Implement a simple wrapper around runtime_error to isolate the errors thrown by the Eagle XML parser.
Definition: eagle_parser.h:82
VECTOR3I v1(5, 5, 5)
VECTOR2I center
int radius
VECTOR2I end
VECTOR2I v2(1, 0)
int delta
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
const VECTOR2I CalcArcMid(const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter, bool aMinArcAngle=true)
Return the middle point of an arc, half-way between aStart and aEnd.
Definition: trigo.cpp:209
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:229
double DEG2RAD(double deg)
Definition: trigo.h:166
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:101
constexpr int sign(T val)
Definition: util.h:145
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695
ZONE_BORDER_DISPLAY_STYLE
Zone border styles.
Definition: zone_settings.h:59
#define ZONE_THICKNESS_MIN_VALUE_MM
Definition: zones.h:36