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 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".
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