KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_io_easyeda_parser.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) 2023 Alex Shvartzkop <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
22
23#include <memory>
24
25#include <json_common.h>
26#include <core/map_helpers.h>
28#include <string_utils.h>
29
30#include <wx/log.h>
31
32#include <font/font.h>
33#include <footprint.h>
34#include <progress_reporter.h>
35#include <board.h>
38#include <bezier_curves.h>
39#include <pcb_group.h>
40#include <pcb_track.h>
41#include <pcb_shape.h>
42#include <pcb_text.h>
43#include <zone.h>
44#include <pad.h>
45#include <project.h>
46#include <fix_board_shape.h>
47
48
49static const wxString DIRECT_MODEL_UUID_KEY = wxS( "JLC_3DModel" );
50static const wxString MODEL_SIZE_KEY = wxS( "JLC_3D_Size" );
51
52static const int SHAPE_JOIN_DISTANCE = pcbIUScale.mmToIU( 1.5 );
53static const VECTOR2I HIDDEN_TEXT_SIZE( pcbIUScale.mmToIU( 0.5 ), pcbIUScale.mmToIU( 0.5 ) );
54
55
59
63
65{
66 int elayer = wxAtoi( aLayer );
67
68 switch( elayer )
69 {
70 case 1: return F_Cu;
71 case 2: return B_Cu;
72 case 3: return F_SilkS;
73 case 4: return B_SilkS;
74 case 5: return F_Paste;
75 case 6: return B_Paste;
76 case 7: return F_Mask;
77 case 8: return B_Mask;
78 /*case 9: return UNDEFINED_LAYER;*/ // Ratsnest
79 case 10: return Edge_Cuts;
80 case 11: return Eco1_User;
81 case 12: return Dwgs_User;
82 case 13: return F_Fab;
83 case 14: return B_Fab;
84 case 15: return Eco2_User;
85
86 case 19: return F_Fab; // 3D model
87
88 case 21: return In1_Cu;
89 case 22: return In2_Cu;
90 case 23: return In3_Cu;
91 case 24: return In4_Cu;
92 case 25: return In5_Cu;
93 case 26: return In6_Cu;
94 case 27: return In7_Cu;
95 case 28: return In8_Cu;
96 case 29: return In9_Cu;
97 case 30: return In10_Cu;
98 case 31: return In11_Cu;
99 case 32: return In12_Cu;
100 case 33: return In13_Cu;
101 case 34: return In14_Cu;
102 case 35: return In15_Cu;
103 case 36: return In16_Cu;
104 case 37: return In17_Cu;
105 case 38: return In18_Cu;
106 case 39: return In19_Cu;
107 case 40: return In20_Cu;
108 case 41: return In21_Cu;
109 case 42: return In22_Cu;
110 case 43: return In23_Cu;
111 case 44: return In24_Cu;
112 case 45: return In25_Cu;
113 case 46: return In26_Cu;
114 case 47: return In27_Cu;
115 case 48: return In28_Cu;
116 case 49: return In29_Cu;
117 case 50: return In30_Cu;
118
119 case 99: return User_3;
120 case 100: return User_4;
121 case 101: return User_5;
122
123 default: break;
124 }
125
126 return User_1;
127}
128
129
130static LIB_ID EasyEdaToKiCadLibID( const wxString& aLibName, const wxString& aLibReference )
131{
132 wxString libReference = EscapeString( aLibReference, CTX_LIBID );
133
134 wxString key = !aLibName.empty() ? ( aLibName + ':' + libReference ) : libReference;
135
136 LIB_ID libId;
137 libId.Parse( key, true );
138
139 return libId;
140}
141
142
144 BOARD_ITEM_CONTAINER* aContainer, BOARD* aParent, std::map<wxString, wxString> paramMap,
145 std::map<wxString, std::unique_ptr<FOOTPRINT>>& aFootprintMap, wxArrayString aShapes )
146{
147 // TODO: make this path configurable?
148 const wxString easyedaModelDir = wxS( "EASYEDA_MODELS" );
149 wxString kicadModelPrefix = wxS( "${KIPRJMOD}/" ) + easyedaModelDir + wxS( "/" );
150
151 BOARD* board = aParent ? aParent : dynamic_cast<BOARD*>( aContainer );
152 FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aContainer );
153
154 auto getOrAddNetItem =
155 [&]( const wxString& aNetName ) -> NETINFO_ITEM*
156 {
157 if( !board )
158 return nullptr;
159
160 if( aNetName.empty() )
161 return nullptr;
162
163 if( NETINFO_ITEM* item = board->FindNet( aNetName ) )
164 {
165 return item;
166 }
167 else
168 {
169 item = new NETINFO_ITEM( board, aNetName, board->GetNetCount() + 1 );
170 board->Add( item, ADD_MODE::APPEND );
171 return item;
172 }
173 };
174
175 if( footprint )
176 {
177 // TODO: library name
178 LIB_ID fpID = EasyEdaToKiCadLibID( wxEmptyString, paramMap[wxS( "package" )] );
179 footprint->SetFPID( fpID );
180 }
181
182 for( wxString shape : aShapes )
183 {
184 wxArrayString arr = wxSplit( shape, '~', '\0' );
185
186 wxString elType = arr[0];
187 if( elType == wxS( "LIB" ) )
188 {
189 shape.Replace( wxS( "#@$" ), "\n" );
190 wxArrayString parts = wxSplit( shape, '\n', '\0' );
191
192 if( parts.size() < 1 )
193 continue;
194
195 wxArrayString paramsRoot = wxSplit( parts[0], '~', '\0' );
196
197 if( paramsRoot.size() < 4 )
198 continue;
199
200 VECTOR2D fpOrigin( Convert( paramsRoot[1] ), Convert( paramsRoot[2] ) );
201
202 wxString packageName =
203 wxString::Format( wxS( "Unknown_%s_%s" ), paramsRoot[1], paramsRoot[2] );
204
205 wxArrayString paramParts = wxSplit( paramsRoot[3], '`', '\0' );
206
207 EDA_ANGLE orientation;
208 if( !paramsRoot[4].IsEmpty() )
209 orientation = EDA_ANGLE( Convert( paramsRoot[4] ), DEGREES_T ); // Already applied
210
211 int layer = 1;
212
213 if( !paramsRoot[7].IsEmpty() )
214 layer = Convert( paramsRoot[7] );
215
216 std::map<wxString, wxString> innerParamMap;
217
218 for( int i = 1; i < (int) paramParts.size(); i += 2 )
219 {
220 wxString key = paramParts[i - 1];
221 wxString value = paramParts[i];
222
223 if( key == wxS( "package" ) )
224 packageName = value;
225
226 innerParamMap[key] = value;
227 }
228
229 parts.RemoveAt( 0 );
230
231 VECTOR2D pcbOrigin = m_relOrigin;
232 std::unique_ptr<FOOTPRINT> fp =
233 ParseFootprint( fpOrigin, orientation, layer, board, innerParamMap, aFootprintMap, parts );
234
235 if( !fp )
236 continue;
237
238 m_relOrigin = pcbOrigin;
239
240 fp->Move( RelPos( fpOrigin ) );
241
242 aContainer->Add( fp.release(), ADD_MODE::APPEND );
243 }
244 else if( elType == wxS( "TRACK" ) )
245 {
246 double width = ConvertSize( arr[1] );
247 PCB_LAYER_ID layer = LayerToKi( arr[2] );
248 wxString netname = arr[3];
249 wxArrayString data = wxSplit( arr[4], ' ', '\0' );
250
251 for( int i = 3; i < (int) data.size(); i += 2 )
252 {
253 VECTOR2D start, end;
254 start.x = RelPosX( data[i - 3] );
255 start.y = RelPosY( data[i - 2] );
256 end.x = RelPosX( data[i - 1] );
257 end.y = RelPosY( data[i] );
258
259 if( !footprint && IsCopperLayer( layer ) )
260 {
261 std::unique_ptr<PCB_TRACK> track = std::make_unique<PCB_TRACK>( aContainer );
262
263 track->SetLayer( layer );
264 track->SetWidth( width );
265 track->SetStart( start );
266 track->SetEnd( end );
267 track->SetNet( getOrAddNetItem( netname ) );
268
269 aContainer->Add( track.release(), ADD_MODE::APPEND );
270 }
271 else
272 {
273 std::unique_ptr<PCB_SHAPE> seg =
274 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::SEGMENT );
275
276 seg->SetLayer( layer );
277 seg->SetWidth( width );
278 seg->SetStart( start );
279 seg->SetEnd( end );
280
281 aContainer->Add( seg.release(), ADD_MODE::APPEND );
282 }
283 }
284 }
285 else if( elType == wxS( "CIRCLE" ) )
286 {
287 auto circleShape = std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::CIRCLE );
288 double width = ConvertSize( arr[4] );
289 circleShape->SetWidth( width );
290
291 PCB_LAYER_ID layer = LayerToKi( arr[5] );
292 circleShape->SetLayer( layer );
293
295 center.x = RelPosX( arr[1] );
296 center.y = RelPosY( arr[2] );
297
298 double radius = ConvertSize( arr[3] );
299
300 circleShape->SetCenter( center );
301 circleShape->SetEnd( center + VECTOR2I( radius, 0 ) );
302
303 if( IsCopperLayer( layer ) )
304 circleShape->SetNet( getOrAddNetItem( arr[8] ) );
305
306 aContainer->Add( circleShape.release(), ADD_MODE::APPEND );
307 }
308 else if( elType == wxS( "RECT" ) )
309 {
310 auto rectShape = std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::RECTANGLE );
311 double width = ConvertSize( arr[8] );
312 rectShape->SetWidth( width );
313
314 PCB_LAYER_ID layer = LayerToKi( arr[5] );
315 rectShape->SetLayer( layer );
316
317 bool filled = arr[9] != wxS( "none" );
318 rectShape->SetFilled( filled );
319
320 VECTOR2D rectStart;
321 rectStart.x = RelPosX( arr[1] );
322 rectStart.y = RelPosY( arr[2] );
323
324 VECTOR2D rectSize;
325 rectSize.x = ConvertSize( arr[3] );
326 rectSize.y = ConvertSize( arr[4] );
327
328 rectShape->SetStart( rectStart );
329 rectShape->SetEnd( rectStart + rectSize );
330
331 if( IsCopperLayer( layer ) )
332 rectShape->SetNet( getOrAddNetItem( arr[11] ) );
333
334 aContainer->Add( rectShape.release(), ADD_MODE::APPEND );
335 }
336 else if( elType == wxS( "ARC" ) )
337 {
338 std::unique_ptr<PCB_SHAPE> arcShape =
339 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::ARC );
340
341 double arcWidth = ConvertSize( arr[1] );
342 arcShape->SetWidth( arcWidth );
343
344 PCB_LAYER_ID layer = LayerToKi( arr[2] );
345 arcShape->SetLayer( layer );
346
347 if( IsCopperLayer( layer ) )
348 arcShape->SetNet( getOrAddNetItem( arr[3] ) );
349
350 VECTOR2D arcStart, arcEnd;
351 VECTOR2D rad( 10, 10 );
352 bool isFar = false;
353 bool cw = false;
354
355 int pos = 0;
356 wxString data = arr[4];
357 auto readNumber = [&]( wxString& aOut )
358 {
359 wxUniChar ch = data[pos];
360
361 while( ch == ' ' || ch == ',' )
362 ch = data[++pos];
363
364 while( isdigit( ch ) || ch == '.' || ch == '-' )
365 {
366 aOut += ch;
367 pos++;
368
369 if( pos == (int) data.size() )
370 break;
371
372 ch = data[pos];
373 }
374 };
375
376 do
377 {
378 wxUniChar sym = data[pos++];
379
380 if( sym == 'M' )
381 {
382 wxString xStr, yStr;
383 readNumber( xStr );
384 readNumber( yStr );
385
386 arcStart = VECTOR2D( Convert( xStr ), Convert( yStr ) );
387 }
388 else if( sym == 'A' )
389 {
390 wxString radX, radY, unknown, farFlag, cwFlag, endX, endY;
391 readNumber( radX );
392 readNumber( radY );
393 readNumber( unknown );
394 readNumber( farFlag );
395 readNumber( cwFlag );
396 readNumber( endX );
397 readNumber( endY );
398
399 isFar = farFlag == wxS( "1" );
400 cw = cwFlag == wxS( "1" );
401 rad = VECTOR2D( Convert( radX ), Convert( radY ) );
402 arcEnd = VECTOR2D( Convert( endX ), Convert( endY ) );
403 }
404 } while( pos < (int) data.size() );
405
406 VECTOR2D delta = arcEnd - arcStart;
407
408 double d = delta.EuclideanNorm();
409 double h = sqrt( std::max( 0.0, rad.x * rad.x - d * d / 4 ) );
410
411 //( !far && cw ) => h
412 //( far && cw ) => -h
413 //( !far && !cw ) => -h
414 //( far && !cw ) => h
415 VECTOR2D arcCenter =
416 arcStart + delta / 2 + delta.Perpendicular().Resize( ( isFar ^ cw ) ? h : -h );
417
418 if( !cw )
419 std::swap( arcStart, arcEnd );
420
421 arcShape->SetStart( RelPos( arcStart ) );
422 arcShape->SetEnd( RelPos( arcEnd ) );
423 arcShape->SetCenter( RelPos( arcCenter ) );
424
425 aContainer->Add( arcShape.release(), ADD_MODE::APPEND );
426 }
427 else if( elType == wxS( "DIMENSION" ) )
428 {
429 PCB_LAYER_ID layer = LayerToKi( arr[1] );
430 double lineWidth = ConvertSize( arr[7] );
431 wxString shapeData = arr[2].Trim();
432 //double textHeight = !arr[4].IsEmpty() ? ConvertSize( arr[4] ) : 0;
433
434 std::vector<SHAPE_LINE_CHAIN> lineChains =
436
437 std::unique_ptr<PCB_GROUP> group = std::make_unique<PCB_GROUP>( aContainer );
438 group->SetName( wxS( "Dimension" ) );
439
440 for( const SHAPE_LINE_CHAIN& chain : lineChains )
441 {
442 for( int segId = 0; segId < chain.SegmentCount(); segId++ )
443 {
444 SEG seg = chain.CSegment( segId );
445 auto dimSeg = std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::SEGMENT );
446
447 dimSeg->SetLayer( layer );
448 dimSeg->SetWidth( lineWidth );
449 dimSeg->SetStart( seg.A );
450 dimSeg->SetEnd( seg.B );
451
452 group->AddItem( dimSeg.get() );
453
454 aContainer->Add( dimSeg.release(), ADD_MODE::APPEND );
455 }
456 }
457
458 aContainer->Add( group.release(), ADD_MODE::APPEND );
459 }
460 else if( elType == wxS( "SOLIDREGION" ) )
461 {
462 wxString layer = arr[1];
463
464 SHAPE_POLY_SET polySet =
465 ParseLineChains( arr[3].Trim(), SHAPE_ARC::DefaultAccuracyForPCB(), true );
466
467 bool validPolySet = polySet.OutlineCount() > 0;
468
469 for( const SHAPE_POLY_SET::POLYGON& polygon : polySet.CPolygons() )
470 {
471 for( const SHAPE_LINE_CHAIN& contour : polygon )
472 validPolySet &= contour.PointCount() >= 3;
473 }
474
475 if( !validPolySet )
476 continue;
477
478 if( layer == wxS( "11" ) ) // Multi-layer (board cutout)
479 {
480 for( const SHAPE_POLY_SET::POLYGON& poly : polySet.CPolygons() )
481 {
482 auto cutoutShape = std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::POLY );
483
484 cutoutShape->SetLayer( Edge_Cuts );
485 cutoutShape->SetFilled( false );
486 cutoutShape->SetWidth( pcbIUScale.mmToIU( 0.1 ) );
487 cutoutShape->SetPolyShape( poly );
488
489 aContainer->Add( cutoutShape.release(), ADD_MODE::APPEND );
490 }
491 }
492 else
493 {
494 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aContainer );
495
496 PCB_LAYER_ID klayer = LayerToKi( layer );
497 zone->SetLayer( klayer );
498
499 if( IsCopperLayer( klayer ) )
500 zone->SetNet( getOrAddNetItem( arr[2] ) );
501
502 for( const SHAPE_POLY_SET::POLYGON& poly : polySet.CPolygons() )
503 zone->Outline()->AddPolygon( poly );
504
505 if( zone->GetNumCorners() == 0 )
506 continue;
507
508 if( arr[4].Lower() == wxS( "cutout" ) )
509 {
510 zone->SetIsRuleArea( true );
511 zone->SetDoNotAllowZoneFills( true );
512 zone->SetDoNotAllowTracks( false );
513 zone->SetDoNotAllowVias( false );
514 zone->SetDoNotAllowPads( false );
515 zone->SetDoNotAllowFootprints( false );
516 }
517 else
518 { // solid
519 zone->SetFilledPolysList( klayer, polySet );
520 zone->SetPadConnection( ZONE_CONNECTION::FULL );
521 zone->SetIsFilled( true );
522 zone->SetNeedRefill( false );
523 }
524
525 zone->SetMinThickness( 0 );
526 zone->SetLocalClearance( 0 );
527 zone->SetAssignedPriority( 100 );
528
529 aContainer->Add( zone.release(), ADD_MODE::APPEND );
530 }
531 }
532 else if( elType == wxS( "COPPERAREA" ) )
533 {
534 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aContainer );
535
536 PCB_LAYER_ID layer = LayerToKi( arr[2] );
537 zone->SetLayer( layer );
538
539 wxString netname = arr[3];
540
541 if( IsCopperLayer( layer ) )
542 zone->SetNet( getOrAddNetItem( netname ) );
543
544 zone->SetLocalClearance( ConvertSize( arr[5] ) );
545 zone->SetThermalReliefGap( zone->GetLocalClearance().value() );
546
547 wxString fillStyle = arr[5];
548 if( fillStyle == wxS( "none" ) )
549 {
550 // Do not fill?
551 }
552
553 SHAPE_POLY_SET polySet =
554 ParseLineChains( arr[4].Trim(), SHAPE_ARC::DefaultAccuracyForPCB(), true );
555
556 for( const SHAPE_POLY_SET::POLYGON& poly : polySet.CPolygons() )
557 zone->Outline()->AddPolygon( poly );
558
559 wxString thermal = arr[8];
560 if( thermal == wxS( "direct" ) )
561 zone->SetPadConnection( ZONE_CONNECTION::FULL );
562
563 wxString keepIsland = arr[9];
564 if( keepIsland == wxS( "yes" ) )
565 zone->SetIslandRemovalMode( ISLAND_REMOVAL_MODE::NEVER );
566
567 wxString fillData = arr[10];
568 SHAPE_POLY_SET fillPolySet;
569 try
570 {
571 for( const nlohmann::json& polyData : nlohmann::json::parse( fillData ) )
572 {
573 for( const nlohmann::json& contourData : polyData )
574 {
575 SHAPE_POLY_SET contourPolySet = ParseLineChains(
576 contourData.get<wxString>(), SHAPE_ARC::DefaultAccuracyForPCB(), true );
577
578 SHAPE_POLY_SET currentOutline( contourPolySet.COutline( 0 ) );
579
580 for( int i = 0; i < contourPolySet.HoleCount( 0 ); i++ )
581 currentOutline.AddHole( contourPolySet.CHole( 0, i ) );
582
583 fillPolySet.Append( currentOutline );
584 }
585 }
586
587 fillPolySet.Fracture();
588
589 zone->SetFilledPolysList( layer, fillPolySet );
590 zone->SetIsFilled( true );
591 zone->SetNeedRefill( false );
592 }
593 catch( nlohmann::json::exception& )
594 {
595 }
596
597 int fillOrder = wxAtoi( arr[13] );
598 zone->SetAssignedPriority( 100 - fillOrder );
599
600 wxString improveFabrication = arr[17];
601 if( improveFabrication == wxS( "none" ) )
602 {
603 zone->SetMinThickness( 0 );
604 }
605 else
606 {
607 // arr[1] is "stroke Width" per docs
608 int minThickness = std::max( pcbIUScale.mmToIU( 0.03 ),
609 int( ConvertSize( arr[1] ) ) );
610 zone->SetMinThickness( minThickness );
611 }
612
613 if( arr.size() > 18 )
614 {
615 zone->SetThermalReliefSpokeWidth( std::max( int( ConvertSize( arr[18] ) ),
616 zone->GetMinThickness() ) );
617 }
618 else
619 {
620 wxFAIL_MSG( wxString::Format( "COPPERAREA unexpected size %d: %s ",
621 arr.size(),
622 shape ) );
623
624 zone->SetThermalReliefSpokeWidth( zone->GetMinThickness() );
625 }
626
627 aContainer->Add( zone.release(), ADD_MODE::APPEND );
628 }
629 else if( elType == wxS( "SVGNODE" ) )
630 {
631 nlohmann::json nodeData = nlohmann::json::parse( arr[1] );
632
633 int nodeType = nodeData.at( "nodeType" );
634 wxString layer = nodeData.at( "layerid" );
635 PCB_LAYER_ID klayer = LayerToKi( layer );
636
637 if( nodeType == 1 )
638 {
639 std::map<wxString, wxString> attributes = nodeData.at( "attrs" );
640
641 if( layer == wxS( "19" ) ) // 3DModel
642 {
643 if( !footprint )
644 continue;
645
646 auto ec_eType = get_opt( attributes, "c_etype" );
647 auto ec_rotation = get_opt( attributes, "c_rotation" );
648 auto ec_origin = get_opt( attributes, "c_origin" );
649 auto ec_width = get_opt( attributes, "c_width" );
650 auto ec_height = get_opt( attributes, "c_height" );
651 auto ez = get_opt( attributes, "z" );
652 auto etitle = get_opt( attributes, "title" );
653 auto euuid = get_opt( attributes, "uuid" );
654 auto etransform = get_opt( attributes, "transform" );
655
656 if( !ec_eType || *ec_eType != wxS( "outline3D" ) || !etitle )
657 continue;
658
659 wxString modelTitle = *etitle;
660 VECTOR3D kmodelOffset;
661 VECTOR3D kmodelRotation;
662
663 if( euuid )
664 {
665 PCB_FIELD* field = new PCB_FIELD( footprint, FIELD_T::USER,
667 field->SetLayer( Cmts_User );
668 field->SetVisible( false );
669 field->SetText( *euuid );
670 footprint->Add( field );
671 }
672
673 /*if( etransform )
674 {
675 PCB_FIELD* field = new PCB_FIELD( footprint, FIELD_T::USER,
676 "3D Transform" );
677 field->SetLayer( Cmts_User );
678 field->SetVisible( false );
679 field->SetText( *etransform );
680 footprint->Add( field );
681 }*/
682
683 if( ec_width && ec_height )
684 {
685 double fitXmm = pcbIUScale.IUTomm( ScaleSize( Convert( *ec_width ) ) );
686 double fitYmm = pcbIUScale.IUTomm( ScaleSize( Convert( *ec_height ) ) );
687
688 double rounding = 0.001;
689 fitXmm = KiROUND( fitXmm / rounding ) * rounding;
690 fitYmm = KiROUND( fitYmm / rounding ) * rounding;
691
692 PCB_FIELD* field = new PCB_FIELD( footprint, FIELD_T::USER,
694 field->SetLayer( Cmts_User );
695 field->SetVisible( false );
696 field->SetText( wxString::FromCDouble( fitXmm ) + wxS( " " )
697 + wxString::FromCDouble( fitYmm ) );
698 footprint->Add( field );
699 }
700
701 if( ec_origin )
702 {
703 wxArrayString orParts = wxSplit( *ec_origin, ',', '\0' );
704
705 if( orParts.size() == 2 )
706 {
707 VECTOR2D pos;
708 pos.x = Convert( orParts[0].Trim() );
709 pos.y = Convert( orParts[1].Trim() );
710
711 VECTOR2D rel = RelPos( pos );
712 kmodelOffset.x = -pcbIUScale.IUTomm( rel.x );
713 kmodelOffset.y = -pcbIUScale.IUTomm( rel.y );
714
715 RotatePoint( &kmodelOffset.x, &kmodelOffset.y,
716 -footprint->GetOrientation() );
717 }
718 }
719
720 if( ez )
721 {
722 kmodelOffset.z = pcbIUScale.IUTomm( ScaleSize( Convert( ez->Trim() ) ) );
723 }
724
725 if( ec_rotation )
726 {
727 wxArrayString rotParts = wxSplit( *ec_rotation, ',', '\0' );
728
729 if( rotParts.size() == 3 )
730 {
731 kmodelRotation.x = -Convert( rotParts[0].Trim() );
732 kmodelRotation.y = -Convert( rotParts[1].Trim() );
733 kmodelRotation.z = -Convert( rotParts[2].Trim() )
734 + footprint->GetOrientationDegrees();
735 }
736 }
737
738 if( footprint->GetLayer() == B_Cu )
739 {
740 kmodelRotation.z = 180 - kmodelRotation.z;
741 RotatePoint( &kmodelOffset.x, &kmodelOffset.y, ANGLE_180 );
742 }
743
745 model.m_Filename = kicadModelPrefix
747 + wxS( ".step" );
748 model.m_Offset = kmodelOffset;
749 model.m_Rotation = kmodelRotation;
750 footprint->Models().push_back( model );
751 }
752 else
753 {
754 if( auto dataStr = get_opt( attributes, "d" ) )
755 {
756 int maxError = SHAPE_ARC::DefaultAccuracyForPCB();
757
758 if( dataStr->size() >= 8000 )
759 maxError *= 10;
760
761 SHAPE_POLY_SET polySet = ParseLineChains( dataStr->Trim(), maxError, true );
762
763 polySet.RebuildHolesFromContours();
764
765 std::unique_ptr<PCB_GROUP> group;
766
767 if( polySet.OutlineCount() > 1 )
768 group = std::make_unique<PCB_GROUP>( aContainer );
769
770 for( const SHAPE_POLY_SET::POLYGON& poly : polySet.CPolygons() )
771 {
772 auto svgShape = std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::POLY );
773
774 svgShape->SetFilled( true );
775 svgShape->SetPolyShape( poly );
776 svgShape->SetLayer( klayer );
777 svgShape->SetWidth( 0 );
778
779 if( group )
780 group->AddItem( svgShape.get() );
781
782 aContainer->Add( svgShape.release(), ADD_MODE::APPEND );
783 }
784
785 if( group )
786 aContainer->Add( group.release(), ADD_MODE::APPEND );
787 }
788 }
789 }
790 else
791 {
792 THROW_IO_ERRORF( _( "Unknown SVGNODE nodeType %d" ), nodeType );
793 }
794 }
795 else if( elType == wxS( "TEXT" ) )
796 {
797 PCB_TEXT* text;
798 wxString textType = arr[1];
799
800 if( footprint && textType == wxS( "P" ) )
801 {
802 text = footprint->GetField( FIELD_T::REFERENCE );
803 }
804 else if( footprint && textType == wxS( "N" ) )
805 {
806 text = footprint->GetField( FIELD_T::VALUE );
807 }
808 else if( arr[12] == wxS( "none" ) )
809 {
810 text = new PCB_FIELD( aContainer, FIELD_T::USER );
811 static_cast<PCB_FIELD*>( text )->SetVisible( false );
812 }
813 else
814 {
815 text = new PCB_TEXT( aContainer );
816 aContainer->Add( text, ADD_MODE::APPEND );
817 }
818
819 VECTOR2D start;
820 start.x = RelPosX( arr[2] );
821 start.y = RelPosY( arr[3] );
822 text->SetPosition( start );
823
824 double thickness = ConvertSize( arr[4] );
825 text->SetTextThickness( thickness );
826
827 double rot = Convert( arr[5] );
828 text->SetTextAngleDegrees( rot );
829
830 text->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
831 text->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
832
833 PCB_LAYER_ID layer = LayerToKi( arr[7] );
834 text->SetLayer( layer );
835
836 if( IsBackLayer( layer ) )
837 text->SetMirrored( true );
838
839 double height = ConvertSize( arr[9] ) * 0.8;
840 text->SetTextSize( VECTOR2I( height, height ) );
841
842 wxString textStr = arr[10];
843 textStr.Replace( wxS( "\\n" ), wxS( "\n" ) );
844 text->SetText( UnescapeHTML( textStr ) );
845
846 //arr[11] // Geometry data
847
848 wxString font = arr[14];
849 if( !font.IsEmpty() )
850 text->SetFont( KIFONT::FONT::GetFont( font ) );
851
852 TransformTextToBaseline( text, wxEmptyString );
853 }
854 else if( elType == wxS( "VIA" ) )
855 {
856 VECTOR2D center( RelPosX( arr[1] ), RelPosY( arr[2] ) );
857 int kdia = ConvertSize( arr[3] );
858 int kdrill = ConvertSize( arr[5] ) * 2;
859
860 if( footprint )
861 {
862 std::unique_ptr<PAD> pad = std::make_unique<PAD>( footprint );
863
864 pad->SetPosition( center );
865 pad->SetLayerSet( PAD::PTHMask() );
866 pad->SetAttribute( PAD_ATTRIB::PTH );
867 pad->SetPadstackMode( PADSTACK::MODE::NORMAL ); // EasyEDA doesn't have complex padstacks
869 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( kdia, kdia ) );
870 pad->SetDrillShape( PAD_DRILL_SHAPE::CIRCLE );
871 pad->SetDrillSize( VECTOR2I( kdrill, kdrill ) );
872
873 footprint->Add( pad.release(), ADD_MODE::APPEND );
874 }
875 else
876 {
877 std::unique_ptr<PCB_VIA> via = std::make_unique<PCB_VIA>( aContainer );
878
879 via->SetPosition( center );
880 via->SetPadstackMode( PADSTACK::MODE::NORMAL ); // EasyEDA doesn't have complex padstacks
881 via->SetWidth( PADSTACK::ALL_LAYERS, kdia );
882 via->SetNet( getOrAddNetItem( arr[4] ) );
883 via->SetDrill( kdrill );
884
885 aContainer->Add( via.release(), ADD_MODE::APPEND );
886 }
887 }
888 else if( elType == wxS( "HOLE" ) )
889 {
890 FOOTPRINT* padContainer;
891
892 VECTOR2D center( RelPosX( arr[1] ), RelPosY( arr[2] ) );
893 int kdia = ConvertSize( arr[3] ) * 2;
894 wxString holeUuid = arr[4];
895
896 if( footprint )
897 {
898 padContainer = footprint;
899 }
900 else
901 {
902 std::unique_ptr<FOOTPRINT> newFootprint =
903 std::make_unique<FOOTPRINT>( dynamic_cast<BOARD*>( aContainer ) );
904
905 wxString name = wxS( "Hole_" ) + holeUuid;
906
907 newFootprint->SetFPID( LIB_ID( wxEmptyString, name ) );
908 newFootprint->SetPosition( center );
909 newFootprint->SetLocked( true );
910
911 newFootprint->Reference().SetText( name );
912 newFootprint->Reference().SetVisible( false );
913 newFootprint->Reference().SetTextSize( HIDDEN_TEXT_SIZE );
914 newFootprint->Value().SetText( name );
915 newFootprint->Value().SetVisible( false );
916 newFootprint->Value().SetTextSize( HIDDEN_TEXT_SIZE );
917
918 padContainer = newFootprint.get();
919 aContainer->Add( newFootprint.release(), ADD_MODE::APPEND );
920 }
921
922 std::unique_ptr<PAD> pad = std::make_unique<PAD>( padContainer );
923
924 pad->SetPosition( center );
925 pad->SetLayerSet( PAD::UnplatedHoleMask() );
926 pad->SetAttribute( PAD_ATTRIB::NPTH );
927 pad->SetPadstackMode( PADSTACK::MODE::NORMAL ); // EasyEDA doesn't have complex padstacks
929 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( kdia, kdia ) );
930 pad->SetDrillShape( PAD_DRILL_SHAPE::CIRCLE );
931 pad->SetDrillSize( VECTOR2I( kdia, kdia ) );
932
933 padContainer->Add( pad.release(), ADD_MODE::APPEND );
934 }
935 else if( elType == wxS( "PAD" ) )
936 {
937 FOOTPRINT* padContainer;
938
939 VECTOR2D center( RelPosX( arr[2] ), RelPosY( arr[3] ) );
940 VECTOR2D size( ConvertSize( arr[4] ), ConvertSize( arr[5] ) );
941 wxString padUuid = arr[12];
942
943 if( footprint )
944 {
945 padContainer = footprint;
946 }
947 else
948 {
949 std::unique_ptr<FOOTPRINT> newFootprint =
950 std::make_unique<FOOTPRINT>( dynamic_cast<BOARD*>( aContainer ) );
951
952 wxString name = wxS( "Pad_" ) + padUuid;
953
954 newFootprint->SetFPID( LIB_ID( wxEmptyString, name ) );
955 newFootprint->SetPosition( center );
956 newFootprint->SetLocked( true );
957
958 newFootprint->Reference().SetText( name );
959 newFootprint->Reference().SetVisible( false );
960 newFootprint->Reference().SetTextSize( HIDDEN_TEXT_SIZE );
961 newFootprint->Value().SetText( name );
962 newFootprint->Value().SetVisible( false );
963 newFootprint->Value().SetTextSize( HIDDEN_TEXT_SIZE );
964
965 padContainer = newFootprint.get();
966 aContainer->Add( newFootprint.release(), ADD_MODE::APPEND );
967 }
968
969 std::unique_ptr<PAD> pad = std::make_unique<PAD>( padContainer );
970
971 pad->SetNet( getOrAddNetItem( arr[7] ) );
972 pad->SetNumber( arr[8] );
973 pad->SetPosition( center );
974 pad->SetPadstackMode( PADSTACK::MODE::NORMAL ); // EasyEDA doesn't have complex padstacks
975 pad->SetSize( PADSTACK::ALL_LAYERS, size );
976 pad->SetOrientationDegrees( Convert( arr[11] ) );
977 pad->SetThermalSpokeAngle( ANGLE_0 );
978
979 wxString elayer = arr[6];
980 PCB_LAYER_ID klayer = LayerToKi( elayer );
981
982 bool plated = arr[15] == wxS( "Y" );
983
984 if( klayer == F_Cu )
985 {
986 pad->SetLayer( F_Cu );
987 pad->SetLayerSet( PAD::SMDMask() );
988 pad->SetAttribute( PAD_ATTRIB::SMD );
989 }
990 else if( klayer == B_Cu )
991 {
992 pad->SetLayer( B_Cu );
993 pad->SetLayerSet( PAD::SMDMask().FlipStandardLayers() );
994 pad->SetAttribute( PAD_ATTRIB::SMD );
995 }
996 else if( elayer == wxS( "11" ) )
997 {
998 pad->SetLayerSet( plated ? PAD::PTHMask() : PAD::UnplatedHoleMask() );
999 pad->SetAttribute( plated ? PAD_ATTRIB::PTH : PAD_ATTRIB::NPTH );
1000 }
1001 else
1002 {
1003 pad->SetLayer( klayer );
1004 pad->SetLayerSet( LSET( { klayer } ) );
1005 pad->SetAttribute( PAD_ATTRIB::SMD );
1006 }
1007
1008 const wxString& padType = arr[1];
1009
1010 if( padType == wxS( "ELLIPSE" ) )
1011 {
1013 }
1014 else if( padType == wxS( "RECT" ) )
1015 {
1017 }
1018 else if( padType == wxS( "OVAL" ) )
1019 {
1020 if( pad->GetSize( PADSTACK::ALL_LAYERS ).x == pad->GetSize( PADSTACK::ALL_LAYERS ).y )
1022 else
1024 }
1025 else if( padType == wxS( "POLYGON" ) )
1026 {
1028 pad->SetAnchorPadShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::CIRCLE );
1029 pad->SetSize( PADSTACK::ALL_LAYERS, { 1, 1 } );
1030
1031 wxArrayString data = wxSplit( arr[10], ' ', '\0' );
1032
1034 for( int i = 1; i < (int) data.size(); i += 2 )
1035 {
1036 VECTOR2D pt;
1037 pt.x = RelPosX( data[i - 1] );
1038 pt.y = RelPosY( data[i] );
1039 chain.Append( pt );
1040 }
1041 chain.SetClosed( true );
1042
1043 chain.Move( -center );
1044 chain.Rotate( -pad->GetOrientation() );
1045 pad->AddPrimitivePoly( PADSTACK::ALL_LAYERS, chain, 0, true );
1046 }
1047
1048 wxString holeDia = arr[9];
1049
1050 if( !holeDia.IsEmpty() )
1051 {
1052 double holeD = ConvertSize( holeDia ) * 2;
1053 double holeL = 0;
1054
1055 wxString holeLength = arr[13];
1056 if( !holeLength.IsEmpty() )
1057 holeL = ConvertSize( holeLength );
1058
1059 if( holeL > 0 )
1060 {
1061 pad->SetDrillShape( PAD_DRILL_SHAPE::OBLONG );
1062
1063 if( size.x < size.y )
1064 pad->SetDrillSize( VECTOR2I( holeD, holeL ) );
1065 else
1066 pad->SetDrillSize( VECTOR2I( holeL, holeD ) );
1067 }
1068 else
1069 {
1070 pad->SetDrillShape( PAD_DRILL_SHAPE::CIRCLE );
1071 pad->SetDrillSize( VECTOR2I( holeD, holeD ) );
1072 }
1073 }
1074
1075 wxString pasteExp = arr[17];
1076
1077 if( !pasteExp.IsEmpty() )
1078 {
1079 double pasteExpansion = ConvertSize( pasteExp );
1080 pad->SetLocalSolderPasteMargin( pasteExpansion );
1081 }
1082
1083 wxString maskExp = arr[18];
1084
1085 if( !maskExp.IsEmpty() )
1086 {
1087 double maskExpansion = ConvertSize( maskExp );
1088 pad->SetLocalSolderMaskMargin( maskExpansion );
1089 }
1090
1091 bool badPad = false;
1092
1093 pad->Padstack().ForEachUniqueLayer(
1094 [&]( PCB_LAYER_ID layer )
1095 {
1096 VECTOR2I padSize = pad->GetSize( layer );
1097
1098 if( padSize.x <= 0 || padSize.y <= 0 )
1099 badPad = true;
1100 } );
1101
1102 if( badPad )
1103 {
1104 // Not worth throwing, and we don't (at present) have a reporter....
1105 /*
1106 Report( wxString::Format( _( "Invalid zero-sized pad ignored in\nfile: %s" ),
1107 aParent->GetFileName() ),
1108 RPT_SEVERITY_ERROR );
1109 */
1110 }
1111 else
1112 {
1113 padContainer->Add( pad.release(), ADD_MODE::APPEND );
1114 }
1115 }
1116 }
1117}
1118
1119
1120std::unique_ptr<FOOTPRINT>
1121PCB_IO_EASYEDA_PARSER::ParseFootprint( const VECTOR2D& aOrigin, const EDA_ANGLE& aOrientation, int aLayer,
1122 BOARD* aParent, std::map<wxString, wxString> aParams,
1123 std::map<wxString, std::unique_ptr<FOOTPRINT>>& aFootprintMap,
1124 wxArrayString aShapes )
1125{
1126 std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>( aParent );
1127
1128 if( aLayer == 2 ) // Bottom layer
1129 {
1130 footprint->SetLayer( B_Cu );
1131 footprint->SetOrientation( aOrientation - ANGLE_180 );
1132 }
1133 else
1134 {
1135 footprint->SetLayer( F_Cu );
1136 footprint->SetOrientation( aOrientation );
1137 }
1138
1139 footprint->Value().SetText( aParams[wxS( "package" )] );
1140
1141 m_relOrigin = aOrigin;
1142
1143 ParseToBoardItemContainer( footprint.get(), aParent, aParams, aFootprintMap, aShapes );
1144
1145 // Heal board outlines
1146 std::vector<PCB_SHAPE*> shapes;
1147
1148 for( BOARD_ITEM* item : footprint->GraphicalItems() )
1149 {
1150 if( !item->IsOnLayer( Edge_Cuts ) )
1151 continue;
1152
1153 if( item->Type() == PCB_SHAPE_T )
1154 shapes.push_back( static_cast<PCB_SHAPE*>( item ) );
1155 }
1156
1158
1159 // EasyEDA footprints don't have courtyard, so build a box ourselves
1160 if( !footprint->IsOnLayer( F_CrtYd ) )
1161 {
1162 BOX2I bbox = footprint->GetLayerBoundingBox( { F_Cu, F_Fab, F_Paste, F_Mask, Edge_Cuts } );
1163 bbox.Inflate( pcbIUScale.mmToIU( 0.25 ) ); // Default courtyard clearance
1164
1165 std::unique_ptr<PCB_SHAPE> shape =
1166 std::make_unique<PCB_SHAPE>( footprint.get(), SHAPE_T::RECTANGLE );
1167
1168 shape->SetWidth( pcbIUScale.mmToIU( DEFAULT_COURTYARD_WIDTH ) );
1169 shape->SetLayer( F_CrtYd );
1170 shape->SetStart( bbox.GetOrigin() );
1171 shape->SetEnd( bbox.GetEnd() );
1172
1173 footprint->Add( shape.release(), ADD_MODE::APPEND );
1174 }
1175
1176 bool hasFabRef = false;
1177
1178 for( BOARD_ITEM* item : footprint->GraphicalItems() )
1179 {
1180 if( item->Type() == PCB_TEXT_T && item->IsOnLayer( F_Fab ) )
1181 {
1182 if( static_cast<PCB_TEXT*>( item )->GetText() == wxT( "${REFERENCE}" ) )
1183 {
1184 hasFabRef = true;
1185 break;
1186 }
1187 }
1188 }
1189
1190 if( !hasFabRef )
1191 {
1192 // Add reference text field on F_Fab
1193 int c_refTextSize = pcbIUScale.mmToIU( 0.5 ); // KLC min Fab text size
1194 int c_refTextThickness = pcbIUScale.mmToIU( 0.1 ); // Decent text thickness
1195 std::unique_ptr<PCB_TEXT> refText = std::make_unique<PCB_TEXT>( footprint.get() );
1196
1197 refText->SetLayer( F_Fab );
1198 refText->SetTextSize( VECTOR2I( c_refTextSize, c_refTextSize ) );
1199 refText->SetTextThickness( c_refTextThickness );
1200 refText->SetText( wxT( "${REFERENCE}" ) );
1201
1202 footprint->Add( refText.release(), ADD_MODE::APPEND );
1203 }
1204
1205 return footprint;
1206}
1207
1208
1210 std::map<wxString, std::unique_ptr<FOOTPRINT>>& aFootprintMap,
1211 wxArrayString aShapes )
1212{
1213 m_relOrigin = aOrigin;
1214
1215 ParseToBoardItemContainer( aBoard, nullptr, {}, aFootprintMap, aShapes );
1216
1217 // Heal board outlines
1218 std::vector<PCB_SHAPE*> shapes;
1219
1220 for( BOARD_ITEM* item : aBoard->Drawings() )
1221 {
1222 if( !item->IsOnLayer( Edge_Cuts ) )
1223 continue;
1224
1225 if( item->Type() == PCB_SHAPE_T )
1226 shapes.push_back( static_cast<PCB_SHAPE*>( item ) );
1227 }
1228
1230}
const char * name
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:128
#define DEFAULT_COURTYARD_WIDTH
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
Abstract interface for BOARD_ITEMs capable of storing other items inside.
virtual void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false)=0
Adds an item to the container.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:85
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:383
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:411
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition board.cpp:1520
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition board.cpp:2797
unsigned GetNetCount() const
Definition board.h:1252
const DRAWINGS & Drawings() const
Definition board.h:467
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
constexpr const Vec GetEnd() const
Definition box2.h:209
constexpr const Vec & GetOrigin() const
Definition box2.h:207
double ConvertSize(const wxString &aValue)
static double Convert(const wxString &aValue)
double RelPosX(double aValue)
double RelPosY(double aValue)
VECTOR2< T > RelPos(const VECTOR2< T > &aVec)
void TransformTextToBaseline(EDA_TEXT *textItem, const wxString &baselineAlign)
std::vector< SHAPE_LINE_CHAIN > ParseLineChains(const wxString &aData, int aMaxError, bool aForceClosed)
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:347
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:236
void SetFPID(const LIB_ID &aFPID)
Definition footprint.h:418
EDA_ANGLE GetOrientation() const
Definition footprint.h:382
PCB_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this footprint.
double GetOrientationDegrees() const
Definition footprint.h:412
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition footprint.h:393
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Adds an item to the container.
std::vector< FP_3DMODEL > & Models()
Definition footprint.h:375
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
Definition font.cpp:144
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition lib_id.cpp:65
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
Handle the data for a net.
Definition netinfo.h:50
@ NORMAL
Shape is the same on all layers.
Definition padstack.h:170
static constexpr PCB_LAYER_ID ALL_LAYERS
! The layer identifier to use for the single defintion on normal padstacks
Definition padstack.h:179
static LSET PTHMask()
layer set for a through hole pad
Definition pad.cpp:615
static LSET UnplatedHoleMask()
layer set for a mechanical unplated through hole pad
Definition pad.cpp:636
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition pad.cpp:622
PCB_IO_EASYEDA_PARSER(PROGRESS_REPORTER *aProgressReporter)
void ParseToBoardItemContainer(BOARD_ITEM_CONTAINER *aContainer, BOARD *aParent, std::map< wxString, wxString > paramMap, std::map< wxString, std::unique_ptr< FOOTPRINT > > &aFootprintMap, wxArrayString shapes)
std::unique_ptr< FOOTPRINT > ParseFootprint(const VECTOR2D &aOrigin, const EDA_ANGLE &aOrientation, int aLayer, BOARD *aParent, std::map< wxString, wxString > aParams, std::map< wxString, std::unique_ptr< FOOTPRINT > > &aFootprintMap, wxArrayString aShapes)
double ScaleSize(double aValue) override
void ParseBoard(BOARD *aBoard, const VECTOR2D &aOrigin, std::map< wxString, std::unique_ptr< FOOTPRINT > > &aFootprintMap, wxArrayString aShapes)
PCB_LAYER_ID LayerToKi(const wxString &aLayer)
A progress reporter interface for use in multi-threaded environments.
Definition seg.h:38
VECTOR2I A
Definition seg.h:45
VECTOR2I B
Definition seg.h:46
static int DefaultAccuracyForPCB()
Definition shape_arc.h:283
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
Represent a set of closed polygons.
int HoleCount(int aOutline) const
Returns the number of holes in a given outline.
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)
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
int AddHole(const SHAPE_LINE_CHAIN &aHole, int aOutline=-1)
Adds a new hole to the given outline (default: last) and returns its index.
void RebuildHolesFromContours()
Extract all contours from this polygon set, then recreate polygons with holes.
const SHAPE_LINE_CHAIN & CHole(int aOutline, int aHole) const
int OutlineCount() const
Return the number of outlines in the set.
void Fracture(bool aSimplify=true)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
const std::vector< POLYGON > & CPolygons() const
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:448
@ DEGREES_T
Definition eda_angle.h:30
static constexpr EDA_ANGLE ANGLE_180
Definition eda_angle.h:452
@ SEGMENT
Definition eda_shape.h:56
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:57
void ConnectBoardShapes(std::vector< PCB_SHAPE * > &aShapeList, int aChainingEpsilon)
Connects shapes to each other, making continious contours (adjacent shapes will have a common vertex)...
#define THROW_IO_ERRORF(msg,...)
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition layer_ids.h:867
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:741
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ In22_Cu
Definition layer_ids.h:83
@ In11_Cu
Definition layer_ids.h:72
@ In29_Cu
Definition layer_ids.h:90
@ In30_Cu
Definition layer_ids.h:91
@ F_CrtYd
Definition layer_ids.h:112
@ In17_Cu
Definition layer_ids.h:78
@ Edge_Cuts
Definition layer_ids.h:108
@ Dwgs_User
Definition layer_ids.h:103
@ F_Paste
Definition layer_ids.h:100
@ In9_Cu
Definition layer_ids.h:70
@ Cmts_User
Definition layer_ids.h:104
@ In19_Cu
Definition layer_ids.h:80
@ In7_Cu
Definition layer_ids.h:68
@ In28_Cu
Definition layer_ids.h:89
@ In26_Cu
Definition layer_ids.h:87
@ B_Mask
Definition layer_ids.h:94
@ B_Cu
Definition layer_ids.h:61
@ User_5
Definition layer_ids.h:124
@ Eco1_User
Definition layer_ids.h:105
@ F_Mask
Definition layer_ids.h:93
@ In21_Cu
Definition layer_ids.h:82
@ In23_Cu
Definition layer_ids.h:84
@ B_Paste
Definition layer_ids.h:101
@ In15_Cu
Definition layer_ids.h:76
@ In2_Cu
Definition layer_ids.h:63
@ F_Fab
Definition layer_ids.h:115
@ In10_Cu
Definition layer_ids.h:71
@ F_SilkS
Definition layer_ids.h:96
@ In4_Cu
Definition layer_ids.h:65
@ Eco2_User
Definition layer_ids.h:106
@ In16_Cu
Definition layer_ids.h:77
@ In24_Cu
Definition layer_ids.h:85
@ In1_Cu
Definition layer_ids.h:62
@ User_3
Definition layer_ids.h:122
@ User_1
Definition layer_ids.h:120
@ B_SilkS
Definition layer_ids.h:97
@ In13_Cu
Definition layer_ids.h:74
@ User_4
Definition layer_ids.h:123
@ In8_Cu
Definition layer_ids.h:69
@ In14_Cu
Definition layer_ids.h:75
@ In12_Cu
Definition layer_ids.h:73
@ In27_Cu
Definition layer_ids.h:88
@ In6_Cu
Definition layer_ids.h:67
@ In5_Cu
Definition layer_ids.h:66
@ In3_Cu
Definition layer_ids.h:64
@ In20_Cu
Definition layer_ids.h:81
@ F_Cu
Definition layer_ids.h:60
@ In18_Cu
Definition layer_ids.h:79
@ In25_Cu
Definition layer_ids.h:86
@ B_Fab
Definition layer_ids.h:114
std::optional< V > get_opt(const std::map< wxString, V > &aMap, const wxString &aKey)
Definition map_helpers.h:30
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:102
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:98
@ PTH
Plated through hole pad.
Definition padstack.h:97
@ RECTANGLE
Definition padstack.h:53
Class to handle a set of BOARD_ITEMs.
static const wxString MODEL_SIZE_KEY
static const wxString DIRECT_MODEL_UUID_KEY
static const int SHAPE_JOIN_DISTANCE
static const VECTOR2I HIDDEN_TEXT_SIZE(pcbIUScale.mmToIU(0.5), pcbIUScale.mmToIU(0.5))
static LIB_ID EasyEdaToKiCadLibID(const wxString &aLibName, const wxString &aLibReference)
static LIB_ID EasyEdaToKiCadLibID(const wxString &aLibName, const wxString &aLibReference)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
wxString UnescapeHTML(const wxString &aString)
Return a new wxString unescaped from HTML format.
@ CTX_FILENAME
@ CTX_LIBID
@ USER
The field ID hasn't been set yet; field is invalid.
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
KIBIS_MODEL * model
bool cw
VECTOR2I center
const SHAPE_LINE_CHAIN chain
int radius
VECTOR2I end
int delta
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_TOP
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:227
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:80
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:84
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707
VECTOR3< double > VECTOR3D
Definition vector3.h:230
@ FULL
pads are covered by copper
Definition zones.h:47