288 const std::map<wxString, wxString>& aDeviceAttributes,
289 const std::map<wxString, EASYEDAPRO::BLOB>& aBlobMap )
293 std::unique_ptr<LIB_SYMBOL> ksymbolPtr = std::make_unique<LIB_SYMBOL>( wxEmptyString );
296 std::map<wxString, int> partUnits;
298 std::map<int, std::map<wxString, EASYEDAPRO::SCH_ATTR>> unitAttributes;
299 std::map<int, std::map<wxString, const V3_ROW*>> unitAttributeRows;
300 std::map<int, std::map<wxString, std::vector<const V3_ROW*>>> unitParentedRows;
307 if( row.
type == wxS(
"PART" ) )
309 int unitId = ++totalUnits;
311 partUnits[row.
id] = unitId;
315 if( !partTitle.empty() )
316 partUnits[partTitle] = unitId;
318 else if( row.
type == wxS(
"META" ) )
320 if( row.
inner.contains(
"docType" ) )
332 auto resolveRowUnit = [&](
const V3_ROW& aRow )
334 wxString partId =
V3GetString( aRow.inner,
"partId" );
336 if( !partId.empty() )
338 if(
auto unitOpt =
get_opt( partUnits, partId ) )
348 int rowUnit = resolveRowUnit( row );
350 if( row.
type == wxS(
"PART" ) )
352 currentUnit = partUnits.at( row.
id );
354 else if( row.
type == wxS(
"RECT" ) )
365 rect->SetUnit( rowUnit );
370 else if( row.
type == wxS(
"CIRCLE" ) )
381 circle->SetUnit( rowUnit );
386 else if( row.
type == wxS(
"ARC" ) )
398 shape->SetUnit( rowUnit );
403 else if( row.
type == wxS(
"BEZIER" ) )
405 std::vector<double> points = row.
inner.value(
"controls", nlohmann::json::array() );
409 for(
size_t i = 1; i < points.size(); i += 2 )
415 case 1: shape->SetStart( pt );
break;
416 case 3: shape->SetBezierC1( pt );
break;
417 case 5: shape->SetBezierC2( pt );
break;
418 case 7: shape->SetEnd( pt );
break;
422 shape->SetUnit( rowUnit );
427 else if( row.
type == wxS(
"POLY" ) )
430 row.
inner.value(
"points", nlohmann::json::array() ) );
431 std::vector<double> points = flatPts;
435 for(
size_t i = 1; i < points.size(); i += 2 )
438 shape->SetUnit( rowUnit );
443 else if( row.
type == wxS(
"TEXT" ) )
449 auto text = std::make_unique<SCH_TEXT>(
455 text->SetTextAngleDegrees( angle );
456 text->SetUnit( rowUnit );
461 else if( row.
type == wxS(
"OBJ" ) )
470 wxString mimeType, data;
472 if( imageUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
474 wxArrayString paramsArr =
475 wxSplit( imageUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
477 data = imageUrl.AfterFirst(
',' );
479 if( paramsArr.size() > 0 )
480 mimeType = paramsArr[0];
482 else if( imageUrl.BeforeFirst(
':' ) == wxS(
"blob" ) )
484 wxString objectId = imageUrl.AfterLast(
':' );
486 if(
auto blob =
get_opt( aBlobMap, objectId ) )
488 wxString blobUrl = blob->url;
490 if( blobUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
492 wxArrayString paramsArr =
493 wxSplit( blobUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
495 data = blobUrl.AfterFirst(
',' );
497 if( paramsArr.size() > 0 )
498 mimeType = paramsArr[0];
503 if( mimeType.empty() || data.empty() )
506 wxMemoryBuffer buf = wxBase64Decode( data );
508 if( mimeType == wxS(
"image/svg+xml" ) )
530 libsymImporter.
SetScale( pixelScale );
538 for( std::unique_ptr<EDA_ITEM>& item : libsymImporter.
GetItems() )
543 wxMemoryInputStream memis( buf.GetData(), buf.GetDataLen() );
545 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
546 & ~wxImage::Load_Verbose );
549 if( img.LoadFile( memis, mimeType ) )
551 int dimMul = img.GetWidth() * img.GetHeight();
552 double maxPixels = 30000;
554 if( dimMul > maxPixels )
556 double scale = sqrt( maxPixels / dimMul );
557 img.Rescale( img.GetWidth() *
scale, img.GetHeight() *
scale );
569 else if( row.
type == wxS(
"PIN" ) )
571 unitParentedRows[rowUnit][row.
id].push_back( &row );
573 else if( row.
type == wxS(
"ATTR" ) )
577 if( parentId.empty() )
594 unitAttributes[rowUnit].emplace( attr.
key, attr );
595 unitAttributeRows[rowUnit].emplace( attr.
key, &row );
599 unitParentedRows[rowUnit][parentId].push_back( &row );
615 if(
auto globalNetAttr =
get_opt( unitAttributes[1], wxS(
"Global Net Name" ) ) )
617 wxString powerName = globalNetAttr->value;
619 if( powerName.IsEmpty() )
621 if(
auto nameAttr =
get_opt( unitAttributes[1], wxS(
"Name" ) ) )
622 powerName = nameAttr->value;
626 valueText->
SetText( powerName );
627 valueText->
SetVisible( globalNetAttr->valVisible );
629 if(
auto globalNetAttrRow =
get_opt( unitAttributeRows[1], wxS(
"Global Net Name" ) ) )
631 const nlohmann::json& attrInner = ( *globalNetAttrRow )->inner;
633 wxString color =
V3GetString( attrInner,
"color", wxEmptyString );
634 wxString fontFamily =
V3GetString( attrInner,
"fontFamily", wxS(
"default" ) );
635 wxString align =
V3GetString( attrInner,
"align", wxS(
"LEFT_BOTTOM" ) );
637 if( !color.empty() && color.StartsWith( wxS(
"#" ) ) )
643 if( fontFamily != wxS(
"Arial" ) && !fontFamily.IsSameAs( wxS(
"default" ),
false ) )
653 else if( vAlign == 1 )
660 else if( hAlign == 1 )
666 if( globalNetAttr->position )
669 wxString globalNetname = globalNetAttr->value;
671 if( globalNetname.IsEmpty() )
672 globalNetname = powerName;
674 if( !globalNetname.empty() )
677 _(
"Power symbol creates a global label with name '%s'" ),
684 auto designatorAttr =
get_opt( unitAttributes[1], wxS(
"Designator" ) );
686 if( designatorAttr && !designatorAttr->value.empty() )
688 wxString symbolPrefix = designatorAttr->value;
690 if( symbolPrefix.EndsWith( wxS(
"?" ) ) )
691 symbolPrefix.RemoveLast();
697 aDeviceAttributes,
true,
698 [&](
const wxString& attrName,
const wxString& value )
714 for(
auto& [unitId, parentedRows] : unitParentedRows )
716 for(
auto& [pinId, rows] : parentedRows )
718 const V3_ROW* pinRow =
nullptr;
719 std::map<wxString, EASYEDAPRO::SCH_ATTR> pinAttributes;
721 for(
const V3_ROW* r : rows )
723 if( r->type == wxS(
"ATTR" ) )
730 pinAttributes.emplace( attr.
key, attr );
733 else if( r->type == wxS(
"PIN" ) )
749 pinInfo.
pin.
inverted = ( pinShape == wxS(
"INVERTED" )
750 || pinShape == wxS(
"INVERTED_CLOCK" ) );
752 std::unique_ptr<SCH_PIN>
pin = std::make_unique<SCH_PIN>( ksymbol );
754 pin->SetUnit( unitId );
769 pin->SetOrientation( orient );
777 auto pinNameAttr =
get_opt( pinAttributes, wxS(
"Pin Name" ) );
780 pinNameAttr =
get_opt( pinAttributes, wxS(
"NAME" ) );
784 pin->SetName( pinNameAttr->value );
785 pinInfo.
name = pinNameAttr->value;
787 if( !pinNameAttr->valVisible )
792 auto pinNumAttr =
get_opt( pinAttributes, wxS(
"Pin Number" ) );
795 pinNumAttr =
get_opt( pinAttributes, wxS(
"NUMBER" ) );
799 pin->SetNumber( pinNumAttr->value );
800 pinInfo.
number = pinNumAttr->value;
802 if( !pinNumAttr->valVisible )
810 else if(
auto pinTypeAttr =
get_opt( pinAttributes, wxS(
"Pin Type" ) ) )
812 if( pinTypeAttr->value == wxS(
"IN" ) )
814 if( pinTypeAttr->value == wxS(
"OUT" ) )
816 if( pinTypeAttr->value == wxS(
"BI" ) )
820 if(
get_opt( pinAttributes, wxS(
"NO_CONNECT" ) ) )
823 if(
pin->GetNumberTextSize() *
int(
pin->GetNumber().size() ) >
pin->GetLength() )
824 pin->SetNumberTextSize(
pin->GetLength() /
pin->GetNumber().size() );
826 symInfo.
pins.push_back( pinInfo );
832 symInfo.
libSymbol = std::move( ksymbolPtr );
991 std::map<wxString, EASYEDAPRO::SYM_INFO>& aSymbolMap,
992 const std::map<wxString, EASYEDAPRO::BLOB>& aBlobMap,
995 std::vector<std::unique_ptr<SCH_ITEM>> createdItems;
998 std::map<wxString, std::vector<const EASYEDAPRO::V3_ROW*>> wireGeometry;
999 std::map<wxString, const EASYEDAPRO::V3_ROW*> wireRows;
1002 std::map<wxString, std::vector<const EASYEDAPRO::V3_ROW*>> parentedRows;
1007 if( row.
type == wxS(
"WIRE" ) )
1009 wireRows[row.
id] = &row;
1014 wireGeometry[lineGroup].push_back( &row );
1016 else if( row.
type == wxS(
"COMPONENT" ) )
1018 parentedRows[row.
id].push_back( &row );
1023 parentedRows[parentId].push_back( &row );
1030 if( row.
type == wxS(
"RECT" ) )
1043 createdItems.push_back( std::move( rect ) );
1045 else if( row.
type == wxS(
"CIRCLE" ) )
1058 createdItems.push_back( std::move(
circle ) );
1060 else if( row.
type == wxS(
"ARC" ) )
1069 std::unique_ptr<SCH_SHAPE> arc = std::make_unique<SCH_SHAPE>(
SHAPE_T::ARC );
1074 createdItems.push_back( std::move( arc ) );
1076 else if( row.
type == wxS(
"POLY" ) )
1082 row.
inner.value(
"points", nlohmann::json::array() ) );
1083 std::vector<double> pointsData = flatPts;
1085 if( pointsData.size() < 4 )
1088 std::unique_ptr<SCH_SHAPE> poly = std::make_unique<SCH_SHAPE>(
SHAPE_T::POLY );
1090 for(
size_t i = 1; i < pointsData.size(); i += 2 )
1095 createdItems.push_back( std::move( poly ) );
1097 else if( row.
type == wxS(
"TEXT" ) )
1104 std::unique_ptr<SCH_TEXT> schText = std::make_unique<SCH_TEXT>(
1110 schText->SetTextAngleDegrees( angle );
1114 createdItems.push_back( std::move( schText ) );
1116 else if( row.
type == wxS(
"OBJ" ) )
1138 wxString base64Data;
1140 if( content.BeforeFirst(
':' ) == wxS(
"data" ) )
1142 wxArrayString paramsArr =
1143 wxSplit( content.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
1145 if( paramsArr.size() > 0 )
1146 mimeType = paramsArr[0];
1148 base64Data = content.AfterFirst(
',' );
1150 else if( content.BeforeFirst(
':' ) == wxS(
"blob" ) )
1152 wxString objectId = content.AfterLast(
':' );
1154 if(
auto blob =
get_opt( aBlobMap, objectId ) )
1156 wxString blobUrl = blob->url;
1158 if( blobUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
1160 wxArrayString paramsArr =
1161 wxSplit( blobUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
1163 if( paramsArr.size() > 0 )
1164 mimeType = paramsArr[0];
1166 base64Data = blobUrl.AfterFirst(
',' );
1171 if( mimeType.empty() || base64Data.empty() )
1174 wxMemoryBuffer buf = wxBase64Decode( base64Data );
1176 if( mimeType == wxS(
"image/svg+xml" ) )
1192 schImporter.
SetScale( pixelScale );
1198 svgImportPlugin.
Import();
1200 for( std::unique_ptr<EDA_ITEM>& item : schImporter.
GetItems() )
1204 for(
double i = angle; i > 0; i -= 90 )
1209 schItem->
Rotate( kstart,
false );
1213 schItem->
Rotate( kstart,
false );
1218 schItem->
Rotate( kstart,
false );
1233 createdItems.emplace_back( schItem );
1238 std::unique_ptr<SCH_BITMAP> bitmap = std::make_unique<SCH_BITMAP>();
1241 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
1242 & ~wxImage::Load_Verbose );
1246 VECTOR2D kcenter = kstart + ksize / 2;
1251 bitmap->SetPosition( kcenter );
1253 for(
double i = angle; i > 0; i -= 90 )
1254 bitmap->Rotate( kstart,
false );
1257 bitmap->MirrorHorizontally( kstart.
x );
1259 createdItems.push_back( std::move( bitmap ) );
1266 for(
const auto& [wireId, wireRow] : wireRows )
1268 auto geomIt = wireGeometry.find( wireId );
1269 if( geomIt == wireGeometry.end() )
1272 const std::vector<const EASYEDAPRO::V3_ROW*>& lineRows = geomIt->second;
1274 bool firstPointSet =
false;
1292 if( !firstPointSet )
1295 firstPointSet =
true;
1298 std::unique_ptr<SCH_LINE> line = std::make_unique<SCH_LINE>(
1302 createdItems.push_back( std::move( line ) );
1306 bool netVisible =
false;
1308 bool netPosSet =
false;
1309 wxString netAlign = wxS(
"LEFT_BOTTOM" );
1310 int netRotation = 0;
1312 if(
auto attrRows =
get_opt( parentedRows, wireId ) )
1316 if( row->
type != wxS(
"ATTR" ) )
1339 if( netVisible && !netName.IsEmpty() && firstPointSet )
1341 VECTOR2D labelPos = netPosSet ? netPos : firstPoint;
1343 std::unique_ptr<SCH_LABEL> label = std::make_unique<SCH_LABEL>(
1348 if( netAlign.StartsWith( wxS(
"RIGHT" ) ) )
1350 else if( netAlign.StartsWith( wxS(
"LEFT" ) ) )
1353 int rot = netRotation % 360;
1361 for(
int i = 0; i < rot; i += 90 )
1365 label->SetSpinStyle( spinStyle );
1367 createdItems.push_back( std::move( label ) );
1372 for(
const auto& [parentId, rows] : parentedRows )
1375 std::map<wxString, std::pair<EASYEDAPRO::SCH_ATTR, const EASYEDAPRO::V3_ROW*>> attributes;
1379 if( row->
type == wxS(
"COMPONENT" ) )
1383 else if( row->
type == wxS(
"ATTR" ) )
1386 attributes.emplace( attr.
key, std::make_pair( attr, row ) );
1393 auto deviceAttrIt = attributes.find(
"Device" );
1394 auto symbolAttrIt = attributes.find(
"Symbol" );
1396 std::map<wxString, wxString> compAttrs;
1398 if( deviceAttrIt != attributes.end() && !deviceAttrIt->second.first.value.IsEmpty() )
1402 if( deviceData.
found )
1403 compAttrs = std::move( deviceData.
attributes );
1408 if( symbolAttrIt != attributes.end() && !symbolAttrIt->second.first.value.IsEmpty() )
1409 symbolId = symbolAttrIt->second.first.value;
1411 symbolId =
get_def( compAttrs, wxS(
"Symbol" ), wxEmptyString );
1413 if( symbolId.IsEmpty() )
1415 wxLogTrace(
traceEasyEdaIo, wxT(
"EasyEDA Pro v3 component '%s': missing Symbol attribute, skipping." ),
1420 auto it = aSymbolMap.find( symbolId );
1421 if( it == aSymbolMap.end() )
1424 wxLogTrace(
traceEasyEdaIo,
"Symbol of '%s' with uuid '%s' not found.", compName, symbolId );
1434 if( !unitName.IsEmpty() )
1441 wxT(
"EasyEDA Pro v3 component '%s': partId '%s' not found in "
1442 "symbol '%s', using unit 1." ),
1443 parentId, unitName, symbolId );
1450 if( deviceAttrIt != attributes.end() && !deviceAttrIt->second.first.value.IsEmpty() )
1454 if( !deviceLibName.empty() )
1455 libItemName = deviceLibName;
1460 auto schSym = std::make_unique<SCH_SYMBOL>( newLibSymbol, libId,
1464 schSym->SetFootprintFieldText( newLibSymbol.
GetFootprint() );
1466 auto footprintAttrIt = attributes.find( wxS(
"Footprint" ) );
1468 wxString resolvedFootprint;
1470 if( footprintAttrIt != attributes.end() && !footprintAttrIt->second.first.value.IsEmpty() )
1472 aProject, aLibName );
1475 aProject, aLibName );
1477 if( !resolvedFootprint.IsEmpty() )
1478 schSym->SetFootprintFieldText( resolvedFootprint );
1485 for(
double i = rotation; i > 0; i -= 90 )
1486 schSym->Rotate(
VECTOR2I(),
true );
1489 schSym->MirrorHorizontally( 0 );
1497 auto nameAttrIt = attributes.find( wxS(
"Name" ) );
1499 if( nameAttrIt != attributes.end() && !nameAttrIt->second.first.value.IsEmpty() )
1500 netName = nameAttrIt->second.first.value;
1502 netName =
get_def( compAttrs, wxS(
"Name" ), wxEmptyString );
1504 if( netName.IsEmpty() )
1509 std::vector<SCH_PIN*> pins = schSym->GetPins( &aSchematic->
CurrentSheet() );
1510 SCH_PIN*
pin = pins.empty() ? nullptr : pins.front();
1512 VECTOR2I labelPos = schSym->GetPosition();
1518 labelPos =
pin->GetPosition();
1520 switch(
pin->PinDrawOrient( schSym->GetTransform() ) )
1529 switch(
pin->GetType() )
1553 std::unique_ptr<SCH_GLOBALLABEL> label =
1554 std::make_unique<SCH_GLOBALLABEL>( labelPos, netName );
1555 label->SetSpinStyle( spinStyle );
1556 label->SetShape( labelShape );
1558 bool labelVisible = !netName.IsEmpty();
1560 if( nameAttrIt != attributes.end() && nameAttrIt->second.second )
1566 && !netName.IsEmpty();
1569 wxString fontFamily =
1572 if( !color.empty() && color.StartsWith( wxS(
"#" ) ) )
1573 label->SetTextColor(
COLOR4D( color ) );
1575 if( fontFamily != wxS(
"Arial" )
1576 && !fontFamily.IsSameAs( wxS(
"default" ),
false ) )
1584 label->SetVisible( labelVisible );
1586 createdItems.push_back( std::move( label ) );
1594 auto globalNetNameAttrIt = attributes.find(
"Global Net Name" );
1595 auto nameAttrIt = attributes.find(
"Name" );
1596 wxString globalNetNameFromProject =
1597 get_def( compAttrs,
"Global Net Name", wxEmptyString );
1598 wxString nameFromProject =
get_def( compAttrs,
"Name", wxEmptyString );
1600 const std::pair<EASYEDAPRO::SCH_ATTR, const EASYEDAPRO::V3_ROW*>* valueSource =
nullptr;
1602 if( globalNetNameAttrIt != attributes.end() )
1603 valueSource = &globalNetNameAttrIt->second;
1604 else if( nameAttrIt != attributes.end() )
1605 valueSource = &nameAttrIt->second;
1607 wxString globalNetName;
1614 if( globalNetNameAttrIt != attributes.end()
1615 && !globalNetNameAttrIt->second.first.value.IsEmpty() )
1617 globalNetName = globalNetNameAttrIt->second.first.value;
1619 else if( nameAttrIt != attributes.end()
1620 && !nameAttrIt->second.first.value.IsEmpty() )
1622 globalNetName = nameAttrIt->second.first.value;
1624 else if( !globalNetNameFromProject.IsEmpty() )
1626 globalNetName = globalNetNameFromProject;
1628 else if( !nameFromProject.IsEmpty() )
1630 globalNetName = nameFromProject;
1639 if( valueSource && valueSource->second )
1645 bool valueFromNameAttr = ( nameAttrIt != attributes.end()
1646 && valueSource == &nameAttrIt->second );
1650 if( attrRotation < 0 )
1651 attrRotation += 360;
1653 bool hasExplicitStyleOrPosition =
1660 || attrRotation != 0;
1662 attr.
value = globalNetName;
1664 if( !globalNetName.IsEmpty() )
1666 else if( valueVisibleMissing )
1669 if( valueFromNameAttr && !hasExplicitStyleOrPosition )
1673 if( !globalNetName.IsEmpty() )
1675 else if( valueVisibleMissing )
1681 compAttrs, schSym.get(), attrRow->
inner );
1683 if( !globalNetName.IsEmpty() )
1690 valueField->
SetVisible( !globalNetName.IsEmpty() );
1693 for(
SCH_PIN*
pin : schSym->GetAllLibPins() )
1694 pin->SetName( globalNetName );
1696 schSym->SetRef( &aSchematic->
CurrentSheet(), wxS(
"#PWR?" ) );
1702 auto designatorAttrIt = attributes.find(
"Designator" );
1704 bool hasReferenceValue =
false;
1706 if( designatorAttrIt != attributes.end() )
1712 schSym.get(), attrRow->
inner );
1714 if( !attr.
value.IsEmpty() )
1717 hasReferenceValue =
true;
1721 if( !hasReferenceValue )
1728 [&](
const wxString& attrKey,
const wxString& value )
1730 SCH_FIELD* field = schSym->FindFieldCaseInsensitive( attrKey );
1739 wxString description =
get_def( compAttrs, wxS(
"Description" ), wxEmptyString );
1741 if( !description.empty() )
1747 auto valueAttrIt = attributes.find(
"Value" );
1748 auto nameAttrIt = attributes.find(
"Name" );
1750 wxString fallbackValue =
get_def( compAttrs, wxS(
"Value" ), wxEmptyString );
1752 if( fallbackValue.IsEmpty() )
1753 fallbackValue =
get_def( compAttrs, wxS(
"Name" ), wxEmptyString );
1755 const std::pair<EASYEDAPRO::SCH_ATTR, const EASYEDAPRO::V3_ROW*>* valueSource =
nullptr;
1757 if( valueAttrIt != attributes.end() && valueAttrIt->second.first.valVisible )
1758 valueSource = &valueAttrIt->second;
1759 else if( nameAttrIt != attributes.end() && nameAttrIt->second.first.valVisible )
1760 valueSource = &nameAttrIt->second;
1761 else if( valueAttrIt != attributes.end() )
1762 valueSource = &valueAttrIt->second;
1763 else if( nameAttrIt != attributes.end() )
1764 valueSource = &nameAttrIt->second;
1768 if( valueAttrIt != attributes.end() && !valueAttrIt->second.first.value.IsEmpty() )
1769 valueText = valueAttrIt->second.first.value;
1770 else if( nameAttrIt != attributes.end() && !nameAttrIt->second.first.value.IsEmpty() )
1771 valueText = nameAttrIt->second.first.value;
1773 valueText = fallbackValue;
1777 if( !valueText.IsEmpty() )
1779 if( valueSource && valueSource->second )
1782 attr.
value = valueText;
1785 schSym.get(), valueSource->second->inner );
1798 for(
const auto& [key, attrPair] : attributes )
1800 if( key == wxS(
"Designator" ) || key == wxS(
"Device" ) || key == wxS(
"Symbol" )
1801 || key == wxS(
"Name" ) || key == wxS(
"Value" ) )
1814 if( key == wxS(
"Footprint" ) )
1825 if( key == wxS(
"Footprint" ) )
1832 compAttrs, schSym.get(), attrRow->
inner );
1837 schSym.get(), attrRow->
inner );
1843 createdItems.push_back( std::move( schSym ) );
1847 bool hasBBox =
false;
1849 for( std::unique_ptr<SCH_ITEM>& item : createdItems )
1856 itemBBox = item->GetBoundingBox();
1860 sheetBBox = itemBBox;
1865 sheetBBox.
Merge( itemBBox );
1873 const int margin =
schIUScale.MilsToIU( 200 );
1876 -sheetBBox.
GetTop() + margin );
1880 offset.
x =
KiROUND( offset.
x / alignGrid ) * alignGrid;
1881 offset.
y =
KiROUND( offset.
y / alignGrid ) * alignGrid;
1889 for( std::unique_ptr<SCH_ITEM>& item : createdItems )
1891 item->Move( offset );
1892 screen->
Append( item.release() );
1897 for( std::unique_ptr<SCH_ITEM>& item : createdItems )
1898 screen->
Append( item.release() );