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;
350 if( totalUnits == 0 )
358 for(
const nlohmann::json& line : aLines )
360 wxString type = line.at( 0 );
362 if( type == wxS(
"PART" ) )
364 currentUnit = partUnits.at( line.at( 1 ) );
366 else if( type == wxS(
"RECT" ) )
368 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
370 wxString styleStr = line.at( 9 );
377 rect->SetUnit( currentUnit );
382 else if( type == wxS(
"CIRCLE" ) )
385 double radius = line.at( 4 );
386 wxString styleStr = line.at( 5 );
393 circle->SetUnit( currentUnit );
398 else if( type == wxS(
"ARC" ) )
400 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
401 VECTOR2D mid( line.at( 4 ), line.at( 5 ) );
403 wxString styleStr = line.at( 8 );
411 shape->SetArcOrLine( kstart, kmid, kend );
413 shape->SetUnit( currentUnit );
418 else if( type == wxS(
"BEZIER" ) )
420 std::vector<double> points = line.at( 2 );
421 wxString styleStr = line.at( 3 );
423 std::unique_ptr<SCH_SHAPE> shape =
426 for(
size_t i = 1; i < points.size(); i += 2 )
432 case 1: shape->SetStart( pt );
break;
433 case 3: shape->SetBezierC1( pt );
break;
434 case 5: shape->SetBezierC2( pt );
break;
435 case 7: shape->SetEnd( pt );
break;
439 shape->SetUnit( currentUnit );
444 else if( type == wxS(
"POLY" ) )
446 std::vector<double> points = line.at( 2 );
447 wxString styleStr = line.at( 4 );
451 for(
size_t i = 1; i < points.size(); i += 2 )
454 shape->SetUnit( currentUnit );
459 else if( type == wxS(
"TEXT" ) )
461 VECTOR2D pos( line.at( 2 ), line.at( 3 ) );
462 double angle = line.at( 4 ).is_number() ? line.at( 4 ).get<
double>() : 0.0;
463 wxString textStr = line.at( 5 );
464 wxString fontStyleStr = line.at( 6 );
471 text->SetTextAngleDegrees( angle );
473 text->SetUnit( currentUnit );
478 else if( type == wxS(
"OBJ" ) )
481 wxString mimeType, data;
485 if( line.at( 3 ).is_number() )
487 start =
VECTOR2D( line.at( 3 ), line.at( 4 ) );
488 size =
VECTOR2D( line.at( 5 ), line.at( 6 ) );
490 upsideDown = line.at( 8 );
492 wxString imageUrl = line.at( 9 );
494 if( imageUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
496 wxArrayString paramsArr =
497 wxSplit( imageUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
499 data = imageUrl.AfterFirst(
',' );
501 if( paramsArr.size() > 0 )
503 mimeType = paramsArr[0];
507 else if( line.at( 3 ).is_string() )
509 mimeType = line.at( 3 ).get<wxString>().BeforeFirst(
';' );
511 start =
VECTOR2D( line.at( 4 ), line.at( 5 ) );
512 size =
VECTOR2D( line.at( 6 ), line.at( 7 ) );
514 data = line.at( 9 ).get<wxString>();
517 if( mimeType.empty() || data.empty() )
520 wxMemoryBuffer buf = wxBase64Decode( data );
522 if( mimeType == wxS(
"image/svg+xml" ) )
541 libsymImporter.
SetScale( pixelScale );
550 for( std::unique_ptr<EDA_ITEM>& item : libsymImporter.
GetItems() )
555 wxMemoryInputStream memis( buf.GetData(), buf.GetDataLen() );
557 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
558 & ~wxImage::Load_Verbose );
560 if( img.LoadFile( memis, mimeType ) )
562 int dimMul = img.GetWidth() * img.GetHeight();
563 double maxPixels = 30000;
565 if( dimMul > maxPixels )
567 double scale = sqrt( maxPixels / dimMul );
568 img.Rescale( img.GetWidth() *
scale, img.GetHeight() *
scale );
579 else if( type == wxS(
"HEAD" ) )
583 else if( type == wxS(
"PIN" ) )
585 wxString pinId = line.at( 1 );
586 unitParentedLines[currentUnit][pinId].push_back( line );
588 else if( type == wxS(
"ATTR" ) )
590 wxString parentId = line.at( 2 );
592 if( parentId.empty() )
595 unitAttributes[currentUnit].emplace( attr.
key, attr );
599 unitParentedLines[currentUnit][parentId].push_back( line );
614 if(
auto globalNetAttr =
get_opt( unitAttributes[1], wxS(
"Global Net Name" ) ) )
618 wxString globalNetname = globalNetAttr->value;
620 if( !globalNetname.empty() )
623 _(
"Power symbol creates a global label with name '%s'" ),
630 auto designatorAttr =
get_opt( unitAttributes[1], wxS(
"Designator" ) );
632 if( designatorAttr && !designatorAttr->value.empty() )
634 wxString symbolPrefix = designatorAttr->value;
636 if( symbolPrefix.EndsWith( wxS(
"?" ) ) )
637 symbolPrefix.RemoveLast();
643 aDeviceAttributes,
true,
644 [&](
const wxString& attrName,
const wxString& value )
659 for(
auto& [unitId, parentedLines] : unitParentedLines )
661 for(
auto& [pinId, lines] : parentedLines )
663 std::optional<EASYEDAPRO::SYM_PIN> epin;
664 std::map<wxString, EASYEDAPRO::SCH_ATTR> pinAttributes;
666 for(
const nlohmann::json& line : lines )
668 wxString type = line.at( 0 );
670 if( type == wxS(
"ATTR" ) )
673 pinAttributes.emplace( attr.
key, attr );
675 else if( type == wxS(
"PIN" ) )
687 std::unique_ptr<SCH_PIN>
pin = std::make_unique<SCH_PIN>( ksymbol );
689 pin->SetUnit( unitId );
696 if( epin->rotation == 0 )
698 if( epin->rotation == 90 )
700 if( epin->rotation == 180 )
702 if( epin->rotation == 270 )
705 pin->SetOrientation( orient );
714 auto pinNameAttr =
get_opt( pinAttributes,
"Pin Name" );
717 pinNameAttr =
get_opt( pinAttributes,
"NAME" );
721 pin->SetName( pinNameAttr->value );
722 pinInfo.
name = pinNameAttr->value;
724 if( !pinNameAttr->valVisible )
729 auto pinNumAttr =
get_opt( pinAttributes,
"Pin Number" );
732 pinNumAttr =
get_opt( pinAttributes,
"NUMBER" );
736 pin->SetNumber( pinNumAttr->value );
737 pinInfo.
number = pinNumAttr->value;
739 if( !pinNumAttr->valVisible )
747 else if(
auto pinTypeAttr =
get_opt( pinAttributes,
"Pin Type" ) )
749 if( pinTypeAttr->value == wxS(
"IN" ) )
751 if( pinTypeAttr->value == wxS(
"OUT" ) )
753 if( pinTypeAttr->value == wxS(
"BI" ) )
757 if(
get_opt( pinAttributes,
"NO_CONNECT" ) )
760 if(
pin->GetNumberTextSize() *
int(
pin->GetNumber().size() ) >
pin->GetLength() )
761 pin->SetNumberTextSize(
pin->GetLength() /
pin->GetNumber().size() );
763 symInfo.
pins.push_back( pinInfo );
781 symInfo.
libSymbol = std::move( ksymbolPtr );
788 const nlohmann::json& aProject,
789 std::map<wxString, EASYEDAPRO::SYM_INFO>& aSymbolMap,
790 const std::map<wxString, EASYEDAPRO::BLOB>& aBlobMap,
791 const std::vector<nlohmann::json>& aLines,
792 const wxString& aLibName )
794 std::vector<std::unique_ptr<SCH_ITEM>> createdItems;
796 std::map<wxString, std::vector<nlohmann::json>> parentedLines;
797 std::map<wxString, std::vector<nlohmann::json>> ruleLines;
799 std::map<wxString, nlohmann::json> lineStyles;
800 std::map<wxString, nlohmann::json> fontStyles;
802 for(
const nlohmann::json& line : aLines )
804 wxString type = line.at( 0 );
806 if( type == wxS(
"LINESTYLE" ) )
807 lineStyles[line.at( 1 )] = line;
808 else if( type == wxS(
"FONTSTYLE" ) )
809 fontStyles[line.at( 1 )] = line;
812 for(
const nlohmann::json& line : aLines )
814 wxString type = line.at( 0 );
816 if( type == wxS(
"RECT" ) )
818 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
820 wxString styleStr = line.at( 9 );
824 rect->SetStart(
ScalePos( start ) );
829 createdItems.push_back( std::move( rect ) );
831 else if( type == wxS(
"CIRCLE" ) )
834 double radius = line.at( 4 );
835 wxString styleStr = line.at( 5 );
844 createdItems.push_back( std::move(
circle ) );
846 else if( type == wxS(
"POLY" ) )
848 std::vector<double> points = line.at( 2 );
849 wxString styleStr = line.at( 4 );
853 for(
size_t i = 1; i < points.size(); i += 2 )
856 for(
int segId = 0; segId <
chain.SegmentCount(); segId++ )
858 const SEG& seg =
chain.CSegment( segId );
860 std::unique_ptr<SCH_LINE> schLine =
862 schLine->SetEndPoint( seg.
B );
866 createdItems.push_back( std::move( schLine ) );
869 else if( type == wxS(
"TEXT" ) )
871 VECTOR2D pos( line.at( 2 ), line.at( 3 ) );
872 double angle = line.at( 4 ).is_number() ? line.at( 4 ).get<
double>() : 0.0;
873 wxString textStr = line.at( 5 );
874 wxString fontStyleStr = line.at( 6 );
876 std::unique_ptr<SCH_TEXT>
text =
882 text->SetTextAngleDegrees( angle );
886 createdItems.push_back( std::move(
text ) );
888 else if( type == wxS(
"OBJ" ) )
891 wxString mimeType, base64Data;
895 if( line.at( 3 ).is_number() )
897 start =
VECTOR2D( line.at( 3 ), line.at( 4 ) );
898 size =
VECTOR2D( line.at( 5 ), line.at( 6 ) );
899 angle = line.at( 7 );
900 flipped = line.at( 8 );
902 wxString imageUrl = line.at( 9 );
904 if( imageUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
906 wxArrayString paramsArr =
907 wxSplit( imageUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
909 base64Data = imageUrl.AfterFirst(
',' );
911 if( paramsArr.size() > 0 )
912 mimeType = paramsArr[0];
914 else if( imageUrl.BeforeFirst(
':' ) == wxS(
"blob" ) )
916 wxString objectId = imageUrl.AfterLast(
':' );
918 if(
auto blob =
get_opt( aBlobMap, objectId ) )
920 wxString blobUrl = blob->url;
922 if( blobUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
924 wxArrayString paramsArr = wxSplit(
925 blobUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
927 base64Data = blobUrl.AfterFirst(
',' );
929 if( paramsArr.size() > 0 )
930 mimeType = paramsArr[0];
935 else if( line.at( 3 ).is_string() )
937 mimeType = line.at( 3 ).get<wxString>().BeforeFirst(
';' );
939 start =
VECTOR2D( line.at( 4 ), line.at( 5 ) );
940 size =
VECTOR2D( line.at( 6 ), line.at( 7 ) );
941 angle = line.at( 8 );
942 base64Data = line.at( 9 ).get<wxString>();
948 if( mimeType.empty() || base64Data.empty() )
951 wxMemoryBuffer buf = wxBase64Decode( base64Data );
953 if( mimeType == wxS(
"image/svg+xml" ) )
975 for( std::unique_ptr<EDA_ITEM>& item : schImporter.
GetItems() )
979 for(
double i = angle; i > 0; i -= 90 )
985 schItem->
Rotate( kstart,
false );
989 schItem->
Rotate( kstart,
false );
994 schItem->
Rotate( kstart,
false );
1010 createdItems.emplace_back( schItem );
1015 std::unique_ptr<SCH_BITMAP> bitmap = std::make_unique<SCH_BITMAP>();
1018 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
1019 & ~wxImage::Load_Verbose );
1023 VECTOR2D kcenter = kstart + ksize / 2;
1027 bitmap->SetPosition( kcenter );
1029 for(
double i = angle; i > 0; i -= 90 )
1030 bitmap->Rotate( kstart,
false );
1033 bitmap->MirrorHorizontally( kstart.
x );
1035 createdItems.push_back( std::move( bitmap ) );
1039 if( type == wxS(
"WIRE" ) )
1041 wxString wireId = line.at( 1 );
1042 parentedLines[wireId].push_back( line );
1044 else if( type == wxS(
"COMPONENT" ) )
1046 wxString compId = line.at( 1 );
1047 parentedLines[compId].push_back( line );
1049 else if( type == wxS(
"ATTR" ) )
1051 wxString compId = line.at( 2 );
1052 parentedLines[compId].push_back( line );
1056 for(
auto& [parentId, lines] : parentedLines )
1058 std::optional<EASYEDAPRO::SCH_COMPONENT> component;
1059 std::optional<EASYEDAPRO::SCH_WIRE> wire;
1060 std::map<wxString, EASYEDAPRO::SCH_ATTR> attributes;
1062 for(
const nlohmann::json& line : lines )
1064 if( line.at( 0 ) ==
"COMPONENT" )
1068 else if( line.at( 0 ) ==
"WIRE" )
1072 else if( line.at( 0 ) ==
"ATTR" )
1075 attributes.emplace( attr.
key, attr );
1081 auto deviceAttr =
get_opt( attributes,
"Device" );
1082 auto symbolAttr =
get_opt( attributes,
"Symbol" );
1088 aProject.at(
"devices" ).at( deviceAttr->value ).at(
"attributes" ) );
1091 std::map<wxString, wxString> mergedAttrValues;
1093 for(
const auto& [key, value] : prjCompAttrs )
1094 mergedAttrValues[key] = value;
1096 for(
const auto& [key, attr] : attributes )
1097 mergedAttrValues[key] = attr.value;
1101 if( symbolAttr && !symbolAttr->value.IsEmpty() )
1102 symbolId = symbolAttr->value;
1104 symbolId = prjCompAttrs.at(
"Symbol" );
1106 auto it = aSymbolMap.find( symbolId );
1107 if( it == aSymbolMap.end() )
1109 wxLogTrace(
traceEasyEdaIo,
"Symbol of '%s' with uuid '%s' not found.", component->name, symbolId );
1116 wxString unitName = component->name;
1121 auto schSym = std::make_unique<SCH_SYMBOL>( newLibSymbol, libId,
1125 schSym->SetFootprintFieldText( newLibSymbol.
GetFootprint() );
1127 for(
double i = component->rotation; i > 0; i -= 90 )
1128 schSym->Rotate(
VECTOR2I(),
true );
1130 if( component->mirror )
1131 schSym->MirrorHorizontally( 0 );
1133 schSym->SetPosition(
ScalePos( component->position ) );
1139 auto globalNetNameAttr =
get_opt( attributes,
"Global Net Name" );
1140 wxString globalNetNameFromProject =
get_def( prjCompAttrs,
"Global Net Name", wxEmptyString );
1141 wxString globalNetName;
1146 if( globalNetNameAttr && !globalNetNameAttr->value.IsEmpty() )
1148 globalNetName = globalNetNameAttr->value;
1151 mergedAttrValues, schSym.get() );
1153 else if( !globalNetNameFromProject.IsEmpty() )
1155 globalNetName = globalNetNameFromProject;
1164 for(
SCH_PIN*
pin : schSym->GetAllLibPins() )
1165 pin->SetName( globalNetName );
1167 schSym->SetRef( &aSchematic->
CurrentSheet(), wxS(
"#PWR?" ) );
1172 auto nameAttr =
get_opt( attributes,
"Name" );
1176 if( nameAttr && !nameAttr->value.IsEmpty() )
1177 netName = nameAttr->value;
1179 netName = prjCompAttrs.at(
"Name" );
1181 std::unique_ptr<SCH_GLOBALLABEL> label = std::make_unique<SCH_GLOBALLABEL>(
1182 ScalePos( component->position ), netName );
1184 std::vector<SCH_PIN*> pins = schSym->GetPins( &aSchematic->
CurrentSheet() );
1186 if( pins.size() > 0 )
1188 switch( pins[0]->GetType() )
1204 BOX2I bbox = schSym->GetBodyAndPinsBoundingBox();
1205 bbox.
Offset( -schSym->GetPosition() );
1212 if( bboxCenter.
x >= 0 )
1219 if( bboxCenter.
y >= 0 )
1225 label->SetSpinStyle( spin );
1229 nlohmann::json style = fontStyles[nameAttr->fontStyle];
1231 if( !style.is_null() && style.at( 5 ).is_number() )
1233 double size = style.at( 5 ).get<
double>() * 0.62;
1238 createdItems.push_back( std::move( label ) );
1245 mergedAttrValues,
true,
1246 [&](
const wxString& attrKey,
const wxString& value )
1248 SCH_FIELD*
text = schSym->FindFieldCaseInsensitive( attrKey );
1253 text->SetText( value );
1254 text->SetVisible(
false );
1257 auto nameAttr =
get_opt( attributes,
"Name" );
1258 auto valueAttr =
get_opt( attributes,
"Value" );
1260 if( valueAttr && valueAttr->value.empty() )
1261 valueAttr->value =
get_def( prjCompAttrs,
"Value", wxString() );
1263 if( nameAttr && nameAttr->value.empty() )
1264 nameAttr->value =
get_def( prjCompAttrs,
"Name", wxString() );
1266 std::optional<EASYEDAPRO::SCH_ATTR> targetValueAttr;
1268 if( valueAttr && !valueAttr->value.empty() && valueAttr->valVisible )
1269 targetValueAttr = valueAttr;
1270 else if( nameAttr && !nameAttr->value.empty() && nameAttr->valVisible )
1271 targetValueAttr = nameAttr;
1272 else if( valueAttr && !valueAttr->value.empty() )
1273 targetValueAttr = valueAttr;
1274 else if( nameAttr && !nameAttr->value.empty() )
1275 targetValueAttr = nameAttr;
1277 if( targetValueAttr )
1280 *targetValueAttr,
false,
true, mergedAttrValues, schSym.get() );
1283 if(
auto descrAttr =
get_opt( attributes,
"Description" ) )
1286 *descrAttr,
false,
true, mergedAttrValues, schSym.get() );
1289 if(
auto designatorAttr =
get_opt( attributes,
"Designator" ) )
1292 *designatorAttr,
false,
true, mergedAttrValues, schSym.get() );
1294 schSym->SetRef( &aSchematic->
CurrentSheet(), designatorAttr->value );
1297 for(
auto& [attrKey, attr] : attributes )
1299 if( attrKey == wxS(
"Name" ) || attrKey == wxS(
"Value" )
1300 || attrKey == wxS(
"Global Net Name" ) || attrKey == wxS(
"Designator" )
1301 || attrKey == wxS(
"Description" ) || attrKey == wxS(
"Device" )
1302 || attrKey == wxS(
"Footprint" ) || attrKey == wxS(
"Symbol" )
1303 || attrKey == wxS(
"Unique ID" ) )
1308 if( attr.value.IsEmpty() )
1311 SCH_FIELD*
text = schSym->FindFieldCaseInsensitive( attrKey );
1316 text->SetPosition( schSym->GetPosition() );
1325 wxString pinKey = parentId + pinInfo.
pin.
id;
1326 auto pinLines =
get_opt( parentedLines, pinKey );
1331 for(
const nlohmann::json& pinLine : *pinLines )
1333 if( pinLine.at( 0 ) !=
"ATTR" )
1338 if( attr.
key != wxS(
"NO_CONNECT" ) )
1341 for(
SCH_PIN* schPin : schSym->GetPinsByNumber( pinInfo.
number ) )
1343 VECTOR2I pos = schSym->GetPinPhysicalPosition( schPin->GetLibPin() );
1345 std::unique_ptr<SCH_NO_CONNECT> noConn =
1346 std::make_unique<SCH_NO_CONNECT>( pos );
1348 createdItems.push_back( std::move( noConn ) );
1353 createdItems.push_back( std::move( schSym ) );
1357 std::vector<SHAPE_LINE_CHAIN> wireLines;
1361 for(
const std::vector<double>& ptArr : wire->geometry )
1365 for(
size_t i = 1; i < ptArr.size(); i += 2 )
1368 if(
chain.PointCount() < 2 )
1371 wireLines.push_back(
chain );
1373 for(
int segId = 0; segId <
chain.SegmentCount(); segId++ )
1375 const SEG& seg =
chain.CSegment( segId );
1377 std::unique_ptr<SCH_LINE> schLine =
1379 schLine->SetEndPoint( seg.
B );
1381 createdItems.push_back( std::move( schLine ) );
1386 auto netAttr =
get_opt( attributes,
"NET" );
1390 if( !netAttr->valVisible || netAttr->value.IsEmpty() )
1400 SEG::ecoord dist_sq = ( nearestPt - kpos ).SquaredEuclideanNorm();
1402 if( dist_sq < min_dist_sq )
1404 min_dist_sq = dist_sq;
1405 nearestPos = nearestPt;
1409 std::unique_ptr<SCH_LABEL> label = std::make_unique<SCH_LABEL>();
1414 for(
double i = netAttr->rotation; i > 0; i -= 90 )
1415 label->Rotate90(
true );
1417 label->SetPosition( nearestPos );
1418 label->SetText( netAttr->value );
1422 createdItems.push_back( std::move( label ) );
1430 for( std::unique_ptr<SCH_ITEM>& ptr : createdItems )
1435 sheetBBox.
Merge( ptr->GetBoundingBox() );
1444 offset.
x =
KiROUND( offset.
x / alignGrid ) * alignGrid;
1445 offset.
y =
KiROUND( offset.
y / alignGrid ) * alignGrid;
1452 for( std::unique_ptr<SCH_ITEM>& ptr : createdItems )
1454 ptr->Move( offset );
1455 screen->
Append( ptr.release() );