322 const std::map<wxString, wxString>& aDeviceAttributes )
326 std::unique_ptr<LIB_SYMBOL> ksymbolPtr = std::make_unique<LIB_SYMBOL>( wxEmptyString );
329 std::map<wxString, nlohmann::json> lineStyles;
330 std::map<wxString, nlohmann::json> fontStyles;
331 std::map<wxString, int> partUnits;
333 std::map<int, std::map<wxString, EASYEDAPRO::SCH_ATTR>> unitAttributes;
334 std::map<int, std::map<wxString, std::vector<nlohmann::json>>> unitParentedLines;
338 for(
const nlohmann::json& line : aLines )
340 wxString type = line.at( 0 );
342 if( type == wxS(
"LINESTYLE" ) )
343 lineStyles[line.at( 1 )] = line;
344 else if( type == wxS(
"FONTSTYLE" ) )
345 fontStyles[line.at( 1 )] = line;
346 else if( type == wxS(
"PART" ) )
347 partUnits[line.at( 1 )] = ++totalUnits;
355 for(
const nlohmann::json& line : aLines )
357 wxString type = line.at( 0 );
359 if( type == wxS(
"PART" ) )
361 currentUnit = partUnits.at( line.at( 1 ) );
363 else if( type == wxS(
"RECT" ) )
365 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
367 wxString styleStr = line.at( 9 );
374 rect->SetUnit( currentUnit );
379 else if( type == wxS(
"CIRCLE" ) )
382 double radius = line.at( 4 );
383 wxString styleStr = line.at( 5 );
390 circle->SetUnit( currentUnit );
395 else if( type == wxS(
"ARC" ) )
397 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
398 VECTOR2D mid( line.at( 4 ), line.at( 5 ) );
400 wxString styleStr = line.at( 8 );
408 shape->SetArcGeometry( kstart, kmid, kend );
410 shape->SetUnit( currentUnit );
415 else if( type == wxS(
"BEZIER" ) )
417 std::vector<double> points = line.at( 2 );
418 wxString styleStr = line.at( 3 );
420 std::unique_ptr<SCH_SHAPE> shape =
423 for(
size_t i = 1; i < points.size(); i += 2 )
429 case 1: shape->SetStart( pt );
break;
430 case 3: shape->SetBezierC1( pt );
break;
431 case 5: shape->SetBezierC2( pt );
break;
432 case 7: shape->SetEnd( pt );
break;
436 shape->SetUnit( currentUnit );
441 else if( type == wxS(
"POLY" ) )
443 std::vector<double> points = line.at( 2 );
444 wxString styleStr = line.at( 4 );
448 for(
size_t i = 1; i < points.size(); i += 2 )
451 shape->SetUnit( currentUnit );
456 else if( type == wxS(
"TEXT" ) )
458 VECTOR2D pos( line.at( 2 ), line.at( 3 ) );
459 double angle = line.at( 4 ).is_number() ? line.at( 4 ).get<
double>() : 0.0;
460 wxString textStr = line.at( 5 );
461 wxString fontStyleStr = line.at( 6 );
468 text->SetTextAngleDegrees( angle );
470 text->SetUnit( currentUnit );
475 else if( type == wxS(
"OBJ" ) )
478 wxString mimeType, data;
482 if( line.at( 3 ).is_number() )
484 start =
VECTOR2D( line.at( 3 ), line.at( 4 ) );
485 size =
VECTOR2D( line.at( 5 ), line.at( 6 ) );
487 upsideDown = line.at( 8 );
489 wxString imageUrl = line.at( 9 );
491 if( imageUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
493 wxArrayString paramsArr =
494 wxSplit( imageUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
496 data = imageUrl.AfterFirst(
',' );
498 if( paramsArr.size() > 0 )
500 mimeType = paramsArr[0];
504 else if( line.at( 3 ).is_string() )
506 mimeType = line.at( 3 ).get<wxString>().BeforeFirst(
';' );
508 start =
VECTOR2D( line.at( 4 ), line.at( 5 ) );
509 size =
VECTOR2D( line.at( 6 ), line.at( 7 ) );
511 data = line.at( 9 ).get<wxString>();
514 if( mimeType.empty() || data.empty() )
517 wxMemoryBuffer buf = wxBase64Decode( data );
519 if( mimeType == wxS(
"image/svg+xml" ) )
538 libsymImporter.
SetScale( pixelScale );
547 for( std::unique_ptr<EDA_ITEM>& item : libsymImporter.
GetItems() )
552 wxMemoryInputStream memis( buf.GetData(), buf.GetDataLen() );
554 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
555 & ~wxImage::Load_Verbose );
557 if( img.LoadFile( memis, mimeType ) )
559 int dimMul = img.GetWidth() * img.GetHeight();
560 double maxPixels = 30000;
562 if( dimMul > maxPixels )
564 double scale = sqrt( maxPixels / dimMul );
565 img.Rescale( img.GetWidth() *
scale, img.GetHeight() *
scale );
576 else if( type == wxS(
"HEAD" ) )
580 else if( type == wxS(
"PIN" ) )
582 wxString pinId = line.at( 1 );
583 unitParentedLines[currentUnit][pinId].push_back( line );
585 else if( type == wxS(
"ATTR" ) )
587 wxString parentId = line.at( 2 );
589 if( parentId.empty() )
592 unitAttributes[currentUnit].emplace( attr.
key, attr );
596 unitParentedLines[currentUnit][parentId].push_back( line );
611 if(
auto globalNetAttr =
get_opt( unitAttributes[1], wxS(
"Global Net Name" ) ) )
615 wxString globalNetname = globalNetAttr->value;
617 if( !globalNetname.empty() )
620 _(
"Power symbol creates a global label with name '%s'" ),
627 auto designatorAttr =
get_opt( unitAttributes[1], wxS(
"Designator" ) );
629 if( designatorAttr && !designatorAttr->value.empty() )
631 wxString symbolPrefix = designatorAttr->value;
633 if( symbolPrefix.EndsWith( wxS(
"?" ) ) )
634 symbolPrefix.RemoveLast();
640 aDeviceAttributes,
true,
641 [&](
const wxString& attrName,
const wxString& value )
656 for(
auto& [unitId, parentedLines] : unitParentedLines )
658 for(
auto& [pinId, lines] : parentedLines )
660 std::optional<EASYEDAPRO::SYM_PIN> epin;
661 std::map<wxString, EASYEDAPRO::SCH_ATTR> pinAttributes;
663 for(
const nlohmann::json& line : lines )
665 wxString type = line.at( 0 );
667 if( type == wxS(
"ATTR" ) )
670 pinAttributes.emplace( attr.
key, attr );
672 else if( type == wxS(
"PIN" ) )
684 std::unique_ptr<SCH_PIN>
pin = std::make_unique<SCH_PIN>( ksymbol );
686 pin->SetUnit( unitId );
693 if( epin->rotation == 0 )
695 if( epin->rotation == 90 )
697 if( epin->rotation == 180 )
699 if( epin->rotation == 270 )
702 pin->SetOrientation( orient );
711 auto pinNameAttr =
get_opt( pinAttributes,
"Pin Name" );
714 pinNameAttr =
get_opt( pinAttributes,
"NAME" );
718 pin->SetName( pinNameAttr->value );
719 pinInfo.
name = pinNameAttr->value;
721 if( !pinNameAttr->valVisible )
726 auto pinNumAttr =
get_opt( pinAttributes,
"Pin Number" );
729 pinNumAttr =
get_opt( pinAttributes,
"NUMBER" );
733 pin->SetNumber( pinNumAttr->value );
734 pinInfo.
number = pinNumAttr->value;
736 if( !pinNumAttr->valVisible )
744 else if(
auto pinTypeAttr =
get_opt( pinAttributes,
"Pin Type" ) )
746 if( pinTypeAttr->value == wxS(
"IN" ) )
748 if( pinTypeAttr->value == wxS(
"OUT" ) )
750 if( pinTypeAttr->value == wxS(
"BI" ) )
754 if(
get_opt( pinAttributes,
"NO_CONNECT" ) )
757 if(
pin->GetNumberTextSize() *
int(
pin->GetNumber().size() ) >
pin->GetLength() )
758 pin->SetNumberTextSize(
pin->GetLength() /
pin->GetNumber().size() );
760 symInfo.
pins.push_back( pinInfo );
778 symInfo.
libSymbol = std::move( ksymbolPtr );
785 const nlohmann::json& aProject,
786 std::map<wxString, EASYEDAPRO::SYM_INFO>& aSymbolMap,
787 const std::map<wxString, EASYEDAPRO::BLOB>& aBlobMap,
788 const std::vector<nlohmann::json>& aLines,
789 const wxString& aLibName )
791 std::vector<std::unique_ptr<SCH_ITEM>> createdItems;
793 std::map<wxString, std::vector<nlohmann::json>> parentedLines;
794 std::map<wxString, std::vector<nlohmann::json>> ruleLines;
796 std::map<wxString, nlohmann::json> lineStyles;
797 std::map<wxString, nlohmann::json> fontStyles;
799 for(
const nlohmann::json& line : aLines )
801 wxString type = line.at( 0 );
803 if( type == wxS(
"LINESTYLE" ) )
804 lineStyles[line.at( 1 )] = line;
805 else if( type == wxS(
"FONTSTYLE" ) )
806 fontStyles[line.at( 1 )] = line;
809 for(
const nlohmann::json& line : aLines )
811 wxString type = line.at( 0 );
813 if( type == wxS(
"RECT" ) )
815 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
817 wxString styleStr = line.at( 9 );
821 rect->SetStart(
ScalePos( start ) );
826 createdItems.push_back( std::move( rect ) );
828 else if( type == wxS(
"CIRCLE" ) )
831 double radius = line.at( 4 );
832 wxString styleStr = line.at( 5 );
841 createdItems.push_back( std::move(
circle ) );
843 else if( type == wxS(
"POLY" ) )
845 std::vector<double> points = line.at( 2 );
846 wxString styleStr = line.at( 4 );
850 for(
size_t i = 1; i < points.size(); i += 2 )
853 for(
int segId = 0; segId <
chain.SegmentCount(); segId++ )
855 const SEG& seg =
chain.CSegment( segId );
857 std::unique_ptr<SCH_LINE> schLine =
859 schLine->SetEndPoint( seg.
B );
863 createdItems.push_back( std::move( schLine ) );
866 else if( type == wxS(
"TEXT" ) )
868 VECTOR2D pos( line.at( 2 ), line.at( 3 ) );
869 double angle = line.at( 4 ).is_number() ? line.at( 4 ).get<
double>() : 0.0;
870 wxString textStr = line.at( 5 );
871 wxString fontStyleStr = line.at( 6 );
873 std::unique_ptr<SCH_TEXT>
text =
879 text->SetTextAngleDegrees( angle );
883 createdItems.push_back( std::move(
text ) );
885 else if( type == wxS(
"OBJ" ) )
888 wxString mimeType, base64Data;
892 if( line.at( 3 ).is_number() )
894 start =
VECTOR2D( line.at( 3 ), line.at( 4 ) );
895 size =
VECTOR2D( line.at( 5 ), line.at( 6 ) );
896 angle = line.at( 7 );
897 flipped = line.at( 8 );
899 wxString imageUrl = line.at( 9 );
901 if( imageUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
903 wxArrayString paramsArr =
904 wxSplit( imageUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
906 base64Data = imageUrl.AfterFirst(
',' );
908 if( paramsArr.size() > 0 )
909 mimeType = paramsArr[0];
911 else if( imageUrl.BeforeFirst(
':' ) == wxS(
"blob" ) )
913 wxString objectId = imageUrl.AfterLast(
':' );
915 if(
auto blob =
get_opt( aBlobMap, objectId ) )
917 wxString blobUrl = blob->url;
919 if( blobUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
921 wxArrayString paramsArr = wxSplit(
922 blobUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
924 base64Data = blobUrl.AfterFirst(
',' );
926 if( paramsArr.size() > 0 )
927 mimeType = paramsArr[0];
932 else if( line.at( 3 ).is_string() )
934 mimeType = line.at( 3 ).get<wxString>().BeforeFirst(
';' );
936 start =
VECTOR2D( line.at( 4 ), line.at( 5 ) );
937 size =
VECTOR2D( line.at( 6 ), line.at( 7 ) );
938 angle = line.at( 8 );
939 base64Data = line.at( 9 ).get<wxString>();
945 if( mimeType.empty() || base64Data.empty() )
948 wxMemoryBuffer buf = wxBase64Decode( base64Data );
950 if( mimeType == wxS(
"image/svg+xml" ) )
972 for( std::unique_ptr<EDA_ITEM>& item : schImporter.
GetItems() )
976 for(
double i = angle; i > 0; i -= 90 )
982 schItem->
Rotate( kstart,
false );
986 schItem->
Rotate( kstart,
false );
991 schItem->
Rotate( kstart,
false );
1007 createdItems.emplace_back( schItem );
1012 std::unique_ptr<SCH_BITMAP> bitmap = std::make_unique<SCH_BITMAP>();
1015 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
1016 & ~wxImage::Load_Verbose );
1020 VECTOR2D kcenter = kstart + ksize / 2;
1024 bitmap->SetPosition( kcenter );
1026 for(
double i = angle; i > 0; i -= 90 )
1027 bitmap->Rotate( kstart,
false );
1030 bitmap->MirrorHorizontally( kstart.
x );
1032 createdItems.push_back( std::move( bitmap ) );
1036 if( type == wxS(
"WIRE" ) )
1038 wxString wireId = line.at( 1 );
1039 parentedLines[wireId].push_back( line );
1041 else if( type == wxS(
"COMPONENT" ) )
1043 wxString compId = line.at( 1 );
1044 parentedLines[compId].push_back( line );
1046 else if( type == wxS(
"ATTR" ) )
1048 wxString compId = line.at( 2 );
1049 parentedLines[compId].push_back( line );
1053 for(
auto& [parentId, lines] : parentedLines )
1055 std::optional<EASYEDAPRO::SCH_COMPONENT> component;
1056 std::optional<EASYEDAPRO::SCH_WIRE> wire;
1057 std::map<wxString, EASYEDAPRO::SCH_ATTR> attributes;
1059 for(
const nlohmann::json& line : lines )
1061 if( line.at( 0 ) ==
"COMPONENT" )
1065 else if( line.at( 0 ) ==
"WIRE" )
1069 else if( line.at( 0 ) ==
"ATTR" )
1072 attributes.emplace( attr.
key, attr );
1078 auto deviceAttr =
get_opt( attributes,
"Device" );
1079 auto symbolAttr =
get_opt( attributes,
"Symbol" );
1085 aProject.at(
"devices" ).at( deviceAttr->value ).at(
"attributes" ) );
1088 std::map<wxString, wxString> mergedAttrValues;
1090 for(
const auto& [key, value] : prjCompAttrs )
1091 mergedAttrValues[key] = value;
1093 for(
const auto& [key, attr] : attributes )
1094 mergedAttrValues[key] = attr.value;
1098 if( symbolAttr && !symbolAttr->value.IsEmpty() )
1099 symbolId = symbolAttr->value;
1101 symbolId = prjCompAttrs.at(
"Symbol" );
1103 auto it = aSymbolMap.find( symbolId );
1104 if( it == aSymbolMap.end() )
1106 wxLogTrace(
traceEasyEdaIo,
"Symbol of '%s' with uuid '%s' not found.", component->name, symbolId );
1113 wxString unitName = component->name;
1118 auto schSym = std::make_unique<SCH_SYMBOL>( newLibSymbol, libId,
1122 schSym->SetFootprintFieldText( newLibSymbol.
GetFootprint() );
1124 for(
double i = component->rotation; i > 0; i -= 90 )
1125 schSym->Rotate(
VECTOR2I(),
true );
1127 if( component->mirror )
1128 schSym->MirrorHorizontally( 0 );
1130 schSym->SetPosition(
ScalePos( component->position ) );
1136 auto globalNetNameAttr =
get_opt( attributes,
"Global Net Name" );
1137 wxString globalNetNameFromProject =
get_def( prjCompAttrs,
"Global Net Name", wxEmptyString );
1138 wxString globalNetName;
1143 if( globalNetNameAttr && !globalNetNameAttr->value.IsEmpty() )
1145 globalNetName = globalNetNameAttr->value;
1148 mergedAttrValues, schSym.get() );
1150 else if( !globalNetNameFromProject.IsEmpty() )
1152 globalNetName = globalNetNameFromProject;
1161 for(
SCH_PIN*
pin : schSym->GetAllLibPins() )
1162 pin->SetName( globalNetName );
1164 schSym->SetRef( &aSchematic->
CurrentSheet(), wxS(
"#PWR?" ) );
1169 auto nameAttr =
get_opt( attributes,
"Name" );
1173 if( nameAttr && !nameAttr->value.IsEmpty() )
1174 netName = nameAttr->value;
1176 netName = prjCompAttrs.at(
"Name" );
1178 std::unique_ptr<SCH_GLOBALLABEL> label = std::make_unique<SCH_GLOBALLABEL>(
1179 ScalePos( component->position ), netName );
1181 std::vector<SCH_PIN*> pins = schSym->GetPins( &aSchematic->
CurrentSheet() );
1183 if( pins.size() > 0 )
1185 switch( pins[0]->GetType() )
1201 BOX2I bbox = schSym->GetBodyAndPinsBoundingBox();
1202 bbox.
Offset( -schSym->GetPosition() );
1209 if( bboxCenter.
x >= 0 )
1216 if( bboxCenter.
y >= 0 )
1222 label->SetSpinStyle( spin );
1226 nlohmann::json style = fontStyles[nameAttr->fontStyle];
1228 if( !style.is_null() && style.at( 5 ).is_number() )
1230 double size = style.at( 5 ).get<
double>() * 0.62;
1235 createdItems.push_back( std::move( label ) );
1242 mergedAttrValues,
true,
1243 [&](
const wxString& attrKey,
const wxString& value )
1245 SCH_FIELD*
text = schSym->FindFieldCaseInsensitive( attrKey );
1250 text->SetText( value );
1251 text->SetVisible(
false );
1254 auto nameAttr =
get_opt( attributes,
"Name" );
1255 auto valueAttr =
get_opt( attributes,
"Value" );
1257 if( valueAttr && valueAttr->value.empty() )
1258 valueAttr->value =
get_def( prjCompAttrs,
"Value", wxString() );
1260 if( nameAttr && nameAttr->value.empty() )
1261 nameAttr->value =
get_def( prjCompAttrs,
"Name", wxString() );
1263 std::optional<EASYEDAPRO::SCH_ATTR> targetValueAttr;
1265 if( valueAttr && !valueAttr->value.empty() && valueAttr->valVisible )
1266 targetValueAttr = valueAttr;
1267 else if( nameAttr && !nameAttr->value.empty() && nameAttr->valVisible )
1268 targetValueAttr = nameAttr;
1269 else if( valueAttr && !valueAttr->value.empty() )
1270 targetValueAttr = valueAttr;
1271 else if( nameAttr && !nameAttr->value.empty() )
1272 targetValueAttr = nameAttr;
1274 if( targetValueAttr )
1277 *targetValueAttr,
false,
true, mergedAttrValues, schSym.get() );
1280 if(
auto descrAttr =
get_opt( attributes,
"Description" ) )
1283 *descrAttr,
false,
true, mergedAttrValues, schSym.get() );
1286 if(
auto designatorAttr =
get_opt( attributes,
"Designator" ) )
1289 *designatorAttr,
false,
true, mergedAttrValues, schSym.get() );
1291 schSym->SetRef( &aSchematic->
CurrentSheet(), designatorAttr->value );
1294 for(
auto& [attrKey, attr] : attributes )
1296 if( attrKey == wxS(
"Name" ) || attrKey == wxS(
"Value" )
1297 || attrKey == wxS(
"Global Net Name" ) || attrKey == wxS(
"Designator" )
1298 || attrKey == wxS(
"Description" ) || attrKey == wxS(
"Device" )
1299 || attrKey == wxS(
"Footprint" ) || attrKey == wxS(
"Symbol" )
1300 || attrKey == wxS(
"Unique ID" ) )
1305 if( attr.value.IsEmpty() )
1308 SCH_FIELD*
text = schSym->FindFieldCaseInsensitive( attrKey );
1313 text->SetPosition( schSym->GetPosition() );
1322 wxString pinKey = parentId + pinInfo.
pin.
id;
1323 auto pinLines =
get_opt( parentedLines, pinKey );
1328 for(
const nlohmann::json& pinLine : *pinLines )
1330 if( pinLine.at( 0 ) !=
"ATTR" )
1335 if( attr.
key != wxS(
"NO_CONNECT" ) )
1338 for(
SCH_PIN* schPin : schSym->GetPinsByNumber( pinInfo.
number ) )
1340 VECTOR2I pos = schSym->GetPinPhysicalPosition( schPin->GetLibPin() );
1342 std::unique_ptr<SCH_NO_CONNECT> noConn =
1343 std::make_unique<SCH_NO_CONNECT>( pos );
1345 createdItems.push_back( std::move( noConn ) );
1350 createdItems.push_back( std::move( schSym ) );
1354 std::vector<SHAPE_LINE_CHAIN> wireLines;
1358 for(
const std::vector<double>& ptArr : wire->geometry )
1362 for(
size_t i = 1; i < ptArr.size(); i += 2 )
1365 if(
chain.PointCount() < 2 )
1368 wireLines.push_back(
chain );
1370 for(
int segId = 0; segId <
chain.SegmentCount(); segId++ )
1372 const SEG& seg =
chain.CSegment( segId );
1374 std::unique_ptr<SCH_LINE> schLine =
1376 schLine->SetEndPoint( seg.
B );
1378 createdItems.push_back( std::move( schLine ) );
1383 auto netAttr =
get_opt( attributes,
"NET" );
1387 if( !netAttr->valVisible || netAttr->value.IsEmpty() )
1397 SEG::ecoord dist_sq = ( nearestPt - kpos ).SquaredEuclideanNorm();
1399 if( dist_sq < min_dist_sq )
1401 min_dist_sq = dist_sq;
1402 nearestPos = nearestPt;
1406 std::unique_ptr<SCH_LABEL> label = std::make_unique<SCH_LABEL>();
1411 for(
double i = netAttr->rotation; i > 0; i -= 90 )
1412 label->Rotate90(
true );
1414 label->SetPosition( nearestPos );
1415 label->SetText( netAttr->value );
1419 createdItems.push_back( std::move( label ) );
1427 for( std::unique_ptr<SCH_ITEM>& ptr : createdItems )
1432 sheetBBox.
Merge( ptr->GetBoundingBox() );
1441 offset.
x =
KiROUND( offset.
x / alignGrid ) * alignGrid;
1442 offset.
y =
KiROUND( offset.
y / alignGrid ) * alignGrid;
1449 for( std::unique_ptr<SCH_ITEM>& ptr : createdItems )
1451 ptr->Move( offset );
1452 screen->
Append( ptr.release() );