66 int toIU( int64_t aHalfMils )
68 return schIUScale.MilsToIU(
static_cast<double>( aHalfMils ) / 2.0 );
74 return { toIU( aPoint.
x ), -toIU( aPoint.
y ) };
81 using LIBRARY_SYMBOL_VARIANTS = std::map<wxString, std::vector<std::pair<std::unique_ptr<LIB_SYMBOL>, wxString>>>;
86 return { toIU( aPoint.
x ), aPageHeight - toIU( aPoint.
y ) };
90 std::unique_ptr<SCH_BITMAP> makeEmbeddedImage(
const MODEL_EMBEDDED_IMAGE& aSource,
int aPageHeight,
91 std::vector<PARSER_DIAGNOSTIC>& aDiagnostics )
93 if( aSource.
size.
x <= 0 || aSource.
size.
y <= 0 )
96 wxS(
"embedded OLE image has a degenerate page box and was skipped" ) );
100 auto bitmap = std::make_unique<SCH_BITMAP>( pagePoint( aSource.
position, aPageHeight ) );
102 bool decoded =
false;
103 wxMemoryBuffer buffer;
105 switch( aSource.
type )
108 buffer.AppendData( aSource.
data.data(), aSource.
data.size() );
126 int width = std::clamp<int64_t>(
std::abs(
static_cast<int64_t
>( aSource.
extent[2] ) - aSource.
extent[0] ),
128 int height = std::clamp<int64_t>(
std::abs(
static_cast<int64_t
>( aSource.
extent[3] ) - aSource.
extent[1] ),
134 double scaledHeight =
static_cast<double>( width ) * aSource.
size.
y / aSource.
size.
x;
136 static_cast<int>( std::llround( std::clamp( scaledHeight, 1.0, 4096.0 ) ) );
137 image.Rescale( width, fittedHeight, wxIMAGE_QUALITY_HIGH );
150 wxS(
"embedded OLE image could not be rasterized and was skipped" ) );
154 const int targetWidth = toIU( aSource.
size.
x );
155 const int targetHeight = toIU( aSource.
size.
y );
157 if( targetWidth <= 0 || targetHeight <= 0 )
162 if( decodedImage && decodedImage->IsOk() )
164 const int fittedHeight =
165 std::max( 1,
static_cast<int>( std::llround(
static_cast<double>( decodedImage->GetWidth() )
166 * targetHeight / targetWidth ) ) );
168 if( fittedHeight != decodedImage->GetHeight() )
170 wxImage fitted = decodedImage->Copy();
171 fitted.Rescale( fitted.GetWidth(), fittedHeight, wxIMAGE_QUALITY_HIGH );
181 bitmap->MirrorHorizontally(
center.x );
184 bitmap->MirrorVertically(
center.y );
250 const bool verticalDecal = aPin.
decalName.
text.Contains( wxS(
"VRT" ) );
267 switch( aJustification )
278 switch( aJustification )
288 std::vector<PARSER_DIAGNOSTIC>& aDiagnostics )
290 if( aPresentation.
height > 0 )
299 if( aPresentation.
width > 0 )
302 if( !aPresentation.
font.
text.IsEmpty() && aPresentation.
font.
text != wxS(
"Default Font" ) )
314 wxS(
"PADS underline presentation is unsupported" ) ) );
319 std::unique_ptr<SCH_SHAPE> makeShape(
const MODEL_GRAPHIC& aGraphic,
bool aPageCoordinates,
int aPageHeight )
326 return aPageCoordinates ? pagePoint( aPoint, aPageHeight ) : localPoint( aPoint );
331 switch( aGraphic.
kind )
358 double startAngle = std::atan2(
static_cast<double>( start.
y - aGraphic.
arcCenter.
y ),
359 static_cast<double>( start.
x - aGraphic.
arcCenter.
x ) );
365 double radius = std::hypot(
static_cast<double>( start.
x - aGraphic.
arcCenter.
x ),
366 static_cast<double>( start.
y - aGraphic.
arcCenter.
y ) );
368 mid.
x = aGraphic.
arcCenter.
x + std::llround(
radius * std::cos( startAngle + sweep / 2.0 ) );
369 mid.
y = aGraphic.
arcCenter.
y + std::llround(
radius * std::sin( startAngle + sweep / 2.0 ) );
375 shape->AddPoint(
convert( point ) );
379 shape->SetFillMode( fillStyle( aGraphic.
fill ) );
384 std::unique_ptr<SCH_TEXT> makeGraphicText(
const MODEL_GRAPHIC& aGraphic,
385 std::vector<PARSER_DIAGNOSTIC>& aDiagnostics )
387 if( aGraphic.
points.empty() )
400 std::vector<PARSER_DIAGNOSTIC>& aDiagnostics )
402 auto text = std::make_unique<SCH_TEXT>( pagePoint( aPosition, aPageHeight ), aText.text,
LAYER_NOTES );
411 wxS(
"hidden PADS text is unsupported" ) ) );
414 applyTextPresentation(
text.get(), aPresentation,
true, aDiagnostics );
420 std::vector<PARSER_DIAGNOSTIC>& aDiagnostics )
424 if( aGraphic.
points.empty() )
427 std::unique_ptr<SCH_TEXT>
text = makePageText( aGraphic.
text, aGraphic.
points.front(), aGraphic.
angle,
437 if( aGraphic.
points.size() < 2 )
441 for(
size_t point = 1; point < aGraphic.
points.size(); ++point )
444 std::make_unique<SCH_LINE>( pagePoint( aGraphic.
points[point - 1], aPageHeight ),
LAYER_NOTES );
445 line->SetEndPoint( pagePoint( aGraphic.
points[point], aPageHeight ) );
447 aScreen->
Append( line.get() );
451 return aGraphic.
points.size() - 1;
454 std::unique_ptr<SCH_SHAPE> shape = makeShape( aGraphic,
true, aPageHeight );
459 aScreen->
Append( shape.get() );
465 std::unique_ptr<LIB_SYMBOL> makePadsPowerLibrary(
const MODEL_LABEL& aLabel )
476 auto symbol = std::make_unique<LIB_SYMBOL>(
name );
477 symbol->SetGlobalPower();
478 symbol->SetShowPinNumbers(
false );
479 symbol->SetShowPinNames(
false );
481 auto mil = [](
int aMils )
485 auto addLine = [&]( std::initializer_list<VECTOR2I> aPoints )
489 for(
const VECTOR2I& point : aPoints )
490 line->AddPoint( point );
493 symbol->AddDrawItem( line.release() );
495 auto addTriangle = [&](
int aStemLength )
497 addLine( { { 0, 0 }, { 0, mil( aStemLength ) } } );
499 triangle->AddPoint( { 0, mil( aStemLength ) } );
500 triangle->AddPoint( { -mil( 50 ), mil( 100 ) } );
501 triangle->AddPoint( { mil( 50 ), mil( 100 ) } );
502 triangle->AddPoint( { 0, mil( aStemLength ) } );
505 symbol->AddDrawItem( triangle.release() );
515 { -mil( 100 ), -mil( 50 ) },
517 { mil( 100 ), -mil( 50 ) },
518 { 0, -mil( 50 ) } } );
522 addLine( { { 0, 0 }, { 0, -mil( 100 ) } } );
523 addLine( { { -mil( 100 ), -mil( 100 ) }, { mil( 100 ), -mil( 100 ) } } );
524 addLine( { { -mil( 100 ), -mil( 100 ) }, { -mil( 150 ), -mil( 200 ) } } );
525 addLine( { { 0, -mil( 100 ) }, { -mil( 50 ), -mil( 200 ) } } );
526 addLine( { { mil( 100 ), -mil( 100 ) }, { mil( 50 ), -mil( 200 ) } } );
530 addLine( { { 0, 0 }, { 0, -mil( 100 ) } } );
531 addLine( { { -mil( 100 ), -mil( 100 ) }, { mil( 100 ), -mil( 100 ) } } );
532 addLine( { { -mil( 60 ), -mil( 150 ) }, { mil( 60 ), -mil( 150 ) } } );
533 addLine( { { -mil( 20 ), -mil( 200 ) }, { mil( 20 ), -mil( 200 ) } } );
547 addLine( { { 0, 0 }, { 0, mil( 100 ) } } );
549 circle->SetCenter( { 0, mil( 150 ) } );
550 circle->SetEnd( { mil( 50 ), mil( 150 ) } );
553 symbol->AddDrawItem(
circle.release() );
556 auto pin = std::make_unique<SCH_PIN>( symbol.get() );
557 pin->SetNumber( wxS(
"1" ) );
560 pin->SetVisible(
false );
562 pin->SetPosition( { 0, 0 } );
565 symbol->AddDrawItem(
pin.release() );
566 symbol->GetReferenceField().SetText( wxS(
"#PWR" ) );
567 symbol->GetReferenceField().SetVisible(
false );
573 int aPageHeight,
int aOrdinal,
574 std::vector<PARSER_DIAGNOSTIC>& aDiagnostics )
583 std::unique_ptr<LIB_SYMBOL>
library = makePadsPowerLibrary( aLabel );
588 auto symbol = std::make_unique<SCH_SYMBOL>();
592 symbol->SetLibId( libId );
593 symbol->SetLibSymbol(
library.release() );
594 symbol->SetPosition( pagePoint( aLabel.
position, aPageHeight ) );
595 symbol->SetOrientation( orientation );
596 const wxString reference = wxString::Format( wxS(
"#PWR%04d" ), aOrdinal );
597 symbol->SetRef( &aPath, reference );
598 symbol->AddHierarchicalReference( aPath.
Path(), reference, 1 );
599 symbol->SetValueFieldText( aLabel.
text.
text, &aPath );
602 field->SetVisible(
false );
610 value->SetPosition( pagePoint( textPosition, aPageHeight ) );
621 auto pin = std::make_unique<SCH_PIN>( aParent );
625 pin->SetOrientation( pinOrientation( aPin ) );
642 using POINT_KEY = std::tuple<uint32_t, int64_t, int64_t>;
647 placementsBySheet[placement.
sheet.
id].push_back( &placement );
651 netsById.emplace( net.
id, &net );
652 netsBySheet[net.
sheet.
id].push_back( &net );
656 if( connection.
vertices.size() < 2 )
660 .push_back( connection.
vertices[1] );
667 busesBySheet[bus.
sheet.
id].push_back( &bus );
670 labelsBySheet[label.
sheet.
id].push_back( &label );
673 junctionsBySheet[junction.
sheet.
id].push_back( &junction );
676 textsBySheet[
text.sheet.id].push_back( &
text );
679 graphicsBySheet[graphic.
sheet.
id].push_back( &graphic );
682 imagesBySheet[
image.sheet.id].push_back( &
image );
686 definitionsById.emplace( definition.
id, &definition );
687 std::map<PIN_ID, const MODEL_PIN_DEFINITION*>& definitionPins = pinsByDefinition[definition.
id];
690 definitionPins.emplace(
pin.id, &
pin );
694 partTypesById.emplace( partType.
id, &partType );
697 template <
typename T>
698 static const std::vector<const T*>& ForSheet(
const std::map<
SHEET_ID, std::vector<const T*>>& aMap,
701 static const std::vector<const T*>
empty;
702 auto found = aMap.find( aSheet );
703 return found == aMap.end() ?
empty : found->second;
706 std::map<SHEET_ID, std::vector<const MODEL_PLACEMENT*>> placementsBySheet;
707 std::map<SHEET_ID, std::vector<const MODEL_NET*>> netsBySheet;
708 std::map<SHEET_ID, std::vector<const MODEL_BUS*>> busesBySheet;
709 std::map<SHEET_ID, std::vector<const MODEL_LABEL*>> labelsBySheet;
710 std::map<SHEET_ID, std::vector<const MODEL_JUNCTION*>> junctionsBySheet;
711 std::map<SHEET_ID, std::vector<const MODEL_TEXT*>> textsBySheet;
712 std::map<SHEET_ID, std::vector<const MODEL_PAGE_GRAPHIC*>> graphicsBySheet;
713 std::map<SHEET_ID, std::vector<const MODEL_EMBEDDED_IMAGE*>> imagesBySheet;
714 std::map<NET_ID, const MODEL_NET*> netsById;
715 std::map<POINT_KEY, std::vector<SOURCE_POINT>> endpointAdjacency;
717 std::map<DEFINITION_ID, const MODEL_SYMBOL_DEFINITION*> definitionsById;
718 std::map<PART_TYPE_ID, const MODEL_PART_TYPE*> partTypesById;
719 std::map<DEFINITION_ID, std::map<PIN_ID, const MODEL_PIN_DEFINITION*>> pinsByDefinition;
725 auto definition = aIndex.definitionsById.find( aId );
727 if( definition == aIndex.definitionsById.end() )
728 THROW_IO_ERROR( wxS(
"resolved definition is missing during schematic staging" ) );
730 return *definition->second;
736 auto part = aIndex.partTypesById.find( aId );
738 if( part == aIndex.partTypesById.end() )
739 THROW_IO_ERROR( wxS(
"resolved part type is missing during schematic staging" ) );
741 return *part->second;
748 auto definitionPins = aIndex.pinsByDefinition.find( aDefinition.
id );
750 if( definitionPins == aIndex.pinsByDefinition.end() )
751 THROW_IO_ERROR( wxS(
"resolved pin is missing during schematic staging" ) );
753 auto pin = definitionPins->second.find( aId );
755 if(
pin == definitionPins->second.end() )
756 THROW_IO_ERROR( wxS(
"resolved pin is missing during schematic staging" ) );
762 void addDefinitionUnit(
const MODEL_INDEX& aIndex,
LIB_SYMBOL* aLibrary,
764 int aUnit, std::vector<PARSER_DIAGNOSTIC>& aDiagnostics,
765 const std::vector<PLACED_PIN_REFERENCE>* aPlacementPins =
nullptr,
772 std::unique_ptr<SCH_TEXT>
text = makeGraphicText( graphic, aDiagnostics );
773 text->SetUnit( aUnit );
778 std::unique_ptr<SCH_SHAPE> shape = makeShape( graphic,
false, 0 );
779 shape->SetUnit( aUnit );
784 auto addPin = [&](
const PIN_REFERENCE& aPinReference,
size_t aPinOrdinal )
786 std::unique_ptr<SCH_PIN>
pin = makePin( pinById( aIndex, aDefinition, aPinReference.
id ), aLibrary );
788 if( aGate && aPinOrdinal < aGate->logicalPins.size() )
798 pin->SetNumber( aConnectorPin->number.text );
799 pin->SetName( aConnectorPin->name.text );
800 pin->SetType( pinType( aConnectorPin->electricalType ) );
803 pin->SetUnit( aUnit );
807 if( aPlacementPins && !aPlacementPins->empty() )
809 for(
size_t pinOrdinal = 0; pinOrdinal < aPlacementPins->size(); ++pinOrdinal )
810 addPin( ( *aPlacementPins )[pinOrdinal], pinOrdinal );
812 else if( aGate && !aGate->
pins.empty() )
814 for(
size_t pinOrdinal = 0; pinOrdinal < aGate->
pins.size(); ++pinOrdinal )
815 addPin( aGate->
pins[pinOrdinal], pinOrdinal );
821 std::unique_ptr<SCH_PIN>
pin = makePin( sourcePin, aLibrary );
825 pin->SetNumber( aConnectorPin->number.text );
826 pin->SetName( aConnectorPin->name.text );
827 pin->SetType( pinType( aConnectorPin->electricalType ) );
830 pin->SetUnit( aUnit );
837 std::unique_ptr<LIB_SYMBOL> makeLibrarySymbol(
const MODEL_INDEX& aIndex,
const MODEL_PLACEMENT& aPlacement,
838 std::vector<PARSER_DIAGNOSTIC>& aDiagnostics, wxString& aReference,
842 wxString libraryName = part.
name.
text;
843 auto library = std::make_unique<LIB_SYMBOL>( libraryName );
850 connectorGate = &gate;
862 if( aReference.IsEmpty() )
865 aUnit =
static_cast<int>( aPlacement.
unit );
870 addDefinitionUnit( aIndex,
library.get(), definition, connectorGate,
static_cast<int>(
index + 1 ),
871 aDiagnostics, &aPlacement.
pins, &connectorPin );
874 aUnit =
static_cast<int>(
index + 1 );
877 else if( part.
gates.size() > 1 )
879 library->SetUnitCount(
static_cast<int>( part.
gates.size() ),
false );
883 if( aReference.IsEmpty() )
891 const std::vector<PLACED_PIN_REFERENCE>* placementPins =
892 gate.
unit == aPlacement.
unit ? &aPlacement.
pins :
nullptr;
893 addDefinitionUnit( aIndex,
library.get(), definition, &gate,
static_cast<int>( gate.
unit ),
894 aDiagnostics, placementPins );
901 addDefinitionUnit( aIndex,
library.get(), definition, gate, 0, aDiagnostics, &aPlacement.
pins );
906 auto pin = std::make_unique<SCH_PIN>(
library.get() );
910 pin->SetVisible(
false );
921 void applyField(
SCH_SYMBOL* aSymbol,
const MODEL_FIELD& aSource, std::vector<PARSER_DIAGNOSTIC>& aDiagnostics )
925 if( aSource.name.text.CmpNoCase( wxS(
"REF-DES" ) ) == 0 )
927 else if( aSource.name.text.CmpNoCase( wxS(
"PART-TYPE" ) ) == 0
928 || aSource.name.text.CmpNoCase( wxS(
"VALUE" ) ) == 0 )
932 field = aSymbol->
GetField( aSource.name.text );
938 field = aSymbol->
GetField( aSource.name.text );
945 field->
SetText( aSource.value.text );
948 applyTextPresentation( field, aSource.presentation, aSource.visible && aSource.presentation.visible,
957 wxString resolveLibrarySymbolName( LIBRARY_SYMBOL_VARIANTS& aVariantsByName,
LIB_SYMBOL* aSymbol )
960 auto& variants = aVariantsByName[aSymbol->
GetName()];
962 for(
const auto& [candidate, resolvedName] : variants )
964 if( candidate->Compare( *aSymbol, compareFlags ) == 0 )
968 wxString resolved = aSymbol->
GetName();
970 if( !variants.empty() )
971 resolved = wxString::Format( wxS(
"%s_%zu" ), resolved, variants.size() );
973 variants.emplace_back( std::make_unique<LIB_SYMBOL>( *aSymbol ), resolved );
978 std::unique_ptr<SCH_SYMBOL> makeSymbol( LIBRARY_SYMBOL_VARIANTS& aVariantsByName,
const MODEL_INDEX& aIndex,
980 int aPageHeight, std::vector<PARSER_DIAGNOSTIC>& aDiagnostics )
983 int unit =
static_cast<int>( aPlacement.
unit );
984 std::unique_ptr<LIB_SYMBOL>
library = makeLibrarySymbol( aIndex, aPlacement, aDiagnostics, reference, unit );
985 const wxString libraryName = resolveLibrarySymbolName( aVariantsByName,
library.get() );
987 library->SetName( libraryName );
989 auto symbol = std::make_unique<SCH_SYMBOL>();
993 symbol->SetLibId( libId );
994 symbol->SetExcludedFromBoard(
library->GetPins().empty() );
995 symbol->SetLibSymbol(
library.release() );
996 symbol->SetPosition( pagePoint( aPlacement.
position, aPageHeight ) );
1015 symbol->SetOrientation( orientation );
1017 symbol->SetUnit( unit );
1018 symbol->SetRef( &aPath, reference );
1019 symbol->AddHierarchicalReference( aPath.
Path(), reference, unit );
1022 applyField( symbol.get(), field, aDiagnostics );
1042 static const std::map<wxString, int> commentFields = {
1043 { wxS(
"designed" ), 0 }, { wxS(
"des date" ), 1 }, { wxS(
"drawn by" ), 2 },
1044 { wxS(
"checked by" ), 3 }, { wxS(
"checked date" ), 4 }, { wxS(
"approved" ), 5 },
1045 { wxS(
"app date" ), 6 }, { wxS(
"drawing number" ), 7 }, { wxS(
"scale" ), 8 }
1047 std::array<bool, 9> reservedComments{};
1048 std::vector<const MODEL_FIELD*> fallbackComments;
1049 wxString companyName;
1056 if(
name == wxS(
"title" ) )
1058 else if(
name == wxS(
"revision" ) )
1060 else if(
name == wxS(
"date" ) ||
name == wxS(
"drawn date" ) )
1062 else if(
name == wxS(
"company name" ) )
1064 else if(
name == wxS(
"code" ) )
1066 else if(
auto comment = commentFields.find(
name ); comment != commentFields.end() )
1068 reservedComments[comment->second] =
true;
1073 fallbackComments.push_back( &field );
1077 title.
SetCompany( companyName.IsEmpty() ? code : companyName );
1079 auto fallback = fallbackComments.begin();
1081 for(
size_t comment = 0; comment < reservedComments.size() && fallback != fallbackComments.end(); ++comment )
1083 if( !reservedComments[comment] )
1084 title.
SetComment( comment, ( *fallback++ )->value.text );
1091 std::string quoteWorksheetText(
const wxString& aText )
1095 for(
char character : std::string( aText.utf8_str() ) )
1097 if( character ==
'\\' || character ==
'"' )
1098 result.push_back(
'\\' );
1100 if( character ==
'\n' )
1102 else if( character !=
'\r' )
1103 result.push_back( character );
1110 std::string worksheetVariable(
const wxString& aText )
1112 static const std::map<wxString, std::string> variables = {
1113 { wxS(
"Title" ),
"${TITLE}" }, { wxS(
"Revision" ),
"${REVISION}" },
1114 { wxS(
"Drawn Date" ),
"${ISSUE_DATE}" }, { wxS(
"Code" ),
"${COMPANY}" },
1115 { wxS(
"Designed" ),
"${COMMENT1}" }, { wxS(
"Des Date" ),
"${COMMENT2}" },
1116 { wxS(
"Drawn By" ),
"${COMMENT3}" }, { wxS(
"Checked By" ),
"${COMMENT4}" },
1117 { wxS(
"Checked Date" ),
"${COMMENT5}" }, { wxS(
"Approved" ),
"${COMMENT6}" },
1118 { wxS(
"App Date" ),
"${COMMENT7}" }, { wxS(
"Drawing Number" ),
"${COMMENT8}" },
1119 { wxS(
"Scale" ),
"${COMMENT9}" }, { wxS(
"Sheet Number" ),
"${#}" },
1120 { wxS(
"Number of Sheets" ),
"${##}" }, { wxS(
"Sheet Name" ),
"${SHEETNAME}" },
1121 { wxS(
"Sheet Size" ),
"${PAPER}" }
1123 auto found = variables.find( aText );
1124 return found == variables.end() ? quoteWorksheetText( aText ) : found->second;
1130 return static_cast<double>( aPageSize.
x - aPoint.
x ) * 0.0127;
1136 return static_cast<double>( aPoint.
y ) * 0.0127;
1143 aOutput <<
" (line (name \"\") (start " << worksheetX( aStart, aPageSize ) <<
' ' << worksheetY( aStart )
1144 <<
") (end " << worksheetX( aEnd, aPageSize ) <<
' ' << worksheetY( aEnd ) <<
')';
1147 aOutput <<
" (linewidth " <<
static_cast<double>( aWidth ) * 0.0127 <<
')';
1155 std::ostringstream output;
1156 output.imbue( std::locale::classic() );
1157 output.precision( 8 );
1158 output <<
"(kicad_wks (version 20220228) (generator pads_import)\n"
1159 " (setup (textsize 1.27 1.27) (linewidth 0) (textlinewidth 0)"
1160 " (left_margin 0) (right_margin 0) (top_margin 0) (bottom_margin 0))\n";
1169 output <<
" (tbtext \"" << worksheetVariable( graphic.
text.
text ) <<
"\" (name \"\") (pos "
1171 << worksheetY( graphic.
points.front() );
1173 if( graphic.
angle != 0 )
1174 output <<
") (rotate " <<
static_cast<double>( graphic.
angle ) / 10.0;
1176 output <<
") (font (size " <<
static_cast<double>( graphic.
presentation.
height ) * 0.0127 <<
' '
1180 output <<
" (linewidth " <<
static_cast<double>( graphic.
presentation.
width ) * 0.0127 <<
')';
1186 output <<
" italic";
1193 output <<
" (justify";
1196 output <<
" center";
1203 output <<
" bottom";
1216 const double centerX = (
static_cast<double>( first.
x ) + second.
x ) / 2.0;
1217 const double centerY = (
static_cast<double>( first.
y ) + second.
y ) / 2.0;
1218 const double radius = std::hypot(
static_cast<double>( second.
x - first.
x ),
1219 static_cast<double>( second.
y - first.
y ) )
1221 constexpr int segments = 64;
1223 for(
int segment = 0; segment < segments; ++segment )
1225 const double firstAngle = 2.0 *
M_PI * segment / segments;
1226 const double secondAngle = 2.0 *
M_PI * ( segment + 1 ) / segments;
1239 const double startAngle =
1242 const double sweep =
static_cast<double>( graphic.
arcSweepAngle ) *
M_PI / 1800.0
1244 const int segments = std::max( 1,
static_cast<int>( std::ceil(
std::abs( sweep ) * 16.0 /
M_PI ) ) );
1249 for(
int segment = 0; segment < segments; ++segment )
1251 const double angle1 = startAngle + sweep * segment / segments;
1252 const double angle2 = startAngle + sweep * ( segment + 1 ) / segments;
1270 appendWorksheetLine( output, topRight, bottomRight, aSheet.
pageSize, graphic.
strokeWidth );
1271 appendWorksheetLine( output, bottomRight, bottomLeft, aSheet.
pageSize, graphic.
strokeWidth );
1276 for(
size_t point = 1; point < graphic.
points.size(); ++point )
1278 appendWorksheetLine( output, graphic.
points[point - 1], graphic.
points[point], aSheet.
pageSize,
1284 return output.str();
1288 wxString sanitizedFilename(
const wxString& aName,
size_t aOrdinal, std::set<wxString>& aUsed )
1290 wxString stem = aName;
1292 for( wxUniChar character : wxS(
"<>:\"/\\|?*" ) )
1293 stem.Replace( wxString( character ), wxS(
"_" ) );
1295 stem.Trim(
true ).Trim(
false );
1297 if( stem.IsEmpty() )
1298 stem = wxString::Format( wxS(
"pads_sheet_%zu" ), aOrdinal + 1 );
1303 while( aUsed.contains( candidate.Lower() ) )
1306 aUsed.insert( candidate.Lower() );
1311 struct STAGED_SCHEMATIC
1314 std::unique_ptr<SCH_SCREEN> replacementScreen;
1315 std::unique_ptr<SCH_SCREEN> appendCache;
1317 std::vector<std::unique_ptr<SCH_ITEM>> appendItems;
1318 std::unique_ptr<SCH_SCREEN> topLevelCache;
1320 std::vector<std::unique_ptr<SCH_SHEET>> topLevelOwners;
1321 std::vector<SCH_SHEET*> topLevelSheets;
1323 std::optional<SCH_SHEET_PATH> replacementCurrentSheet;
1324 std::unique_ptr<CONNECTION_GRAPH> connectionGraph;
1325 std::unique_ptr<EMBEDDED_FILES> replacementEmbeddedFiles;
1326 wxString replacementDrawingSheet;
1330 int nextPowerOrdinal = 1;
1332 LIBRARY_SYMBOL_VARIANTS librarySymbolVariants;
1334 static void ValidateScreen(
const SCH_SCREEN* aScreen )
1344 THROW_IO_ERROR( wxS(
"staged symbol is missing its library link" ) );
1348 static void ValidateChildSheet(
const SCH_SHEET* aSheet, std::set<wxString>& aFilenames )
1351 THROW_IO_ERROR( wxS(
"staged child sheet is missing its screen" ) );
1357 if( filename.IsEmpty() || filename.Contains( wxS(
"/" ) ) || filename.Contains( wxS(
"\\" ) )
1358 || filename.Contains( wxS(
":" ) ) || filename.Contains( wxS(
"*" ) ) )
1360 THROW_IO_ERROR( wxS(
"staged child sheet has an invalid filename" ) );
1363 if( !aFilenames.insert( filename.Lower() ).second )
1364 THROW_IO_ERROR( wxS(
"staged child sheet filenames are not unique" ) );
1367 void Validate(
bool aAppending )
const
1369 if( replacementEmbeddedFiles
1370 && ( aAppending || replacementDrawingSheet.IsEmpty()
1371 || !replacementEmbeddedFiles->HasFile( wxS(
"pads_import.kicad_wks" ) ) ) )
1373 THROW_IO_ERROR( wxS(
"embedded worksheet staging is incomplete" ) );
1376 if( !replacementEmbeddedFiles && !replacementDrawingSheet.IsEmpty() )
1377 THROW_IO_ERROR( wxS(
"worksheet path has no staged embedded file" ) );
1381 if( replacementScreen || appendCache || topLevelOwners.empty()
1382 || topLevelOwners.size() != topLevelSheets.size() || topLevelSheets.size() !=
result.counts.sheets )
1384 THROW_IO_ERROR( wxS(
"top-level sheet staging has invalid ownership" ) );
1387 for(
const std::unique_ptr<SCH_SHEET>& sheet : topLevelOwners )
1389 if( !sheet || !sheet->GetScreen() || !sheet->GetScreen()->Items().OfType(
SCH_SHEET_T ).empty() )
1390 THROW_IO_ERROR( wxS(
"staged top-level sheet has invalid content" ) );
1392 ValidateScreen( sheet->GetScreen() );
1395 if( hierarchy.size() != topLevelSheets.size() || !replacementCurrentSheet || !connectionGraph )
1396 THROW_IO_ERROR( wxS(
"top-level sheet staging has incomplete hierarchy state" ) );
1401 if( aAppending && ( replacementScreen || !appendCache ) )
1402 THROW_IO_ERROR( wxS(
"append staging has invalid screen ownership" ) );
1404 if( !aAppending && ( !destinationRoot || !replacementScreen || !replacementCurrentSheet ) )
1405 THROW_IO_ERROR( wxS(
"replacement staging has no destination root or screen" ) );
1407 std::set<wxString> filenames;
1409 if( replacementScreen )
1411 ValidateScreen( replacementScreen.get() );
1413 size_t childCount = 0;
1417 ValidateChildSheet(
static_cast<SCH_SHEET*
>( item ), filenames );
1421 if(
result.counts.sheets > 1 && childCount !=
result.counts.sheets )
1422 THROW_IO_ERROR( wxS(
"staged replacement hierarchy does not own every source sheet" ) );
1424 if(
result.counts.sheets == 1 && childCount != 0 )
1425 THROW_IO_ERROR( wxS(
"single-sheet staging unexpectedly contains child sheets" ) );
1428 size_t appendedSheetCount = 0;
1430 for(
const std::unique_ptr<SCH_ITEM>& item : appendItems )
1433 THROW_IO_ERROR( wxS(
"staged schematic contains an empty object" ) );
1437 ValidateChildSheet(
static_cast<const SCH_SHEET*
>( item.get() ), filenames );
1438 ++appendedSheetCount;
1445 THROW_IO_ERROR( wxS(
"staged symbol is missing its library link" ) );
1449 if( aAppending &&
result.counts.sheets > 1 && appendedSheetCount !=
result.counts.sheets )
1450 THROW_IO_ERROR( wxS(
"staged append hierarchy does not own every source sheet" ) );
1452 if( hierarchy.empty() || !connectionGraph )
1453 THROW_IO_ERROR( wxS(
"staged schematic has incomplete hierarchy state" ) );
1461 content.
hierarchy = std::move( hierarchy );
1462 content.
currentSheet = std::move( replacementCurrentSheet );
1465 if( replacementEmbeddedFiles )
1467 content.
embeddedFiles.emplace( std::move( *replacementEmbeddedFiles ) );
1471 if( replacementScreen )
1474 content.
screen = std::move( replacementScreen );
1476 else if( topLevelCache )
1483 for( std::unique_ptr<SCH_SHEET>& sheet : topLevelOwners )
1484 content.
itemOwners.emplace_back( std::move( sheet ) );
1492 content.
itemOwners = std::move( appendItems );
1498 void Commit(
SCHEMATIC* aSchematic,
SCH_SHEET* aAppendToMe,
const std::function<
void()>& aBeforeCommit )
1510 void collectDispositionDiagnostics(
const std::vector<SOURCE_PROPERTY>& aProperties,
1511 std::vector<PARSER_DIAGNOSTIC>& aDiagnostics )
1521 wxString::Format( wxS(
"PADS property '%s' retained with %s disposition" ), property.name.text,
1523 ? wxS(
"approximate" )
1524 : wxS(
"unsupported" ) ) ) );
1530 std::vector<PARSER_DIAGNOSTIC>& aDiagnostics )
1532 collectDispositionDiagnostics( aPresentation.
properties, aDiagnostics );
1536 void validatePropertyDispositions(
const PADS_SCH_MODEL& aModel, std::vector<PARSER_DIAGNOSTIC>& aDiagnostics )
1542 collectDispositionDiagnostics( sheet.
properties, aDiagnostics );
1546 collectDispositionDiagnostics( graphic.
properties, aDiagnostics );
1547 collectPresentationDiagnostics( graphic.
presentation, aDiagnostics );
1552 collectDispositionDiagnostics( field.
properties, aDiagnostics );
1553 collectPresentationDiagnostics( field.
presentation, aDiagnostics );
1559 collectDispositionDiagnostics( definition.
properties, aDiagnostics );
1563 collectDispositionDiagnostics( graphic.
properties, aDiagnostics );
1564 collectPresentationDiagnostics( graphic.
presentation, aDiagnostics );
1569 collectDispositionDiagnostics(
pin.properties, aDiagnostics );
1570 collectPresentationDiagnostics(
pin.presentation, aDiagnostics );
1571 collectPresentationDiagnostics(
pin.namePresentation, aDiagnostics );
1572 collectPresentationDiagnostics(
pin.numberPresentation, aDiagnostics );
1577 collectDispositionDiagnostics( field.
properties, aDiagnostics );
1578 collectPresentationDiagnostics( field.
presentation, aDiagnostics );
1584 collectDispositionDiagnostics( part.
properties, aDiagnostics );
1587 collectDispositionDiagnostics( gate.
properties, aDiagnostics );
1591 collectDispositionDiagnostics( field.
properties, aDiagnostics );
1592 collectPresentationDiagnostics( field.
presentation, aDiagnostics );
1598 collectDispositionDiagnostics( placement.
properties, aDiagnostics );
1602 collectDispositionDiagnostics( field.
properties, aDiagnostics );
1603 collectPresentationDiagnostics( field.
presentation, aDiagnostics );
1609 collectDispositionDiagnostics( net.
properties, aDiagnostics );
1613 collectDispositionDiagnostics( connection.
properties, aDiagnostics );
1616 collectDispositionDiagnostics( endpoint.
properties, aDiagnostics );
1622 collectDispositionDiagnostics( bus.
properties, aDiagnostics );
1625 collectDispositionDiagnostics( entry.
properties, aDiagnostics );
1630 collectDispositionDiagnostics( label.
properties, aDiagnostics );
1631 collectPresentationDiagnostics( label.
presentation, aDiagnostics );
1635 collectDispositionDiagnostics( junction.
properties, aDiagnostics );
1639 collectDispositionDiagnostics(
text.properties, aDiagnostics );
1640 collectPresentationDiagnostics(
text.presentation, aDiagnostics );
1653 collectDispositionDiagnostics( graphic.
properties, aDiagnostics );
1654 collectPresentationDiagnostics( graphic.
presentation, aDiagnostics );
1659 collectDispositionDiagnostics(
image.properties, aDiagnostics );
1665 wxS(
"PADS controller payload retained without schematic construction" ) ) );
1668 std::set<DIAGNOSTIC_PROPERTY_KEY> parserOwnedProperties;
1673 parserOwnedProperties.insert( std::move( *key ) );
1676 std::erase_if( aDiagnostics,
1680 return key && parserOwnedProperties.contains( *key );
1685 void stageSheetContent( STAGED_SCHEMATIC& aStaged,
const MODEL_INDEX& aIndex,
1688 PAGE_INFO page = pageInfo( aSourceSheet );
1690 applyTitleBlock( aScreen, aSourceSheet );
1693 for(
const MODEL_PLACEMENT* placement : MODEL_INDEX::ForSheet( aIndex.placementsBySheet, aSourceSheet.
id ) )
1695 std::unique_ptr<SCH_SYMBOL> symbol =
1696 makeSymbol( aStaged.librarySymbolVariants, aIndex, *placement, aPath, pageHeight,
1698 aScreen->
Append( symbol.get() );
1707 appendPageGraphic( aScreen, graphic, pageHeight, aStaged.result.
diagnostics );
1713 appendPageGraphic( aScreen, graphic, pageHeight, aStaged.result.
diagnostics );
1716 using SEGMENT_KEY = std::tuple<uint32_t, uint32_t, int64_t, int64_t, int64_t, int64_t>;
1717 std::set<SEGMENT_KEY> busEntrySegments;
1721 if( std::tie( aStart.x, aStart.y ) <= std::tie( aEnd.
x, aEnd.
y ) )
1722 return SEGMENT_KEY( aSheet.
Value(), aNet.Value(), aStart.x, aStart.y, aEnd.
x, aEnd.
y );
1724 return SEGMENT_KEY( aSheet.
Value(), aNet.Value(), aEnd.
x, aEnd.
y, aStart.x, aStart.y );
1727 for(
const MODEL_BUS* bus : MODEL_INDEX::ForSheet( aIndex.busesBySheet, aSourceSheet.
id ) )
1729 if( bus->vertices.size() < 2 )
1732 for(
size_t vertex = 1; vertex < bus->vertices.size(); ++vertex )
1734 auto line = std::make_unique<SCH_LINE>( pagePoint( bus->vertices[vertex - 1], pageHeight ),
LAYER_BUS );
1735 line->SetEndPoint( pagePoint( bus->vertices[vertex], pageHeight ) );
1737 aScreen->
Append( line.get() );
1742 wxString busLabel = bus->name.text;
1744 if( !bus->declaredMembers.empty() )
1746 busLabel += wxS(
"{" );
1748 for(
size_t member = 0; member < bus->declaredMembers.size(); ++member )
1751 busLabel += wxS(
" " );
1753 busLabel += bus->declaredMembers[member].text;
1756 busLabel += wxS(
"}" );
1759 auto label = std::make_unique<SCH_LABEL>( pagePoint( bus->vertices.front(), pageHeight ), busLabel );
1760 aScreen->
Append( label.get() );
1766 auto ownerNet = aIndex.netsById.find( entry.
memberNet.
id );
1768 if( ownerNet == aIndex.netsById.end() )
1770 wxS(
"resolved bus-entry net is missing during staging" ) ) );
1772 auto adjacency = aIndex.endpointAdjacency.find(
1775 if( adjacency == aIndex.endpointAdjacency.end() )
1778 if( adjacency->second.size() != 1 )
1782 const VECTOR2I end = pagePoint( adjacency->second.front(), pageHeight );
1787 auto clamped = [&](
int aDelta )
1789 return static_cast<int>(
static_cast<int64_t
>( aDelta ) * entrySpan / span );
1793 auto entryItem = std::make_unique<SCH_BUS_WIRE_ENTRY>( start );
1794 entryItem->SetSize( entryEnd - start );
1795 aScreen->
Append( entryItem.get() );
1796 entryItem.release();
1798 if( entryEnd !=
end )
1800 auto wire = std::make_unique<SCH_LINE>( entryEnd,
LAYER_WIRE );
1801 wire->SetEndPoint(
end );
1803 aScreen->
Append( wire.get() );
1808 busEntrySegments.insert(
1814 for(
const MODEL_NET* net : MODEL_INDEX::ForSheet( aIndex.netsBySheet, aSourceSheet.
id ) )
1818 if( connection.
vertices.size() < 2 )
1822 for(
size_t vertex = 1; vertex < connection.
vertices.size(); ++vertex )
1824 if( busEntrySegments.contains( segmentKey( aSourceSheet.
id, net->id,
1831 auto line = std::make_unique<SCH_LINE>( pagePoint( connection.
vertices[vertex - 1], pageHeight ),
1833 line->SetEndPoint( pagePoint( connection.
vertices[vertex], pageHeight ) );
1835 aScreen->
Append( line.get() );
1844 if( pinEndpoint != connection.
endpoints.end() )
1845 labelPoint = pinEndpoint->point;
1846 else if( connection.
vertices.size() >= 2
1847 && busEntrySegments.contains( segmentKey( aSourceSheet.
id, net->id, connection.
vertices[0],
1849 labelPoint = connection.
vertices[1];
1851 const bool hasSourceLabel = std::ranges::any_of(
1852 MODEL_INDEX::ForSheet( aIndex.labelsBySheet, aSourceSheet.
id ),
1855 return ( aLabel->kind == MODEL_LABEL_KIND::GLOBAL || aLabel->kind == MODEL_LABEL_KIND::POWER
1856 || aLabel->kind == MODEL_LABEL_KIND::GROUND )
1857 && aLabel->text.text == net->name.text && aLabel->position.x == labelPoint.x
1858 && aLabel->position.y == labelPoint.y;
1861 if( !hasSourceLabel )
1864 std::make_unique<SCH_GLOBALLABEL>( pagePoint( labelPoint, pageHeight ), net->name.text );
1865 label->SetTextSize(
VECTOR2I( 1, 1 ) );
1866 aScreen->
Append( label.get() );
1872 for(
const MODEL_JUNCTION* junction : MODEL_INDEX::ForSheet( aIndex.junctionsBySheet, aSourceSheet.
id ) )
1874 auto item = std::make_unique<SCH_JUNCTION>( pagePoint( junction->position, pageHeight ) );
1875 aScreen->
Append( item.get() );
1880 for(
const MODEL_LABEL* labelPointer : MODEL_INDEX::ForSheet( aIndex.labelsBySheet, aSourceSheet.
id ) )
1884 std::unique_ptr<SCH_ITEM> item;
1886 switch( label.
kind )
1890 item = std::make_unique<SCH_LABEL>( pagePoint( label.
position, pageHeight ), label.
text.
text );
1894 item = std::make_unique<SCH_GLOBALLABEL>( pagePoint( label.
position, pageHeight ), label.
text.
text );
1898 item = std::make_unique<SCH_HIERLABEL>( pagePoint( label.
position, pageHeight ), label.
text.
text );
1903 item = makePowerSymbol( label, aPath, pageHeight, aStaged.nextPowerOrdinal++,
1914 return aProperty.name.text == wxS(
"unsupported_offpage_decal" );
1922 wxS(
"PADS unsupported label has no KiCad schematic representation" ) ) );
1929 if(
auto*
text =
dynamic_cast<EDA_TEXT*
>( item.get() ) )
1936 aScreen->
Append( item.get() );
1941 for(
const MODEL_TEXT* sourceTextPointer : MODEL_INDEX::ForSheet( aIndex.textsBySheet, aSourceSheet.
id ) )
1943 const MODEL_TEXT& sourceText = *sourceTextPointer;
1945 std::unique_ptr<SCH_TEXT>
text =
1954 MODEL_INDEX::ForSheet( aIndex.graphicsBySheet, aSourceSheet.
id ) )
1960 appendPageGraphic( aScreen, pageGraphic.
graphic, pageHeight, aStaged.result.
diagnostics );
1966 appendPageGraphic( aScreen, pageGraphic.
graphic, pageHeight, aStaged.result.
diagnostics );
1970 for(
const MODEL_EMBEDDED_IMAGE* sourceImage : MODEL_INDEX::ForSheet( aIndex.imagesBySheet, aSourceSheet.
id ) )
1972 std::unique_ptr<SCH_BITMAP> bitmap =
1973 makeEmbeddedImage( *sourceImage, pageHeight, aStaged.result.
diagnostics );
1978 aScreen->
Append( bitmap.get() );
1988 SCH_SHEET* aAppendToMe,
const wxString& aSourcePath )
1991 THROW_IO_ERROR( wxS(
"cannot build a PADS schematic without a destination" ) );
1993 if( aSourcePath.IsEmpty() )
1994 THROW_IO_ERROR( wxS(
"cannot build a PADS schematic without a source filename" ) );
1996 if( aModel.
sheets.empty() )
1999 if( aAppendToMe && !aAppendToMe->
GetScreen() )
2000 THROW_IO_ERROR( wxS(
"cannot append a PADS schematic to a sheet without a screen" ) );
2003 std::vector<const MODEL_SHEET*> sourceSheets;
2004 sourceSheets.reserve( aModel.
sheets.size() );
2007 sourceSheets.push_back( &sheet );
2011 MODEL_INDEX modelIndex( aModel );
2012 STAGED_SCHEMATIC staged;
2014 staged.connectionGraph = std::make_unique<CONNECTION_GRAPH>( aSchematic );
2019 validatePropertyDispositions( aModel, staged.result.
diagnostics );
2021 if( !aAppendToMe && !aModel.
worksheets.empty() )
2023 auto worksheet = std::ranges::find_if( aModel.
worksheets,
2026 return aWorksheet.name.text == wxS(
"DRW5982" );
2034 if( sourceSheet == aModel.
sheets.end() )
2037 const std::string serialized = serializeWorksheet( *worksheet, *sourceSheet );
2038 auto embeddedWorksheet = std::make_shared<EMBEDDED_FILES::EMBEDDED_FILE>();
2039 embeddedWorksheet->name = wxS(
"pads_import.kicad_wks" );
2041 embeddedWorksheet->decompressedData.assign( serialized.begin(), serialized.end() );
2046 embeddedWorksheet->is_valid =
true;
2047 staged.replacementEmbeddedFiles = std::make_unique<EMBEDDED_FILES>();
2049 staged.replacementEmbeddedFiles->AddFile( embeddedWorksheet );
2050 staged.replacementDrawingSheet = embeddedWorksheet->GetLink();
2053 const bool multiSheet = aModel.
sheets.size() > 1;
2054 std::set<wxString> usedFilenames;
2055 size_t firstChildPage = 2;
2061 unsigned long page = 0;
2063 if(
path.GetPageNumber().ToULong( &page ) )
2065 if( page >= std::numeric_limits<size_t>::max() )
2066 THROW_IO_ERROR( wxS(
"existing schematic page number leaves no append range" ) );
2068 firstChildPage = std::max( firstChildPage,
static_cast<size_t>( page ) + 1 );
2072 if( multiSheet && sourceSheets.size() > std::numeric_limits<size_t>::max() - firstChildPage )
2073 THROW_IO_ERROR( wxS(
"imported hierarchy page range overflows" ) );
2075 staged.appendCache = std::make_unique<SCH_SCREEN>( aSchematic );
2080 THROW_IO_ERROR( wxString::Format( wxS(
"destination library cache entry '%s' is null" ),
name ) );
2082 auto clone = std::make_unique<LIB_SYMBOL>( *symbol );
2099 if( !staged.destinationRoot || !staged.destinationRoot->
GetScreen() )
2100 THROW_IO_ERROR( wxS(
"cannot replace a schematic without a top-level sheet and screen" ) );
2102 staged.replacementScreen = std::make_unique<SCH_SCREEN>( aSchematic );
2103 staged.replacementScreen->
SetFileName( aSourcePath );
2105 rootPath.
push_back( staged.destinationRoot );
2106 staged.hierarchy.push_back( rootPath );
2107 staged.replacementCurrentSheet.emplace( rootPath );
2108 stageSheetContent( staged, modelIndex, *sourceSheets.front(), staged.replacementScreen.get(), rootPath );
2112 staged.topLevelCache = std::make_unique<SCH_SCREEN>( aSchematic );
2117 auto sheet = std::make_unique<SCH_SHEET>( aSchematic );
2119 sheet->SetScreen( screen );
2120 sheet->SyncUuidToScreen();
2121 sheet->SetParent( &aSchematic->
Root() );
2123 wxString filename = sanitizedFilename( sourceSheet.
name.
text,
index, usedFilenames );
2125 screen->SetFileName( filename );
2126 screen->SetPageNumber( wxString::Format( wxS(
"%zu" ),
index + 1 ) );
2128 path.push_back( sheet.get() );
2129 path.SetPageNumber( wxString::Format( wxS(
"%zu" ),
index + 1 ) );
2130 stageSheetContent( staged, modelIndex, sourceSheet, screen,
path );
2131 staged.hierarchy.push_back(
path );
2134 staged.replacementCurrentSheet.emplace(
path );
2136 staged.topLevelIndex.
insert( sheet.get() );
2137 staged.topLevelSheets.push_back( sheet.get() );
2138 staged.topLevelOwners.push_back( std::move( sheet ) );
2142 else if( !multiSheet )
2144 const MODEL_SHEET& sourceSheet = *sourceSheets.front();
2145 SCH_SCREEN* temporaryScreen = staged.appendCache.get();
2147 path.push_back( aAppendToMe );
2148 stageSheetContent( staged, modelIndex, sourceSheet, temporaryScreen,
path );
2150 std::vector<SCH_ITEM*> temporaryItems;
2153 temporaryItems.push_back( item );
2155 for(
SCH_ITEM* item : temporaryItems )
2157 std::unique_ptr<SCH_ITEM> itemOwner( item );
2162 THROW_IO_ERROR( wxS(
"staged append item is missing from its spatial index" ) );
2164 item->SetParent( aAppendToMe->
GetScreen() );
2165 staged.appendItems.emplace_back( std::move( itemOwner ) );
2178 auto child = std::make_unique<SCH_SHEET>(
2180 auto childScreen =
new SCH_SCREEN( aSchematic );
2181 child->SetScreen( childScreen );
2183 wxString filename = sanitizedFilename( sourceSheet.
name.
text,
index, usedFilenames );
2185 childScreen->SetFileName( filename );
2186 childScreen->SetPageNumber( wxString::Format( wxS(
"%zu" ), firstChildPage +
index ) );
2190 stageSheetContent( staged, modelIndex, sourceSheet, childScreen, childPath );
2191 child->SetParent( aAppendToMe->
GetScreen() );
2192 staged.appendItems.emplace_back( std::move( child ) );
2199 staged.hierarchy.assign( currentHierarchy.begin(), currentHierarchy.end() );
2202 staged.appendIndex.
insert( item );
2204 for(
const std::unique_ptr<SCH_ITEM>& item : staged.appendItems )
2206 staged.appendIndex.
insert( item.get() );
2211 path.push_back( aAppendToMe );
2213 staged.hierarchy.push_back(
path );
2218 staged.Validate( aAppendToMe !=
nullptr );