148 std::map<wxString, std::unique_ptr<FOOTPRINT>>& aFootprintMap, wxArrayString aShapes )
151 const wxString easyedaModelDir = wxS(
"EASYEDA_MODELS" );
152 wxString kicadModelPrefix = wxS(
"${KIPRJMOD}/" ) + easyedaModelDir + wxS(
"/" );
154 BOARD* board = aParent ? aParent :
dynamic_cast<BOARD*
>( aContainer );
157 auto getOrAddNetItem = [&](
const wxString& aNetName ) ->
NETINFO_ITEM*
162 if( aNetName.empty() )
184 for( wxString shape : aShapes )
186 wxArrayString arr = wxSplit( shape,
'~',
'\0' );
188 wxString elType = arr[0];
189 if( elType == wxS(
"LIB" ) )
191 shape.Replace( wxS(
"#@$" ),
"\n" );
192 wxArrayString parts = wxSplit( shape,
'\n',
'\0' );
194 if( parts.size() < 1 )
197 wxArrayString paramsRoot = wxSplit( parts[0],
'~',
'\0' );
199 if( paramsRoot.size() < 4 )
204 wxString packageName =
205 wxString::Format( wxS(
"Unknown_%s_%s" ), paramsRoot[1], paramsRoot[2] );
207 wxArrayString paramParts = wxSplit( paramsRoot[3],
'`',
'\0' );
210 if( !paramsRoot[4].IsEmpty() )
215 if( !paramsRoot[7].IsEmpty() )
216 layer =
Convert( paramsRoot[7] );
218 std::map<wxString, wxString> paramMap;
220 for(
int i = 1; i < paramParts.size(); i += 2 )
222 wxString key = paramParts[i - 1];
223 wxString value = paramParts[i];
225 if( key == wxS(
"package" ) )
228 paramMap[key] = value;
235 aFootprintMap, parts );
246 else if( elType == wxS(
"TRACK" ) )
250 wxString netname = arr[3];
251 wxArrayString data = wxSplit( arr[4],
' ',
'\0' );
253 for(
int i = 3; i < data.size(); i += 2 )
263 std::unique_ptr<PCB_TRACK> track = std::make_unique<PCB_TRACK>( aContainer );
265 track->SetLayer( layer );
266 track->SetWidth( width );
267 track->SetStart( start );
268 track->SetEnd(
end );
269 track->SetNet( getOrAddNetItem( netname ) );
275 std::unique_ptr<PCB_SHAPE> seg =
278 seg->SetLayer( layer );
279 seg->SetWidth( width );
280 seg->SetStart( start );
287 else if( elType == wxS(
"CIRCLE" ) )
289 auto shape = std::make_unique<PCB_SHAPE>( aContainer,
SHAPE_T::CIRCLE );
291 shape->SetWidth( width );
294 shape->SetLayer( layer );
302 shape->SetCenter(
center );
306 shape->SetNet( getOrAddNetItem( arr[8] ) );
310 else if( elType == wxS(
"RECT" ) )
314 shape->SetWidth( width );
317 shape->SetLayer( layer );
319 bool filled = arr[9] != wxS(
"none" );
320 shape->SetFilled( filled );
330 shape->SetStart( start );
331 shape->SetEnd( start + size );
334 shape->SetNet( getOrAddNetItem( arr[11] ) );
338 else if( elType == wxS(
"ARC" ) )
340 std::unique_ptr<PCB_SHAPE> shape =
341 std::make_unique<PCB_SHAPE>( aContainer,
SHAPE_T::ARC );
344 shape->SetWidth( width );
347 shape->SetLayer( layer );
350 shape->SetNet( getOrAddNetItem( arr[3] ) );
358 wxString data = arr[4];
359 auto readNumber = [&]( wxString& aOut )
361 wxUniChar ch = data[pos];
363 while( ch ==
' ' || ch ==
',' )
366 while( isdigit( ch ) || ch ==
'.' || ch ==
'-' )
371 if( pos == data.size() )
380 wxUniChar sym = data[pos++];
390 else if( sym ==
'A' )
392 wxString radX, radY,
unknown, farFlag, cwFlag, endX, endY;
396 readNumber( farFlag );
397 readNumber( cwFlag );
401 isFar = farFlag == wxS(
"1" );
402 cw = cwFlag == wxS(
"1" );
406 }
while( pos < data.size() );
410 double d =
delta.EuclideanNorm();
411 double h = sqrt( std::max( 0.0, rad.
x * rad.
x - d * d / 4 ) );
418 start +
delta / 2 +
delta.Perpendicular().Resize( ( isFar ^
cw ) ? h : -h );
421 std::swap( start,
end );
423 shape->SetStart(
RelPos( start ) );
425 shape->SetCenter(
RelPos( arcCenter ) );
429 else if( elType == wxS(
"DIMENSION" ) )
433 wxString shapeData = arr[2].Trim();
436 std::vector<SHAPE_LINE_CHAIN> lineChains =
439 std::unique_ptr<PCB_GROUP>
group = std::make_unique<PCB_GROUP>( aContainer );
440 group->SetName( wxS(
"Dimension" ) );
444 for(
int segId = 0; segId <
chain.SegmentCount(); segId++ )
449 shape->SetLayer( layer );
450 shape->SetWidth( lineWidth );
451 shape->SetStart( seg.
A );
452 shape->SetEnd( seg.
B );
454 group->AddItem( shape.get() );
462 else if( elType == wxS(
"SOLIDREGION" ) )
464 wxString layer = arr[1];
469 if( layer == wxS(
"11" ) )
473 auto shape = std::make_unique<PCB_SHAPE>( aContainer,
SHAPE_T::POLY );
476 shape->SetFilled(
false );
478 shape->SetPolyShape( poly );
485 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aContainer );
488 zone->SetLayer( klayer );
491 zone->SetNet( getOrAddNetItem( arr[2] ) );
494 zone->Outline()->AddPolygon( poly );
496 if( arr[4].Lower() == wxS(
"cutout" ) )
498 zone->SetIsRuleArea(
true );
499 zone->SetDoNotAllowZoneFills(
true );
500 zone->SetDoNotAllowTracks(
false );
501 zone->SetDoNotAllowVias(
false );
502 zone->SetDoNotAllowPads(
false );
503 zone->SetDoNotAllowFootprints(
false );
507 zone->SetFilledPolysList( klayer, polySet );
509 zone->SetIsFilled(
true );
510 zone->SetNeedRefill(
false );
513 zone->SetMinThickness( 0 );
514 zone->SetLocalClearance( 0 );
515 zone->SetAssignedPriority( 100 );
520 else if( elType == wxS(
"COPPERAREA" ) )
522 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aContainer );
525 zone->SetLayer( layer );
527 wxString netname = arr[3];
530 zone->SetNet( getOrAddNetItem( netname ) );
533 zone->SetThermalReliefGap( zone->GetLocalClearance().value() );
535 wxString fillStyle = arr[5];
536 if( fillStyle == wxS(
"none" ) )
545 zone->Outline()->AddPolygon( poly );
547 wxString thermal = arr[8];
548 if( thermal == wxS(
"direct" ) )
551 wxString keepIsland = arr[9];
552 if( keepIsland == wxS(
"yes" ) )
555 wxString fillData = arr[10];
559 for(
const nlohmann::json& polyData : nlohmann::json::parse( fillData ) )
561 for(
const nlohmann::json& contourData : polyData )
568 for(
int i = 1; i < contourPolySet.
OutlineCount(); i++ )
571 fillPolySet.
Append( currentOutline );
577 zone->SetFilledPolysList( layer, fillPolySet );
578 zone->SetIsFilled(
true );
579 zone->SetNeedRefill(
false );
581 catch( nlohmann::json::exception& e )
585 int fillOrder = wxAtoi( arr[13] );
586 zone->SetAssignedPriority( 100 - fillOrder );
588 wxString improveFabrication = arr[17];
589 if( improveFabrication == wxS(
"none" ) )
591 zone->SetMinThickness( 0 );
596 int minThickness = std::max(
pcbIUScale.mmToIU( 0.03 ),
598 zone->SetMinThickness( minThickness );
601 if( arr.size() > 18 )
603 zone->SetThermalReliefSpokeWidth( std::max(
int(
ConvertSize( arr[18] ) ),
604 zone->GetMinThickness() ) );
608 wxFAIL_MSG( wxString::Format(
"COPPERAREA unexpected size %d: %s ",
612 zone->SetThermalReliefSpokeWidth( zone->GetMinThickness() );
617 else if( elType == wxS(
"SVGNODE" ) )
619 nlohmann::json nodeData = nlohmann::json::parse( arr[1] );
621 int nodeType = nodeData.at(
"nodeType" );
622 wxString layer = nodeData.at(
"layerid" );
627 std::map<wxString, wxString> attributes = nodeData.at(
"attrs" );
629 if( layer == wxS(
"19" ) )
634 auto ec_eType =
get_opt( attributes,
"c_etype" );
635 auto ec_rotation =
get_opt( attributes,
"c_rotation" );
636 auto ec_origin =
get_opt( attributes,
"c_origin" );
637 auto ec_width =
get_opt( attributes,
"c_width" );
638 auto ec_height =
get_opt( attributes,
"c_height" );
639 auto ez =
get_opt( attributes,
"z" );
640 auto etitle =
get_opt( attributes,
"title" );
641 auto euuid =
get_opt( attributes,
"uuid" );
642 auto etransform =
get_opt( attributes,
"transform" );
644 if( !ec_eType || *ec_eType != wxS(
"outline3D" ) || !etitle )
647 wxString modelTitle = *etitle;
658 footprint->
Add( field );
671 if( ec_width && ec_height )
676 double rounding = 0.001;
677 fitXmm =
KiROUND( fitXmm / rounding ) * rounding;
678 fitYmm =
KiROUND( fitYmm / rounding ) * rounding;
684 field->
SetText( wxString::FromCDouble( fitXmm ) + wxS(
" " )
685 + wxString::FromCDouble( fitYmm ) );
686 footprint->
Add( field );
691 wxArrayString orParts = wxSplit( *ec_origin,
',',
'\0' );
693 if( orParts.size() == 2 )
696 pos.
x =
Convert( orParts[0].Trim() );
697 pos.
y =
Convert( orParts[1].Trim() );
715 wxArrayString rotParts = wxSplit( *ec_rotation,
',',
'\0' );
717 if( rotParts.size() == 3 )
719 kmodelRotation.
x = -
Convert( rotParts[0].Trim() );
720 kmodelRotation.
y = -
Convert( rotParts[1].Trim() );
721 kmodelRotation.
z = -
Convert( rotParts[2].Trim() )
728 kmodelRotation.
z = 180 - kmodelRotation.
z;
738 footprint->
Models().push_back( model );
742 if(
auto dataStr =
get_opt( attributes,
"d" ) )
746 if( dataStr->size() >= 8000 )
753 std::unique_ptr<PCB_GROUP>
group;
756 group = std::make_unique<PCB_GROUP>( aContainer );
760 auto shape = std::make_unique<PCB_SHAPE>( aContainer,
SHAPE_T::POLY );
762 shape->SetFilled(
true );
763 shape->SetPolyShape( poly );
764 shape->SetLayer( klayer );
765 shape->SetWidth( 0 );
768 group->AddItem( shape.get() );
780 THROW_IO_ERROR( wxString::Format(
_(
"Unknown SVGNODE nodeType %d" ), nodeType ) );
783 else if( elType == wxS(
"TEXT" ) )
786 wxString textType = arr[1];
788 if( footprint && textType == wxS(
"P" ) )
792 else if( footprint && textType == wxS(
"N" ) )
796 else if( arr[12] == wxS(
"none" ) )
810 text->SetPosition( start );
813 text->SetTextThickness( thickness );
815 double rot =
Convert( arr[5] );
816 text->SetTextAngleDegrees( rot );
822 text->SetLayer( layer );
825 text->SetMirrored(
true );
830 wxString textStr = arr[10];
831 textStr.Replace( wxS(
"\\n" ), wxS(
"\n" ) );
836 wxString font = arr[14];
837 if( !font.IsEmpty() )
842 else if( elType == wxS(
"VIA" ) )
850 std::unique_ptr<PAD>
pad = std::make_unique<PAD>( footprint );
864 std::unique_ptr<PCB_VIA>
via = std::make_unique<PCB_VIA>( aContainer );
869 via->SetNet( getOrAddNetItem( arr[4] ) );
870 via->SetDrill( kdrill );
875 else if( elType == wxS(
"HOLE" ) )
881 wxString holeUuid = arr[4];
885 padContainer = footprint;
889 std::unique_ptr<FOOTPRINT> newFootprint =
890 std::make_unique<FOOTPRINT>(
dynamic_cast<BOARD*
>( aContainer ) );
892 wxString
name = wxS(
"Hole_" ) + holeUuid;
894 newFootprint->SetFPID(
LIB_ID( wxEmptyString,
name ) );
895 newFootprint->SetPosition(
center );
896 newFootprint->SetLocked(
true );
898 newFootprint->Reference().SetText(
name );
899 newFootprint->Reference().SetVisible(
false );
901 newFootprint->Value().SetText(
name );
902 newFootprint->Value().SetVisible(
false );
905 padContainer = newFootprint.get();
909 std::unique_ptr<PAD>
pad = std::make_unique<PAD>( padContainer );
921 else if( elType == wxS(
"PAD" ) )
927 wxString padUuid = arr[12];
931 padContainer = footprint;
935 std::unique_ptr<FOOTPRINT> newFootprint =
936 std::make_unique<FOOTPRINT>(
dynamic_cast<BOARD*
>( aContainer ) );
938 wxString
name = wxS(
"Pad_" ) + padUuid;
940 newFootprint->SetFPID(
LIB_ID( wxEmptyString,
name ) );
941 newFootprint->SetPosition(
center );
942 newFootprint->SetLocked(
true );
944 newFootprint->Reference().SetText(
name );
945 newFootprint->Reference().SetVisible(
false );
947 newFootprint->Value().SetText(
name );
948 newFootprint->Value().SetVisible(
false );
951 padContainer = newFootprint.get();
955 std::unique_ptr<PAD>
pad = std::make_unique<PAD>( padContainer );
957 pad->SetNet( getOrAddNetItem( arr[7] ) );
958 pad->SetNumber( arr[8] );
961 pad->SetOrientationDegrees(
Convert( arr[11] ) );
964 wxString elayer = arr[6];
967 bool plated = arr[15] == wxS(
"Y" );
975 else if( klayer ==
B_Cu )
981 else if( elayer == wxS(
"11" ) )
988 pad->SetLayer( klayer );
989 pad->SetLayerSet(
LSET( { klayer } ) );
993 wxString padType = arr[1];
994 if( padType == wxS(
"ELLIPSE" ) )
998 else if( padType == wxS(
"RECT" ) )
1002 else if( padType == wxS(
"OVAL" ) )
1004 if(
pad->GetSizeX() ==
pad->GetSizeY() )
1009 else if( padType == wxS(
"POLYGON" ) )
1015 wxArrayString data = wxSplit( arr[10],
' ',
'\0' );
1018 for(
int i = 1; i < data.size(); i += 2 )
1025 chain.SetClosed(
true );
1028 chain.Rotate( -
pad->GetOrientation() );
1032 wxString holeDia = arr[9];
1033 if( !holeDia.IsEmpty() )
1038 wxString holeLength = arr[13];
1039 if( !holeLength.IsEmpty() )
1046 if( size.
x < size.
y )
1058 wxString pasteExp = arr[17];
1059 if( !pasteExp.IsEmpty() )
1062 pad->SetLocalSolderPasteMargin( pasteExpansion );
1065 wxString maskExp = arr[18];
1066 if( !maskExp.IsEmpty() )
1069 pad->SetLocalSolderMaskMargin( maskExpansion );