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