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 );