404 const std::map<wxString, wxString>& aDeviceAttributes )
408 std::unique_ptr<LIB_SYMBOL> ksymbolPtr = std::make_unique<LIB_SYMBOL>( wxEmptyString );
411 std::map<wxString, nlohmann::json> lineStyles;
412 std::map<wxString, nlohmann::json> fontStyles;
413 std::map<wxString, int> partUnits;
415 std::map<int, std::map<wxString, EASYEDAPRO::SCH_ATTR>> unitAttributes;
416 std::map<int, std::map<wxString, std::vector<nlohmann::json>>> unitParentedLines;
420 for(
const nlohmann::json& line : aLines )
422 wxString type = line.at( 0 );
424 if( type == wxS(
"LINESTYLE" ) )
425 lineStyles[line.at( 1 )] = line;
426 else if( type == wxS(
"FONTSTYLE" ) )
427 fontStyles[line.at( 1 )] = line;
428 else if( type == wxS(
"PART" ) )
429 partUnits[line.at( 1 )] = ++totalUnits;
437 for(
const nlohmann::json& line : aLines )
439 wxString type = line.at( 0 );
441 if( type == wxS(
"PART" ) )
443 currentUnit = partUnits.at( line.at( 1 ) );
445 else if( type == wxS(
"RECT" ) )
447 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
449 wxString styleStr = line.at( 9 );
456 rect->SetUnit( currentUnit );
461 else if( type == wxS(
"CIRCLE" ) )
464 double radius = line.at( 4 );
465 wxString styleStr = line.at( 5 );
472 circle->SetUnit( currentUnit );
477 else if( type == wxS(
"ARC" ) )
479 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
480 VECTOR2D mid( line.at( 4 ), line.at( 5 ) );
482 wxString styleStr = line.at( 8 );
490 shape->SetArcGeometry( kstart, kmid, kend );
492 shape->SetUnit( currentUnit );
497 else if( type == wxS(
"BEZIER" ) )
499 std::vector<double> points = line.at( 2 );
500 wxString styleStr = line.at( 3 );
502 std::unique_ptr<SCH_SHAPE> shape =
505 for(
size_t i = 1; i < points.size(); i += 2 )
511 case 1: shape->SetStart( pt );
break;
512 case 3: shape->SetBezierC1( pt );
break;
513 case 5: shape->SetBezierC2( pt );
break;
514 case 7: shape->SetEnd( pt );
break;
518 shape->SetUnit( currentUnit );
523 else if( type == wxS(
"POLY" ) )
525 std::vector<double> points = line.at( 2 );
526 wxString styleStr = line.at( 4 );
530 for(
size_t i = 1; i < points.size(); i += 2 )
533 shape->SetUnit( currentUnit );
538 else if( type == wxS(
"TEXT" ) )
540 VECTOR2D pos( line.at( 2 ), line.at( 3 ) );
541 double angle = line.at( 4 ).is_number() ? line.at( 4 ).get<
double>() : 0.0;
542 wxString textStr = line.at( 5 );
543 wxString fontStyleStr = line.at( 6 );
550 text->SetTextAngleDegrees( angle );
552 text->SetUnit( currentUnit );
557 else if( type == wxS(
"OBJ" ) )
560 wxString mimeType, data;
564 if( line.at( 3 ).is_number() )
566 start =
VECTOR2D( line.at( 3 ), line.at( 4 ) );
567 size =
VECTOR2D( line.at( 5 ), line.at( 6 ) );
569 upsideDown = line.at( 8 );
571 wxString imageUrl = line.at( 9 );
573 if( imageUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
575 wxArrayString paramsArr =
576 wxSplit( imageUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
578 data = imageUrl.AfterFirst(
',' );
580 if( paramsArr.size() > 0 )
582 mimeType = paramsArr[0];
586 else if( line.at( 3 ).is_string() )
588 mimeType = line.at( 3 ).get<wxString>().BeforeFirst(
';' );
590 start =
VECTOR2D( line.at( 4 ), line.at( 5 ) );
591 size =
VECTOR2D( line.at( 6 ), line.at( 7 ) );
593 data = line.at( 9 ).get<wxString>();
596 if( mimeType.empty() || data.empty() )
599 wxMemoryBuffer buf = wxBase64Decode( data );
601 if( mimeType == wxS(
"image/svg+xml" ) )
620 libsymImporter.
SetScale( pixelScale );
629 for( std::unique_ptr<EDA_ITEM>& item : libsymImporter.
GetItems() )
634 wxMemoryInputStream memis( buf.GetData(), buf.GetDataLen() );
636 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
637 & ~wxImage::Load_Verbose );
639 if( img.LoadFile( memis, mimeType ) )
641 int dimMul = img.GetWidth() * img.GetHeight();
642 double maxPixels = 30000;
644 if( dimMul > maxPixels )
646 double scale = sqrt( maxPixels / dimMul );
647 img.Rescale( img.GetWidth() *
scale, img.GetHeight() *
scale );
658 else if( type == wxS(
"HEAD" ) )
662 else if( type == wxS(
"PIN" ) )
664 wxString pinId = line.at( 1 );
665 unitParentedLines[currentUnit][pinId].push_back( line );
667 else if( type == wxS(
"ATTR" ) )
669 wxString parentId = line.at( 2 );
671 if( parentId.empty() )
674 unitAttributes[currentUnit].emplace( attr.
key, attr );
678 unitParentedLines[currentUnit][parentId].push_back( line );
693 if(
auto globalNetAttr =
get_opt( unitAttributes[1], wxS(
"Global Net Name" ) ) )
697 wxString globalNetname = globalNetAttr->value;
699 if( !globalNetname.empty() )
702 _(
"Power symbol creates a global label with name '%s'" ),
709 auto designatorAttr =
get_opt( unitAttributes[1], wxS(
"Designator" ) );
711 if( designatorAttr && !designatorAttr->value.empty() )
713 wxString symbolPrefix = designatorAttr->value;
715 if( symbolPrefix.EndsWith( wxS(
"?" ) ) )
716 symbolPrefix.RemoveLast();
723 if(
auto valOpt =
get_opt( aDeviceAttributes, attrName ) )
725 if( valOpt->empty() )
736 wxString value = *valOpt;
738 value.
Replace( wxS(
"\u2103" ), wxS(
"\u00B0C" ),
true );
746 for(
auto& [unitId, parentedLines] : unitParentedLines )
748 for(
auto& [pinId, lines] : parentedLines )
750 std::optional<EASYEDAPRO::SYM_PIN> epin;
751 std::map<wxString, EASYEDAPRO::SCH_ATTR> pinAttributes;
753 for(
const nlohmann::json& line : lines )
755 wxString type = line.at( 0 );
757 if( type == wxS(
"ATTR" ) )
760 pinAttributes.emplace( attr.
key, attr );
762 else if( type == wxS(
"PIN" ) )
774 std::unique_ptr<SCH_PIN>
pin = std::make_unique<SCH_PIN>( ksymbol );
776 pin->SetUnit( unitId );
783 if( epin->rotation == 0 )
785 if( epin->rotation == 90 )
787 if( epin->rotation == 180 )
789 if( epin->rotation == 270 )
792 pin->SetOrientation( orient );
799 else if(
auto pinNameAttr =
get_opt( pinAttributes,
"NAME" ) )
801 pin->SetName( pinNameAttr->value );
802 pinInfo.
name = pinNameAttr->value;
804 if( !pinNameAttr->valVisible )
808 if(
auto pinNumAttr =
get_opt( pinAttributes,
"NUMBER" ) )
810 pin->SetNumber( pinNumAttr->value );
811 pinInfo.
number = pinNumAttr->value;
813 if( !pinNumAttr->valVisible )
821 else if(
auto pinTypeAttr =
get_opt( pinAttributes,
"Pin Type" ) )
823 if( pinTypeAttr->value == wxS(
"IN" ) )
825 if( pinTypeAttr->value == wxS(
"OUT" ) )
827 if( pinTypeAttr->value == wxS(
"BI" ) )
831 if(
get_opt( pinAttributes,
"NO_CONNECT" ) )
834 if(
pin->GetNumberTextSize() *
int(
pin->GetNumber().size() ) >
pin->GetLength() )
835 pin->SetNumberTextSize(
pin->GetLength() /
pin->GetNumber().size() );
837 symInfo.
pins.push_back( pinInfo );
855 symInfo.
libSymbol = std::move( ksymbolPtr );
862 const nlohmann::json& aProject,
863 std::map<wxString, EASYEDAPRO::SYM_INFO>& aSymbolMap,
864 const std::map<wxString, EASYEDAPRO::BLOB>& aBlobMap,
865 const std::vector<nlohmann::json>& aLines,
866 const wxString& aLibName )
868 std::vector<std::unique_ptr<SCH_ITEM>> createdItems;
870 std::map<wxString, std::vector<nlohmann::json>> parentedLines;
871 std::map<wxString, std::vector<nlohmann::json>> ruleLines;
873 std::map<wxString, nlohmann::json> lineStyles;
874 std::map<wxString, nlohmann::json> fontStyles;
876 for(
const nlohmann::json& line : aLines )
878 wxString type = line.at( 0 );
880 if( type == wxS(
"LINESTYLE" ) )
881 lineStyles[line.at( 1 )] = line;
882 else if( type == wxS(
"FONTSTYLE" ) )
883 fontStyles[line.at( 1 )] = line;
886 for(
const nlohmann::json& line : aLines )
888 wxString type = line.at( 0 );
890 if( type == wxS(
"RECT" ) )
892 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
894 wxString styleStr = line.at( 9 );
898 rect->SetStart(
ScalePos( start ) );
903 createdItems.push_back( std::move( rect ) );
905 else if( type == wxS(
"CIRCLE" ) )
908 double radius = line.at( 4 );
909 wxString styleStr = line.at( 5 );
918 createdItems.push_back( std::move(
circle ) );
920 else if( type == wxS(
"POLY" ) )
922 std::vector<double> points = line.at( 2 );
923 wxString styleStr = line.at( 4 );
927 for(
size_t i = 1; i < points.size(); i += 2 )
930 for(
int segId = 0; segId <
chain.SegmentCount(); segId++ )
932 const SEG& seg =
chain.CSegment( segId );
934 std::unique_ptr<SCH_LINE> schLine =
936 schLine->SetEndPoint( seg.
B );
940 createdItems.push_back( std::move( schLine ) );
943 else if( type == wxS(
"TEXT" ) )
945 VECTOR2D pos( line.at( 2 ), line.at( 3 ) );
946 double angle = line.at( 4 ).is_number() ? line.at( 4 ).get<
double>() : 0.0;
947 wxString textStr = line.at( 5 );
948 wxString fontStyleStr = line.at( 6 );
950 std::unique_ptr<SCH_TEXT>
text =
956 text->SetTextAngleDegrees( angle );
960 createdItems.push_back( std::move(
text ) );
962 else if( type == wxS(
"OBJ" ) )
965 wxString mimeType, base64Data;
969 if( line.at( 3 ).is_number() )
971 start =
VECTOR2D( line.at( 3 ), line.at( 4 ) );
972 size =
VECTOR2D( line.at( 5 ), line.at( 6 ) );
973 angle = line.at( 7 );
974 flipped = line.at( 8 );
976 wxString imageUrl = line.at( 9 );
978 if( imageUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
980 wxArrayString paramsArr =
981 wxSplit( imageUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
983 base64Data = imageUrl.AfterFirst(
',' );
985 if( paramsArr.size() > 0 )
986 mimeType = paramsArr[0];
988 else if( imageUrl.BeforeFirst(
':' ) == wxS(
"blob" ) )
990 wxString objectId = imageUrl.AfterLast(
':' );
992 if(
auto blob =
get_opt( aBlobMap, objectId ) )
994 wxString blobUrl = blob->url;
996 if( blobUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
998 wxArrayString paramsArr = wxSplit(
999 blobUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
1001 base64Data = blobUrl.AfterFirst(
',' );
1003 if( paramsArr.size() > 0 )
1004 mimeType = paramsArr[0];
1009 else if( line.at( 3 ).is_string() )
1011 mimeType = line.at( 3 ).get<wxString>().BeforeFirst(
';' );
1013 start =
VECTOR2D( line.at( 4 ), line.at( 5 ) );
1014 size =
VECTOR2D( line.at( 6 ), line.at( 7 ) );
1015 angle = line.at( 8 );
1016 base64Data = line.at( 9 ).get<wxString>();
1022 if( mimeType.empty() || base64Data.empty() )
1025 wxMemoryBuffer buf = wxBase64Decode( base64Data );
1027 if( mimeType == wxS(
"image/svg+xml" ) )
1041 schImporter.
SetScale( pixelScale );
1047 svgImportPlugin.
Import();
1049 for( std::unique_ptr<EDA_ITEM>& item : schImporter.
GetItems() )
1053 for(
double i = angle; i > 0; i -= 90 )
1059 schItem->
Rotate( kstart,
false );
1063 schItem->
Rotate( kstart,
false );
1068 schItem->
Rotate( kstart,
false );
1084 createdItems.emplace_back( schItem );
1089 std::unique_ptr<SCH_BITMAP> bitmap = std::make_unique<SCH_BITMAP>();
1092 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
1093 & ~wxImage::Load_Verbose );
1097 VECTOR2D kcenter = kstart + ksize / 2;
1101 bitmap->SetPosition( kcenter );
1103 for(
double i = angle; i > 0; i -= 90 )
1104 bitmap->Rotate( kstart,
false );
1107 bitmap->MirrorHorizontally( kstart.
x );
1109 createdItems.push_back( std::move( bitmap ) );
1113 if( type == wxS(
"WIRE" ) )
1115 wxString wireId = line.at( 1 );
1116 parentedLines[wireId].push_back( line );
1118 else if( type == wxS(
"COMPONENT" ) )
1120 wxString compId = line.at( 1 );
1121 parentedLines[compId].push_back( line );
1123 else if( type == wxS(
"ATTR" ) )
1125 wxString compId = line.at( 2 );
1126 parentedLines[compId].push_back( line );
1130 for(
auto& [parentId, lines] : parentedLines )
1132 std::optional<EASYEDAPRO::SCH_COMPONENT> component;
1133 std::optional<EASYEDAPRO::SCH_WIRE> wire;
1134 std::map<wxString, EASYEDAPRO::SCH_ATTR> attributes;
1136 for(
const nlohmann::json& line : lines )
1138 if( line.at( 0 ) ==
"COMPONENT" )
1142 else if( line.at( 0 ) ==
"WIRE" )
1146 else if( line.at( 0 ) ==
"ATTR" )
1149 attributes.emplace( attr.
key, attr );
1155 auto deviceAttr =
get_opt( attributes,
"Device" );
1156 auto symbolAttr =
get_opt( attributes,
"Symbol" );
1162 aProject.at(
"devices" ).at( deviceAttr->value ).at(
"attributes" ) );
1166 if( symbolAttr && !symbolAttr->value.IsEmpty() )
1167 symbolId = symbolAttr->value;
1169 symbolId = compAttrs.at(
"Symbol" );
1171 auto it = aSymbolMap.find( symbolId );
1172 if( it == aSymbolMap.end() )
1174 wxLogError(
"Symbol of '%s' with uuid '%s' not found.", component->name, symbolId );
1181 wxString unitName = component->name;
1186 auto schSym = std::make_unique<SCH_SYMBOL>( newLibSymbol, libId,
1190 schSym->SetFootprintFieldText( newLibSymbol.
GetFootprint() );
1192 for(
double i = component->rotation; i > 0; i -= 90 )
1193 schSym->Rotate(
VECTOR2I(),
true );
1195 if( component->mirror )
1196 schSym->MirrorHorizontally( 0 );
1198 schSym->SetPosition(
ScalePos( component->position ) );
1202 if(
auto globalNetAttr =
get_opt( attributes,
"Global Net Name" ) )
1205 *globalNetAttr,
false,
true, compAttrs, schSym.get() );
1207 for(
SCH_PIN*
pin : schSym->GetAllLibPins() )
1208 pin->SetName( globalNetAttr->value );
1210 else if(
auto nameAttr =
get_opt( attributes,
"Name" ) )
1213 *nameAttr,
false,
true, compAttrs, schSym.get() );
1215 for(
SCH_PIN*
pin : schSym->GetAllLibPins() )
1216 pin->SetName( nameAttr->value );
1224 schSym->SetRef( &aSchematic->
CurrentSheet(), wxS(
"#PWR?" ) );
1229 auto nameAttr =
get_opt( attributes,
"Name" );
1233 if( nameAttr && !nameAttr->value.IsEmpty() )
1234 netName = nameAttr->value;
1236 netName = compAttrs.at(
"Name" );
1238 std::unique_ptr<SCH_GLOBALLABEL> label = std::make_unique<SCH_GLOBALLABEL>(
1239 ScalePos( component->position ), netName );
1241 std::vector<SCH_PIN*> pins = schSym->GetPins( &aSchematic->
CurrentSheet() );
1243 if( pins.size() > 0 )
1245 switch( pins[0]->GetType() )
1260 BOX2I bbox = schSym->GetBodyAndPinsBoundingBox();
1261 bbox.
Offset( -schSym->GetPosition() );
1268 if( bboxCenter.
x >= 0 )
1275 if( bboxCenter.
y >= 0 )
1281 label->SetSpinStyle( spin );
1285 nlohmann::json style = fontStyles[nameAttr->fontStyle];
1287 if( !style.is_null() && style.at( 5 ).is_number() )
1289 double size = style.at( 5 ).get<
double>() * 0.5;
1294 createdItems.push_back( std::move( label ) );
1302 if(
auto valOpt =
get_opt( compAttrs, attrKey ) )
1304 if( valOpt->empty() )
1307 SCH_FIELD*
text = schSym->FindFieldCaseInsensitive( attrKey );
1312 schSym->AddField(
text );
1315 wxString value = *valOpt;
1317 value.Replace( wxS(
"\u2103" ), wxS(
"\u00B0C" ),
true );
1319 text->SetText( value );
1320 text->SetVisible(
false );
1324 auto nameAttr =
get_opt( attributes,
"Name" );
1325 auto valueAttr =
get_opt( attributes,
"Value" );
1327 if( valueAttr && valueAttr->value.empty() )
1328 valueAttr->value =
get_def( compAttrs,
"Value", wxString() );
1330 if( nameAttr && nameAttr->value.empty() )
1331 nameAttr->value =
get_def( compAttrs,
"Name", wxString() );
1333 std::optional<EASYEDAPRO::SCH_ATTR> targetValueAttr;
1335 if( valueAttr && !valueAttr->value.empty() && valueAttr->valVisible )
1336 targetValueAttr = valueAttr;
1337 else if( nameAttr && !nameAttr->value.empty() && nameAttr->valVisible )
1338 targetValueAttr = nameAttr;
1339 else if( valueAttr && !valueAttr->value.empty() )
1340 targetValueAttr = valueAttr;
1341 else if( nameAttr && !nameAttr->value.empty() )
1342 targetValueAttr = nameAttr;
1344 if( targetValueAttr )
1347 *targetValueAttr,
false,
true, compAttrs, schSym.get() );
1350 if(
auto descrAttr =
get_opt( attributes,
"Description" ) )
1353 *descrAttr,
false,
true, compAttrs, schSym.get() );
1356 if(
auto designatorAttr =
get_opt( attributes,
"Designator" ) )
1359 *designatorAttr,
false,
true, compAttrs, schSym.get() );
1361 schSym->SetRef( &aSchematic->
CurrentSheet(), designatorAttr->value );
1364 for(
auto& [attrKey, attr] : attributes )
1366 if( attrKey == wxS(
"Name" ) || attrKey == wxS(
"Value" )
1367 || attrKey == wxS(
"Global Net Name" ) || attrKey == wxS(
"Designator" )
1368 || attrKey == wxS(
"Description" ) || attrKey == wxS(
"Device" )
1369 || attrKey == wxS(
"Footprint" ) || attrKey == wxS(
"Symbol" )
1370 || attrKey == wxS(
"Unique ID" ) )
1375 if( attr.value.IsEmpty() )
1378 SCH_FIELD*
text = schSym->FindFieldCaseInsensitive( attrKey );
1383 schSym->AddField(
text );
1386 text->SetPosition( schSym->GetPosition() );
1395 wxString pinKey = parentId + pinInfo.
pin.
id;
1396 auto pinLines =
get_opt( parentedLines, pinKey );
1401 for(
const nlohmann::json& pinLine : *pinLines )
1403 if( pinLine.at( 0 ) !=
"ATTR" )
1408 if( attr.
key != wxS(
"NO_CONNECT" ) )
1413 VECTOR2I pos = schSym->GetPinPhysicalPosition( schPin->GetLibPin() );
1415 std::unique_ptr<SCH_NO_CONNECT> noConn =
1416 std::make_unique<SCH_NO_CONNECT>( pos );
1418 createdItems.push_back( std::move( noConn ) );
1423 createdItems.push_back( std::move( schSym ) );
1427 std::vector<SHAPE_LINE_CHAIN> wireLines;
1431 for(
const std::vector<double>& ptArr : wire->geometry )
1435 for(
size_t i = 1; i < ptArr.size(); i += 2 )
1438 if(
chain.PointCount() < 2 )
1441 wireLines.push_back(
chain );
1443 for(
int segId = 0; segId <
chain.SegmentCount(); segId++ )
1445 const SEG& seg =
chain.CSegment( segId );
1447 std::unique_ptr<SCH_LINE> schLine =
1449 schLine->SetEndPoint( seg.
B );
1451 createdItems.push_back( std::move( schLine ) );
1456 auto netAttr =
get_opt( attributes,
"NET" );
1460 if( !netAttr->valVisible || netAttr->value.IsEmpty() )
1470 SEG::ecoord dist_sq = ( nearestPt - kpos ).SquaredEuclideanNorm();
1472 if( dist_sq < min_dist_sq )
1474 min_dist_sq = dist_sq;
1475 nearestPos = nearestPt;
1479 std::unique_ptr<SCH_LABEL> label = std::make_unique<SCH_LABEL>();
1484 for(
double i = netAttr->rotation; i > 0; i -= 90 )
1485 label->Rotate90(
true );
1487 label->SetPosition( nearestPos );
1488 label->SetText( netAttr->value );
1492 createdItems.push_back( std::move( label ) );
1500 for( std::unique_ptr<SCH_ITEM>& ptr : createdItems )
1505 sheetBBox.
Merge( ptr->GetBoundingBox() );
1514 offset.
x =
KiROUND( offset.
x / alignGrid ) * alignGrid;
1515 offset.
y =
KiROUND( offset.
y / alignGrid ) * alignGrid;
1522 for( std::unique_ptr<SCH_ITEM>& ptr : createdItems )
1524 ptr->Move( offset );
1525 screen->
Append( ptr.release() );