30#include <nlohmann/json.hpp>
35#include <wx/wfstream.h>
36#include <wx/stdstream.h>
74 if( !aValue.ToCDouble( &value ) )
75 THROW_IO_ERROR( wxString::Format(
_(
"Failed to parse value: '%s'" ), aValue ) );
104 case 9:
return F_Fab;
105 case 10:
return B_Fab;
204 const wxString& modelTitle,
205 const wxString& modelTransform )
const
208 const wxString easyedaModelDir = wxS(
"EASYEDA_MODELS" );
209 const wxString kicadModelPrefix = wxS(
"${KIPRJMOD}/" ) + easyedaModelDir + wxS(
"/" );
225 wxArrayString arr = wxSplit( modelTransform,
',',
'\0' );
230 if( fitXmm > 0.0 && fitYmm > 0.0 )
235 field.
SetText( wxString::FromCDouble( fitXmm ) + wxS(
" " )
236 + wxString::FromCDouble( fitYmm ) );
240 kmodelRotation.
z = -
Convert( arr[3] );
241 kmodelRotation.
x = -
Convert( arr[4] );
242 kmodelRotation.
y = -
Convert( arr[5] );
249 if( !modelTitle.IsEmpty() && footprint->
Models().empty() )
253 +
EscapeString( modelTitle, ESCAPE_CONTEXT::CTX_FILENAME )
257 footprint->
Models().push_back( model );
262std::vector<std::unique_ptr<PCB_SHAPE>>
264 bool aClosed,
bool aInFill )
const
266 std::vector<std::unique_ptr<PCB_SHAPE>> results;
269 for(
int i = 0; i < polyData.size(); i++ )
271 nlohmann::json val = polyData.at( i );
273 if( val.is_string() )
276 if( str == wxS(
"CIRCLE" ) )
279 center.
x = ( polyData.at( ++i ) );
280 center.
y = ( polyData.at( ++i ) );
281 double r = ( polyData.at( ++i ) );
283 std::unique_ptr<PCB_SHAPE> shape =
284 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::CIRCLE );
288 shape->SetFilled( aClosed );
290 results.emplace_back( std::move( shape ) );
292 else if( str == wxS(
"R" ) )
295 start.
x = ( polyData.at( ++i ) );
296 start.
y = ( polyData.at( ++i ) );
297 size.
x = ( polyData.at( ++i ) );
298 size.
y = -( polyData.at( ++i ).get<
double>() );
299 double angle = polyData.at( ++i );
300 double cr = ( i + 1 ) < polyData.size() ? polyData.at( ++i ).get<
double>() : 0;
304 std::unique_ptr<PCB_SHAPE> shape =
305 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::RECTANGLE );
307 shape->SetStart(
ScalePos( start ) );
308 shape->SetEnd(
ScalePos( start + size ) );
309 shape->SetFilled( aClosed );
312 results.emplace_back( std::move( shape ) );
320 std::unique_ptr<PCB_SHAPE> shape =
321 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::SEGMENT );
323 shape->SetStart(
ScalePos( aStart ) );
325 shape->SetFilled( aClosed );
328 results.emplace_back( std::move( shape ) );
333 std::unique_ptr<PCB_SHAPE> shape =
334 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::ARC );
336 shape->SetStart(
ScalePos( aStart ) );
339 shape->SetFilled( aClosed );
342 results.emplace_back( std::move( shape ) );
350 addArc( {
end.
x - cr, start.
y }, {
end.
x, start.
y - cr },
351 {
end.
x - cr, start.
y - cr } );
356 addArc( { start.
x + cr,
end.
y }, { start.
x,
end.
y + cr },
357 { start.
x + cr,
end.
y + cr } );
359 addArc( { start.
x, start.
y - cr }, { start.
x + cr, start.
y },
360 { start.
x + cr, start.
y - cr } );
363 else if( str == wxS(
"ARC" ) || str == wxS(
"CARC" ) )
366 double angle = polyData.at( ++i ).get<
double>() / ( aInFill ? 10 : 1 );
367 end.
x = ( polyData.at( ++i ) );
368 end.
y = ( polyData.at( ++i ) );
370 std::unique_ptr<PCB_SHAPE> shape =
371 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::ARC );
375 shape->SetStart(
ScalePos( prevPt ) );
381 shape->SetEnd(
ScalePos( prevPt ) );
387 double ha = angle / 2;
388 double hd =
delta.EuclideanNorm() / 2;
389 double cdist = hd / tan(
DEG2RAD( ha ) );
393 shape->SetFilled( aClosed );
395 results.emplace_back( std::move( shape ) );
399 else if( str == wxS(
"L" ) )
404 while( i < polyData.size() - 2 && polyData.at( i + 1 ).is_number() )
407 pt.
x = ( polyData.at( ++i ) );
408 pt.
y = ( polyData.at( ++i ) );
417 std::unique_ptr<PCB_SHAPE> shape =
418 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::POLY );
425 shape->SetFilled(
true );
426 shape->SetPolyShape(
chain );
428 results.emplace_back( std::move( shape ) );
437 std::unique_ptr<PCB_SHAPE> shape =
438 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::SEGMENT );
440 shape->SetStart( seg.
A );
441 shape->SetEnd( seg.
B );
443 results.emplace_back( std::move( shape ) );
448 else if( val.is_number() )
450 prevPt.
x = ( polyData.at( i ) );
451 prevPt.
y = ( polyData.at( ++i ) );
461 double aArcAccuracy )
const
466 for(
int i = 0; i < polyData.size(); i++ )
468 nlohmann::json val = polyData.at( i );
470 if( val.is_string() )
473 if( str == wxS(
"CIRCLE" ) )
476 center.
x = ( polyData.at( ++i ) );
477 center.
y = ( polyData.at( ++i ) );
478 double r = ( polyData.at( ++i ) );
483 else if( str == wxS(
"R" ) )
486 start.
x = ( polyData.at( ++i ) );
487 start.
y = ( polyData.at( ++i ) );
488 size.
x = ( polyData.at( ++i ) );
489 size.
y = ( polyData.at( ++i ).get<
double>() );
490 double angle = polyData.at( ++i );
491 double cr = ( i + 1 ) < polyData.size() ? polyData.at( ++i ).get<
double>() : 0;
497 VECTOR2D kcenter = kstart + ksize / 2;
504 result.
Append( poly.Outline( 0 ) );
506 else if( str == wxS(
"ARC" ) || str == wxS(
"CARC" ) )
509 double angle = polyData.at( ++i ).get<
double>();
514 end.
x = ( polyData.at( ++i ) );
515 end.
y = ( polyData.at( ++i ) );
524 double ha = angle / 2;
525 double hd =
delta.EuclideanNorm() / 2;
526 double cdist = hd / tan(
DEG2RAD( ha ) );
533 result.
Append( sarc, aArcAccuracy );
537 else if( str == wxS(
"C" ) )
540 pt1.
x = ( polyData.at( ++i ) );
541 pt1.
y = ( polyData.at( ++i ) );
544 pt2.
x = ( polyData.at( ++i ) );
545 pt2.
y = ( polyData.at( ++i ) );
548 pt3.
x = ( polyData.at( ++i ) );
549 pt3.
y = ( polyData.at( ++i ) );
555 std::vector<VECTOR2I> bezierPoints;
556 converter.
GetPoly( bezierPoints, aArcAccuracy );
558 result.
Append( bezierPoints );
562 else if( str == wxS(
"L" ) )
566 while( i < polyData.size() - 2 && polyData.at( i + 1 ).is_number() )
569 pt.
x = ( polyData.at( ++i ) );
570 pt.
y = ( polyData.at( ++i ) );
578 else if( val.is_number() )
580 prevPt.
x = ( polyData.at( i ) );
581 prevPt.
y = ( polyData.at( ++i ) );
590 const nlohmann::json& line )
592 wxString uuid = line.at( 1 );
599 wxString netname = line.at( 3 );
600 int layer = line.at( 4 ).get<
int>();
603 wxString padNumber = line.at( 5 );
609 double orientation = line.at( 8 );
611 nlohmann::json padHole = line.at( 9 );
612 nlohmann::json padShape = line.at( 10 );
614 std::unique_ptr<PAD>
pad = std::make_unique<PAD>( aFootprint );
616 pad->SetNumber( padNumber );
618 pad->SetOrientationDegrees( orientation );
620 if( !padHole.is_null() )
622 double drill_dir = 0;
624 if( line.at( 14 ).is_number() )
625 drill_dir = line.at( 14 );
627 wxString holeShape = padHole.at( 0 );
629 if( holeShape == wxS(
"ROUND" ) || holeShape == wxS(
"SLOT" ) )
632 drill.
x = padHole.at( 1 );
633 drill.
y = padHole.at( 2 );
638 std::swap( drill.
x, drill.
y );
640 if( holeShape == wxS(
"SLOT" ) )
642 pad->SetDrillShape( PAD_DRILL_SHAPE::OBLONG );
647 pad->SetAttribute( PAD_ATTRIB::PTH );
656 else if( klayer ==
B_Cu )
661 pad->SetAttribute( PAD_ATTRIB::SMD );
664 wxString padSh = padShape.at( 0 );
665 if( padSh == wxS(
"RECT" ) )
668 size.
x = padShape.at( 1 );
669 size.
y = padShape.at( 2 );
670 double cr_p = padShape.size() > 3 ? padShape.at( 3 ).get<
double>() : 0;
684 else if( padSh == wxS(
"ELLIPSE" ) )
687 size.
x = padShape.at( 1 );
688 size.
y = padShape.at( 2 );
693 else if( padSh == wxS(
"OVAL" ) )
696 size.
x = padShape.at( 1 );
697 size.
y = padShape.at( 2 );
702 else if( padSh == wxS(
"POLY" ) )
708 nlohmann::json polyData = padShape.at( 1 );
710 std::vector<std::unique_ptr<PCB_SHAPE>> results =
711 ParsePoly( aFootprint, polyData,
true,
false );
713 for(
auto& shape : results )
715 shape->SetLayer( klayer );
716 shape->SetWidth( 0 );
718 shape->Move( -
pad->GetPosition() );
726 return std::move(
pad );
731 const wxString& aFpUuid,
732 const std::vector<nlohmann::json>& aLines )
734 std::unique_ptr<FOOTPRINT> footprintPtr = std::make_unique<FOOTPRINT>(
m_board );
735 FOOTPRINT* footprint = footprintPtr.get();
742 field->SetTextSize( defaultTextSize );
743 field->SetTextThickness( defaultTextThickness );
746 for(
const nlohmann::json& line : aLines )
748 if( line.size() == 0 )
751 wxString type = line.at( 0 );
753 if( type == wxS(
"POLY" ) || type == wxS(
"PAD" ) || type == wxS(
"FILL" )
754 || type == wxS(
"ATTR" ) )
756 wxString uuid = line.at( 1 );
763 wxString netname = line.at( 3 );
764 int layer = line.at( 4 ).get<
int>();
767 if( type == wxS(
"POLY" ) )
769 double thickness = ( line.at( 5 ) );
770 nlohmann::json polyData = line.at( 6 );
772 std::vector<std::unique_ptr<PCB_SHAPE>> results =
773 ParsePoly( footprint, polyData,
false,
false );
775 for(
auto& shape : results )
777 shape->SetLayer( klayer );
778 shape->SetWidth(
ScaleSize( thickness ) );
780 footprint->
Add( shape.release(), ADD_MODE::APPEND );
783 else if( type == wxS(
"PAD" ) )
785 std::unique_ptr<PAD>
pad =
createPAD( footprint, line );
787 footprint->
Add(
pad.release(), ADD_MODE::APPEND );
789 else if( type == wxS(
"FILL" ) )
791 int layer = line.at( 4 ).get<
int>();
794 double width = line.at( 5 );
796 nlohmann::json polyDataList = line.at( 7 );
798 if( !polyDataList.is_null() && !polyDataList.empty() )
800 if( !polyDataList.at( 0 ).is_array() )
801 polyDataList = nlohmann::json::array( { polyDataList } );
803 std::vector<SHAPE_LINE_CHAIN> contours;
804 for( nlohmann::json& polyData : polyDataList )
809 contours.push_back( contour );
819 std::unique_ptr<PCB_GROUP>
group;
822 group = std::make_unique<PCB_GROUP>( footprint );
828 std::unique_ptr<PCB_SHAPE> shape =
829 std::make_unique<PCB_SHAPE>( footprint, SHAPE_T::POLY );
831 shape->SetFilled(
true );
832 shape->SetPolyShape( poly );
833 shape->SetLayer( klayer );
834 shape->SetWidth( 0 );
837 group->AddItem( shape.get() );
839 footprint->
Add( shape.release(), ADD_MODE::APPEND );
843 footprint->
Add(
group.release(), ADD_MODE::APPEND );
846 else if( type == wxS(
"ATTR" ) )
850 if( attr.
key == wxS(
"Designator" ) )
854 else if( type == wxS(
"REGION" ) )
856 wxString uuid = line.at( 1 );
863 int layer = line.at( 3 ).get<
int>();
866 double width = line.at( 4 );
867 std::set<int> flags = line.at( 5 );
868 nlohmann::json polyDataList = line.at( 6 );
870 for( nlohmann::json& polyData : polyDataList )
874 std::vector<std::unique_ptr<PCB_SHAPE>> results =
875 ParsePoly(
nullptr, polyData,
true,
false );
877 for(
auto& shape : results )
879 shape->SetFilled(
true );
886 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( footprint );
888 zone->SetIsRuleArea(
true );
889 zone->SetDoNotAllowFootprints( !!flags.count( 2 ) );
890 zone->SetDoNotAllowCopperPour( !!flags.count( 7 ) || !!flags.count( 6 )
891 || !!flags.count( 8 ) );
892 zone->SetDoNotAllowPads( !!flags.count( 7 ) );
893 zone->SetDoNotAllowTracks( !!flags.count( 7 ) || !!flags.count( 5 ) );
894 zone->SetDoNotAllowVias( !!flags.count( 7 ) );
896 zone->SetLayer( klayer );
897 zone->Outline()->Append( polySet );
899 footprint->
Add( zone.release(), ADD_MODE::APPEND );
904 if( aProject.is_object() && aProject.contains(
"devices" ) )
906 std::map<wxString, EASYEDAPRO::PRJ_DEVICE> devicesMap = aProject.at(
"devices" );
907 std::map<wxString, wxString> compAttrs;
909 for(
auto& [devUuid, devData] : devicesMap )
911 if(
auto fp =
get_opt( devData.attributes,
"Footprint" ) )
915 compAttrs = devData.attributes;
921 wxString modelUuid, modelTitle, modelTransform;
923 modelUuid =
get_def( compAttrs,
"3D Model",
"" );
924 modelTitle =
get_def( compAttrs,
"3D Model Title", modelUuid );
925 modelTransform =
get_def( compAttrs,
"3D Model Transform",
"" );
931 std::vector<PCB_SHAPE*> shapes;
932 std::vector<std::unique_ptr<PCB_SHAPE>> newShapes;
940 shapes.push_back(
static_cast<PCB_SHAPE*
>( item ) );
945 for( std::unique_ptr<PCB_SHAPE>& ptr : newShapes )
946 footprint->
Add( ptr.release(), ADD_MODE::APPEND );
948 return footprintPtr.release();
953 BOARD* aBoard,
const nlohmann::json& aProject,
954 std::map<wxString, std::unique_ptr<FOOTPRINT>>& aFootprintMap,
955 const std::map<wxString, EASYEDAPRO::BLOB>& aBlobMap,
956 const std::multimap<wxString, EASYEDAPRO::POURED>& aPouredMap,
957 const std::vector<nlohmann::json>& aLines,
const wxString& aFpLibName )
959 std::map<wxString, std::vector<nlohmann::json>> componentLines;
960 std::map<wxString, std::vector<nlohmann::json>> ruleLines;
962 std::multimap<wxString, EASYEDAPRO::POURED> boardPouredMap = aPouredMap;
963 std::map<wxString, ZONE*> poursToFill;
967 for(
const nlohmann::json& line : aLines )
969 if( line.size() == 0 )
972 wxString type = line.at( 0 );
974 if( type == wxS(
"LAYER" ) )
976 int layer = line.at( 1 );
979 wxString layerType = line.at( 2 );
980 wxString layerName = line.at( 3 );
981 int layerFlag = line.at( 4 );
986 blayers.
set( klayer );
991 else if( type == wxS(
"NET" ) )
993 wxString netname = line.at( 1 );
998 else if( type == wxS(
"RULE" ) )
1000 wxString ruleType = line.at( 1 );
1001 wxString ruleName = line.at( 2 );
1002 int isDefault = line.at( 3 );
1003 nlohmann::json ruleData = line.at( 4 );
1005 if( ruleType == wxS(
"3" ) && isDefault )
1007 wxString units = ruleData.at( 0 );
1008 double minVal = ruleData.at( 1 );
1009 double optVal = ruleData.at( 2 );
1010 double maxVal = ruleData.at( 3 );
1014 else if( ruleType == wxS(
"1" ) && isDefault )
1016 wxString units = ruleData.at( 0 );
1017 nlohmann::json
table = ruleData.at( 1 );
1019 int minVal = INT_MAX;
1020 for(
const std::vector<int>& arr :
table )
1022 for(
int val : arr )
1032 ruleLines[ruleType].push_back( line );
1034 else if( type == wxS(
"POURED" ) )
1036 if( !line.at( 2 ).is_string() )
1040 boardPouredMap.emplace( poured.
parentId, poured );
1042 else if( type == wxS(
"VIA" ) || type == wxS(
"LINE" ) || type == wxS(
"ARC" )
1043 || type == wxS(
"POLY" ) || type == wxS(
"FILL" ) || type == wxS(
"POUR" ) )
1045 wxString uuid = line.at( 1 );
1052 wxString netname = line.at( 3 );
1054 if( type == wxS(
"VIA" ) )
1060 double drill = line.at( 7 );
1061 double dia = line.at( 8 );
1063 std::unique_ptr<PCB_VIA>
via = std::make_unique<PCB_VIA>( aBoard );
1071 aBoard->
Add(
via.release(), ADD_MODE::APPEND );
1073 else if( type == wxS(
"LINE" ) )
1075 int layer = line.at( 4 ).get<
int>();
1079 start.
x = line.at( 5 );
1080 start.
y = line.at( 6 );
1083 end.
x = line.at( 7 );
1084 end.
y = line.at( 8 );
1086 double width = line.at( 9 );
1088 std::unique_ptr<PCB_TRACK> track = std::make_unique<PCB_TRACK>( aBoard );
1090 track->SetLayer( klayer );
1091 track->SetStart(
ScalePos( start ) );
1095 track->SetNet( aBoard->
FindNet( netname ) );
1097 aBoard->
Add( track.release(), ADD_MODE::APPEND );
1099 else if( type == wxS(
"ARC" ) )
1101 int layer = line.at( 4 ).get<
int>();
1105 start.
x = line.at( 5 );
1106 start.
y = line.at( 6 );
1109 end.
x = line.at( 7 );
1110 end.
y = line.at( 8 );
1112 double angle = line.at( 9 );
1113 double width = line.at( 10 );
1118 double ha = angle / 2;
1119 double hd =
delta.EuclideanNorm() / 2;
1120 double cdist = hd / tan(
DEG2RAD( ha ) );
1127 std::unique_ptr<PCB_ARC> arc = std::make_unique<PCB_ARC>( aBoard, &sarc );
1130 arc->SetLayer( klayer );
1131 arc->SetNet( aBoard->
FindNet( netname ) );
1133 aBoard->
Add( arc.release(), ADD_MODE::APPEND );
1135 else if( type == wxS(
"FILL" ) )
1137 int layer = line.at( 4 ).get<
int>();
1140 double width = line.at( 5 );
1142 nlohmann::json polyDataList = line.at( 7 );
1144 if( !polyDataList.at( 0 ).is_array() )
1145 polyDataList = nlohmann::json::array( { polyDataList } );
1147 std::vector<SHAPE_LINE_CHAIN> contours;
1148 for( nlohmann::json& polyData : polyDataList )
1153 contours.push_back( contour );
1164 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aBoard );
1166 zone->SetNet( aBoard->
FindNet( netname ) );
1167 zone->SetLayer( klayer );
1169 zone->SetFilledPolysList( klayer, zoneFillPoly );
1170 zone->SetAssignedPriority( 500 );
1171 zone->SetIsFilled(
true );
1172 zone->SetNeedRefill(
false );
1177 aBoard->
Add( zone.release(), ADD_MODE::APPEND );
1179 else if( type == wxS(
"POLY" ) )
1181 int layer = line.at( 4 );
1184 double thickness = line.at( 5 );
1185 nlohmann::json polyData = line.at( 6 );
1187 std::vector<std::unique_ptr<PCB_SHAPE>> results =
1188 ParsePoly( aBoard, polyData,
false,
false );
1190 for(
auto& shape : results )
1192 shape->SetLayer( klayer );
1193 shape->SetWidth(
ScaleSize( thickness ) );
1195 aBoard->
Add( shape.release(), ADD_MODE::APPEND );
1198 else if( type == wxS(
"POUR" ) )
1200 int layer = line.at( 4 ).get<
int>();
1203 double lineWidth = line.at( 5 );
1204 wxString pourname = line.at( 6 );
1205 int fillOrder = line.at( 7 ).get<
int>();
1206 nlohmann::json polyDataList = line.at( 8 );
1208 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aBoard );
1210 zone->SetNet( aBoard->
FindNet( netname ) );
1211 zone->SetLayer( klayer );
1212 zone->SetAssignedPriority( 500 - fillOrder );
1216 for( nlohmann::json& polyData : polyDataList )
1221 zone->Outline()->Append( contour );
1224 wxASSERT( zone->Outline()->OutlineCount() == 1 );
1226 poursToFill.emplace( uuid, zone.get() );
1228 aBoard->
Add( zone.release(), ADD_MODE::APPEND );
1231 else if( type == wxS(
"TEARDROP" ) )
1233 wxString uuid = line.at( 1 );
1234 wxString netname = line.at( 2 );
1235 int layer = line.at( 3 ).get<
int>();
1238 nlohmann::json polyData = line.at( 4 );
1243 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aBoard );
1245 zone->SetNet( aBoard->
FindNet( netname ) );
1246 zone->SetLayer( klayer );
1247 zone->Outline()->Append( contour );
1248 zone->SetFilledPolysList( klayer, contour );
1249 zone->SetNeedRefill(
false );
1250 zone->SetIsFilled(
true );
1252 zone->SetAssignedPriority( 600 );
1253 zone->SetLocalClearance( 0 );
1254 zone->SetMinThickness( 0 );
1255 zone->SetTeardropAreaType( TEARDROP_TYPE::TD_UNSPECIFIED );
1257 aBoard->
Add( zone.release(), ADD_MODE::APPEND );
1259 else if( type == wxS(
"REGION" ) )
1261 wxString uuid = line.at( 1 );
1268 int layer = line.at( 3 ).get<
int>();
1271 double width = line.at( 4 );
1272 std::set<int> flags = line.at( 5 );
1273 nlohmann::json polyDataList = line.at( 6 );
1275 for( nlohmann::json& polyData : polyDataList )
1280 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aBoard );
1282 zone->SetIsRuleArea(
true );
1283 zone->SetDoNotAllowFootprints( !!flags.count( 2 ) );
1284 zone->SetDoNotAllowCopperPour( !!flags.count( 7 ) || !!flags.count( 6 )
1285 || !!flags.count( 8 ) );
1286 zone->SetDoNotAllowPads( !!flags.count( 7 ) );
1287 zone->SetDoNotAllowTracks( !!flags.count( 7 ) || !!flags.count( 5 ) );
1288 zone->SetDoNotAllowVias( !!flags.count( 7 ) );
1290 zone->SetLayer( klayer );
1291 zone->Outline()->Append( contour );
1293 aBoard->
Add( zone.release(), ADD_MODE::APPEND );
1296 else if( type == wxS(
"PAD" ) )
1298 wxString netname = line.at( 3 );
1300 std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>( aBoard );
1301 std::unique_ptr<PAD>
pad =
createPAD( footprint.get(), line );
1311 footprint->Add(
pad.release(), ADD_MODE::APPEND );
1312 footprint->SetPosition( pos );
1313 footprint->SetOrientation( orient );
1315 wxString fpName = wxS(
"Pad_" ) + line.at( 1 ).get<wxString>();
1318 footprint->SetFPID( fpID );
1319 footprint->Reference().SetVisible(
true );
1320 footprint->Value().SetVisible(
true );
1321 footprint->AutoPositionFields();
1323 aBoard->
Add( footprint.release(), ADD_MODE::APPEND );
1325 else if( type == wxS(
"IMAGE" ) )
1327 wxString uuid = line.at( 1 );
1334 int layer = line.at( 3 ).get<
int>();
1337 VECTOR2D start( line.at( 4 ), line.at( 5 ) );
1338 VECTOR2D size( line.at( 6 ), line.at( 7 ) );
1340 double angle = line.at( 8 );
1341 int mirror = line.at( 9 );
1342 nlohmann::json polyDataList = line.at( 10 );
1345 std::vector<SHAPE_LINE_CHAIN> contours;
1346 for( nlohmann::json& polyData : polyDataList )
1351 contours.push_back( contour );
1363 for(
int i = 0; i < contour.PointCount(); i++ )
1374 std::unique_ptr<PCB_GROUP>
group;
1377 group = std::make_unique<PCB_GROUP>( aBoard );
1383 std::unique_ptr<PCB_SHAPE> shape =
1384 std::make_unique<PCB_SHAPE>( aBoard, SHAPE_T::POLY );
1386 shape->SetFilled(
true );
1387 shape->SetPolyShape( poly );
1388 shape->SetLayer( klayer );
1389 shape->SetWidth( 0 );
1397 ? FLIP_DIRECTION::TOP_BOTTOM
1398 : FLIP_DIRECTION::LEFT_RIGHT;
1399 shape->Mirror(
ScalePos( start ), flipDirection );
1403 group->AddItem( shape.get() );
1405 aBoard->
Add( shape.release(), ADD_MODE::APPEND );
1409 aBoard->
Add(
group.release(), ADD_MODE::APPEND );
1411 else if( type == wxS(
"OBJ" ) )
1414 wxString mimeType, base64Data;
1418 if( !line.at( 3 ).is_number() )
1421 int layer = line.at( 3 ).get<
int>();
1424 start =
VECTOR2D( line.at( 5 ), line.at( 6 ) );
1425 size =
VECTOR2D( line.at( 7 ), line.at( 8 ) );
1426 angle = line.at( 9 );
1427 flipped = line.at( 10 );
1429 wxString imageUrl = line.at( 11 );
1431 if( imageUrl.BeforeFirst(
':' ) == wxS(
"blob" ) )
1433 wxString objectId = imageUrl.AfterLast(
':' );
1435 if(
auto blob =
get_opt( aBlobMap, objectId ) )
1437 wxString blobUrl = blob->url;
1439 if( blobUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
1441 wxArrayString paramsArr =
1442 wxSplit( blobUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
1444 base64Data = blobUrl.AfterFirst(
',' );
1446 if( paramsArr.size() > 0 )
1447 mimeType = paramsArr[0];
1455 if( mimeType.empty() || base64Data.empty() )
1458 wxMemoryBuffer buf = wxBase64Decode( base64Data );
1460 if( mimeType == wxS(
"image/svg+xml" ) )
1466 VECTOR2D kcenter = kstart + ksize / 2;
1468 std::unique_ptr<PCB_REFERENCE_IMAGE> bitmap =
1469 std::make_unique<PCB_REFERENCE_IMAGE>( aBoard, kcenter, klayer );
1472 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
1473 & ~wxImage::Load_Verbose );
1485 int x = bitmap->GetPosition().x;
1492 aBoard->
Add( bitmap.release(), ADD_MODE::APPEND );
1496 else if( type == wxS(
"STRING" ) )
1498 wxString uuid = line.at( 1 );
1505 int layer = line.at( 3 ).get<
int>();
1509 wxString
string = line.at( 6 );
1510 wxString font = line.at( 7 );
1512 double height = line.at( 8 );
1513 double strokew = line.at( 9 );
1515 int align = line.at( 12 );
1516 double angle = line.at( 13 );
1517 int inverted = line.at( 14 );
1518 int mirror = line.at( 16 );
1522 text->SetText(
string );
1523 text->SetLayer( klayer );
1525 text->SetIsKnockout( inverted );
1529 if( font != wxS(
"default" ) )
1542 text->SetMirrored(
true );
1543 text->SetTextAngleDegrees( -angle );
1547 text->SetTextAngleDegrees( angle );
1550 aBoard->
Add(
text, ADD_MODE::APPEND );
1552 else if( type == wxS(
"COMPONENT" ) )
1554 wxString compId = line.at( 1 );
1555 componentLines[compId].push_back( line );
1557 else if( type == wxS(
"ATTR" ) )
1559 wxString compId = line.at( 3 );
1560 componentLines[compId].push_back( line );
1562 else if( type == wxS(
"PAD_NET" ) )
1564 wxString compId = line.at( 1 );
1565 componentLines[compId].push_back( line );
1569 for(
auto const& [compId, lines] : componentLines )
1572 wxString fpIdOverride;
1573 wxString fpDesignator;
1574 std::map<wxString, wxString> localCompAttribs;
1576 for(
auto& line : lines )
1578 if( line.size() == 0 )
1581 wxString type = line.at( 0 );
1583 if( type == wxS(
"COMPONENT" ) )
1585 localCompAttribs = line.at( 7 );
1587 else if( type == wxS(
"ATTR" ) )
1591 if( attr.
key == wxS(
"Device" ) )
1592 deviceId = attr.
value;
1594 else if( attr.
key == wxS(
"Footprint" ) )
1595 fpIdOverride = attr.
value;
1597 else if( attr.
key == wxS(
"Designator" ) )
1598 fpDesignator = attr.
value;
1602 if( deviceId.empty() )
1605 nlohmann::json compAttrs = aProject.at(
"devices" ).at( deviceId ).at(
"attributes" );
1609 if( !fpIdOverride.IsEmpty() )
1610 fpId = fpIdOverride;
1612 fpId = compAttrs.at(
"Footprint" ).get<wxString>();
1614 auto it = aFootprintMap.find( fpId );
1615 if( it == aFootprintMap.end() )
1617 wxLogError(
"Footprint of '%s' with uuid '%s' not found.", fpDesignator, fpId );
1621 std::unique_ptr<FOOTPRINT>& footprintOrig = it->second;
1622 std::unique_ptr<FOOTPRINT> footprint(
static_cast<FOOTPRINT*
>( footprintOrig->Clone() ) );
1624 wxString modelUuid, modelTitle, modelTransform;
1626 if(
auto val =
get_opt( localCompAttribs,
"3D Model" ) )
1629 modelUuid = compAttrs.value<wxString>(
"3D Model",
"" );
1631 if(
auto val =
get_opt( localCompAttribs,
"3D Model Title" ) )
1632 modelTitle = val->Trim();
1634 modelTitle = compAttrs.value<wxString>(
"3D Model Title", modelUuid ).Trim();
1636 if(
auto val =
get_opt( localCompAttribs,
"3D Model Transform" ) )
1637 modelTransform = *val;
1639 modelTransform = compAttrs.value<wxString>(
"3D Model Transform",
"" );
1643 footprint->SetParent( aBoard );
1645 for(
auto& line : lines )
1647 if( line.size() == 0 )
1650 wxString type = line.at( 0 );
1652 if( type == wxS(
"COMPONENT" ) )
1654 int layer = line.at( 3 );
1659 double orient = line.at( 6 );
1662 if( klayer ==
B_Cu )
1663 footprint->Flip( footprint->GetPosition(), FLIP_DIRECTION::TOP_BOTTOM );
1665 footprint->SetOrientationDegrees( orient );
1668 else if( type == wxS(
"ATTR" ) )
1677 if( attr.
key == wxS(
"Designator" ) )
1679 if( attr.
key == wxS(
"Designator" ) )
1685 field =
new PCB_FIELD( footprint.get(), -1, attr.
key );
1689 if( attr.
fontName != wxS(
"default" ) )
1718 footprint->Add( field, ADD_MODE::APPEND );
1721 else if( type == wxS(
"PAD_NET" ) )
1723 wxString padNumber = line.at( 2 );
1724 wxString padNet = line.at( 3 );
1726 PAD*
pad = footprint->FindPadByNumber( padNumber );
1738 aBoard->
Add( footprint.release(), ADD_MODE::APPEND );
1744 for(
auto& [uuid, zone] : poursToFill )
1749 auto range = boardPouredMap.equal_range( uuid );
1750 for(
auto& it = range.first; it != range.second; ++it )
1753 int unki = poured.
unki;
1757 for(
int dataId = 0; dataId < poured.
polyData.size(); dataId++ )
1759 const nlohmann::json& fillData = poured.
polyData[dataId];
1760 const double ptScale = 10;
1766 for(
int i = 0; i < contour.
PointCount(); i++ )
1779 thisPoly.
Append( simple );
1790 for(
int segId = 0; segId < contour.
SegmentCount(); segId++ )
1800 fillPolySet.
Append( thisPoly );
1809 fillPolySet.
Inflate( strokeWidth / 2, CORNER_STRATEGY::ROUND_ALL_CORNERS,
1816 zone->SetFilledPolysList( zone->GetFirstLayer(), fillPolySet );
1817 zone->SetNeedRefill(
false );
1818 zone->SetIsFilled(
true );
1824 std::vector<PCB_SHAPE*> shapes;
1825 std::vector<std::unique_ptr<PCB_SHAPE>> newShapes;
1833 shapes.push_back(
static_cast<PCB_SHAPE*
>( item ) );
1838 for( std::unique_ptr<PCB_SHAPE>& ptr : newShapes )
1839 aBoard->
Add( ptr.release(), ADD_MODE::APPEND );
1851 offset.
x =
KiROUND( offset.
x / alignGrid ) * alignGrid;
1852 offset.
y =
KiROUND( offset.
y / alignGrid ) * alignGrid;
1854 aBoard->
Move( offset );
constexpr int ARC_HIGH_DEF
constexpr EDA_IU_SCALE pcbIUScale
constexpr int ARC_LOW_DEF
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
BASE_SET & set(size_t pos)
Bezier curves to polygon converter.
void GetPoly(std::vector< VECTOR2I > &aOutput, int aMaxError=10)
Convert a Bezier curve to a polygon.
void Mirror(FLIP_DIRECTION aFlipDirection)
Mirror image vertically (i.e.
Container for design settings for a BOARD object.
void SetAuxOrigin(const VECTOR2I &aOrigin)
Abstract interface for BOARD_ITEMs capable of storing other items inside.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual void SetIsKnockout(bool aKnockout)
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Information pertinent to a Pcbnew printed circuit board.
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
void SetEnabledLayers(LSET aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
const PAGE_INFO & GetPageSettings() const
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
bool SetLayerName(PCB_LAYER_ID aLayer, const wxString &aLayerName)
Changes the name of the layer given by aLayer.
void Move(const VECTOR2I &aMoveVector) override
Move this object.
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
unsigned GetNetCount() const
const DRAWINGS & Drawings() const
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
constexpr const Vec GetCenter() const
constexpr const Vec & GetOrigin() const
constexpr const SizeVec & GetSize() const
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
virtual void SetVisible(bool aVisible)
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
void SetTextAngleDegrees(double aOrientation)
virtual void SetText(const wxString &aText)
void SetFont(KIFONT::FONT *aFont)
VECTOR3D m_Offset
3D model offset (mm)
VECTOR3D m_Rotation
3D model rotation (degrees)
wxString m_Filename
The 3D shape filename in 3D library.
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
A logical library item identifier and consists of various portions much like a URI.
LSET is a set of PCB_LAYER_IDs.
Handle the data for a net.
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
static LSET PTHMask()
layer set for a through hole pad
static LSET SMDMask()
layer set for a SMD pad on Front layer
Describe the page size and margins of a paper page on which to eventually print or plot.
double GetHeightMils() const
double GetWidthMils() const
static T ScaleSize(T aValue)
SHAPE_LINE_CHAIN ParseContour(nlohmann::json polyData, bool aInFill, double aArcAccuracy=SHAPE_ARC::DefaultAccuracyForPCB()) const
static VECTOR2< T > ScalePos(VECTOR2< T > aValue)
PCB_IO_EASYEDAPRO_PARSER(BOARD *aBoard, PROGRESS_REPORTER *aProgressReporter)
std::vector< std::unique_ptr< PCB_SHAPE > > ParsePoly(BOARD_ITEM_CONTAINER *aContainer, nlohmann::json polyData, bool aClosed, bool aInFill) const
void ParseBoard(BOARD *aBoard, const nlohmann::json &aProject, std::map< wxString, std::unique_ptr< FOOTPRINT > > &aFootprintMap, const std::map< wxString, EASYEDAPRO::BLOB > &aBlobMap, const std::multimap< wxString, EASYEDAPRO::POURED > &aPouredMap, const std::vector< nlohmann::json > &aLines, const wxString &aFpLibName)
std::unique_ptr< PAD > createPAD(FOOTPRINT *aFootprint, const nlohmann::json &line)
PCB_LAYER_ID LayerToKi(int aLayer)
FOOTPRINT * ParseFootprint(const nlohmann::json &aProject, const wxString &aFpUuid, const std::vector< nlohmann::json > &aLines)
static double Convert(wxString aValue)
void fillFootprintModelInfo(FOOTPRINT *footprint, const wxString &modelUuid, const wxString &modelTitle, const wxString &modelTransform) const
~PCB_IO_EASYEDAPRO_PARSER()
virtual void SetPosition(const VECTOR2I &aPos) override
A progress reporter interface for use in multi-threaded environments.
A REFERENCE_IMAGE is a wrapper around a BITMAP_IMAGE that is displayed in an editor as a reference fo...
BITMAP_BASE & MutableImage() const
Only use this if you really need to modify the underlying image.
bool ReadImageFile(const wxString &aFullFilename)
Read and store an image file.
void SetImageScale(double aScale)
Set the image "zoom" value.
SHAPE_ARC & ConstructFromStartEndCenter(const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter, bool aClockwise=false, double aWidth=0)
Constructs this arc from the given start, end and center.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
virtual const VECTOR2I GetPoint(int aIndex) const override
void SetPoint(int aIndex, const VECTOR2I &aPos)
Move a point to a specific location.
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this line chain.
SEG Segment(int aIndex) const
Return a copy of the aIndex-th segment in the line chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
int SegmentCount() const
Return the number of segments in this line chain.
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
Represent a set of closed polygons.
void BooleanAdd(const SHAPE_POLY_SET &b)
Perform boolean polyset union.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
void Fracture()
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
void RebuildHolesFromContours()
Extract all contours from this polygon set, then recreate polygons with holes.
int OutlineCount() const
Return the number of outlines in the set.
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
const std::vector< POLYGON > & CPolygons() const
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
const SHAPE_LINE_CHAIN Outline() const
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void TransformRoundChamferedRectToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aPosition, const VECTOR2I &aSize, const EDA_ANGLE &aRotation, int aCornerRadius, double aChamferRatio, int aChamferCorners, int aInflate, int aError, ERROR_LOC aErrorLoc)
Convert a rectangle with rounded corners and/or chamfered corners to a polygon.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
static constexpr EDA_ANGLE ANGLE_0
static constexpr EDA_ANGLE ANGLE_90
void ConnectBoardShapes(std::vector< PCB_SHAPE * > &aShapeList, std::vector< std::unique_ptr< PCB_SHAPE > > &aNewShapes, int aChainingEpsilon)
Connects shapes to each other, making continious contours (adjacent shapes will have a common vertex)...
#define THROW_IO_ERROR(msg)
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
PCB_LAYER_ID
A quick note on layer IDs:
wxString get_def(const std::map< wxString, wxString > &aMap, const char *aKey, const char *aDefval="")
std::optional< V > get_opt(const std::map< wxString, V > &aMap, const wxString &aKey)
constexpr void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
LIB_ID ToKiCadLibID(const wxString &aLibName, const wxString &aLibReference)
static const bool IMPORT_POURED
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Class to handle a set of BOARD_ITEMs.
static const wxString MODEL_SIZE_KEY
static const int SHAPE_JOIN_DISTANCE
static void AlignText(EDA_TEXT *text, int align)
static const wxString MODEL_SIZE_KEY
static const int SHAPE_JOIN_DISTANCE
static const wxString QUERY_MODEL_UUID_KEY
static bool addSegment(VRML_LAYER &model, IDF_SEGMENT *seg, int icont, int iseg)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
constexpr double IUTomm(int iu) const
constexpr int MilsToIU(int mils) const
constexpr int mmToIU(double mm) const
@ REFERENCE_FIELD
Field Reference of part, i.e. "IC21".
const SHAPE_LINE_CHAIN chain
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
double DEG2RAD(double deg)
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D