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