401 const std::map<wxString, wxString>& aDeviceAttributes )
405 std::unique_ptr<LIB_SYMBOL> ksymbolPtr = std::make_unique<LIB_SYMBOL>( wxEmptyString );
408 std::map<wxString, nlohmann::json> lineStyles;
409 std::map<wxString, nlohmann::json> fontStyles;
410 std::map<wxString, int> partUnits;
412 std::map<int, std::map<wxString, EASYEDAPRO::SCH_ATTR>> unitAttributes;
413 std::map<int, std::map<wxString, std::vector<nlohmann::json>>> unitParentedLines;
417 for(
const nlohmann::json& line : aLines )
419 wxString type = line.at( 0 );
421 if( type == wxS(
"LINESTYLE" ) )
422 lineStyles[line.at( 1 )] = line;
423 else if( type == wxS(
"FONTSTYLE" ) )
424 fontStyles[line.at( 1 )] = line;
425 else if( type == wxS(
"PART" ) )
426 partUnits[line.at( 1 )] = ++totalUnits;
434 for(
const nlohmann::json& line : aLines )
436 wxString type = line.at( 0 );
438 if( type == wxS(
"PART" ) )
440 currentUnit = partUnits.at( line.at( 1 ) );
442 else if( type == wxS(
"RECT" ) )
444 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
446 wxString styleStr = line.at( 9 );
453 rect->SetUnit( currentUnit );
458 else if( type == wxS(
"CIRCLE" ) )
461 double radius = line.at( 4 );
462 wxString styleStr = line.at( 5 );
469 circle->SetUnit( currentUnit );
474 else if( type == wxS(
"ARC" ) )
476 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
477 VECTOR2D mid( line.at( 4 ), line.at( 5 ) );
479 wxString styleStr = line.at( 8 );
487 shape->SetArcGeometry( kstart, kmid, kend );
489 shape->SetUnit( currentUnit );
494 else if( type == wxS(
"BEZIER" ) )
496 std::vector<double> points = line.at( 2 );
497 wxString styleStr = line.at( 3 );
499 std::unique_ptr<SCH_SHAPE> shape =
502 for(
size_t i = 1; i < points.size(); i += 2 )
508 case 1: shape->SetStart( pt );
break;
509 case 3: shape->SetBezierC1( pt );
break;
510 case 5: shape->SetBezierC2( pt );
break;
511 case 7: shape->SetEnd( pt );
break;
515 shape->SetUnit( currentUnit );
520 else if( type == wxS(
"POLY" ) )
522 std::vector<double> points = line.at( 2 );
523 wxString styleStr = line.at( 4 );
527 for(
size_t i = 1; i < points.size(); i += 2 )
530 shape->SetUnit( currentUnit );
535 else if( type == wxS(
"TEXT" ) )
537 VECTOR2D pos( line.at( 2 ), line.at( 3 ) );
538 double angle = line.at( 4 ).is_number() ? line.at( 4 ).get<
double>() : 0.0;
539 wxString textStr = line.at( 5 );
540 wxString fontStyleStr = line.at( 6 );
547 text->SetTextAngleDegrees( angle );
549 text->SetUnit( currentUnit );
554 else if( type == wxS(
"OBJ" ) )
557 wxString mimeType, data;
561 if( line.at( 3 ).is_number() )
563 start =
VECTOR2D( line.at( 3 ), line.at( 4 ) );
564 size =
VECTOR2D( line.at( 5 ), line.at( 6 ) );
566 upsideDown = line.at( 8 );
568 wxString imageUrl = line.at( 9 );
570 if( imageUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
572 wxArrayString paramsArr =
573 wxSplit( imageUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
575 data = imageUrl.AfterFirst(
',' );
577 if( paramsArr.size() > 0 )
579 mimeType = paramsArr[0];
583 else if( line.at( 3 ).is_string() )
585 mimeType = line.at( 3 ).get<wxString>().BeforeFirst(
';' );
587 start =
VECTOR2D( line.at( 4 ), line.at( 5 ) );
588 size =
VECTOR2D( line.at( 6 ), line.at( 7 ) );
590 data = line.at( 9 ).get<wxString>();
593 if( mimeType.empty() || data.empty() )
596 wxMemoryBuffer buf = wxBase64Decode( data );
598 if( mimeType == wxS(
"image/svg+xml" ) )
617 libsymImporter.
SetScale( pixelScale );
626 for( std::unique_ptr<EDA_ITEM>& item : libsymImporter.
GetItems() )
631 wxMemoryInputStream memis( buf.GetData(), buf.GetDataLen() );
633 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
634 & ~wxImage::Load_Verbose );
636 if( img.LoadFile( memis, mimeType ) )
638 int dimMul = img.GetWidth() * img.GetHeight();
639 double maxPixels = 30000;
641 if( dimMul > maxPixels )
643 double scale = sqrt( maxPixels / dimMul );
644 img.Rescale( img.GetWidth() *
scale, img.GetHeight() *
scale );
655 else if( type == wxS(
"HEAD" ) )
659 else if( type == wxS(
"PIN" ) )
661 wxString pinId = line.at( 1 );
662 unitParentedLines[currentUnit][pinId].push_back( line );
664 else if( type == wxS(
"ATTR" ) )
666 wxString parentId = line.at( 2 );
668 if( parentId.empty() )
671 unitAttributes[currentUnit].emplace( attr.
key, attr );
675 unitParentedLines[currentUnit][parentId].push_back( line );
690 if(
auto globalNetAttr =
get_opt( unitAttributes[1], wxS(
"Global Net Name" ) ) )
694 wxString globalNetname = globalNetAttr->value;
696 if( !globalNetname.empty() )
699 _(
"Power symbol creates a global label with name '%s'" ),
706 auto designatorAttr =
get_opt( unitAttributes[1], wxS(
"Designator" ) );
708 if( designatorAttr && !designatorAttr->value.empty() )
710 wxString symbolPrefix = designatorAttr->value;
712 if( symbolPrefix.EndsWith( wxS(
"?" ) ) )
713 symbolPrefix.RemoveLast();
720 if(
auto valOpt =
get_opt( aDeviceAttributes, attrName ) )
722 if( valOpt->empty() )
733 wxString value = *valOpt;
735 value.
Replace( wxS(
"\u2103" ), wxS(
"\u00B0C" ),
true );
743 for(
auto& [unitId, parentedLines] : unitParentedLines )
745 for(
auto& [pinId, lines] : parentedLines )
747 std::optional<EASYEDAPRO::SYM_PIN> epin;
748 std::map<wxString, EASYEDAPRO::SCH_ATTR> pinAttributes;
750 for(
const nlohmann::json& line : lines )
752 wxString type = line.at( 0 );
754 if( type == wxS(
"ATTR" ) )
757 pinAttributes.emplace( attr.
key, attr );
759 else if( type == wxS(
"PIN" ) )
771 std::unique_ptr<SCH_PIN>
pin = std::make_unique<SCH_PIN>( ksymbol );
773 pin->SetUnit( unitId );
780 if( epin->rotation == 0 )
782 if( epin->rotation == 90 )
784 if( epin->rotation == 180 )
786 if( epin->rotation == 270 )
789 pin->SetOrientation( orient );
798 auto pinNameAttr =
get_opt( pinAttributes,
"Pin Name" );
801 pinNameAttr =
get_opt( pinAttributes,
"NAME" );
805 pin->SetName( pinNameAttr->value );
806 pinInfo.
name = pinNameAttr->value;
808 if( !pinNameAttr->valVisible )
813 auto pinNumAttr =
get_opt( pinAttributes,
"Pin Number" );
816 pinNumAttr =
get_opt( pinAttributes,
"NUMBER" );
820 pin->SetNumber( pinNumAttr->value );
821 pinInfo.
number = pinNumAttr->value;
823 if( !pinNumAttr->valVisible )
831 else if(
auto pinTypeAttr =
get_opt( pinAttributes,
"Pin Type" ) )
833 if( pinTypeAttr->value == wxS(
"IN" ) )
835 if( pinTypeAttr->value == wxS(
"OUT" ) )
837 if( pinTypeAttr->value == wxS(
"BI" ) )
841 if(
get_opt( pinAttributes,
"NO_CONNECT" ) )
844 if(
pin->GetNumberTextSize() *
int(
pin->GetNumber().size() ) >
pin->GetLength() )
845 pin->SetNumberTextSize(
pin->GetLength() /
pin->GetNumber().size() );
847 symInfo.
pins.push_back( pinInfo );
865 symInfo.
libSymbol = std::move( ksymbolPtr );
872 const nlohmann::json& aProject,
873 std::map<wxString, EASYEDAPRO::SYM_INFO>& aSymbolMap,
874 const std::map<wxString, EASYEDAPRO::BLOB>& aBlobMap,
875 const std::vector<nlohmann::json>& aLines,
876 const wxString& aLibName )
878 std::vector<std::unique_ptr<SCH_ITEM>> createdItems;
880 std::map<wxString, std::vector<nlohmann::json>> parentedLines;
881 std::map<wxString, std::vector<nlohmann::json>> ruleLines;
883 std::map<wxString, nlohmann::json> lineStyles;
884 std::map<wxString, nlohmann::json> fontStyles;
886 for(
const nlohmann::json& line : aLines )
888 wxString type = line.at( 0 );
890 if( type == wxS(
"LINESTYLE" ) )
891 lineStyles[line.at( 1 )] = line;
892 else if( type == wxS(
"FONTSTYLE" ) )
893 fontStyles[line.at( 1 )] = line;
896 for(
const nlohmann::json& line : aLines )
898 wxString type = line.at( 0 );
900 if( type == wxS(
"RECT" ) )
902 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
904 wxString styleStr = line.at( 9 );
908 rect->SetStart(
ScalePos( start ) );
913 createdItems.push_back( std::move( rect ) );
915 else if( type == wxS(
"CIRCLE" ) )
918 double radius = line.at( 4 );
919 wxString styleStr = line.at( 5 );
928 createdItems.push_back( std::move(
circle ) );
930 else if( type == wxS(
"POLY" ) )
932 std::vector<double> points = line.at( 2 );
933 wxString styleStr = line.at( 4 );
937 for(
size_t i = 1; i < points.size(); i += 2 )
940 for(
int segId = 0; segId <
chain.SegmentCount(); segId++ )
942 const SEG& seg =
chain.CSegment( segId );
944 std::unique_ptr<SCH_LINE> schLine =
946 schLine->SetEndPoint( seg.
B );
950 createdItems.push_back( std::move( schLine ) );
953 else if( type == wxS(
"TEXT" ) )
955 VECTOR2D pos( line.at( 2 ), line.at( 3 ) );
956 double angle = line.at( 4 ).is_number() ? line.at( 4 ).get<
double>() : 0.0;
957 wxString textStr = line.at( 5 );
958 wxString fontStyleStr = line.at( 6 );
960 std::unique_ptr<SCH_TEXT>
text =
966 text->SetTextAngleDegrees( angle );
970 createdItems.push_back( std::move(
text ) );
972 else if( type == wxS(
"OBJ" ) )
975 wxString mimeType, base64Data;
979 if( line.at( 3 ).is_number() )
981 start =
VECTOR2D( line.at( 3 ), line.at( 4 ) );
982 size =
VECTOR2D( line.at( 5 ), line.at( 6 ) );
983 angle = line.at( 7 );
984 flipped = line.at( 8 );
986 wxString imageUrl = line.at( 9 );
988 if( imageUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
990 wxArrayString paramsArr =
991 wxSplit( imageUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
993 base64Data = imageUrl.AfterFirst(
',' );
995 if( paramsArr.size() > 0 )
996 mimeType = paramsArr[0];
998 else if( imageUrl.BeforeFirst(
':' ) == wxS(
"blob" ) )
1000 wxString objectId = imageUrl.AfterLast(
':' );
1002 if(
auto blob =
get_opt( aBlobMap, objectId ) )
1004 wxString blobUrl = blob->url;
1006 if( blobUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
1008 wxArrayString paramsArr = wxSplit(
1009 blobUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
1011 base64Data = blobUrl.AfterFirst(
',' );
1013 if( paramsArr.size() > 0 )
1014 mimeType = paramsArr[0];
1019 else if( line.at( 3 ).is_string() )
1021 mimeType = line.at( 3 ).get<wxString>().BeforeFirst(
';' );
1023 start =
VECTOR2D( line.at( 4 ), line.at( 5 ) );
1024 size =
VECTOR2D( line.at( 6 ), line.at( 7 ) );
1025 angle = line.at( 8 );
1026 base64Data = line.at( 9 ).get<wxString>();
1032 if( mimeType.empty() || base64Data.empty() )
1035 wxMemoryBuffer buf = wxBase64Decode( base64Data );
1037 if( mimeType == wxS(
"image/svg+xml" ) )
1051 schImporter.
SetScale( pixelScale );
1057 svgImportPlugin.
Import();
1059 for( std::unique_ptr<EDA_ITEM>& item : schImporter.
GetItems() )
1063 for(
double i = angle; i > 0; i -= 90 )
1069 schItem->
Rotate( kstart,
false );
1073 schItem->
Rotate( kstart,
false );
1078 schItem->
Rotate( kstart,
false );
1094 createdItems.emplace_back( schItem );
1099 std::unique_ptr<SCH_BITMAP> bitmap = std::make_unique<SCH_BITMAP>();
1102 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
1103 & ~wxImage::Load_Verbose );
1107 VECTOR2D kcenter = kstart + ksize / 2;
1111 bitmap->SetPosition( kcenter );
1113 for(
double i = angle; i > 0; i -= 90 )
1114 bitmap->Rotate( kstart,
false );
1117 bitmap->MirrorHorizontally( kstart.
x );
1119 createdItems.push_back( std::move( bitmap ) );
1123 if( type == wxS(
"WIRE" ) )
1125 wxString wireId = line.at( 1 );
1126 parentedLines[wireId].push_back( line );
1128 else if( type == wxS(
"COMPONENT" ) )
1130 wxString compId = line.at( 1 );
1131 parentedLines[compId].push_back( line );
1133 else if( type == wxS(
"ATTR" ) )
1135 wxString compId = line.at( 2 );
1136 parentedLines[compId].push_back( line );
1140 for(
auto& [parentId, lines] : parentedLines )
1142 std::optional<EASYEDAPRO::SCH_COMPONENT> component;
1143 std::optional<EASYEDAPRO::SCH_WIRE> wire;
1144 std::map<wxString, EASYEDAPRO::SCH_ATTR> attributes;
1146 for(
const nlohmann::json& line : lines )
1148 if( line.at( 0 ) ==
"COMPONENT" )
1152 else if( line.at( 0 ) ==
"WIRE" )
1156 else if( line.at( 0 ) ==
"ATTR" )
1159 attributes.emplace( attr.
key, attr );
1165 auto deviceAttr =
get_opt( attributes,
"Device" );
1166 auto symbolAttr =
get_opt( attributes,
"Symbol" );
1172 aProject.at(
"devices" ).at( deviceAttr->value ).at(
"attributes" ) );
1176 if( symbolAttr && !symbolAttr->value.IsEmpty() )
1177 symbolId = symbolAttr->value;
1179 symbolId = compAttrs.at(
"Symbol" );
1181 auto it = aSymbolMap.find( symbolId );
1182 if( it == aSymbolMap.end() )
1184 wxLogError(
"Symbol of '%s' with uuid '%s' not found.", component->name, symbolId );
1191 wxString unitName = component->name;
1196 auto schSym = std::make_unique<SCH_SYMBOL>( newLibSymbol, libId,
1200 schSym->SetFootprintFieldText( newLibSymbol.
GetFootprint() );
1202 for(
double i = component->rotation; i > 0; i -= 90 )
1203 schSym->Rotate(
VECTOR2I(),
true );
1205 if( component->mirror )
1206 schSym->MirrorHorizontally( 0 );
1208 schSym->SetPosition(
ScalePos( component->position ) );
1214 auto globalNetNameAttr =
get_opt( attributes,
"Global Net Name" );
1215 wxString globalNetNameFromProject =
get_def( compAttrs,
"Global Net Name", wxEmptyString );
1216 wxString globalNetName;
1221 if( globalNetNameAttr && !globalNetNameAttr->value.IsEmpty() )
1223 globalNetName = globalNetNameAttr->value;
1226 compAttrs, schSym.get() );
1228 else if( !globalNetNameFromProject.IsEmpty() )
1230 globalNetName = globalNetNameFromProject;
1239 for(
SCH_PIN*
pin : schSym->GetAllLibPins() )
1240 pin->SetName( globalNetName );
1242 schSym->SetRef( &aSchematic->
CurrentSheet(), wxS(
"#PWR?" ) );
1247 auto nameAttr =
get_opt( attributes,
"Name" );
1251 if( nameAttr && !nameAttr->value.IsEmpty() )
1252 netName = nameAttr->value;
1254 netName = compAttrs.at(
"Name" );
1256 std::unique_ptr<SCH_GLOBALLABEL> label = std::make_unique<SCH_GLOBALLABEL>(
1257 ScalePos( component->position ), netName );
1259 std::vector<SCH_PIN*> pins = schSym->GetPins( &aSchematic->
CurrentSheet() );
1261 if( pins.size() > 0 )
1263 switch( pins[0]->GetType() )
1278 BOX2I bbox = schSym->GetBodyAndPinsBoundingBox();
1279 bbox.
Offset( -schSym->GetPosition() );
1286 if( bboxCenter.
x >= 0 )
1293 if( bboxCenter.
y >= 0 )
1299 label->SetSpinStyle( spin );
1303 nlohmann::json style = fontStyles[nameAttr->fontStyle];
1305 if( !style.is_null() && style.at( 5 ).is_number() )
1307 double size = style.at( 5 ).get<
double>() * 0.62;
1312 createdItems.push_back( std::move( label ) );
1320 if(
auto valOpt =
get_opt( compAttrs, attrKey ) )
1322 if( valOpt->empty() )
1325 SCH_FIELD*
text = schSym->FindFieldCaseInsensitive( attrKey );
1330 schSym->AddField(
text );
1333 wxString value = *valOpt;
1335 value.Replace( wxS(
"\u2103" ), wxS(
"\u00B0C" ),
true );
1337 text->SetText( value );
1338 text->SetVisible(
false );
1342 auto nameAttr =
get_opt( attributes,
"Name" );
1343 auto valueAttr =
get_opt( attributes,
"Value" );
1345 if( valueAttr && valueAttr->value.empty() )
1346 valueAttr->value =
get_def( compAttrs,
"Value", wxString() );
1348 if( nameAttr && nameAttr->value.empty() )
1349 nameAttr->value =
get_def( compAttrs,
"Name", wxString() );
1351 std::optional<EASYEDAPRO::SCH_ATTR> targetValueAttr;
1353 if( valueAttr && !valueAttr->value.empty() && valueAttr->valVisible )
1354 targetValueAttr = valueAttr;
1355 else if( nameAttr && !nameAttr->value.empty() && nameAttr->valVisible )
1356 targetValueAttr = nameAttr;
1357 else if( valueAttr && !valueAttr->value.empty() )
1358 targetValueAttr = valueAttr;
1359 else if( nameAttr && !nameAttr->value.empty() )
1360 targetValueAttr = nameAttr;
1362 if( targetValueAttr )
1365 *targetValueAttr,
false,
true, compAttrs, schSym.get() );
1368 if(
auto descrAttr =
get_opt( attributes,
"Description" ) )
1371 *descrAttr,
false,
true, compAttrs, schSym.get() );
1374 if(
auto designatorAttr =
get_opt( attributes,
"Designator" ) )
1377 *designatorAttr,
false,
true, compAttrs, schSym.get() );
1379 schSym->SetRef( &aSchematic->
CurrentSheet(), designatorAttr->value );
1382 for(
auto& [attrKey, attr] : attributes )
1384 if( attrKey == wxS(
"Name" ) || attrKey == wxS(
"Value" )
1385 || attrKey == wxS(
"Global Net Name" ) || attrKey == wxS(
"Designator" )
1386 || attrKey == wxS(
"Description" ) || attrKey == wxS(
"Device" )
1387 || attrKey == wxS(
"Footprint" ) || attrKey == wxS(
"Symbol" )
1388 || attrKey == wxS(
"Unique ID" ) )
1393 if( attr.value.IsEmpty() )
1396 SCH_FIELD*
text = schSym->FindFieldCaseInsensitive( attrKey );
1401 schSym->AddField(
text );
1404 text->SetPosition( schSym->GetPosition() );
1413 wxString pinKey = parentId + pinInfo.
pin.
id;
1414 auto pinLines =
get_opt( parentedLines, pinKey );
1419 for(
const nlohmann::json& pinLine : *pinLines )
1421 if( pinLine.at( 0 ) !=
"ATTR" )
1426 if( attr.
key != wxS(
"NO_CONNECT" ) )
1431 VECTOR2I pos = schSym->GetPinPhysicalPosition( schPin->GetLibPin() );
1433 std::unique_ptr<SCH_NO_CONNECT> noConn =
1434 std::make_unique<SCH_NO_CONNECT>( pos );
1436 createdItems.push_back( std::move( noConn ) );
1441 createdItems.push_back( std::move( schSym ) );
1445 std::vector<SHAPE_LINE_CHAIN> wireLines;
1449 for(
const std::vector<double>& ptArr : wire->geometry )
1453 for(
size_t i = 1; i < ptArr.size(); i += 2 )
1456 if(
chain.PointCount() < 2 )
1459 wireLines.push_back(
chain );
1461 for(
int segId = 0; segId <
chain.SegmentCount(); segId++ )
1463 const SEG& seg =
chain.CSegment( segId );
1465 std::unique_ptr<SCH_LINE> schLine =
1467 schLine->SetEndPoint( seg.
B );
1469 createdItems.push_back( std::move( schLine ) );
1474 auto netAttr =
get_opt( attributes,
"NET" );
1478 if( !netAttr->valVisible || netAttr->value.IsEmpty() )
1488 SEG::ecoord dist_sq = ( nearestPt - kpos ).SquaredEuclideanNorm();
1490 if( dist_sq < min_dist_sq )
1492 min_dist_sq = dist_sq;
1493 nearestPos = nearestPt;
1497 std::unique_ptr<SCH_LABEL> label = std::make_unique<SCH_LABEL>();
1502 for(
double i = netAttr->rotation; i > 0; i -= 90 )
1503 label->Rotate90(
true );
1505 label->SetPosition( nearestPos );
1506 label->SetText( netAttr->value );
1510 createdItems.push_back( std::move( label ) );
1518 for( std::unique_ptr<SCH_ITEM>& ptr : createdItems )
1523 sheetBBox.
Merge( ptr->GetBoundingBox() );
1532 offset.
x =
KiROUND( offset.
x / alignGrid ) * alignGrid;
1533 offset.
y =
KiROUND( offset.
y / alignGrid ) * alignGrid;
1540 for( std::unique_ptr<SCH_ITEM>& ptr : createdItems )
1542 ptr->Move( offset );
1543 screen->
Append( ptr.release() );