397 const std::map<wxString, wxString>& aDeviceAttributes )
401 std::unique_ptr<LIB_SYMBOL> ksymbolPtr = std::make_unique<LIB_SYMBOL>( wxEmptyString );
404 std::map<wxString, nlohmann::json> lineStyles;
405 std::map<wxString, nlohmann::json> fontStyles;
406 std::map<wxString, int> partUnits;
408 std::map<int, std::map<wxString, EASYEDAPRO::SCH_ATTR>> unitAttributes;
409 std::map<int, std::map<wxString, std::vector<nlohmann::json>>> unitParentedLines;
413 for(
const nlohmann::json& line : aLines )
415 wxString type = line.at( 0 );
417 if( type == wxS(
"LINESTYLE" ) )
418 lineStyles[line.at( 1 )] = line;
419 else if( type == wxS(
"FONTSTYLE" ) )
420 fontStyles[line.at( 1 )] = line;
421 else if( type == wxS(
"PART" ) )
422 partUnits[line.at( 1 )] = ++totalUnits;
430 for(
const nlohmann::json& line : aLines )
432 wxString type = line.at( 0 );
434 if( type == wxS(
"PART" ) )
436 currentUnit = partUnits.at( line.at( 1 ) );
438 else if( type == wxS(
"RECT" ) )
440 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
442 wxString styleStr = line.at( 9 );
449 rect->SetUnit( currentUnit );
454 else if( type == wxS(
"CIRCLE" ) )
457 double radius = line.at( 4 );
458 wxString styleStr = line.at( 5 );
465 circle->SetUnit( currentUnit );
470 else if( type == wxS(
"ARC" ) )
472 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
473 VECTOR2D mid( line.at( 4 ), line.at( 5 ) );
475 wxString styleStr = line.at( 8 );
483 shape->SetArcGeometry( kstart, kmid, kend );
485 shape->SetUnit( currentUnit );
490 else if( type == wxS(
"BEZIER" ) )
492 std::vector<double> points = line.at( 2 );
493 wxString styleStr = line.at( 3 );
495 std::unique_ptr<SCH_SHAPE> shape =
498 for(
size_t i = 1; i < points.size(); i += 2 )
504 case 1: shape->SetStart( pt );
break;
505 case 3: shape->SetBezierC1( pt );
break;
506 case 5: shape->SetBezierC2( pt );
break;
507 case 7: shape->SetEnd( pt );
break;
511 shape->SetUnit( currentUnit );
516 else if( type == wxS(
"POLY" ) )
518 std::vector<double> points = line.at( 2 );
519 wxString styleStr = line.at( 4 );
523 for(
size_t i = 1; i < points.size(); i += 2 )
526 shape->SetUnit( currentUnit );
531 else if( type == wxS(
"TEXT" ) )
533 VECTOR2D pos( line.at( 2 ), line.at( 3 ) );
534 double angle = line.at( 4 ).is_number() ? line.at( 4 ).get<
double>() : 0.0;
535 wxString textStr = line.at( 5 );
536 wxString fontStyleStr = line.at( 6 );
543 text->SetTextAngleDegrees( angle );
545 text->SetUnit( currentUnit );
550 else if( type == wxS(
"OBJ" ) )
553 wxString mimeType, data;
557 if( line.at( 3 ).is_number() )
559 start =
VECTOR2D( line.at( 3 ), line.at( 4 ) );
560 size =
VECTOR2D( line.at( 5 ), line.at( 6 ) );
562 upsideDown = line.at( 8 );
564 wxString imageUrl = line.at( 9 );
566 if( imageUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
568 wxArrayString paramsArr =
569 wxSplit( imageUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
571 data = imageUrl.AfterFirst(
',' );
573 if( paramsArr.size() > 0 )
575 mimeType = paramsArr[0];
579 else if( line.at( 3 ).is_string() )
581 mimeType = line.at( 3 ).get<wxString>().BeforeFirst(
';' );
583 start =
VECTOR2D( line.at( 4 ), line.at( 5 ) );
584 size =
VECTOR2D( line.at( 6 ), line.at( 7 ) );
586 data = line.at( 9 ).get<wxString>();
589 if( mimeType.empty() || data.empty() )
592 wxMemoryBuffer buf = wxBase64Decode( data );
594 if( mimeType == wxS(
"image/svg+xml" ) )
613 libsymImporter.
SetScale( pixelScale );
622 for( std::unique_ptr<EDA_ITEM>& item : libsymImporter.
GetItems() )
627 wxMemoryInputStream memis( buf.GetData(), buf.GetDataLen() );
629 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
630 & ~wxImage::Load_Verbose );
632 if( img.LoadFile( memis, mimeType ) )
634 int dimMul = img.GetWidth() * img.GetHeight();
635 double maxPixels = 30000;
637 if( dimMul > maxPixels )
639 double scale = sqrt( maxPixels / dimMul );
640 img.Rescale( img.GetWidth() *
scale, img.GetHeight() *
scale );
651 else if( type == wxS(
"HEAD" ) )
655 else if( type == wxS(
"PIN" ) )
657 wxString pinId = line.at( 1 );
658 unitParentedLines[currentUnit][pinId].push_back( line );
660 else if( type == wxS(
"ATTR" ) )
662 wxString parentId = line.at( 2 );
664 if( parentId.empty() )
667 unitAttributes[currentUnit].emplace( attr.
key, attr );
671 unitParentedLines[currentUnit][parentId].push_back( line );
686 if(
auto globalNetAttr =
get_opt( unitAttributes[1], wxS(
"Global Net Name" ) ) )
690 wxString globalNetname = globalNetAttr->value;
692 if( !globalNetname.empty() )
695 _(
"Power symbol creates a global label with name '%s'" ),
702 auto designatorAttr =
get_opt( unitAttributes[1], wxS(
"Designator" ) );
704 if( designatorAttr && !designatorAttr->value.empty() )
706 wxString symbolPrefix = designatorAttr->value;
708 if( symbolPrefix.EndsWith( wxS(
"?" ) ) )
709 symbolPrefix.RemoveLast();
716 if(
auto valOpt =
get_opt( aDeviceAttributes, attrName ) )
718 if( valOpt->empty() )
729 wxString value = *valOpt;
731 value.
Replace( wxS(
"\u2103" ), wxS(
"\u00B0C" ),
true );
739 for(
auto& [unitId, parentedLines] : unitParentedLines )
741 for(
auto& [pinId, lines] : parentedLines )
743 std::optional<EASYEDAPRO::SYM_PIN> epin;
744 std::map<wxString, EASYEDAPRO::SCH_ATTR> pinAttributes;
746 for(
const nlohmann::json& line : lines )
748 wxString type = line.at( 0 );
750 if( type == wxS(
"ATTR" ) )
753 pinAttributes.emplace( attr.
key, attr );
755 else if( type == wxS(
"PIN" ) )
767 std::unique_ptr<SCH_PIN>
pin = std::make_unique<SCH_PIN>( ksymbol );
769 pin->SetUnit( unitId );
776 if( epin->rotation == 0 )
778 if( epin->rotation == 90 )
780 if( epin->rotation == 180 )
782 if( epin->rotation == 270 )
785 pin->SetOrientation( orient );
794 auto pinNameAttr =
get_opt( pinAttributes,
"Pin Name" );
797 pinNameAttr =
get_opt( pinAttributes,
"NAME" );
801 pin->SetName( pinNameAttr->value );
802 pinInfo.
name = pinNameAttr->value;
804 if( !pinNameAttr->valVisible )
809 auto pinNumAttr =
get_opt( pinAttributes,
"Pin Number" );
812 pinNumAttr =
get_opt( pinAttributes,
"NUMBER" );
816 pin->SetNumber( pinNumAttr->value );
817 pinInfo.
number = pinNumAttr->value;
819 if( !pinNumAttr->valVisible )
827 else if(
auto pinTypeAttr =
get_opt( pinAttributes,
"Pin Type" ) )
829 if( pinTypeAttr->value == wxS(
"IN" ) )
831 if( pinTypeAttr->value == wxS(
"OUT" ) )
833 if( pinTypeAttr->value == wxS(
"BI" ) )
837 if(
get_opt( pinAttributes,
"NO_CONNECT" ) )
840 if(
pin->GetNumberTextSize() *
int(
pin->GetNumber().size() ) >
pin->GetLength() )
841 pin->SetNumberTextSize(
pin->GetLength() /
pin->GetNumber().size() );
843 symInfo.
pins.push_back( pinInfo );
861 symInfo.
libSymbol = std::move( ksymbolPtr );
868 const nlohmann::json& aProject,
869 std::map<wxString, EASYEDAPRO::SYM_INFO>& aSymbolMap,
870 const std::map<wxString, EASYEDAPRO::BLOB>& aBlobMap,
871 const std::vector<nlohmann::json>& aLines,
872 const wxString& aLibName )
874 std::vector<std::unique_ptr<SCH_ITEM>> createdItems;
876 std::map<wxString, std::vector<nlohmann::json>> parentedLines;
877 std::map<wxString, std::vector<nlohmann::json>> ruleLines;
879 std::map<wxString, nlohmann::json> lineStyles;
880 std::map<wxString, nlohmann::json> fontStyles;
882 for(
const nlohmann::json& line : aLines )
884 wxString type = line.at( 0 );
886 if( type == wxS(
"LINESTYLE" ) )
887 lineStyles[line.at( 1 )] = line;
888 else if( type == wxS(
"FONTSTYLE" ) )
889 fontStyles[line.at( 1 )] = line;
892 for(
const nlohmann::json& line : aLines )
894 wxString type = line.at( 0 );
896 if( type == wxS(
"RECT" ) )
898 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
900 wxString styleStr = line.at( 9 );
904 rect->SetStart(
ScalePos( start ) );
909 createdItems.push_back( std::move( rect ) );
911 else if( type == wxS(
"CIRCLE" ) )
914 double radius = line.at( 4 );
915 wxString styleStr = line.at( 5 );
924 createdItems.push_back( std::move(
circle ) );
926 else if( type == wxS(
"POLY" ) )
928 std::vector<double> points = line.at( 2 );
929 wxString styleStr = line.at( 4 );
933 for(
size_t i = 1; i < points.size(); i += 2 )
936 for(
int segId = 0; segId <
chain.SegmentCount(); segId++ )
938 const SEG& seg =
chain.CSegment( segId );
940 std::unique_ptr<SCH_LINE> schLine =
942 schLine->SetEndPoint( seg.
B );
946 createdItems.push_back( std::move( schLine ) );
949 else if( type == wxS(
"TEXT" ) )
951 VECTOR2D pos( line.at( 2 ), line.at( 3 ) );
952 double angle = line.at( 4 ).is_number() ? line.at( 4 ).get<
double>() : 0.0;
953 wxString textStr = line.at( 5 );
954 wxString fontStyleStr = line.at( 6 );
956 std::unique_ptr<SCH_TEXT>
text =
962 text->SetTextAngleDegrees( angle );
966 createdItems.push_back( std::move(
text ) );
968 else if( type == wxS(
"OBJ" ) )
971 wxString mimeType, base64Data;
975 if( line.at( 3 ).is_number() )
977 start =
VECTOR2D( line.at( 3 ), line.at( 4 ) );
978 size =
VECTOR2D( line.at( 5 ), line.at( 6 ) );
979 angle = line.at( 7 );
980 flipped = line.at( 8 );
982 wxString imageUrl = line.at( 9 );
984 if( imageUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
986 wxArrayString paramsArr =
987 wxSplit( imageUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
989 base64Data = imageUrl.AfterFirst(
',' );
991 if( paramsArr.size() > 0 )
992 mimeType = paramsArr[0];
994 else if( imageUrl.BeforeFirst(
':' ) == wxS(
"blob" ) )
996 wxString objectId = imageUrl.AfterLast(
':' );
998 if(
auto blob =
get_opt( aBlobMap, objectId ) )
1000 wxString blobUrl = blob->url;
1002 if( blobUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
1004 wxArrayString paramsArr = wxSplit(
1005 blobUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
1007 base64Data = blobUrl.AfterFirst(
',' );
1009 if( paramsArr.size() > 0 )
1010 mimeType = paramsArr[0];
1015 else if( line.at( 3 ).is_string() )
1017 mimeType = line.at( 3 ).get<wxString>().BeforeFirst(
';' );
1019 start =
VECTOR2D( line.at( 4 ), line.at( 5 ) );
1020 size =
VECTOR2D( line.at( 6 ), line.at( 7 ) );
1021 angle = line.at( 8 );
1022 base64Data = line.at( 9 ).get<wxString>();
1028 if( mimeType.empty() || base64Data.empty() )
1031 wxMemoryBuffer buf = wxBase64Decode( base64Data );
1033 if( mimeType == wxS(
"image/svg+xml" ) )
1047 schImporter.
SetScale( pixelScale );
1053 svgImportPlugin.
Import();
1055 for( std::unique_ptr<EDA_ITEM>& item : schImporter.
GetItems() )
1059 for(
double i = angle; i > 0; i -= 90 )
1065 schItem->
Rotate( kstart,
false );
1069 schItem->
Rotate( kstart,
false );
1074 schItem->
Rotate( kstart,
false );
1090 createdItems.emplace_back( schItem );
1095 std::unique_ptr<SCH_BITMAP> bitmap = std::make_unique<SCH_BITMAP>();
1098 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
1099 & ~wxImage::Load_Verbose );
1103 VECTOR2D kcenter = kstart + ksize / 2;
1107 bitmap->SetPosition( kcenter );
1109 for(
double i = angle; i > 0; i -= 90 )
1110 bitmap->Rotate( kstart,
false );
1113 bitmap->MirrorHorizontally( kstart.
x );
1115 createdItems.push_back( std::move( bitmap ) );
1119 if( type == wxS(
"WIRE" ) )
1121 wxString wireId = line.at( 1 );
1122 parentedLines[wireId].push_back( line );
1124 else if( type == wxS(
"COMPONENT" ) )
1126 wxString compId = line.at( 1 );
1127 parentedLines[compId].push_back( line );
1129 else if( type == wxS(
"ATTR" ) )
1131 wxString compId = line.at( 2 );
1132 parentedLines[compId].push_back( line );
1136 for(
auto& [parentId, lines] : parentedLines )
1138 std::optional<EASYEDAPRO::SCH_COMPONENT> component;
1139 std::optional<EASYEDAPRO::SCH_WIRE> wire;
1140 std::map<wxString, EASYEDAPRO::SCH_ATTR> attributes;
1142 for(
const nlohmann::json& line : lines )
1144 if( line.at( 0 ) ==
"COMPONENT" )
1148 else if( line.at( 0 ) ==
"WIRE" )
1152 else if( line.at( 0 ) ==
"ATTR" )
1155 attributes.emplace( attr.
key, attr );
1161 auto deviceAttr =
get_opt( attributes,
"Device" );
1162 auto symbolAttr =
get_opt( attributes,
"Symbol" );
1168 aProject.at(
"devices" ).at( deviceAttr->value ).at(
"attributes" ) );
1171 std::map<wxString, wxString> mergedAttrValues;
1173 for(
const auto& [key, value] : prjCompAttrs )
1174 mergedAttrValues[key] = value;
1176 for(
const auto& [key, attr] : attributes )
1177 mergedAttrValues[key] = attr.value;
1181 if( symbolAttr && !symbolAttr->value.IsEmpty() )
1182 symbolId = symbolAttr->value;
1184 symbolId = prjCompAttrs.at(
"Symbol" );
1186 auto it = aSymbolMap.find( symbolId );
1187 if( it == aSymbolMap.end() )
1189 wxLogError(
"Symbol of '%s' with uuid '%s' not found.", component->name, symbolId );
1196 wxString unitName = component->name;
1201 auto schSym = std::make_unique<SCH_SYMBOL>( newLibSymbol, libId,
1205 schSym->SetFootprintFieldText( newLibSymbol.
GetFootprint() );
1207 for(
double i = component->rotation; i > 0; i -= 90 )
1208 schSym->Rotate(
VECTOR2I(),
true );
1210 if( component->mirror )
1211 schSym->MirrorHorizontally( 0 );
1213 schSym->SetPosition(
ScalePos( component->position ) );
1219 auto globalNetNameAttr =
get_opt( attributes,
"Global Net Name" );
1220 wxString globalNetNameFromProject =
get_def( prjCompAttrs,
"Global Net Name", wxEmptyString );
1221 wxString globalNetName;
1226 if( globalNetNameAttr && !globalNetNameAttr->value.IsEmpty() )
1228 globalNetName = globalNetNameAttr->value;
1231 mergedAttrValues, schSym.get() );
1233 else if( !globalNetNameFromProject.IsEmpty() )
1235 globalNetName = globalNetNameFromProject;
1244 for(
SCH_PIN*
pin : schSym->GetAllLibPins() )
1245 pin->SetName( globalNetName );
1247 schSym->SetRef( &aSchematic->
CurrentSheet(), wxS(
"#PWR?" ) );
1252 auto nameAttr =
get_opt( attributes,
"Name" );
1256 if( nameAttr && !nameAttr->value.IsEmpty() )
1257 netName = nameAttr->value;
1259 netName = prjCompAttrs.at(
"Name" );
1261 std::unique_ptr<SCH_GLOBALLABEL> label = std::make_unique<SCH_GLOBALLABEL>(
1262 ScalePos( component->position ), netName );
1264 std::vector<SCH_PIN*> pins = schSym->GetPins( &aSchematic->
CurrentSheet() );
1266 if( pins.size() > 0 )
1268 switch( pins[0]->GetType() )
1284 BOX2I bbox = schSym->GetBodyAndPinsBoundingBox();
1285 bbox.
Offset( -schSym->GetPosition() );
1292 if( bboxCenter.
x >= 0 )
1299 if( bboxCenter.
y >= 0 )
1305 label->SetSpinStyle( spin );
1309 nlohmann::json style = fontStyles[nameAttr->fontStyle];
1311 if( !style.is_null() && style.at( 5 ).is_number() )
1313 double size = style.at( 5 ).get<
double>() * 0.62;
1318 createdItems.push_back( std::move( label ) );
1326 if(
auto valOpt =
get_opt( mergedAttrValues, attrKey ) )
1328 if( valOpt->empty() )
1331 SCH_FIELD*
text = schSym->FindFieldCaseInsensitive( attrKey );
1336 wxString value = *valOpt;
1338 value.Replace( wxS(
"\u2103" ), wxS(
"\u00B0C" ),
true );
1340 text->SetText( value );
1341 text->SetVisible(
false );
1345 auto nameAttr =
get_opt( attributes,
"Name" );
1346 auto valueAttr =
get_opt( attributes,
"Value" );
1348 if( valueAttr && valueAttr->value.empty() )
1349 valueAttr->value =
get_def( prjCompAttrs,
"Value", wxString() );
1351 if( nameAttr && nameAttr->value.empty() )
1352 nameAttr->value =
get_def( prjCompAttrs,
"Name", wxString() );
1354 std::optional<EASYEDAPRO::SCH_ATTR> targetValueAttr;
1356 if( valueAttr && !valueAttr->value.empty() && valueAttr->valVisible )
1357 targetValueAttr = valueAttr;
1358 else if( nameAttr && !nameAttr->value.empty() && nameAttr->valVisible )
1359 targetValueAttr = nameAttr;
1360 else if( valueAttr && !valueAttr->value.empty() )
1361 targetValueAttr = valueAttr;
1362 else if( nameAttr && !nameAttr->value.empty() )
1363 targetValueAttr = nameAttr;
1365 if( targetValueAttr )
1368 *targetValueAttr,
false,
true, mergedAttrValues, schSym.get() );
1371 if(
auto descrAttr =
get_opt( attributes,
"Description" ) )
1374 *descrAttr,
false,
true, mergedAttrValues, schSym.get() );
1377 if(
auto designatorAttr =
get_opt( attributes,
"Designator" ) )
1380 *designatorAttr,
false,
true, mergedAttrValues, schSym.get() );
1382 schSym->SetRef( &aSchematic->
CurrentSheet(), designatorAttr->value );
1385 for(
auto& [attrKey, attr] : attributes )
1387 if( attrKey == wxS(
"Name" ) || attrKey == wxS(
"Value" )
1388 || attrKey == wxS(
"Global Net Name" ) || attrKey == wxS(
"Designator" )
1389 || attrKey == wxS(
"Description" ) || attrKey == wxS(
"Device" )
1390 || attrKey == wxS(
"Footprint" ) || attrKey == wxS(
"Symbol" )
1391 || attrKey == wxS(
"Unique ID" ) )
1396 if( attr.value.IsEmpty() )
1399 SCH_FIELD*
text = schSym->FindFieldCaseInsensitive( attrKey );
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" ) )
1429 for(
SCH_PIN* schPin : schSym->GetPinsByNumber( pinInfo.
number ) )
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() );