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 ) );
241 kmodelRotation.
z = -
Convert( arr[3] );
248 if( !modelTitle.IsEmpty() && footprint->
Models().empty() )
252 +
EscapeString( modelTitle, ESCAPE_CONTEXT::CTX_FILENAME )
256 footprint->
Models().push_back( model );
261std::vector<std::unique_ptr<PCB_SHAPE>>
263 bool aClosed,
bool aInFill )
const
265 std::vector<std::unique_ptr<PCB_SHAPE>> results;
268 for(
int i = 0; i < polyData.size(); i++ )
270 nlohmann::json val = polyData.at( i );
272 if( val.is_string() )
275 if( str == wxS(
"CIRCLE" ) )
278 center.
x = ( polyData.at( ++i ) );
279 center.
y = ( polyData.at( ++i ) );
280 double r = ( polyData.at( ++i ) );
282 std::unique_ptr<PCB_SHAPE> shape =
283 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::CIRCLE );
285 shape->SetCenter(
ScalePos( center ) );
287 shape->SetFilled( aClosed );
289 results.emplace_back( std::move( shape ) );
291 else if( str == wxS(
"R" ) )
294 start.
x = ( polyData.at( ++i ) );
295 start.
y = ( polyData.at( ++i ) );
296 size.
x = ( polyData.at( ++i ) );
297 size.
y = -( polyData.at( ++i ).get<
double>() );
298 double angle = polyData.at( ++i );
299 double cr = ( i + 1 ) < polyData.size() ? polyData.at( ++i ).get<
double>() : 0;
303 std::unique_ptr<PCB_SHAPE> shape =
304 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::RECTANGLE );
306 shape->SetStart(
ScalePos( start ) );
307 shape->SetEnd(
ScalePos( start + size ) );
308 shape->SetFilled( aClosed );
311 results.emplace_back( std::move( shape ) );
319 std::unique_ptr<PCB_SHAPE> shape =
320 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::SEGMENT );
322 shape->SetStart(
ScalePos( aStart ) );
324 shape->SetFilled( aClosed );
327 results.emplace_back( std::move( shape ) );
332 std::unique_ptr<PCB_SHAPE> shape =
333 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::ARC );
335 shape->SetStart(
ScalePos( aStart ) );
337 shape->SetCenter(
ScalePos( center ) );
338 shape->SetFilled( aClosed );
341 results.emplace_back( std::move( shape ) );
349 addArc( { end.
x - cr, start.
y }, { end.
x, start.
y - cr },
350 { end.
x - cr, start.
y - cr } );
352 addArc( { end.
x, end.
y + cr }, { end.
x - cr, end.
y },
353 { end.
x - cr, end.
y + cr } );
355 addArc( { start.
x + cr, end.
y }, { start.
x, end.
y + cr },
356 { start.
x + cr, end.
y + cr } );
358 addArc( { start.
x, start.
y - cr }, { start.
x + cr, start.
y },
359 { start.
x + cr, start.
y - cr } );
362 else if( str == wxS(
"ARC" ) || str == wxS(
"CARC" ) )
365 double angle = polyData.at( ++i ).get<
double>() / ( aInFill ? 10 : 1 );
366 end.
x = ( polyData.at( ++i ) );
367 end.
y = ( polyData.at( ++i ) );
369 std::unique_ptr<PCB_SHAPE> shape =
370 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::ARC );
374 shape->SetStart(
ScalePos( prevPt ) );
380 shape->SetEnd(
ScalePos( prevPt ) );
386 double ha = angle / 2;
387 double hd =
delta.EuclideanNorm() / 2;
388 double cdist = hd / tan(
DEG2RAD( ha ) );
389 VECTOR2D center = mid +
delta.Perpendicular().Resize( cdist );
390 shape->SetCenter(
ScalePos( center ) );
392 shape->SetFilled( aClosed );
394 results.emplace_back( std::move( shape ) );
398 else if( str == wxS(
"L" ) )
403 while( i < polyData.size() - 2 && polyData.at( i + 1 ).is_number() )
406 pt.
x = ( polyData.at( ++i ) );
407 pt.
y = ( polyData.at( ++i ) );
416 std::unique_ptr<PCB_SHAPE> shape =
417 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::POLY );
424 shape->SetFilled(
true );
425 shape->SetPolyShape( chain );
427 results.emplace_back( std::move( shape ) );
436 std::unique_ptr<PCB_SHAPE> shape =
437 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::SEGMENT );
439 shape->SetStart( seg.
A );
440 shape->SetEnd( seg.
B );
442 results.emplace_back( std::move( shape ) );
447 else if( val.is_number() )
449 prevPt.
x = ( polyData.at( i ) );
450 prevPt.
y = ( polyData.at( ++i ) );
460 double aArcAccuracy )
const
465 for(
int i = 0; i < polyData.size(); i++ )
467 nlohmann::json val = polyData.at( i );
469 if( val.is_string() )
472 if( str == wxS(
"CIRCLE" ) )
475 center.
x = ( polyData.at( ++i ) );
476 center.
y = ( polyData.at( ++i ) );
477 double r = ( polyData.at( ++i ) );
482 else if( str == wxS(
"R" ) )
485 start.
x = ( polyData.at( ++i ) );
486 start.
y = ( polyData.at( ++i ) );
487 size.
x = ( polyData.at( ++i ) );
488 size.
y = ( polyData.at( ++i ).get<
double>() );
489 double angle = polyData.at( ++i );
490 double cr = ( i + 1 ) < polyData.size() ? polyData.at( ++i ).get<
double>() : 0;
496 VECTOR2D kcenter = kstart + ksize / 2;
503 result.
Append( poly.Outline( 0 ) );
505 else if( str == wxS(
"ARC" ) || str == wxS(
"CARC" ) )
508 double angle = polyData.at( ++i ).get<
double>();
513 end.
x = ( polyData.at( ++i ) );
514 end.
y = ( polyData.at( ++i ) );
523 double ha = angle / 2;
524 double hd =
delta.EuclideanNorm() / 2;
525 double cdist = hd / tan(
DEG2RAD( ha ) );
526 VECTOR2D center = mid +
delta.Perpendicular().Resize( cdist );
530 ScalePos( center ), angle >= 0, 0 );
532 result.
Append( sarc, aArcAccuracy );
536 else if( str == wxS(
"C" ) )
539 pt1.
x = ( polyData.at( ++i ) );
540 pt1.
y = ( polyData.at( ++i ) );
543 pt2.
x = ( polyData.at( ++i ) );
544 pt2.
y = ( polyData.at( ++i ) );
547 pt3.
x = ( polyData.at( ++i ) );
548 pt3.
y = ( polyData.at( ++i ) );
554 std::vector<VECTOR2I> bezierPoints;
555 converter.
GetPoly( bezierPoints, aArcAccuracy );
557 result.
Append( bezierPoints );
561 else if( str == wxS(
"L" ) )
565 while( i < polyData.size() - 2 && polyData.at( i + 1 ).is_number() )
568 pt.
x = ( polyData.at( ++i ) );
569 pt.
y = ( polyData.at( ++i ) );
577 else if( val.is_number() )
579 prevPt.
x = ( polyData.at( i ) );
580 prevPt.
y = ( polyData.at( ++i ) );
589 const nlohmann::json& line )
591 wxString uuid = line.at( 1 );
598 wxString netname = line.at( 3 );
599 int layer = line.at( 4 ).get<
int>();
602 wxString padNumber = line.at( 5 );
605 center.
x = line.at( 6 );
606 center.
y = line.at( 7 );
608 double orientation = line.at( 8 );
610 nlohmann::json padHole = line.at( 9 );
611 nlohmann::json padShape = line.at( 10 );
613 std::unique_ptr<PAD>
pad = std::make_unique<PAD>( aFootprint );
615 pad->SetNumber( padNumber );
617 pad->SetOrientationDegrees( orientation );
619 if( !padHole.is_null() )
621 double drill_dir = 0;
623 if( line.at( 14 ).is_number() )
624 drill_dir = line.at( 14 );
626 wxString holeShape = padHole.at( 0 );
628 if( holeShape == wxS(
"ROUND" ) || holeShape == wxS(
"SLOT" ) )
631 drill.
x = padHole.at( 1 );
632 drill.
y = padHole.at( 2 );
637 std::swap( drill.
x, drill.
y );
639 if( holeShape == wxS(
"SLOT" ) )
641 pad->SetDrillShape( PAD_DRILL_SHAPE::OBLONG );
646 pad->SetAttribute( PAD_ATTRIB::PTH );
655 else if( klayer ==
B_Cu )
660 pad->SetAttribute( PAD_ATTRIB::SMD );
663 wxString padSh = padShape.at( 0 );
664 if( padSh == wxS(
"RECT" ) )
667 size.
x = padShape.at( 1 );
668 size.
y = padShape.at( 2 );
669 double cr_p = padShape.size() > 3 ? padShape.at( 3 ).get<
double>() : 0;
683 else if( padSh == wxS(
"ELLIPSE" ) )
686 size.
x = padShape.at( 1 );
687 size.
y = padShape.at( 2 );
692 else if( padSh == wxS(
"OVAL" ) )
695 size.
x = padShape.at( 1 );
696 size.
y = padShape.at( 2 );
701 else if( padSh == wxS(
"POLY" ) )
707 nlohmann::json polyData = padShape.at( 1 );
709 std::vector<std::unique_ptr<PCB_SHAPE>> results =
710 ParsePoly( aFootprint, polyData,
true,
false );
712 for(
auto& shape : results )
714 shape->SetLayer( klayer );
715 shape->SetWidth( 0 );
717 shape->Move( -
pad->GetPosition() );
725 return std::move(
pad );
730 const wxString& aFpUuid,
731 const std::vector<nlohmann::json>& aLines )
733 std::unique_ptr<FOOTPRINT> footprintPtr = std::make_unique<FOOTPRINT>(
m_board );
734 FOOTPRINT* footprint = footprintPtr.get();
741 field->SetTextSize( defaultTextSize );
742 field->SetTextThickness( defaultTextThickness );
745 for(
const nlohmann::json& line : aLines )
747 if( line.size() == 0 )
750 wxString type = line.at( 0 );
752 if( type == wxS(
"POLY" ) || type == wxS(
"PAD" ) || type == wxS(
"FILL" )
753 || type == wxS(
"ATTR" ) )
755 wxString uuid = line.at( 1 );
762 wxString netname = line.at( 3 );
763 int layer = line.at( 4 ).get<
int>();
766 if( type == wxS(
"POLY" ) )
768 double thickness = ( line.at( 5 ) );
769 nlohmann::json polyData = line.at( 6 );
771 std::vector<std::unique_ptr<PCB_SHAPE>> results =
772 ParsePoly( footprint, polyData,
false,
false );
774 for(
auto& shape : results )
776 shape->SetLayer( klayer );
777 shape->SetWidth(
ScaleSize( thickness ) );
779 footprint->
Add( shape.release(), ADD_MODE::APPEND );
782 else if( type == wxS(
"PAD" ) )
784 std::unique_ptr<PAD>
pad =
createPAD( footprint, line );
786 footprint->
Add(
pad.release(), ADD_MODE::APPEND );
788 else if( type == wxS(
"FILL" ) )
790 int layer = line.at( 4 ).get<
int>();
793 double width = line.at( 5 );
795 nlohmann::json polyDataList = line.at( 7 );
797 if( !polyDataList.is_null() && !polyDataList.empty() )
799 if( !polyDataList.at( 0 ).is_array() )
800 polyDataList = nlohmann::json::array( { polyDataList } );
802 std::vector<SHAPE_LINE_CHAIN> contours;
803 for( nlohmann::json& polyData : polyDataList )
808 contours.push_back( contour );
818 std::unique_ptr<PCB_GROUP>
group;
821 group = std::make_unique<PCB_GROUP>( footprint );
827 std::unique_ptr<PCB_SHAPE> shape =
828 std::make_unique<PCB_SHAPE>( footprint, SHAPE_T::POLY );
830 shape->SetFilled(
true );
831 shape->SetPolyShape( poly );
832 shape->SetLayer( klayer );
833 shape->SetWidth( 0 );
836 group->AddItem( shape.get() );
838 footprint->
Add( shape.release(), ADD_MODE::APPEND );
842 footprint->
Add(
group.release(), ADD_MODE::APPEND );
845 else if( type == wxS(
"ATTR" ) )
849 if( attr.
key == wxS(
"Designator" ) )
853 else if( type == wxS(
"REGION" ) )
855 wxString uuid = line.at( 1 );
862 int layer = line.at( 3 ).get<
int>();
865 double width = line.at( 4 );
866 std::set<int> flags = line.at( 5 );
867 nlohmann::json polyDataList = line.at( 6 );
869 for( nlohmann::json& polyData : polyDataList )
873 std::vector<std::unique_ptr<PCB_SHAPE>> results =
874 ParsePoly(
nullptr, polyData,
true,
false );
876 for(
auto& shape : results )
878 shape->SetFilled(
true );
885 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( footprint );
887 zone->SetIsRuleArea(
true );
888 zone->SetDoNotAllowFootprints( !!flags.count( 2 ) );
889 zone->SetDoNotAllowCopperPour( !!flags.count( 7 ) || !!flags.count( 6 )
890 || !!flags.count( 8 ) );
891 zone->SetDoNotAllowPads( !!flags.count( 7 ) );
892 zone->SetDoNotAllowTracks( !!flags.count( 7 ) || !!flags.count( 5 ) );
893 zone->SetDoNotAllowVias( !!flags.count( 7 ) );
895 zone->SetLayer( klayer );
896 zone->Outline()->Append( polySet );
898 footprint->
Add( zone.release(), ADD_MODE::APPEND );
903 if( aProject.is_object() && aProject.contains(
"devices" ) )
905 std::map<wxString, EASYEDAPRO::PRJ_DEVICE> devicesMap = aProject.at(
"devices" );
906 std::map<wxString, wxString> compAttrs;
908 for(
auto& [devUuid, devData] : devicesMap )
910 if(
auto fp =
get_opt( devData.attributes,
"Footprint" ) )
914 compAttrs = devData.attributes;
920 wxString modelUuid, modelTitle, modelTransform;
922 modelUuid =
get_def( compAttrs,
"3D Model",
"" );
923 modelTitle =
get_def( compAttrs,
"3D Model Title", modelUuid );
924 modelTransform =
get_def( compAttrs,
"3D Model Transform",
"" );
930 std::vector<PCB_SHAPE*> shapes;
931 std::vector<std::unique_ptr<PCB_SHAPE>> newShapes;
939 shapes.push_back(
static_cast<PCB_SHAPE*
>( item ) );
944 for( std::unique_ptr<PCB_SHAPE>& ptr : newShapes )
945 footprint->
Add( ptr.release(), ADD_MODE::APPEND );
947 return footprintPtr.release();
952 BOARD* aBoard,
const nlohmann::json& aProject,
953 std::map<wxString, std::unique_ptr<FOOTPRINT>>& aFootprintMap,
954 const std::map<wxString, EASYEDAPRO::BLOB>& aBlobMap,
955 const std::multimap<wxString, EASYEDAPRO::POURED>& aPouredMap,
956 const std::vector<nlohmann::json>& aLines,
const wxString& aFpLibName )
958 std::map<wxString, std::vector<nlohmann::json>> componentLines;
959 std::map<wxString, std::vector<nlohmann::json>> ruleLines;
961 std::multimap<wxString, EASYEDAPRO::POURED> boardPouredMap = aPouredMap;
962 std::map<wxString, ZONE*> poursToFill;
966 for(
const nlohmann::json& line : aLines )
968 if( line.size() == 0 )
971 wxString type = line.at( 0 );
973 if( type == wxS(
"LAYER" ) )
975 int layer = line.at( 1 );
978 wxString layerType = line.at( 2 );
979 wxString layerName = line.at( 3 );
980 int layerFlag = line.at( 4 );
985 blayers.
set( klayer );
990 else if( type == wxS(
"NET" ) )
992 wxString netname = line.at( 1 );
997 else if( type == wxS(
"RULE" ) )
999 wxString ruleType = line.at( 1 );
1000 wxString ruleName = line.at( 2 );
1001 int isDefault = line.at( 3 );
1002 nlohmann::json ruleData = line.at( 4 );
1004 if( ruleType == wxS(
"3" ) && isDefault )
1006 wxString units = ruleData.at( 0 );
1007 double minVal = ruleData.at( 1 );
1008 double optVal = ruleData.at( 2 );
1009 double maxVal = ruleData.at( 3 );
1013 else if( ruleType == wxS(
"1" ) && isDefault )
1015 wxString units = ruleData.at( 0 );
1016 nlohmann::json table = ruleData.at( 1 );
1018 int minVal = INT_MAX;
1019 for(
const std::vector<int>& arr : table )
1021 for(
int val : arr )
1031 ruleLines[ruleType].push_back( line );
1033 else if( type == wxS(
"POURED" ) )
1035 if( !line.at( 2 ).is_string() )
1039 boardPouredMap.emplace( poured.
parentId, poured );
1041 else if( type == wxS(
"VIA" ) || type == wxS(
"LINE" ) || type == wxS(
"ARC" )
1042 || type == wxS(
"POLY" ) || type == wxS(
"FILL" ) || type == wxS(
"POUR" ) )
1044 wxString uuid = line.at( 1 );
1051 wxString netname = line.at( 3 );
1053 if( type == wxS(
"VIA" ) )
1056 center.
x = line.at( 5 );
1057 center.
y = line.at( 6 );
1059 double drill = line.at( 7 );
1060 double dia = line.at( 8 );
1062 std::unique_ptr<PCB_VIA>
via = std::make_unique<PCB_VIA>( aBoard );
1070 aBoard->
Add(
via.release(), ADD_MODE::APPEND );
1072 else if( type == wxS(
"LINE" ) )
1074 int layer = line.at( 4 ).get<
int>();
1078 start.
x = line.at( 5 );
1079 start.
y = line.at( 6 );
1082 end.
x = line.at( 7 );
1083 end.
y = line.at( 8 );
1085 double width = line.at( 9 );
1087 std::unique_ptr<PCB_TRACK> track = std::make_unique<PCB_TRACK>( aBoard );
1089 track->SetLayer( klayer );
1090 track->SetStart(
ScalePos( start ) );
1094 track->SetNet( aBoard->
FindNet( netname ) );
1096 aBoard->
Add( track.release(), ADD_MODE::APPEND );
1098 else if( type == wxS(
"ARC" ) )
1100 int layer = line.at( 4 ).get<
int>();
1104 start.
x = line.at( 5 );
1105 start.
y = line.at( 6 );
1108 end.
x = line.at( 7 );
1109 end.
y = line.at( 8 );
1111 double angle = line.at( 9 );
1112 double width = line.at( 10 );
1117 double ha = angle / 2;
1118 double hd =
delta.EuclideanNorm() / 2;
1119 double cdist = hd / tan(
DEG2RAD( ha ) );
1120 VECTOR2D center = mid +
delta.Perpendicular().Resize( cdist );
1124 ScalePos( center ), angle >= 0, width );
1126 std::unique_ptr<PCB_ARC> arc = std::make_unique<PCB_ARC>( aBoard, &sarc );
1129 arc->SetLayer( klayer );
1130 arc->SetNet( aBoard->
FindNet( netname ) );
1132 aBoard->
Add( arc.release(), ADD_MODE::APPEND );
1134 else if( type == wxS(
"FILL" ) )
1136 int layer = line.at( 4 ).get<
int>();
1139 double width = line.at( 5 );
1141 nlohmann::json polyDataList = line.at( 7 );
1143 if( !polyDataList.at( 0 ).is_array() )
1144 polyDataList = nlohmann::json::array( { polyDataList } );
1146 std::vector<SHAPE_LINE_CHAIN> contours;
1147 for( nlohmann::json& polyData : polyDataList )
1152 contours.push_back( contour );
1163 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aBoard );
1165 zone->SetNet( aBoard->
FindNet( netname ) );
1166 zone->SetLayer( klayer );
1168 zone->SetFilledPolysList( klayer, zoneFillPoly );
1169 zone->SetAssignedPriority( 500 );
1170 zone->SetIsFilled(
true );
1171 zone->SetNeedRefill(
false );
1176 aBoard->
Add( zone.release(), ADD_MODE::APPEND );
1178 else if( type == wxS(
"POLY" ) )
1180 int layer = line.at( 4 );
1183 double thickness = line.at( 5 );
1184 nlohmann::json polyData = line.at( 6 );
1186 std::vector<std::unique_ptr<PCB_SHAPE>> results =
1187 ParsePoly( aBoard, polyData,
false,
false );
1189 for(
auto& shape : results )
1191 shape->SetLayer( klayer );
1192 shape->SetWidth(
ScaleSize( thickness ) );
1194 aBoard->
Add( shape.release(), ADD_MODE::APPEND );
1197 else if( type == wxS(
"POUR" ) )
1199 int layer = line.at( 4 ).get<
int>();
1202 double lineWidth = line.at( 5 );
1203 wxString pourname = line.at( 6 );
1204 int fillOrder = line.at( 7 ).get<
int>();
1205 nlohmann::json polyDataList = line.at( 8 );
1207 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aBoard );
1209 zone->SetNet( aBoard->
FindNet( netname ) );
1210 zone->SetLayer( klayer );
1211 zone->SetAssignedPriority( 500 - fillOrder );
1215 for( nlohmann::json& polyData : polyDataList )
1220 zone->Outline()->Append( contour );
1223 wxASSERT( zone->Outline()->OutlineCount() == 1 );
1225 poursToFill.emplace( uuid, zone.get() );
1227 aBoard->
Add( zone.release(), ADD_MODE::APPEND );
1230 else if( type == wxS(
"TEARDROP" ) )
1232 wxString uuid = line.at( 1 );
1233 wxString netname = line.at( 2 );
1234 int layer = line.at( 3 ).get<
int>();
1237 nlohmann::json polyData = line.at( 4 );
1242 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aBoard );
1244 zone->SetNet( aBoard->
FindNet( netname ) );
1245 zone->SetLayer( klayer );
1246 zone->Outline()->Append( contour );
1247 zone->SetFilledPolysList( klayer, contour );
1248 zone->SetNeedRefill(
false );
1249 zone->SetIsFilled(
true );
1251 zone->SetAssignedPriority( 600 );
1252 zone->SetLocalClearance( 0 );
1253 zone->SetMinThickness( 0 );
1254 zone->SetTeardropAreaType( TEARDROP_TYPE::TD_UNSPECIFIED );
1256 aBoard->
Add( zone.release(), ADD_MODE::APPEND );
1258 else if( type == wxS(
"REGION" ) )
1260 wxString uuid = line.at( 1 );
1267 int layer = line.at( 3 ).get<
int>();
1270 double width = line.at( 4 );
1271 std::set<int> flags = line.at( 5 );
1272 nlohmann::json polyDataList = line.at( 6 );
1274 for( nlohmann::json& polyData : polyDataList )
1279 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aBoard );
1281 zone->SetIsRuleArea(
true );
1282 zone->SetDoNotAllowFootprints( !!flags.count( 2 ) );
1283 zone->SetDoNotAllowCopperPour( !!flags.count( 7 ) || !!flags.count( 6 )
1284 || !!flags.count( 8 ) );
1285 zone->SetDoNotAllowPads( !!flags.count( 7 ) );
1286 zone->SetDoNotAllowTracks( !!flags.count( 7 ) || !!flags.count( 5 ) );
1287 zone->SetDoNotAllowVias( !!flags.count( 7 ) );
1289 zone->SetLayer( klayer );
1290 zone->Outline()->Append( contour );
1292 aBoard->
Add( zone.release(), ADD_MODE::APPEND );
1295 else if( type == wxS(
"PAD" ) )
1297 wxString netname = line.at( 3 );
1299 std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>( aBoard );
1300 std::unique_ptr<PAD>
pad =
createPAD( footprint.get(), line );
1310 footprint->Add(
pad.release(), ADD_MODE::APPEND );
1311 footprint->SetPosition( pos );
1312 footprint->SetOrientation( orient );
1314 wxString fpName = wxS(
"Pad_" ) + line.at( 1 ).get<wxString>();
1317 footprint->SetFPID( fpID );
1318 footprint->Reference().SetVisible(
true );
1319 footprint->Value().SetVisible(
true );
1320 footprint->AutoPositionFields();
1322 aBoard->
Add( footprint.release(), ADD_MODE::APPEND );
1324 else if( type == wxS(
"IMAGE" ) )
1326 wxString uuid = line.at( 1 );
1333 int layer = line.at( 3 ).get<
int>();
1336 VECTOR2D start( line.at( 4 ), line.at( 5 ) );
1337 VECTOR2D size( line.at( 6 ), line.at( 7 ) );
1339 double angle = line.at( 8 );
1340 int mirror = line.at( 9 );
1341 nlohmann::json polyDataList = line.at( 10 );
1344 std::vector<SHAPE_LINE_CHAIN> contours;
1345 for( nlohmann::json& polyData : polyDataList )
1350 contours.push_back( contour );
1362 for(
int i = 0; i < contour.PointCount(); i++ )
1373 std::unique_ptr<PCB_GROUP>
group;
1376 group = std::make_unique<PCB_GROUP>( aBoard );
1382 std::unique_ptr<PCB_SHAPE> shape =
1383 std::make_unique<PCB_SHAPE>( aBoard, SHAPE_T::POLY );
1385 shape->SetFilled(
true );
1386 shape->SetPolyShape( poly );
1387 shape->SetLayer( klayer );
1388 shape->SetWidth( 0 );
1396 ? FLIP_DIRECTION::TOP_BOTTOM
1397 : FLIP_DIRECTION::LEFT_RIGHT;
1398 shape->Mirror(
ScalePos( start ), flipDirection );
1402 group->AddItem( shape.get() );
1404 aBoard->
Add( shape.release(), ADD_MODE::APPEND );
1408 aBoard->
Add(
group.release(), ADD_MODE::APPEND );
1410 else if( type == wxS(
"OBJ" ) )
1413 wxString mimeType, base64Data;
1417 if( !line.at( 3 ).is_number() )
1420 int layer = line.at( 3 ).get<
int>();
1423 start =
VECTOR2D( line.at( 5 ), line.at( 6 ) );
1424 size =
VECTOR2D( line.at( 7 ), line.at( 8 ) );
1425 angle = line.at( 9 );
1426 flipped = line.at( 10 );
1428 wxString imageUrl = line.at( 11 );
1430 if( imageUrl.BeforeFirst(
':' ) == wxS(
"blob" ) )
1432 wxString objectId = imageUrl.AfterLast(
':' );
1434 if(
auto blob =
get_opt( aBlobMap, objectId ) )
1436 wxString blobUrl = blob->url;
1438 if( blobUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
1440 wxArrayString paramsArr =
1441 wxSplit( blobUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
1443 base64Data = blobUrl.AfterFirst(
',' );
1445 if( paramsArr.size() > 0 )
1446 mimeType = paramsArr[0];
1454 if( mimeType.empty() || base64Data.empty() )
1457 wxMemoryBuffer buf = wxBase64Decode( base64Data );
1459 if( mimeType == wxS(
"image/svg+xml" ) )
1465 VECTOR2D kcenter = kstart + ksize / 2;
1467 std::unique_ptr<PCB_REFERENCE_IMAGE> bitmap =
1468 std::make_unique<PCB_REFERENCE_IMAGE>( aBoard, kcenter, klayer );
1471 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
1472 & ~wxImage::Load_Verbose );
1484 int x = bitmap->GetPosition().x;
1491 aBoard->
Add( bitmap.release(), ADD_MODE::APPEND );
1495 else if( type == wxS(
"STRING" ) )
1497 wxString uuid = line.at( 1 );
1504 int layer = line.at( 3 ).get<
int>();
1507 VECTOR2D location( line.at( 4 ), line.at( 5 ) );
1508 wxString
string = line.at( 6 );
1509 wxString font = line.at( 7 );
1511 double height = line.at( 8 );
1512 double strokew = line.at( 9 );
1514 int align = line.at( 12 );
1515 double angle = line.at( 13 );
1516 int inverted = line.at( 14 );
1517 int mirror = line.at( 16 );
1521 text->SetText(
string );
1522 text->SetLayer( klayer );
1524 text->SetIsKnockout( inverted );
1528 if( font != wxS(
"default" ) )
1541 text->SetMirrored(
true );
1542 text->SetTextAngleDegrees( -angle );
1546 text->SetTextAngleDegrees( angle );
1549 aBoard->
Add(
text, ADD_MODE::APPEND );
1551 else if( type == wxS(
"COMPONENT" ) )
1553 wxString compId = line.at( 1 );
1554 componentLines[compId].push_back( line );
1556 else if( type == wxS(
"ATTR" ) )
1558 wxString compId = line.at( 3 );
1559 componentLines[compId].push_back( line );
1561 else if( type == wxS(
"PAD_NET" ) )
1563 wxString compId = line.at( 1 );
1564 componentLines[compId].push_back( line );
1568 for(
auto const& [compId, lines] : componentLines )
1571 wxString fpIdOverride;
1572 wxString fpDesignator;
1573 std::map<wxString, wxString> localCompAttribs;
1575 for(
auto& line : lines )
1577 if( line.size() == 0 )
1580 wxString type = line.at( 0 );
1582 if( type == wxS(
"COMPONENT" ) )
1584 localCompAttribs = line.at( 7 );
1586 else if( type == wxS(
"ATTR" ) )
1590 if( attr.
key == wxS(
"Device" ) )
1591 deviceId = attr.
value;
1593 else if( attr.
key == wxS(
"Footprint" ) )
1594 fpIdOverride = attr.
value;
1596 else if( attr.
key == wxS(
"Designator" ) )
1597 fpDesignator = attr.
value;
1601 if( deviceId.empty() )
1604 nlohmann::json compAttrs = aProject.at(
"devices" ).at( deviceId ).at(
"attributes" );
1608 if( !fpIdOverride.IsEmpty() )
1609 fpId = fpIdOverride;
1611 fpId = compAttrs.at(
"Footprint" ).get<wxString>();
1613 auto it = aFootprintMap.find( fpId );
1614 if( it == aFootprintMap.end() )
1616 wxLogError(
"Footprint of '%s' with uuid '%s' not found.", fpDesignator, fpId );
1620 std::unique_ptr<FOOTPRINT>& footprintOrig = it->second;
1621 std::unique_ptr<FOOTPRINT> footprint(
static_cast<FOOTPRINT*
>( footprintOrig->Clone() ) );
1623 wxString modelUuid, modelTitle, modelTransform;
1625 if(
auto val =
get_opt( localCompAttribs,
"3D Model" ) )
1628 modelUuid = compAttrs.value<wxString>(
"3D Model",
"" );
1630 if(
auto val =
get_opt( localCompAttribs,
"3D Model Title" ) )
1631 modelTitle = val->Trim();
1633 modelTitle = compAttrs.value<wxString>(
"3D Model Title", modelUuid ).Trim();
1635 if(
auto val =
get_opt( localCompAttribs,
"3D Model Transform" ) )
1636 modelTransform = *val;
1638 modelTransform = compAttrs.value<wxString>(
"3D Model Transform",
"" );
1642 footprint->SetParent( aBoard );
1644 for(
auto& line : lines )
1646 if( line.size() == 0 )
1649 wxString type = line.at( 0 );
1651 if( type == wxS(
"COMPONENT" ) )
1653 int layer = line.at( 3 );
1656 VECTOR2D center( line.at( 4 ), line.at( 5 ) );
1658 double orient = line.at( 6 );
1661 if( klayer ==
B_Cu )
1662 footprint->Flip( footprint->GetPosition(), FLIP_DIRECTION::TOP_BOTTOM );
1664 footprint->SetOrientationDegrees( orient );
1665 footprint->SetPosition(
ScalePos( center ) );
1667 else if( type == wxS(
"ATTR" ) )
1676 if( attr.
key == wxS(
"Designator" ) )
1678 if( attr.
key == wxS(
"Designator" ) )
1688 if( attr.
fontName != wxS(
"default" ) )
1705 text->SetLayer( klayer );
1707 text->SetTextAngleDegrees( footprint->IsFlipped() ? -attr.
rotation
1717 footprint->Add(
text, ADD_MODE::APPEND );
1720 else if( type == wxS(
"PAD_NET" ) )
1722 wxString padNumber = line.at( 2 );
1723 wxString padNet = line.at( 3 );
1725 PAD*
pad = footprint->FindPadByNumber( padNumber );
1737 aBoard->
Add( footprint.release(), ADD_MODE::APPEND );
1743 for(
auto& [uuid, zone] : poursToFill )
1748 auto range = boardPouredMap.equal_range( uuid );
1749 for(
auto& it = range.first; it != range.second; ++it )
1752 int unki = poured.
unki;
1756 for(
int dataId = 0; dataId < poured.
polyData.size(); dataId++ )
1758 const nlohmann::json& fillData = poured.
polyData[dataId];
1759 const double ptScale = 10;
1765 for(
int i = 0; i < contour.
PointCount(); i++ )
1778 thisPoly.
Append( simple );
1789 for(
int segId = 0; segId < contour.
SegmentCount(); segId++ )
1799 fillPolySet.
Append( thisPoly );
1808 fillPolySet.
Inflate( strokeWidth / 2, CORNER_STRATEGY::ROUND_ALL_CORNERS,
1815 zone->SetFilledPolysList( zone->GetFirstLayer(), fillPolySet );
1816 zone->SetNeedRefill(
false );
1817 zone->SetIsFilled(
true );
1823 std::vector<PCB_SHAPE*> shapes;
1824 std::vector<std::unique_ptr<PCB_SHAPE>> newShapes;
1832 shapes.push_back(
static_cast<PCB_SHAPE*
>( item ) );
1837 for( std::unique_ptr<PCB_SHAPE>& ptr : newShapes )
1838 aBoard->
Add( ptr.release(), ADD_MODE::APPEND );
1850 offset.
x =
KiROUND( offset.
x / alignGrid ) * alignGrid;
1851 offset.
y =
KiROUND( offset.
y / alignGrid ) * alignGrid;
1853 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 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,...
virtual void SetVisible(bool aVisible)
virtual void SetText(const wxString &aText)
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()
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 BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset difference For aFastMode meaning, see function booleanOp.
void Fracture(POLYGON_MODE aFastMode)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
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 BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset union For aFastMode meaning, see function booleanOp.
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)
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
void Simplify(POLYGON_MODE aFastMode)
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFastMo...
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.
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".
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